How to add CSS file or Javascript file by action of controller

Would it be great to specify for a specific action what CSS or Javascript file to load? With Asp.Net MVC it’s possible to do something custom pretty fast and useful with attribute. Attribute is something that the developer add at the top of the method (action). The syntax is simple. It uses the square bracket and between you have the name of the attribute and parameters.

Above is the result of how to use the Javascript attribute to get 2 Javascripts file loaded only when Index is called. We could improve by also let the developer add the tag over the controller class which would load the Javascript for all actions of this controller.

    public class HomeController : Controller {
        [JavaScript("MyFile1", "MyFile2")]
        public ActionResult Index() {
            ViewBag.Message = "Welcome to ASP.NET MVC!";

            return View();
        }

        public ActionResult About() {
            return View();
        }
    }

The first step is to create an attribute for each of the specific file you want. For example, one for CSS and one for Javascript. For simplicity, we will only do Javascript here.

    [AttributeUsage(AttributeTargets.Class | AttributeTargets.Method)]
    public class JavaScript : Attribute {
        public string[] FileNames { get; set; }

        public JavaScript(params string[] fileName) {
            this.FileNames = fileName;
        }
    }

Then, we need to add to the master page (by default _Layout.cshtml) a code that will read those attributes and add the Javascript include tag in the header of the Html code.

<!DOCTYPE html>
<html>
<head>
    <meta charset="utf-8" />
    <title>@ViewBag.Title</title>
    <link href="@Url.Content("~/Content/Site.css")" rel="stylesheet" type="text/css" />
    <script src="@Url.Content("~/Scripts/jquery-1.5.1.min.js")" type="text/javascript"></script>
    <script src="@Url.Content("~/Scripts/modernizr-1.7.min.js")" type="text/javascript"></script>
    @Html.GetJavascript();
</head>

The GetJavascript() helper code will loop all attributes to find what has been defined at the controller side.

public static class JavascriptHelper {
        public static MvcHtmlString GetJavascript(this HtmlHelper helper) {
            IList<string> fileNames = new List<string>();

            //The class may have more than one Javascript file. Need to loop them all and also loop all entries
            MemberInfo controllerInfo = helper.ViewContext.Controller.GetType();
            object[] listOfcontrollerAttributes = controllerInfo.GetCustomAttributes(typeof(JavaScript), true);
            FillUpFileArray(fileNames, listOfcontrollerAttributes);

            //Method attributes. First get the method that has been called and loop all possible Javascript tag and entries
            MethodInfo method;
            if (helper.ViewContext.HttpContext.Request.HttpMethod == "POST"){
                method = helper.ViewContext.Controller.GetType().GetMethods().FirstOrDefault(t => t.Name == helper.ViewContext.RouteData.GetRequiredString("action") && t.GetCustomAttributes(typeof(JavaScript), true).Any() && t.GetCustomAttributes(typeof(HttpPostAttribute), true).Any());
            }
            else{
                method = helper.ViewContext.Controller.GetType().GetMethods().FirstOrDefault(t => t.Name == helper.ViewContext.RouteData.GetRequiredString("action") && t.GetCustomAttributes(typeof(JavaScript), true).Any() && !t.GetCustomAttributes(typeof(HttpPostAttribute), true).Any());
            }
     
            if(method!=null){
                object[] methodAttributes = method.GetCustomAttributes(typeof(JavaScript), true);
                FillUpFileArray(fileNames, methodAttributes);
            }

            //Create Html
            if (fileNames.Any()) {
                var sb = new StringBuilder();
                var url = new UrlHelper(helper.ViewContext.RequestContext);
                const string JS_SCRIPT_FORMAT = "<script src=\"{0}.js\" type=\"text/javascript\"></script>";
                foreach (string fmt in fileNames.Select(name => string.Format(JS_SCRIPT_FORMAT, url.Content("~/Scripts/") + name))){
                    sb.AppendLine(fmt);
                }
                return new MvcHtmlString(sb.ToString());
            }

            return new MvcHtmlString(string.Empty);
        }

        private static void FillUpFileArray(ICollection<string> fileNames, IEnumerable<object> listOfcontrollerAttributes){
            if (listOfcontrollerAttributes != null){
                foreach (string name in listOfcontrollerAttributes.OfType<JavaScript>().SelectMany(classAttributes => classAttributes.FileNames.Where(name => !string.IsNullOrEmpty(name) && !fileNames.Contains(name)))){
                    fileNames.Add(name);
                }
            }
        }
    }

