Convert a string to URL in asp.net mvc [duplicate] - asp.net-mvc

How can I quickly determine what the root URL is for my ASP.NET MVC application? I.e., if IIS is set to serve my application at http://example.com/foo/bar, then I'd like to be able to get that URL in a reliable way that doesn't involve getting the current URL from the request and chopping it up in some fragile way that breaks if I re-route my action.
The reason that I need the base URL is that this web application calls another one that needs the root to the caller web application for callback purposes.

Assuming you have a Request object available, you can use:
string.Format("{0}://{1}{2}", Request.Url.Scheme, Request.Url.Authority, Url.Content("~"));
If it's not available, you can get to it via the context:
var request = HttpContext.Current.Request

So none of the ones listed here worked for me, but using a few of the answers, I got something working:
public string GetBaseUrl()
{
var request = HttpContext.Current.Request;
var appUrl = HttpRuntime.AppDomainAppVirtualPath;
if (appUrl != "/")
appUrl = "/" + appUrl;
var baseUrl = string.Format("{0}://{1}{2}", request.Url.Scheme, request.Url.Authority, appUrl);
return baseUrl;
}
Update for ASP.NET Core / MVC 6:
ASP.NET Core makes this process a bit more painful, especially if you are deep in your code. You have 2 options to get at the HttpContext
1) Pass it in from your controller:
var model = new MyClass(HttpContext);
then in model:
private HttpContext currentContext;
public MyClass(HttpContext currentContext)
{
this.currentContext = currentContext;
}
2) Perhaps the cleaner way is to inject it into your class, which starts with registering the types in your Startup:
public void ConfigureServices(IServiceCollection services)
{
// Add framework services.
services.AddMvc();
services.AddTransient<MyClass, MyClass>();
services.TryAddSingleton<IHttpContextAccessor, HttpContextAccessor>();
}
then have it injected for you like this:
private HttpContext currentContext;
public MyClass(IHttpContextAccessor httpContextAccessor)
{
currentContext = httpContextAccessor.HttpContext;
}
in either case, here is the updated for .NET Core GetBaseUrl():
public string GetBaseUrl()
{
var request = currentContext.Request;
var host = request.Host.ToUriComponent();
var pathBase = request.PathBase.ToUriComponent();
return $"{request.Scheme}://{host}{pathBase}";
}

In Code:
Url.Content("~/");
MVC3 Razor Syntax:
#Url.Content("~/")

Maybe it is extension or modification of the answers posted here but I use simply the following line and it works:
Request.Url.GetLeftPart(UriPartial.Authority) + Url.Content("~")
When my path is: http://host/iis_foldername/controller/action
then I receive : http://host/iis_foldername/

The following snippet works nicely for me in MVC4, and doesn't need an HttpContext available:
System.Web.HttpRuntime.AppDomainAppVirtualPath

The trick with relying upon IIS is that IIS bindings can be different from your public URLs (WCF I'm looking at you), especially with multi-homed production machines. I tend to vector toward using configuration to explicitly define the "base" url for external purposes as that tends to be a bit more successful than extracting it from the Request object.

For an absolute base URL use this. Works with both HTTP and HTTPS.
new Uri(Request.Url, Url.Content("~"))

This is a conversion of an asp.net property to MVC . It's a pretty much all singing all dancing get root url method.
Declare a helper class:
namespace MyTestProject.Helpers
{
using System.Web;
public static class PathHelper
{
public static string FullyQualifiedApplicationPath(HttpRequestBase httpRequestBase)
{
string appPath = string.Empty;
if (httpRequestBase != null)
{
//Formatting the fully qualified website url/name
appPath = string.Format("{0}://{1}{2}{3}",
httpRequestBase.Url.Scheme,
httpRequestBase.Url.Host,
httpRequestBase.Url.Port == 80 ? string.Empty : ":" + httpRequestBase.Url.Port,
httpRequestBase.ApplicationPath);
}
if (!appPath.EndsWith("/"))
{
appPath += "/";
}
return appPath;
}
}
}
Usage:
To use from a controller:
PathHelper.FullyQualifiedApplicationPath(ControllerContext.RequestContext.HttpContext.Request)
To use in a view:
#using MyTestProject.Helpers
PathHelper.FullyQualifiedApplicationPath(Request)

In MVC _Layout.cshtml:
<base href="#Request.GetBaseUrl()" />
Thats what we use!
public static class ExtensionMethods
{
public static string GetBaseUrl(this HttpRequestBase request)
{
if (request.Url == (Uri) null)
return string.Empty;
else
return request.Url.Scheme + "://" + request.Url.Authority + VirtualPathUtility.ToAbsolute("~/");
}
}

This works fine for me (also with a load balancer):
#{
var urlHelper = new UrlHelper(Html.ViewContext.RequestContext);
var baseurl = urlHelper.Content(“~”);
}
<script>
var base_url = "#baseurl";
</script>
Especially if you are using non-standard port numbers, using Request.Url.Authority appears like a good lead at first, but fails in a LB environment.

