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)
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
I’ve gotten stuck on an “Object reference not set to an instance of an object” error message.
We’re trying to use a PagePart field that is attached to the Page type to dynamically link a CSS file in the HEAD of a layout file. See below code.
<!-- DYNAMIC CSS-->
var contentItem = Model.ContentItem;
var pagePart = (PagePart)contentItem.PagePart;
if (!String.IsNullOrWhiteSpace(pagePart.FestivalProgramName))
{
<link ref="#Url.Content("/Themes/MyTheme/Styles/festival-programs/" + pagePart.FestivalProgramName + ".css")" rel="stylesheet" type="text/css">
}
This is in a file called:
Layout.cshtml
Something is wrong about this (obviously) since pagePart is “null” when I Attach to Debugger and look. I get that the Layout file doesn’t know that it’s associated with a “Page” Content Type but this layout is only used with Pages. Anyway, this is very similar to code that works elsewhere in our Orchard site. Any help or advice is hugely appreciated!
Thanks, T
In the Layout, the Model is the Layout object. It has nothing to do whatsoever with whatever content is going to get rendered into the Content zone.
I think what you are trying to do should be done by overriding the Page template (Content-Page.Detail.cshtml). (Note the Detail part, you probably don't want to import every css when displaying multiple pages in summary)
In there you can do:
#{
var contentItem = Model.ContentItem; // The Page content item
var pagePart = contentItem.Page; // Note that casting to PagePart won't work, because it does not exist
if (!String.IsNullOrWhiteSpace(pagePart.FestivalProgramName.Value))
{
// "Orchard's" way to include styles
Style.Include("festival-programs/" + pagePart.FestivalProgramName.Value + ".css");
}
}
EDIT:
What you probably should do (I assume not every page is a festival page) is create a new Content Type: FestivalPage. Then attach the following parts to this content type (same as the Page content type):
Common
Publish later
Title
Autoroute
Body (Orchard 1.8.1 and lower)
Layout (Orchard 1.9.x)
Tags
Localization
Menu
And your field:
FestivalProgramName
Then create an alternate Content-FestivalPage.Detail.cshtml with the following content:
#using Orchard.Utility.Extensions;
#{
if (Model.Title != null) {
Layout.Title = Model.Title;
}
Model.Classes.Add("content-item");
var contentTypeClassName = ((string)Model.ContentItem.ContentType).HtmlClassify();
Model.Classes.Add(contentTypeClassName);
var tag = Tag(Model, "article");
var contentItem = Model.ContentItem; // The FestivalPage content item
var pagePart = contentItem.FestivalPage; // The FestivalPage part with the FestivalProgramName field
if (!String.IsNullOrWhiteSpace(pagePart.FestivalProgramName.Value))
{
// "Orchard's" way to include styles
Style.Include("festival-programs/" + pagePart.FestivalProgramName.Value + ".css");
}
}
// -- Default Orchard content --
#tag.StartElement
<header>
#Display(Model.Header)
#if (Model.Meta != null) {
<div class="metadata">
#Display(Model.Meta)
</div>
}
</header>
#Display(Model.Content)
#if(Model.Footer != null) {
<footer>
#Display(Model.Footer)
</footer>
}
#tag.EndElement
// ----
This way you won't get in the way with the normal pages of the application.
Thank you so much for responding. Your solution works but not in my case since I use the Layout Selector module and can't override at the Page.Detail level since that would imply one layout - or at least from my perspective it seems that way. I found another option though that does the trick.
We already take advantage of the Handlers class to insert META stuff into the HEAD of the page and thanks to your feedback and this thread Adding an element to page <head> in Orchard CMS, it dawned on me to use the same Handler to insert the CSS link.
PagePartHandler.cs.
using System;
using MyModuleName.Models;
using Orchard.ContentManagement.Handlers;
using Orchard.Core.Title.Models;
using Orchard.Data;
using Orchard.UI.Resources;
using Orchard.Utility.Extensions;
namespace MyModuleName.Handlers {
public class PagePartHandler : ContentHandler {
private readonly IResourceManager _resourceManager;
public PagePartHandler(
IRepository<PagePartRecord> repository,
IResourceManager resourceManager) {
_resourceManager = resourceManager;
Filters.Add(StorageFilter.For(repository));
OnGetDisplayShape<PagePart>(RegisterFestivalProgramStyle);
}
private void RegisterFestivalProgramStyle(BuildDisplayContext context, PagePart part) {
if (context.DisplayType != "Detail")
return;
if (String.IsNullOrWhiteSpace(part.FestivalProgramName))
return;
_resourceManager.RegisterLink(new LinkEntry
{
Rel = "stylesheet",
Type = "text/css",
Href = "/Themes/Bootstrap/Styles/festival-programs/" + part.FestivalProgramName + ".css"
});
}
}
}
This uses the tradition link style, not ResourceManifest.cs, but WORKS!
I have a textarea control that accepts input. I am trying to later render that text to a view by simply using:
#Model.CommentText
This is properly encoding any values. However, I want to replace the line break characters with <br /> and I can't find a way to make sure that the new br tags don't get encoded. I have tried using HtmlString but haven't had any luck yet.
Use the CSS white-space property instead of opening yourself up to XSS vulnerabilities!
<span style="white-space: pre-line">#Model.CommentText</span>
Try the following:
#MvcHtmlString.Create(Model.CommentText.Replace(Environment.NewLine, "<br />"))
Update:
According to marcind's comment on this related question, the ASP.NET MVC team is looking to implement something similar to the <%: and <%= for the Razor view engine.
Update 2:
We can turn any question about HTML encoding into a discussion on harmful user inputs, but enough of that already exists.
Anyway, take care of potential harmful user input.
#MvcHtmlString.Create(Html.Encode(Model.CommentText).Replace(Environment.NewLine, "<br />"))
Update 3 (Asp.Net MVC 3):
#Html.Raw(Html.Encode(Model.CommentText).Replace("\n", "<br />"))
Split on newlines (environment agnostic) and print regularly -- no need to worry about encoding or xss:
#if (!string.IsNullOrWhiteSpace(text))
{
var lines = text.Split(new[] { '\r', '\n' }, StringSplitOptions.RemoveEmptyEntries);
foreach (var line in lines)
{
<p>#line</p>
}
}
(remove empty entries is optional)
Omar's third solution as an HTML Helper would be:
public static IHtmlString FormatNewLines(this HtmlHelper helper, string input)
{
return helper.Raw(helper.Encode(input).Replace("\n", "<br />"));
}
Applying the DRY principle to Omar's solution, here's an HTML Helper extension:
using System.Web.Mvc;
using System.Text.RegularExpressions;
namespace System.Web.Mvc.Html {
public static class MyHtmlHelpers {
public static MvcHtmlString EncodedReplace(this HtmlHelper helper, string input, string pattern, string replacement) {
return new MvcHtmlString(Regex.Replace(helper.Encode(input), pattern, replacement));
}
}
}
Usage (with improved regex):
#Html.EncodedReplace(Model.CommentText, "[\n\r]+", "<br />")
This also has the added benefit of putting less onus on the Razor View developer to ensure security from XSS vulnerabilities.
My concern with Jacob's solution is that rendering the line breaks with CSS breaks the HTML semantics.
I needed to break some text into paragraphs ("p" tags), so I created a simple helper using some of the recommendations in previous answers (thank you guys).
public static MvcHtmlString ToParagraphs(this HtmlHelper html, string value)
{
value = html.Encode(value).Replace("\r", String.Empty);
var arr = value.Split('\n').Where(a => a.Trim() != string.Empty);
var htmlStr = "<p>" + String.Join("</p><p>", arr) + "</p>";
return MvcHtmlString.Create(htmlStr);
}
Usage:
#Html.ToParagraphs(Model.Comments)
I prefer this method as it doesn't require manually emitting markup. I use this because I'm rendering Razor Pages to strings and sending them out via email, which is an environment where the white-space styling won't always work.
public static IHtmlContent RenderNewlines<TModel>(this IHtmlHelper<TModel> html, string content)
{
if (string.IsNullOrEmpty(content) || html is null)
{
return null;
}
TagBuilder brTag = new TagBuilder("br");
IHtmlContent br = brTag.RenderSelfClosingTag();
HtmlContentBuilder htmlContent = new HtmlContentBuilder();
// JAS: On the off chance a browser is using LF instead of CRLF we strip out CR before splitting on LF.
string lfContent = content.Replace("\r", string.Empty, StringComparison.InvariantCulture);
string[] lines = lfContent.Split('\n', StringSplitOptions.None);
foreach(string line in lines)
{
_ = htmlContent.Append(line);
_ = htmlContent.AppendHtml(br);
}
return htmlContent;
}