Here is the explication step by step:

            MemberInfo controllerInfo = helper.ViewContext.Controller.GetType();
            object[] listOfcontrollerAttributes = controllerInfo.GetCustomAttributes(typeof(JavaScript), true);
            FillUpFileArray(fileNames, listOfcontrollerAttributes);

The first section get everything from the controller that has been called the view to get all possibles attributes defined and loop through them. Every time it finds an attribute, it loops through the list of string that represent a Javascript file.

            MethodInfo method;
            if (helper.ViewContext.HttpContext.Request.HttpMethod == "POST"){
                method = helper.ViewContext.Controller.GetType().GetMethods().FirstOrDefault(t => t.Name == helper.ViewContext.RouteData.GetRequiredString("action") && t.GetCustomAttributes(typeof(JavaScript), true).Any() && t.GetCustomAttributes(typeof(HttpPostAttribute), true).Any());
            }
            else{
                method = helper.ViewContext.Controller.GetType().GetMethods().FirstOrDefault(t => t.Name == helper.ViewContext.RouteData.GetRequiredString("action") && t.GetCustomAttributes(typeof(JavaScript), true).Any() && !t.GetCustomAttributes(typeof(HttpPostAttribute), true).Any());
            }
     
            if(method!=null){
                object[] methodAttributes = method.GetCustomAttributes(typeof(JavaScript), true);
                FillUpFileArray(fileNames, methodAttributes);
            }

It’s almost the same with method, but this time, we need to get the good action method. A same method can be good for GET or HTTP so we need to figure out the good one. As you can see, we do not search explicitly for GET because action’s method is implicitly GET.

 if (fileNames.Any()) {
                var sb = new StringBuilder();
                var url = new UrlHelper(helper.ViewContext.RequestContext);
                const string JS_SCRIPT_FORMAT = "<script src=\"{0}.js\" type=\"text/javascript\"></script>";
                foreach (string fmt in fileNames.Select(name => string.Format(JS_SCRIPT_FORMAT, url.Content("~/Scripts/") + name))){
                    sb.AppendLine(fmt);
                }
                return new MvcHtmlString(sb.ToString());
            }

            return new MvcHtmlString(string.Empty);

At the end, we print the list of Javascript file by adding the extension and but referring to the good script folder.

Here is an example of a controller that works pretty well with this kind of scenario:

[JavaScript("Controller1", "Controller2")]
    public class HomeController : Controller {

        [JavaScript("MyFileAction1", "MyFileAction2")]
        public ActionResult Index() {
            ViewBag.Message = "Welcome to ASP.NET MVC!";

            return View();
        }

        [JavaScript("Integer", "Integer")]
        [HttpGet]
        public ActionResult Test(int i, int j) {
            ViewBag.Message = "Welcome to ASP.NET MVC!" + i + " " + j;

            return View("Index");
        }

        [JavaScript("PostFile1")]
        [HttpPost]
        public ActionResult Test(string s) {
            ViewBag.Message = "Welcome to ASP.NET MVC!" + s;

            return View("Index");
        }

        public ActionResult About() {
            return View();
        }
    }

Hope it helps you to get cleaner code!

How to create a HttpHandler with Asp Mvc

With traditional Asp.Net, doing an http handler required without a doubt to add a new Http Handler in IIS to handle a specific extension and then doing some work to get the request and to send back a response. This is about the same with Asp.Net MVC but you have the leverage to do everything in code with routing.

In this article, we will do a Http Handler for image. This will allow us to instead of using directly a server path for our image in our website to call this image http handler to get the image. This can be useful if you want to protect who access the image. Direct linking from outside of the website won’t be allowed for example. You could also decide to implement a special algorithm that return image depending of who is logged to the website, etc.

First of all, you need to create a new class that will inherit from IRouteHandler.

public class ImageHandler : IRouteHandler
{
    public IHttpHandler GetHttpHandler(RequestContext requestContext)
	{
	}
}

Once created, you need to specify the website that this routing handler exist. This is done with global.asax.cs You need to add the route into the Application_Start().

