ASP.NET MVC URL auto-resolution in CSS files - asp.net

In normal WebForms scenario, any root-relative URLs (e.g. ~/folder/file.txt) inside CSS files such as:
.form { background-image: url(~/Content/Images/form_bg.gif); }
will automatically get resolved during runtime if I specify
<head runat="server">
In the referencing page.
However, that is no longer happening on an ASP.NET MVC Beta1 website.
Is there a way I could enable this functionality without resorting to hacks or CSS-loader file? Like maybe HttpModules or something?
Or am I not desigining my website correctly? What is supposed to be a good design?
Since original ASP.NET WebForms already has this feature, I'd prefer to utilize any existing functionality if possible. But I don't have much clue.
This web application will be deployed in several environments where the ~ root folder might not be obvious.
EDIT: I mean the url in the file's CONTENT not the file's url itself.

I would not bother with the auto-root-finding ~ character. I understand that you want the same solution to work where the root directory differs between deployments, but within the CSS document you shouldn't have any problems using relative paths. The paths in the CSS document (to the image URL in your example) will always be relative to the location of the CSS file regardless of the path of any page that loads that CSS file. So if your images are in ~/Content/Images and your stylesheets are in ~/Content/Stylesheets, you'll always be able to use background-image: url(../Images/form_bg.gif); and it will work regardless of the location of the page that loads the stylesheet.
Is there a reason this wouldn't work?

One trick I have used in the past, was to actually make my CSS file have a .ASPX extension, and set the ContentType property in the page signature:
<%# Page Language="C#" ContentType="text/css" %>
body {
margin: 0;
padding: 0;
background: #C32605 url(<%= ResolveUrl("~/Content/themes/base/images/BodyBackground.png") %>) repeat-x;
font-family: Verdana, Arial, sans-serif;
font-size: small;
color: #d7f9ff;
}
This will ensure that the CSS file goes through the ASP.NET framework, and replaces the server side code with your relative path.

Here are some resources on implementing IHttpModule to intercept web requests to your app...
Write/adapt one to check for filetype (e.g. pseudocode: if (request ends with ".css") ...)
then use a regular expression to replace all instances of "~/" with System.Web.VirtualPathUtility.ToAbsolute("~/")
I don't know what this will do to performance, running every request through this kind of a filter, but you can probably fiddle with your web.config file and/or your MVC URL routes to funnel all .css requests through this kind of a filter while skipping past it for other files.
Come to think of it, you can probably achieve the same effect inside an ASP.NET MVC app by pointing all your CSS refrences at a special controller.action that performs this kind of preprocessing for you. i doubt that would be as performant as an IHttpModule though.

If you're trying to parse the ~/ out of any file, including text files, javascript, etc, you can write a handler that assigns a filter to it and you can use that to search for those paths... for example...
public class StringParsingFilter : MemoryStream {
public Stream OriginalStream {
get { return this.m_OriginalStream; }
set { this.m_OriginalStream = value; }
}
private System.IO.Stream m_OriginalStream;
public StringParsingFilter() : base() {
this.m_OriginalStream = null;
}
public override void Flush() {
this.m_OriginalStream.Flush();
}
public override void Write(byte[] buffer, int offset, int count) {
//otherwise, parse for the correct content
string value = System.Text.Encoding.Default.GetString(buffer);
string contentType = HttpContext.Current.Response.ContentType;
//Do any parsing here
...
//write the new bytes to the stream
byte[] bytes = System.Text.Encoding.Default.GetBytes(value);
this.m_OriginalStream.Write(bytes, offset, count + (bytes.Length - buffer.Length));
}
}
And you'll write a custom handler to know when to assign this filter... like the following...
public class FilterControlModule : IHttpModule {
public void Init(HttpApplication context) {
HttpApplication oAppContext = context;
oAppContext.BeginRequest += new EventHandler(_HandleSettingFilter);
}
private void _HandleSettingFilter(object sender, EventArgs e) {
//You might check the file at this part to make sure
//it is a file type you want to parse
//if (!CurrentFile.isStyleSheet()) { return; }
...
//assign the new filter
StringParsingFilter filter = new StringParsingFilter();
filter.OriginalStream = HttpContext.Current.Response.Filter;
HttpContext.Current.Response.Filter = (Stream)filter;
}
}
It may have actually been easier just to say "look up IHttpModules" but this is some code that I've used to parse files for paths other than ASP.net files.
You'll also have to change some things in your IIS settings to allow the files to be parsed by setting the ASP.net ISAPI to be a wildcard for all of the files that get handled. You can see more at this website, if you're using IIS6 that is...
You can also use this to modify any file types so you could assign some filters for images, some for javascript or stylesheets or ... really anything...