You could have a static method that looks at HttpContext.Current and decides which URL to use (development or live server) depending on the host ID. HttpContext might even offer some easier way to do it, but this is the first option I found and it works fine.

You can use the following script in view:
<script type="text/javascript">
var BASE_URL = '<%= ResolveUrl("~/") %>';
</script>

For ASP.NET MVC 4 it is a bit different:
string url = HttpContext.Request.Url.AbsoluteUri;

This is working in ASP .NET MVC 4
In any controller action you can write:
1stline gets the whole url+Query String.
2nd line remove local path & query ,last '/' symbol.
3rd line add '/' symbol at last position.
Uri url = System.Web.HttpContext.Current.Request.Url;
string UrlLink = url.OriginalString.Replace(url.PathAndQuery,"");
UrlLink = String.Concat(UrlLink,"/" );

in simple html and ASP.NET or ASP.NET MVC if you are using tag:
About us

For url with aplication alias like http://example.com/appAlias/... You can try this:
var req = HttpContext.Current.Request;
string baseUrl = string.Format("{0}://{1}/{2}", req.Url.Scheme, req.Url.Authority, req.ApplicationPath);

On the webpage itself:
<input type="hidden" id="basePath" value="#string.Format("{0}://{1}{2}",
HttpContext.Current.Request.Url.Scheme,
HttpContext.Current.Request.Url.Authority,
Url.Content("~"))" />
In the javascript:
function getReportFormGeneratorPath() {
var formPath = $('#reportForm').attr('action');
var newPath = $("#basePath").val() + formPath;
return newPath;
}
This works for my MVC project, hope it helps

This was my solution (using .net core 3.1, in an api controller):
string baseUrl = $"{Request.Scheme}://{Request.Headers.Where(h => h.Key == "Host").First().Value}";

For MVC 4:
String.Format("{0}://{1}{2}", Url.Request.RequestUri.Scheme, Url.Request.RequestUri.Authority, ControllerContext.Configuration.VirtualPathRoot);

I put this in the head of my _Layout.cshtml
<base href="~/" />

Maybe it is a better solution.
#{
var baseUrl = #Request.Host("/");
}
using
Base URL

#{
var baseurl = Request.Url.Scheme + "://" + Request.Url.Host + ":" + Request.Url.Port + Url.Content("~");
}
#baseurl
--output
http://localhost:49626/TEST/

In .net core 3.1 I used this approach:
$"{Request.Scheme}://{Request.Host}{Url.Content("~/")}"

The following worked solidly for me
var request = HttpContext.Request;
var appUrl = System.Web.HttpRuntime.AppDomainAppVirtualPath;
if (appUrl != "/")
appUrl = "/" + appUrl + "/";
var newUrl = string.Format("{0}://{1}{2}{3}/{4}", request.Url.Scheme, request.UrlReferrer.Host, appUrl, "Controller", "Action");