RouteTable.Routes.Add("ImagesRoute", new Route("privateImage/{uniqueIdentifier}", new ImageHandler())); 

As you can see, I have decided that any url that will have privateImage/#### will be routed to the new http handler.

Let’s go back to the Http handler. Now we need to verify that the uniqueIdentifier is present when the handler is called. Otherwise, we will return a 404 Http error. This is done by returning null.

public class ImageHandler : IRouteHandler
{
    public IHttpHandler GetHttpHandler(RequestContext requestContext)
	{
		var routeValues = requestContext.RouteData.Values;
		if(routeValues.ContainsKey("UniqueIdentifier"))
		{
			
		}
		else
		{
			return null;
		}
	}
}

No we need to get the image and to send it back to the user. This is done by opening the file one the server in a stream and to write it back to the response stream which will go the the client via http.

public class ImageHandler : IRouteHandler
{
    public IHttpHandler GetHttpHandler(RequestContext requestContext)
	{
		var routeValues = requestContext.RouteData.Values;
		if(routeValues.ContainsKey("UniqueIdentifier"))
		{
			//Do something with the parameter (UniqueIdentifier) to get the image on the server
			string serverPathToImageToOutput = //What ever you want like database call or file server algo;
			//Start a new Response
			requestContext.HttpContext.Response.Clear();
			//Response type will be the same as the one requested
            requestContext.HttpContext.Response.ContentType = GetContentType(requestContext.HttpContext.Request.Url.ToString());
			//We buffer the data to send back until it's done
			requestContext.HttpContext.Response.BufferOutput = true;
			Image image = Image.FromStream(new FileStream(serverPathToImageToOutput, FileMode.Open));
			image.Save(requestContext.HttpContext.Response.OutputStream, ImageFormat.Png);
			requestContext.HttpContext.Response.End();
		}
		else
		{
			return null;
		}
	}
}

As you may notice, nothing is yet written for security purpose. In fact, it’s quite simple. What we need to do is to check from where the request as been sent. Since we are the only one who should use the http handler, we can authorize only server request by checking the referer variable.

request.ServerVariables["HTTP_REFERER"]

This can be added at the beginning of the GetHttpHandler method and return a static image that say “Image is not authorized”.

How to remove trailing slash in C#

I see often people using substring to remove the last character if this one is a slash in a path or url. This can if misused lead to an error because maybe the string is empty and doesn’t have count()-1 over 0.

Also, this require to have a conditional statement to verify if the string contain at its latest position a slash.

A cleaner way to proceed with this kind of string clean up it’s to use the TRIM function of the string. The method TrimEnd let you specify an array of char that you want to remove at the end of the specified string.

Here is an example:

string fileName = "Test/";
fileName= fileName.TrimEnd(new[] { '/' });

With this method you can also specify multiple characters so you may want to remove all slash or backslash using the array.

string fileName = "Test\\";
fileName= fileName.TrimEnd(new[] { '/', '\\' });

Do not forget that this method will trim more than only the last character but all ending characters. This mean that a string ending with two slashes will see both slashes removed. I think it’s even better!

How to map 1 table to 2 objects with Entity Framework 4.3 Code-First (POCO)?

In some scenario, your database table may look different from your classes. You could have a class that contain an object which is a subdivision of some data with high cohesive representation and in the same time you may not want to divide this information in a 1-1 table. This is often the case if you cannot refactor an existing database or the case where information belong in a single table but since the data is conceptually better to be together in a second object that you need to be different from your database. In that case, Entity Framework call this scenario “Complex Type”.

Let say that you have a table with these fields:


[Table]
-Field1
-Field2
-Field3
-Field4

And let say that you end up having classes like this:


[Class1]
-Field1
-Field2
-Class2 object here

[Class2]
-Field3
-Field4

In fact, as you can see, the Class1 can access Class2 data with the property Class2. For example : myClass1.Class2.Field3.

To be able to map automatically data with Entity Framework, you need to setup a complex type.

First of all, you need to ensure that the property doesn’t have a null value. This mean that you have to initialize this property. The best way is to initialize the inner object (Class2) in the constructor of the main class (Class1).

Second, Entity Framework will do his mapping of the property inside the inner object with the property name of this one. That mean that Entity Framework will think that the table look like this:


[Table]
-Field1
-Field2
-Class2_Field3
-Class2_Field4

If you do not want to alter your table, you will need to configure the Database Context.

protected override void OnModelCreating(DbModelBuilder modelBuilder) {
    modelBuilder.Configuration.Add(new MyTable2Configuration());
    //Add subsequent configuration...
}

public class MyTable2Configuration: ComplexTypeConfiguration<Class2> {
   public MyTable2Configuration() {
      Property(o => o.Field3).HasColumnName("Field3");
      Property(o => o.Field4).HasColumnName("Field4");
   }
}

You do not have to configure the Table1 class, only the complex type. If you need more information about Complex Type, you can always check this blog which give additional information.

Getting resource value with explicit localization

Sometime, it’s interesting to get a string value from a resource file without getting the one from the current Thread.CurrentThread.CurrentUICulture. Some scenario may be that you are logged in a specific language and you need to sent something to someone who is in a different language.

To be able to do this, you need to change the line of code that use the static property and to call the ResourceManager instead.

Let say that your resource file name is “MyResource.resx”. If you have set the visibility to public, the file MyResource.Designer.resx will contains a static property for all your entries. If you have a key value of “Res1” inside your file you will have a static property called “Res1” which will return a string.

public class MyResource{
 public static string Res1
 {
    get 
    {
         return ResourceManager.GetString("Res1", resourceCulture);
    }
 }
}

If you want to have access to a specific language without using the current resource culture, you need to instead calling the resource by this static property to call the resource manager directly.

//Instead of :
string myString = MyResource.Res1;
//You have to call :
string myString = MyResource.ResourceManager.GetString("Res1", new CultureInfo("FR"));

That’s it. Of course, you have to make sure that you have the culture requested otherwise, an exception will be thrown.

How to change master page for a specific view with Asp.Net MVC

You may want to have a specific master page for a specific page. This can be handled in many way.

The first way is the simplest and can be good enough for few pages that need a specific master page. This is done by returning the view with the master page parameter.

public ActionResult Index()
{
    return View("Index", "MasterPageCustom");
}

You could also use the View object and setting the master page name with a setter.

public ActionResult SomeOtherPage()
{
    var view = View("Index");
    view.MasterName = "MasterPageCustom";
    return view;
}

Generally, if you have a bigger website, you would prefer to handle master page at a higher level like the controller. This can be done by using the OnActionExecuted. Right after the action is executed, the controller can change the master page of the returned view.

protected override void OnActionExecuted(ActionExecutedContext filterContext)
{
    var action = filterContext.Result as ViewResult;
    //Verify that nothing has been previously set. This give the possibility to
    //still be able to set the master page at a more atomic position (action).
    if (action != null && String.IsNullOrEmpty(action.MasterName))
    {
       action.MasterName = "MasterPageCustom";
    }
    //Default stuff
    base.OnActionExecuted(filterContext);
}

The later solution is the best one in the case that you have multiple action methods that use the same master page. It also give the flexibility to change it for specific action. The first solution should be used if the master page is used for few actions only.

JQuery .on() function

JQuery provide good examples concerning adding event to an Html Dom object dynamically. This mean that event if the Dom doesn’t exist, when the event is attached, that the event will be hooked when the Html Dom object. The methodology of this thinking has changed since Jquery version 1.3. At first, we had to use the live method.

$("a.offsite").live("click", function(){ alert("Goodbye!"); });                // jQuery 1.3+

In the version 1.4.3, we could have used the delegate function.

$(document).delegate("a.offsite", "click", function(){ alert("Goodbye!"); });  // jQuery 1.4.3+

But now, to reduce the confusion between all the function to attach event (bind(), live(), delegate()) to Html Dom object, we simply use the ON function.

$(document).on("click", "a.offsite", function(){ alert("Goodbye!"); });        // jQuery 1.7+

In this example, since the .on() function is called from the $(document) this will listen every html that change to hook the function if the selector match.

The syntax of the on function in Jquery is :

.on( events [, selector] [, data], handler(eventObject) )
or
.on( events-map [, selector] [, data] )

This mean that you first select the event you want to add, then the selector in the Jquery syntax and finallywhat you want to hook to.

But you are not limited to listen every thing on the web page. This is usefull is you load content from Ajax but if you want to add an event only on a specify part of the page you can specify it instead of document and add the event.