You could use an URL Rewriter to fix the URL as the request comes in, though I am not so sure it is so much elegant as a hack in this case.

I created a PathHelper util class that gives me all the paths I need.
For example
<link href="<%=PathHelper.CssUrl("FormulaIndex.css")%>" rel="Stylesheet" type="text/css"/>
Gives me the correct full url with the help of System.Web.VirtualPathUtility.ToAbsolute() and my own convention (content/css/yourFile.css).
I did the same for js, xml, t9n, pics...
Its central, reusable and now I only had to change one line to catch the move of the scripts folder from content/js to Scripts in all my websites and pages.
A moronic move if you ask me, but it's reality in the current beta :(

Related

Sitefinity 11 adding sandbox attributes to iframe dynamically.

We have a Sitefinity 11.0.6701.0 site in which I have a page that contains a Content Block with an iframe in it. The page we are displaying in the iframe is dynamic and has a form in it - we are not concerned with clickjacking or anything like that as we host the src page as well.
We recently upgraded our site from version 8 and now the iframe's content (which we also host on a separate site) does not allow for the dynamic content to work.
I noticed that Sitefinity seems to be adding a sandbox="allow-scripts allow-same-origin" attribute to the iframe at runtime. I have attempted to change this to sandbox="allow-forms" as well as simply removing the sandbox attribute altogether, but Sitefinity dynamically adds the first attribute back in a runtime. It replace the "allow-forms" with the "allow-scripts allow-same-origin" attribute.
Does anyone know where this is controlled in Sitefinity and how we can overcome this problem? We need this page to be dynamic. For contractual reasons, I can't change actual code in our Sitefinity environment, only work within the CMS.
Thanks in advance,
Jamie
This is caused by the Html Sanitizer.
One option is to disable it under
Administration > Settings > Advanced > Security > Disable HTML sanitization
and restart the site.
Another option is to try and modify the sanitizer configuration as shown here:
https://docs.sitefinity.com/html-sanitization#modify-the-html-sanitizer-configuration
But looking at the decompiled code of v.11 it may not be that easy:
private class GanssHtmlSanitizer : HtmlSanitizer
{
private const string IframeNodeName = "iframe";
public GanssHtmlSanitizer() : base(null, null, null, null, null)
{
base.AllowedTags.Add("iframe");
base.PostProcessNode += new EventHandler<PostProcessNodeEventArgs>(this.GanssHtmlSanitizer_PostProcessNode);
}
private void GanssHtmlSanitizer_PostProcessNode(object sender, PostProcessNodeEventArgs e)
{
if (string.Compare(e.Node.NodeName, "iframe", true) == 0)
{
(e.Node as IElement).SetAttribute("sandbox", "allow-scripts allow-same-origin");
string attribute = (e.Node as IElement).GetAttribute("src");
(e.Node as IElement).SetAttribute("src", this.SanitizeUrl(attribute));
}
}
/// <inheritdoc />
public string SanitizeUrl(string url)
{
return base.SanitizeUrl(url, null);
}
}

Preparing for Internationalization of Asp.net MVC website