Also you can use this. For the razor pages, it is better to use it than the others.
https://ml-software.ch/posts/getting-the-base-url-for-an-asp-net-core-mvc-web-application-in-your-static-javascript-files
<!DOCTYPE html>
<html>
<head>
<meta charset="utf-8" />
<base href='#Url.AbsoluteContent("~/")'>
<title>#ViewBag.Title - ASP.NET Core Web Application</title>
<!-- ... -->
</head>
<body>

add this function in static class in project like utility class:
utility.cs content:
public static class Utility
{
public static string GetBaseUrl()
{
var request = HttpContext.Current.Request;
var urlHelper = new UrlHelper(request.RequestContext);
var baseUrl = $"{request.Url.Scheme}://{request.Url.Authority}{urlHelper.Content("~")}";
return baseUrl;
}
}
use this code any where and enjoy it:
var baseUrl = Utility.GetBaseUrl();

Simply in one line get BaseUrl
string baseUrl = new Uri(Request.Url, Url.Content("~")).AbsoluteUri;
//output example: https://stackoverflow.com

Related

Html helper messes with relative url's on IIS, ok in IISExpress and Azure

Ok,
I use MVC with .Net core, I have a html helper that formats a column header a bit.
public static HtmlString SortableColumnName(string controller, string sortFieldOrder, string columnName, string displayName)
{
string[] split = sortFieldOrder.Split('_');
string resultSort;
string sortField = split[0];
string sortOrder = split[1];
if (columnName == sortField)
{
if (sortOrder == "asc")
{
resultSort = columnName + "_desc";
return new HtmlString($"<a href='/{controller}/index?sortFieldOrder={resultSort}'>{displayName}</a><span class='fas fa-long-arrow-alt-down'></span>");
}
else
{
resultSort = columnName + "_asc";
return new HtmlString($"<a href='/{controller}/index?sortFieldOrder={resultSort}'>{displayName}</a><span class='fas fa-long-arrow-alt-up'></span>");
}
}
else
{
resultSort = columnName + "_asc";
return new HtmlString($"<a href='/{controller}/index?sortFieldOrder={resultSort}'>{displayName}</a>");
}
}
This has worked well in the past (.net 4.7 on IIS and Azure) but now the code base is .Net Core.
And here is the funny part. I always use "~/" and these links get expanded correct.
So the name of the site is correct in the url.
<script src="~/lib/jquery/dist/jquery.min.js"></script>
is expanded (correct) to
<script src="/MvcPortal/lib/jquery/dist/jquery.min.js"></script>
However, if i put a "~" in my HtmlHelper code it will not expand but stay a "~".
Because it is deployed to IIS my url is missing something. (Works on azure and iisExpres)
Url's created with the taghelpers are correct:
<a href="/MvcPortal/PSqueries/Create">
But url's created with the HtmlHelper look like this:
<a href='/PSQueries/index?sortFieldOrder=PSQueryName_desc'>Query Name</a>
They are missing the virtual directory name....
I tried a lot but cannot figure out how to solve this.
I think I am struggeling with the Tilde/Slash option. (https://www.davidhayden.me/blog/asp.net-mvc-4-the-new-tilde-slash-feature-in-razor-2)

MVC redirect changing domain

I am trying to redirect to a page in MVC website so I have the following code in my controller:
return Redirect("/test");
I am running my site locally through IIS on a domain of test.local and when I hit this controller I would expect to go off to http://test.local/test but instead, for some reason, it is redirecting me to http://localhost/test
Does anyone know how I can make it stay on the same domain without having to put the domain name into the redirect or do I have to include the domain name as well?
Please note as well that I am unable to use RedirectToRoute or RedirectToAction as the url is a separate application (under the same domain as the current site)
I have created a extension method that provides to redirect on the same domain. Maybe this helps
public static class ControllerExtension
{
public static string FullyQualifiedApplicationPath
{
get
{
//Return variable declaration
var appPath = string.Empty;
//Getting the current context of HTTP request
var context = HttpContext.Current;
//Checking the current context content
if (context != null)
{
//Formatting the fully qualified website url/name
appPath = string.Format("{0}://{1}{2}{3}",
context.Request.Url.Scheme,
context.Request.Url.Host,
context.Request.Url.Port == 80
? string.Empty
: ":" + context.Request.Url.Port,
context.Request.ApplicationPath);
}
if (!appPath.EndsWith("/"))
appPath += "/";
return appPath;
}
}
public static RedirectResult RedirectSameDomain(this Controller controller, string url)
{
return new RedirectResult(FullyQualifiedApplicationPath + url);
}
}
You can use it like this
return this.RedirectSameDomain("/test");
Thanks to SO User Brian Hasden for FullyQualifiedApplicationPath and his answer on How can I get the root domain URI in ASP.NET?

Azure: Read files from App_Data [duplicate]

What is the correct way to find the absolute path to the App_Data folder from a Controller in an ASP.NET MVC project? I'd like to be able to temporarily work with an .xml file and I don't want to hardcode the path.
This does not work:
[HandleError]
public class HomeController : Controller
{
public ActionResult Index()
{
string path = VirtualPathUtility.ToAbsolute("~/App_Data/somedata.xml");
//.... do whatever
return View();
}
}
I think outside of the web context VirtualPathUtility.ToAbsolute() doesn't work.
string path comes back as "C:\App_Data\somedata.xml"
Where should I determine the path of the .xml file in an MVC app?
global.asax and stick it an application-level variable?
ASP.NET MVC1 -> MVC3
string path = HttpContext.Current.Server.MapPath("~/App_Data/somedata.xml");
ASP.NET MVC4
string path = Server.MapPath("~/App_Data/somedata.xml");
MSDN Reference:
HttpServerUtility.MapPath Method
string path = AppDomain.CurrentDomain.GetData("DataDirectory").ToString();
This is probably a more "correct" way of getting it.
I try to get in the habit of using HostingEnvironment instead of Server as it works within the context of WCF services too.
HostingEnvironment.MapPath(#"~/App_Data/PriceModels.xml");
The most correct way is to use HttpContext.Current.Server.MapPath("~/App_Data");. This means you can only retrieve the path from a method where the HttpContext is available. It makes sense: the App_Data directory is a web project folder structure [1].
If you need the path to ~/App_Data from a class where you don't have access to the HttpContext you can always inject a provider interface using your IoC container:
public interface IAppDataPathProvider
{
string GetAppDataPath();
}
Implement it using your HttpApplication:
public class AppDataPathProvider : IAppDataPathProvider
{
public string GetAppDataPath()
{
return MyHttpApplication.GetAppDataPath();
}
}
Where MyHttpApplication.GetAppDataPath looks like:
public class MyHttpApplication : HttpApplication
{
// of course you can fetch&store the value at Application_Start
public static string GetAppDataPath()
{
return HttpContext.Current.Server.MapPath("~/App_Data");
}
}
[1] http://msdn.microsoft.com/en-us/library/ex526337%28v=vs.100%29.aspx
Phil Haak has an example that I think is a bit more stable when dealing with paths with crazy "\" style directory separators. It also safely handles path concatenation. It comes for free in System.IO
var fileName = Path.GetFileName(file.FileName);
var path = Path.Combine(Server.MapPath("~/App_Data/uploads"), fileName);
However, you could also try "AppDomain.CurrentDomain.BaseDirector" instead of "Server.MapPath".
string filePath = HttpContext.Current.Server.MapPath("~/folderName/filename.extension");
OR
string filePath = HttpContext.Server.MapPath("~/folderName/filename.extension");
This way i got the hosting path.
using Microsoft.AspNetCore.Hosting;
using Microsoft.AspNetCore.Mvc;
namespace IHostingEnvironmentExample.Controllers
{
public class HomeController : Controller
{
private IHostingEnvironment _env;
public HomeController(IHostingEnvironment env)
{
_env = env;
}
public IActionResult Index()
{
var webRoot = _env.WebRootPath;
var file = System.IO.Path.Combine(webRoot, "test.txt");
System.IO.File.WriteAllText(file, "Hello World!");
return View();
}
}
}
https://forums.asp.net/t/1696005.aspx?How+to+get+Local+Server+path+in+mvc
string Index = i;
string FileName = "Mutton" + Index + ".xml";
XmlDocument xmlDoc = new XmlDocument();
var path = Path.Combine(Server.MapPath("~/Content/FilesXML"), FileName);
xmlDoc.Load(path); // Can use xmlDoc.LoadXml(YourString);
this is the best Solution to get the path what is exactly need for now

A localized scriptbundle solution

Hi I am currently using the asp.net MVC 4 rc with System.Web.Optimization. Since my site needs to be localized according to the user preference I am working with the jquery.globalize plugin.
I would very much want to subclass the ScriptBundle class and determine what files to bundle according to the System.Threading.Thread.CurrentThread.CurrentUICulture. That would look like this:
bundles.Add(new LocalizedScriptBundle("~/bundles/jqueryglobal")
.Include("~/Scripts/jquery.globalize/globalize.js")
.Include("~/Scripts/jquery.globalize/cultures/globalize.culture.{0}.js",
() => new object[] { Thread.CurrentThread.CurrentUICulture })
));
For example if the ui culture is "en-GB" I would like the following files to be picked up (minified of course and if possible cached aswell until a script file or the currentui culture changes).
"~/Scripts/jquery.globalize/globalize.js"
"~/Scripts/jquery.globalize/globalize-en-GB.js" <-- if this file does not exist on the sever file system so fallback to globalize-en.js.
I tried overloading the Include method with something like the following but this wont work because it is not evaluated on request but on startup of the application.
public class LocalizedScriptBundle : ScriptBundle
{
public LocalizedScriptBundle(string virtualPath)
: base(virtualPath) {
}
public Bundle Include(string virtualPathMask, Func<object[]> getargs) {
string virtualPath = string.Format(virtualPathMask, getargs());
this.Include(virtualPath);
return this;
}
}
Thanks
Constantinos
That is correct, bundles should only be configured pre app start. Otherwise in a multi server scenario, if the request for the bundle is routed to a different server other than the one that served the page, the request for the bundle resource would not be found.
Does that make sense? Basically all of your bundles need to be configured and defined in advance, and not dynamically registered on a per request basis.
take a look: https://stackoverflow.com/questions/18509506/search-and-replace-in-javascript-before-bundling
I coded this way for my needs:
public class MultiLanguageBundler : IBundleTransform
{
public void Process(BundleContext context, BundleResponse bundle)
{
var content = new StringBuilder();
var uicult = Thread.CurrentThread.CurrentUICulture.ToString();
var localizedstrings = GetFileFullPath(uicult);
if (!File.Exists(localizedstrings))
{
localizedstrings = GetFileFullPath(string.Empty);
}
using (var fs = new FileStream(localizedstrings, FileMode.Open, FileAccess.Read))
{
var m_streamReader = new StreamReader(fs);
var str = m_streamReader.ReadToEnd();
content.Append(str);
content.AppendLine();
}
foreach (var file in bundle.Files)
{
var f = file.VirtualFile.Name ?? "";
if (!f.Contains("localizedstrings"))
{
using (var reader = new StreamReader(VirtualPathProvider.OpenFile(file.VirtualFile.VirtualPath)))
{
content.Append(reader.ReadToEnd());
content.AppendLine();
}
}
}
bundle.ContentType = "text/javascript";
bundle.Content = content.ToString();
}
private string GetFileFullPath(string uicult)
{
if (uicult.StartsWith("en"))
uicult = string.Empty;
else if (!string.IsNullOrEmpty(uicult))
uicult = ("." + uicult);
return Kit.ToAbsolutePath(string.Format("~/Scripts/locale/localizedstrings{0}.js", uicult));
}
}

URLs with slash in parameter?

Question:
I am creating a wiki software, basically a clone of wikipedia/mediawiki, but in ASP.NET MVC (the MVC is the point, so don't recommend me ScrewTurn).
Now I have a question:
I use this route mapping, to route a URL like:
http://en.wikipedia.org/wiki/ASP.NET
routes.MapRoute(
"Wiki", // Routenname
//"{controller}/{action}/{id}", // URL mit Parametern
"wiki/{id}", // URL mit Parametern
new { controller = "Wiki", action = "dbLookup", id = UrlParameter.Optional } // Parameterstandardwerte
);
Now it just occured to me, that there might be titles like 'AS/400':
http://en.wikipedia.org/wiki/AS/400
Incidentially, there is also this one (title 'Slash'):
http://en.wikipedia.org/wiki//
And this one:
http://en.wikipedia.org/wiki//dev/null
Overall, Wikipedia seems to have a list of interesting titles like this:
http://en.wikipedia.org/wiki/Wikipedia:Articles_with_slashes_in_title
How do I make routes like this route correctly ?
Edit:
Something like:
If the URL starts with /Wiki/, and if it doesn't start with /wiki/Edit/
(but not /Wiki/Edit)
then pass all the rest of the URL as Id.
Edit:
Hmm, just another problem:
How can I route this one:
http://en.wikipedia.org/wiki/C&A
Wikipedia can...
Edit:
According to wikipedia, due to clashes with wikitext syntax, only the following characters can never be used in page titles (nor are they supported by DISPLAYTITLE):
# < > [ ] | { }
http://en.wikipedia.org/wiki/Wikipedia:Naming_conventions_(technical_restrictions)#Forbidden_characters
Edit:
To allow * and &, put
<httpRuntime requestPathInvalidCharacters="" />
into section <system.web> in file web.config
(Found here: http://www.christophercrooker.com/use-any-characters-you-want-in-your-urls-with-aspnet-4-and-iis)
You could use a catchall route to capture everything that follows the wiki part of the url into the id token:
routes.MapRoute(
"Wiki",
"wiki/{*id}",
new { controller = "Wiki", action = "DbLookup", id = UrlParameter.Optional }
);
Now if you have the following request: /wiki/AS/400 it will map to the following action on the Wiki controller:
public ActionResult DbLookup(string id)
{
// id will equal AS/400 here
...
}
As far as /wiki// is concerned I believe you will get a 400 Bad Request error from the web server before this request ever reaches the ASP.NET pipeline. You may checkout the following blog post.
in Attribute Routing in mvc i had the same problem having / in string abc/cde in HttpGet
[Route("verifytoken/{*token}")]
[AllowAnonymous]
[HttpGet]
public ActionResult VerifyToken(string token)
{
//logic here
}
so you have to place * because after this it will be considered as parameter
#Darin: Well, that much is obvious, the question is: Why ? controller
+ action + id are given, it's like it's passing all these to routing again... – Quandary Jun 13 '11 at 17:38
Quandry - maybe you have already figured this out since your question is over a year old, but when you call RedirectToAction, you are actually sending an HTTP 302 response to the browser, which causes the browser to make a GET request to the specified action. Hence, the infinite loop you are seeing.
See: Controller.RedirectToAction Method
Still as an option write in the file Global.asax:
var uri = Context.Request.Url.ToString();
if (UriHasRedundantSlashes(uri))
{
var correctUri = RemoveRedundantSlashes(uri);
Response.RedirectPermanent(correctUri);
}
}
private string RemoveRedundantSlashes(string uri)
{
const string http = "http://";
const string https = "https://";
string prefix = string.Empty;
if (uri.Contains(http))
{
uri = uri.Replace(http, string.Empty);
prefix = http;
}
else if (uri.Contains(https))
{
uri = uri.Replace(https, string.Empty);
prefix = https;
}
while (uri.Contains("//"))
{
uri = uri.Replace("//", "/");
}
if (!string.IsNullOrEmpty(prefix))
{
return prefix + uri;
}
return uri;
}
private bool UriHasRedundantSlashes(string uri)
{
const string http = "http://";
const string https = "https://";
if (uri.Contains(http))
{
uri = uri.Replace(http, string.Empty);
}
else if (uri.Contains(https))
{
uri = uri.Replace(https, string.Empty);
}
return uri.Contains("//");
}

Resources