$("#myTable tr").on("click", function(event){
	alert($(this).text());
});

This will add to every line of the myTable the possibility to click. If you want to have new line (Javascript added tr) of this grid to be automatically bound to the click event, you need to change the above code to setup the onclick on the table.

$("#myTable").on("click", "tr", function(event){
	alert($(this).text());
});

This way, it bubbles up to the myTable, which is always available and the click will occur.

Watch out with attaching from the document. Attaching many delegated event handlers near the top of the document tree can degrade performance rapidly. This is even more true with event like mousemouve that is called a lot of time consequently.

Alternative to clear:both when you need to have container to expand to your floating content

Instead of adding a Html tag after floating division, it’s better to add a class that will do this. It’s better because you do not have to alter the Html for visual stuff that the CSS is designed too handle. The solution is known as “Clear fix”. It’s possible with CSS 2.0 to add :after which will add an element after the one that will carry this class.

	.clear-fix:after
	{
		 visibility: hidden;
		 display: block;
		 font-size: 0;
		 line-height: 0;
		 content: " ";
		 clear: both;
		 height: 0;
		 width: 0;
	}

In fact, this will create an invisible division after any dom element that has the clear-fix class. It will act the same as the old way to do it with an empty division with the clear:both style. But it’s cleaner.

Memorystream : Invalid Operation Exception

Memorystream that is initialized with the constructor that take another stream can raise the exception “Invalid Operation Exception”.

The proper way to is to use the Write property after using the empty constructor.

     var encoding= new UnicodeEncoding();
     Byte[] bytesToCompress = encoding.GetBytes("Test123);
     var streamToCompress = new MemoryStream();
     streamToCompress .Write(bytesToCompress, 0, bytesToCompress.Length);

You can use Unicode encoding but also UTF8 or any other file encoding available.

MvcHtmlString.Create to encode Html with Asp.net MVC

You may want to use a string that contain Html and display this one not with the Html tag but to execute it. Of course, you would like to do it encoded with Html (to have secure rendering).

This can be done by using MvcHtmlString.Create.

This method takes a string as parameter and return a MvcHtmlString.

So, instead of using directly @Model.YourStringProperty, you should use MvcHtmlString.Create(Model.YourStringProperty)

This method will check if the input (parameter) inherit of IHtmlString, if it does, it won’t do anything. The reason is that class that inherit from IHtmlString. If not, it will encode the html output.

From here, you can create your own Html extension to extend

public static class HtmlHelpers
{
    public static MvcHtmlString HtmlEncode(this string data)
    {
       return MvcHtmlString.Create(data);
    }
}

This extension will let you encode any string so you could use it with you properties.

This is my property : @Model.Name.HtmlEncode()

On the other side, if you do not want to have the Html encoded, you could use Html.Raw() method which return a IHtmlString which won’t be encoded by MVC framework.

If you go inside the source code of Asp.Net we will find that Html.Raw() use the string and generate a simple IHtmlString from the concrete class HtmlString.

public IHtmlString Raw(string value)
{
    return new HtmlString(value);
}

public IHtmlString Raw(object value)
{
    return new HtmlString(value == null ? null : value.ToString());
}

This is different from MvcHtmlString.Create()

 public sealed class MvcHtmlString : HtmlString
    {
      
        public static readonly MvcHtmlString Empty = Create(String.Empty);

        private readonly string _value;

        public MvcHtmlString(string value)
            : base(value ?? String.Empty)
        {
            _value = value ?? String.Empty;
        }

        public static MvcHtmlString Create(string value)
        {
            return new MvcHtmlString(value);
        }

        public static bool IsNullOrEmpty(MvcHtmlString value)
        {
            return (value == null || value._value.Length == 0);
        }
    }

Are you can see, this one return a MvcHtmlString. At the end, both return something similar and encoded html.

In the scenario you want to display the html’s string you simply need to use the variable:

@{ 
    var x= "<b>Test</b>"; 
}

@x

To conclude, if you need to display html rendered to the browser, you can use one of the two methods and it will work. The reason is that MvcHtmlString inherit from HtmlString which inherit from IHtmlString. If you need to display the content of the string which contain Html (which will print the Html’s string and not the rendered content) simply use directly the variable like : @Model.MyStringWithHtml