I'm going to start a website which I know is going to be presented in multiple languages. However, for the first version we're only going to need the English version. Once the features are all working, we'll add the other languages.
Unfortunately since there are not enough enough features baked into Asp.Net Core, we have to use the Asp.Net MVC 5 for the website. My question has 2 parts:
Right now, which practice is considered the best approach for this? Using resource files and loading them in razor pages? Using a framework? Can we use the new localization and globalization features of Asp.Net MVC 6 somehow? Or is there a better alternative? I personally hate using the resource files. It adds too much clutter to the code.
Would you suggest just using plane text for now and then adding the Internationalization features to the website or start now and only add the translations?
I would use resource files, seems to be the easiest solution. You can also use a Database resource provider, so you have less clutter.
If you start with plain text, it will get more complicated and cumbersome to add the translations later. So I would not do that.
We use Smart internationalization for ASP.NET.
Features
Localize everything: HTML, Razor, C#, VB, JavaScript, .NET attributes
and data annotations, ...;
SEO-friendly: language selection varies the URL, and Content-Language is set appropriately;
Automatic: no URL/routing changes required in the app;
High performance, minimal overhead and minimal heap allocations; Unit testing support;
Smart: knows when to hold them, fold them, walk away, or run, based on i18n best practices.
How I use i18n in the project step by step:
Add the I18N nuget package to your MVC project.
in Web.config:
Add a folder named "locale" to the root of your site. Create a subfolder for each culture you wish to support. For example, /locale/fr/.
copy i18n.PostBuild.exe into locale folder
Right click on tne project name --> Properties --> Build Events:
in Post-build event command line:
"$(TargetDir)i18n.PostBuild.exe" "$(ProjectDir)\web.config"
In views use [[[some text]]] to translate it later
Build the project
Refresh Solution Explorer and push Show All Files
Include all files in "locale" folder into the project
Provide translation of the words in locale\fr\messages.po
In Global.aspx add :
public class MvcApplication : System.Web.HttpApplication
{
protected void Application_Start()
{
//other app start code
UrlLocalizer.UrlLocalizationScheme = UrlLocalizationScheme.Void;
}
}
Create DefaultController :
public class DefaultController : Controller
{
protected override void OnActionExecuting(ActionExecutingContext filterContext)
{
base.OnActionExecuting(filterContext);
if (Session["currentLanguage"] == null)
{
Session["currentLanguage"] = "en";
}
}
}
In HomeController add inheritance of DefaultController and SwitchLanguage(string lang):
public class HomeController : DefaultController
{
public HomeController() : base()
{
[AllowAnonymous]
public async Task<ActionResult> SwitchLanguage(string lang)
{
LocalizedApplication.Current.DefaultLanguage = lang;
Session["currentLanguage"] = lang;
return Redirect(Request.UrlReferrer.PathAndQuery);
}
}
}
In navigation bar View (_LoginPartial.cshtml in my case) add links to switch between languages:
#if (Session["currentLanguage"].ToString() == "fr")
{
<li class="navItem">#Html.ActionLink("EN", "SwitchLanguage", "Home", new { lang = "en", area = "" }, null)</li>
}
else
{
<li class="navItem">#Html.ActionLink("FR", "SwitchLanguage", "Home", new { lang = "fr", area = "" }, null)</li>
}
Build project, Start in Browser and enjoy!!!
see some help in:
https://www.codeday.top/2017/09/19/42409.html

How to add JS and CSS to all content parts in an Orchard module

I am writing a module for Orchard CMS 1.8.1
I would like to add custom styles to all content parts that I have written for the module. I need these to work regardless of the theme chosen by the website admins. I could add links to the CSS and JS files in every view file for every content part - but that seems messy and prone to future bugs - what's the best way to have a single file that loads up the styles needed for all my content parts?
Should I provide a different Content.cshtml that includes the links? This also seems like it could be problematic if the admins need their own control over the main Content.cshtml
Many thanks
Handler should do the trick, I wrote this from the top of my head so not sure if it really works.
First create ResourceManifest.cs and define your stylesheets and scripts
public class ResourceManifest : IResourceManifestProvider
{
public void BuildManifests(ResourceManifestBuilder builder)
{
var manifest = builder.Add();
manifest.DefineStyle("MyStylesheet").SetUrl("mystylesheet.min.css", "mystylesheet.css").SetVersion("1.0.0");
manifest.DefineScript("MyScript").SetUrl("myscript.min.js", "myscript.js").SetVersion("1.0.0");
}
}
Then it should be enough to create content handler and override the BuildDisplayShape
public class MyResourceHandler : ContentHandler
{
private readonly Work<IResourceManager> _resourceManager;
public MyResourceHandler(Work<IResourceManager> resourceManager)
{
_resourceManager = resourceManager;
}
protected override void BuildDisplayShape(BuildDisplayContext context)
{
if (context.DisplayType == "Detail" && context.ContentItem.Has(typeof(MyPart)))
{
this._resourceManager.Value.Require("stylesheet", "MyStylesheet");
this._resourceManager.Value.Require("script", "MyScript");
}
base.BuildDisplayShape(context);
}
}
Adjust the IF as necessary. And let me know if it works ;)
Beauty of using ResourceManifest with versioning is that anyone can replace your stylesheets/javascript with their own just by defining style in their own ResourceManifest (module/theme) with same name and higher version number and don't have to touch any original files.

ASP.net - How to achieve CSS with constant values, arithmetic and string manipulation

When developing ASP.NET websites (using VB.NET web forms) - a lot of my time is spend writing CSS files and they always seem to get messy (code duplication) and very long.
All I want to achieve is to be able to manipulate the CSS using VB.NET code in the following ways:
Use an integer variable to store my "golden" number 7 and use that for width, padding, margin etc where needed
Use string variables to store my "golden" hex color codes e.g. "#44C5F2" and use them for color, background-color, border-color etc. where needed
Use an integer variable to set the height of an element and have four child elements each with height: mynum / 4
I just want to use basic VB.net number and string manipulation in order to create a CSS file on the fly.
I understand that the end product - the CSS file shouldn't change much - it should at most change on a daily basis otherwise caching couldn't be used.
I also understand that I would lose Visual Studio CSS intellisense support but...
How do I achieve this?
Should I be using:
Generic handlers (ASHX)
ASP.NET Themes
ASP.NET Skins
Something else?
I just some pointers.
Any help is appreciated.
Thanks.
I believe you are looking for something like http://www.dotlesscss.org/
You should take a look at LESS, which extends CSS to allow
dynamic behavior such as variables, mixins, operations and functions
dot less is a .NET version with integration to ASP.NET.
I decided to go with a WebHandler (ASHX file) in the end:
CssOnTheFly.ashx
<%# WebHandler Language="C#" Class="CssOnTheFly" CodeBehind="CssOnTheFly.ashx.cs" %>
CssOnTheFly.ashx.cs
using System;
using System.Web;
public class CssOnTheFly : IHttpHandler
{
private HttpResponse r;
public void ProcessRequest(HttpContext context)
{
context.Response.ContentType = "text/css";
r = context.Response;
writeCss();
}
public bool IsReusable
{
get
{
return false;
}
}
private void writeCss()
{
wl("body {");
wl("height: 100%;");
wl("}");
}
private void wl(string s)
{
r.Write(s + Environment.NewLine);
}
}
Because I could create bespoke classes to generate CSS on the fly - so I have more flexibility.
I think I need to use C# for this because VB.NET doesn't really have multi-line string literals.

Add my own page extension in asp.net

I am trying to add page with custom extension, say .asp2 with my set of html tags.
Now whenever i try to access the page on browser...it asks me "Save as". This happens because I am using an extn which the server is not able to recognise.
What should I do to so that my server, IIS 5.1 recognises this extension??
Please suggest
Also please suggest on how to associate custom events on such custom page?
In Internet Services Manager, right click on Default Web Site, select Properties, in Home Directory press the Configuration button. Click the Add button and fill the Executable field with the path to the aspnet_isapi.dll file and put asp2 in the Extension field.
Using a non-standard extension, you should also be sure to set the response's Content Type to text/html, so the browser knows how to interpret the document you're sending. Something like:
public class HttpHandler1 : IHttpHandler
{
public bool IsReusable
{
get { return true; }
}
public void ProcessRequest(HttpContext context)
{
context.Response.ContentType = "text/html";
// Your code here.
}
}

Resources