Archive

Archive for the ‘ASP.NET MVC’ Category

ASP.NET MVC 3: Unobtrusive Client Side Validation

June 6, 2011 6 comments

In this post we will look at one of the new features of the fresh new release of ASP.NET MVC 3 – using unobtrusive client side validation through the new HTML5 data-* attributes. I will show what these attributes look like and how they come into play.

Client Validation by Default

One of the main differences between the new version and the previous two MVC 1 and MVC 2 is that client side validation is turned on by default. This is done using an AppSetting in the web.config file:

<appSettings>
  <add key="ClientValidationEnabled" value="true"/>
</appSettings> 

If you remember up until ASP.NET MVC 3 you had to explicitly specify that you want client side validation to be performed like this in your view:

<% Html.EnableClientValidation(); %>

If you don’t want any validation in the browser you could turn it off by changing the AppSetting value of ClientValidationEnabled to false.

Unobtrusive Validation

Validation in ASP.NET MVC is based on meta data provided by DataAnnotations. There are quite a few classes that are really handy in describing what rules your properties must obey and the framework will take care of the rest. The HTML Helper classes (Html.TextBoxFor, Html.EditorFor, etc.) used to render different HTML controls look up these meta data attributes when the response is being generated and render the appropriate output so that validation can occur on the client’s browser.

By taking advantage of Unobtrusive JavaScript you don’t clatter your HTML markup with unnecessary JavaScript event handlers and so on. The HTML elements describe themselves through attributes and you get a HTML5 ready markup by default. Here is a sample UserModel class that I will use in a create user form annotated with validation attributes:

public class UserModel
{
    [Required]
    [StringLength(50)]
    public string Username { get; set; }

    [Required]
    public string Password { get; set; }

    [Required]
    [Compare("Password")]
    public string ConfirmPassword { get; set; }

    [Required]
    [StringLength(50)]
    public string FirstName { get; set; }

    [Required]
    [StringLength(50)]
    public string LastName { get; set; }

    [Required]
    [StringLength(50)]
    [RegularExpression("^[a-z0-9_\\+-]+(\\.[a-z0-9_\\+-]+)*@[a-z0-9-]+(\\.[a-z0-9-]+)*\\.([a-z]{2,4})$")]
    public string Email { get; set; }
}

When the user tries to submit the form with invalid data he/she will see the following messages:

Unobtrusive Client Side Validation

If we look at the confirm password input element for example we will see the following HTML markup:

<div class="editor-field">
    <input type="password" name="ConfirmPassword" id="ConfirmPassword" data-val-required="The ConfirmPassword field is required." data-val-equalto-other="*.Password" data-val-equalto="&amp;#39;ConfirmPassword&amp;#39; and &amp;#39;Password&amp;#39; do not match." data-val="true">
    <span data-valmsg-replace="true" data-valmsg-for="ConfirmPassword" class="field-validation-valid"></span>
</div>

As you can see there are a few data-val* attributes that add meta data to both this field and the span element that shows validation messages. Behind the scenes ASP.NET MVC uses jQuery Validation plugin and the Unobtrusive validation support library for jQuery Validate written by Microsoft. If you however decide to turn unobtrusive validation off your HTML markup won’t include the new HTML5 data-* attributes but a JavaScript code that will set up the Validation plugin.

For the ConfirmPassword property I have used one new attribute that comes with this new release part of .NET Framework 4.0 – CompareAttribute. It gives you the ability to compare two properties of a model.

Summary

As you can see ASP.NET MVC 3 is not lagging behind the current trends in web development utilizing some of the new HTML5 features and unobtrusive JavaScript. What I like about ASP.NET MVC and DataAnnotations is that we as developers don’t need to focus and waste too much time on simple validations like required fields, maximum length, etc. and focus on the business logic and any business rules that need to be enforced.

Advertisements

Architecting Loosely Coupled ASP.NET MVC Web Applications Talk

June 6, 2011 1 comment

Last week Kaloyan Bochevski and I gave a talk for the Web Platform User Group at Microsoft, Bulgaria. The topic was Architecting Loosely Coupled ASP.NET MVC Web Applications. For both of us it was quite an interesting experience as it was our first presentation and we for sure have a lot to improve for any future talks we might have.

The agenda

Our agenda covered a lot of areas even though it was mainly focused on how to design a loosely coupled ASP.NET MVC application. This was our list for the talk:

  • Dependency Injection with Spring.NET
  • Custom Authentication
  • Custom Attributes
  • jQuery Grid with Model Binders
  • Unobtrusive Validation with Data Annotations
  • Security (XSS Anti-Forgery token)
  • Covariance & Contravariance – IQueryable<out T> interface in .NET 4.0 and extension methods for .NET 3.5
  • Unit testing (NUnit, Selenium)

Over the next few weeks we will post articles that cover some of the bullets in the list. Any comments would be greatly appreciated.

How to Handle Forms Authentication Timeout During an AJAX Request

October 26, 2010 3 comments

I stumbled upon an interesting issue the other day – how to respond to an error during an AJAX request after a period of user inactivity and a session expiration of the logged in user. In such situation you should either redirect the user to the login page or show a modal dialog where he/she could enter his or her credentials and continue their work. But this seemingly simple task turned out to be not so trivial. Here is the scenario:

  • the user logs in
  • after a period of inactivity the session times out
  • the user makes some action which triggers an AJAX request to the server which results in a response with a status code of 302 (Redirect) and the URL to the login page
  • the browser parses the response and issues a request to the provided redirection URL
  • the AJAX request completes, the response is the HTML markup of the login page with a status code of 200 (OK) which results in an error because the expected data type is JSON and it cannot be parsed correctly

The problem occurs during the last two points and the inability to determine the right cause of the error. It took me an hour or so to pinpoint and understand why this is happening. After this I tried some ideas and came up with a really simple solution.

What I needed was to pass the information to the XmlHttpRequest object that the user’s session had expired and to show a modal dialog so he or she could enter his or her credentials. That’s why I had to get rid of the redirection but only for AJAX requests because I still needed unauthenticated users to be redirected to the login page for non-AJAX requests. In order to do that I removed the Response.RedirectLocation in the Application_EndRequest event inside the Global.asax file:

protected void Application_EndRequest(object sender, EventArgs args)
{
    HttpContextWrapper context = new HttpContextWrapper(Context);
    if (context.Response.StatusCode == 302 && context.Request.IsAjaxRequest())
        context.Response.RedirectLocation = string.Empty;
}

After that it was easy to check the status code in the error handler of the AJAX request and since I knew that a 302 status code is sent by my application only when the user is not authenticated I was able to respond accordingly.

Categories: ASP.NET, ASP.NET MVC, CSharp

Show Save As Dialog With Content-Disposition Response Header

June 27, 2010 6 comments

In this post I will talk about how you can force the browser to show a Save As dialog with a predefined filename. For the purpose of my example I will build on my previous post.

Applicability

This might be really useful in some type of applications – a file manager, email client application like Gmail (downloading file attachments) and exporting data into different formats. You could rely on the browser to show Save As dialog but that might not be the case. It will prompt you to save a file if it can’t render its contents (the content type is unknown) but it will set the filename to the url it was downloaded from (you do not have a choice to give it a more proper name). Luckily there is a special response header part of the HTTP Specification that accomplishes that.

Content-Disposition Header

The Content-Disposition header is optional and gives you the ability to explicitly specify the file name of the requested resource and force the showing of a Save As dialog. The file resource could be specified as inline (default one) or attachment. If omitted the browser tries to render it as if it is specified as inline. In our case we need to set it as an attachment so that we can force the Show As dialog to pop up:

Content-Disposition: attachment

With the filename parameter we notify what the file name of the requested resource should be. We can give it any meaningful name we want. If the requested relative url is the following /MySite/Export and the filename parameter is missing then the file name that the browser would suggest will be Export. This is in no way user-friendly. Here is how we can set the file name using the Content-Disposition header:

Content-Disposition: attachment; filename=ExportedUser_06272010.xml

Now the Save As dialog would suggest the file be saved as ExportedUser_06272010.xml. You can implement any kind of naming convention for your application and make it more user-friendly.

Server side modifications

Since we already know how to accomplish everything we can change the action method responsible for exporting users to xml from my previous post:

[HttpPost]
public ActionResult Export()
{
    User user = HttpContext.Cache["user"] as User;
    if (user == null)
        return View("Index");

    HttpContext.Response.AddHeader("Content-Disposition", string.Format("attachment; filename={0}_{1}.xml", user.FirstName, user.LastName));
    return View("User", user);
}

The important part is where we add the Content-Disposition header to the response using the AddHeader method on the HttpContext’s Response property. If we start the application and click on the Export button the Save As dialog pops up:

Content-Disposition Header

Content-Disposition Header

Summary

In some scenarios you need to have control over the browser and force it to show the Save As dialog and explicitly set the file name of the resource. This is accomplished with the Content-Disposition response header. I have attached the updated application so you can play around with it.

Categories: ASP.NET MVC

Output XML Using Strongly Typed Views in ASP.NET MVC

June 17, 2010 3 comments

Recently I had to create an export to XML functionality in an ASP.NET MVC application. The first thing that came up to my mind was to use LINQ to XML to serialize my entity and then write it to the output stream with the FileStreamResult class. It could not be much more easy, right? But what is really a single HTML page – one irregular XML document (XHTML is well formed XML). Then I give it a thought and realized that I could use a strongly typed view for my entity and have it change its content type to text/xml.

XML View

Here is my sample User class that would be used to generate the XML file:

public class User
{
    [Required(ErrorMessage = "First Name is required")]
    public string FirstName { get; set; }

    [Required(ErrorMessage = "Last Name is required")]
    public string LastName { get; set; }

    public string Street { get; set; }
    public string City { get; set; }

    [Required(ErrorMessage = "Country is required")]
    public string Country { get; set; }

    public string PhoneNumber { get; set; }

    [Required(ErrorMessage = "Email Address is required")]
    public string EmailAddress { get; set; }

    [Required(ErrorMessage = "Age is required")]
    [Range(0, 100, ErrorMessage = "Age must be between 0 and 100")]
    public int Age { get; set; }
}

In Solution Explorer right click on your view folder and choose Add > View. On the following dialog enter the name of the view and check the Create a strongly-typed view checkbox which enables you to select a view data class. Finally click on the Add button and you have created the view.

Now you are ready to edit its contents. The first thing you need to do is to change the ContentType attribute of the Page directive to text/xml:

<%@ Page Language="C#" Inherits="System.Web.Mvc.ViewPage<ExportToXml.Models.User>" ContentType="text/xml" %>

This way you tell your ASP.NET MVC application to change the response header for this resource. The client’s browser would parse it and render the document as XML since it knows how to handle such type of resources.

Replace any other generated content with the XML you want to output. This is what the XML markup for my entity looks like:

<%@ Page Language="C#" Inherits="System.Web.Mvc.ViewPage<ExportToXml.Models.User>" ContentType="text/xml" %><?xml version="1.0" encoding="utf-8" ?>
<User>
    <FirstName><%= Model.FirstName %></FirstName>
    <LastName><%= Model.LastName %></LastName>
    <Street><%= Model.Street %></Street>
    <City><%= Model.City %></City>
    <Country><%= Model.Country %></Country>
    <PhoneNumber><%= Model.PhoneNumber %></PhoneNumber>
    <EmailAddress><%= Model.EmailAddress %></EmailAddress>
    <Age><%= Model.Age %></Age>
</User>

As you can see it’s all really simple, no rocket science. Just be sure to put the declaration of the XML right after the page directive (not on a new line) otherwise it won’t be parsed properly by the browser.

Action Method

The action method responsible for returning the XML document has a return type of ActionResult and calls the View helper method passing the name of the view and the entity that would be exported:

[HttpPost]
public ActionResult Export()
{
    User user = HttpContext.Cache["user"] as User;
    if (user == null)
        return View("Index");

    return View("User", user);
}

As you can see if there is no user in the cache the default view is rendered, otherwise the strongly typed XML view is rendered passing the user entity instance.

Putting It All Together

Now that we have created this we can create an user and then export it. This is what the create user page looks like:

Create User

Create User

After the user is created clicking on the Export button will call the Export action method which will render the strongly typed XML view. The generated XML is the following:

Generated XML

Generated XML

Summary

Using this technique is really simple and makes your code more readable and maintainable because you are relying on declarative code. If you need to make a change you just edit your view’s aspx page and you are ready – no need to recompile and redeploy on the production server. Keep in mind that this solution might not be applicable to your scenario – it is just one way to solve a problem. In a future post I will show you how you can make the browser show a Save As dialog with a specific file name (very useful in some situations).

You could download this sample application from here.

Categories: ASP.NET MVC

Performance tips – minification and deferred JavaScript loading

December 9, 2009 9 comments

In the past few years a lot of research has been done on page load times and where the hot spots occur. Surprisingly around 90% of the page load time is spent inside the browser. Why could this be happenning and what can be done in order to reduce these numbers?

How browsers work?

When a page is requested it is downloaded, parsed and rendered. During the rendering phase a lot is going on behind the scenes – static resources referenced by the page are downloaded, parsed and executed (in case of CSS and JavaScript). These static resources require additional HTTP requests which might dramatically slow down the loading of the page. Browsers have a limit of requests that could be performed in parallel, hence the resources are downloaded somewhat sequentially. The numbers differ from browser to browser, but in general two image files could be downloaded in parallel from a single domain, only a single JavaScript file could be downloaded at a time which also blocks the rendering of the page.

JavaScript hot spots

In this article the subject of interest are the bottlenecks that arise from requesting JavaScript files. There are different steps that could be taken to tune the page load time that is influenced by script files – minification and compression, combining all scripts in a single file (this is the recommended approach for CSS as well). There are several tools that are available for this purpose – JSMin and YUI Compressor (there is a .NET version that could be used in a MSBuild task) are some of them. You could make significant performance gains by minimizing and compressing – that could really be felt if your users are on a slow internet connection. By combining your scripts the browser will make only a single HTTP request which results in faster load times.

I will show you how to use YUI Compressor for .NET to combine and minify JavaScript files with MSBuild. To get started you need to copy Yahoo.Yui.Compressor.dll and EcmaScript.NET.modified.dll assemblies to your project. Create a so called project file (XML file that is constructed according to the MSBuild XML Schema definition) that is used to instruct the build engine what to do. I will not get into the details because MSBuild is not the subject of this post. Here is the project file:

<?xml version="1.0" encoding="utf-8" ?>
<Project xmlns="http://schemas.microsoft.com/developer/MsBuild/2003">
  <UsingTask
      TaskName="CompressorTask"
      AssemblyFile="Yahoo.Yui.Compressor.dll" />

  <Target Name="MyTaskTarget">
    <ItemGroup>
      <JavaScriptFiles Include="..\Scripts\jquery-1.3.2.js"/>
      <JavaScriptFiles Include="..\Scripts\MicrosoftAjax.js"/>
      <JavaScriptFiles Include="..\Scripts\MicrosoftMvcAjax.js"/>
    </ItemGroup>
    <CompressorTask
        CssFiles="@(CssFiles)"
        DeleteCssFiles="false"
        CssOutputFile="$(CssOutputFile)"
        CssCompressionType="YuiStockCompression"
        JavaScriptFiles="@(JavaScriptFiles)"
        ObfuscateJavaScript="True"
        PreserveAllSemicolons="False"
        DisableOptimizations="Nope"
        EncodingType="Default"
        DeleteJavaScriptFiles="false"
        LineBreakPosition="-1"
        JavaScriptOutputFile="$(JavaScriptOutputFile)"
        LoggingType="ALittleBit"
        ThreadCulture="en-us"
        IsEvalIgnored="false"
            />
  </Target>
</Project>

The important part is the ItemGroup element in which you specify the scripts that will be acted upon by YUI Compressor. Next you should edit the Build event script in order to run the MSBuild task. Right-click the project and choose Properties, then select Build Events. In the Post-build event command line enter the following script:

$(MSBuildBinPath)\msbuild.exe "$(ProjectDir)MSBuild\MSBuildXML.xml" /p:JavaScriptOutputFile="$(TargetDir)..\Scripts\JavaScriptFinal.js"
Project Properties - Build Events

Project Properties - Build Events

Now when you build your project your JavaScript files would be combined and minified – the output can be seen in this screenshot:

MSBuild output

MSBuild output

Another important aspect is where exactly in the page are the references for the JavaScript files. You should put them in the head section of the HTML document only if the scripts are essential for the page rendering phase (generation of HTML), otherwise you should put them at the end of the page to prevent blocking of the rendering. If you know that your script won’t be needed until a specific time on your page you could defer its loading. This way the browser won’t make a request for it and you will improve the page load time. It is really easy to accomplish – all you need to do is to attach an event handler to the onload event and download the file after a specified amount of time. Here is a sample HTML extension method for ASP.NET MVC that I wrote but this could be easily rewritten for ASP.NET:

private static string RegisterDeferredLoader(this HtmlHelper helper)
{
    HttpContextBase context = helper.ViewContext.HttpContext;
    if (context.Items.Contains("__DeferredLoader"))
        return "";

    context.Items.Add("__DeferredLoader", "__DeferredLoader");

    StringBuilder strBuilder = new StringBuilder();
    strBuilder.AppendLine("<script type=\"text/javascript\">");
    strBuilder.AppendLine("function loadScript(file){");
    strBuilder.AppendLine("var script = document.createElement('script');");
    strBuilder.AppendLine("script.type = \"text/javascript\";");
    strBuilder.AppendLine("script.src = file;");
    strBuilder.AppendLine("document.body.appendChild(script);");
    strBuilder.AppendLine("};");
    strBuilder.AppendLine("</script>");

    return strBuilder.ToString();
}

This private helper method outputs a JavaScript function on the page that initiates the request for the script file itself – it simply creates a SCRIPT DOM element and sets its src attribute to the URI of the file. When it is appended to the document the script file is downloaded automatically. The method also ensures that the JavaScript function is written only once in the HTML document – we do not want it multiple times which increases the overall size of the document that would be transferred.

Here is the extension method that would be used to defer the loading of scripts on the page:

public static string RegisterScript(this HtmlHelper helper, string resourceUri, int delayInMilliseconds)
{
    HttpContextBase context = helper.ViewContext.HttpContext;
    if (context.Items.Contains(resourceUri))
        return "";

    context.Items.Add(resourceUri, resourceUri);
    StringBuilder strBuilder = new StringBuilder();
    strBuilder.AppendLine(helper.RegisterDeferredLoader());

    strBuilder.AppendLine("<script type=\"text/javascript\">");
    strBuilder.AppendFormat("if (window.addEventListener) window.addEventListener('load', function(){{window.setTimeout(function(){{loadScript(\"{0}\");}}, {1});}}, false);", resourceUri, delayInMilliseconds);
    strBuilder.AppendFormat("else if (window.attachEvent) window.attachEvent('onload', function(){{window.setTimeout(function(){{loadScript(\"{0}\");}}, {1});}});", resourceUri, delayInMilliseconds);
    strBuilder.AppendLine("</script>");

    return strBuilder.ToString();
}

This method outputs JavaScript code that attaches an event handler to the onload event of the window in which the loadScript function is called after a specified number of milliseconds. As you can see all of this is accomplished with a minimum amount of code and there is no complex logic. In order to use the extension method in your pages you should add its namespace to the pages/namespaces element inside the web.config file:

<pages>
    ...
    <namespaces>
        ...
        <add namespace="JSOptimizations.Helpers"/>
    </namespaces>
</pages>

What follows is a simple test of the extension method. This is a very simple JavaScript file that renders the time at which it is executed:

document.body.innerHTML += 'I am now loaded at ' + new Date();

And the HTML for the page is as follows:

<%@ Page Language="C#" Inherits="System.Web.Mvc.ViewPage" %>

<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd">

<html xmlns="http://www.w3.org/1999/xhtml" >
<head runat="server">
    <title>DeferLoading</title>
    <%= Html.RegisterScript("../../Scripts/DeferLoading.js", 5000) %>
</head>
<body>
    <script type="text/javascript">
        document.body.innerHTML += 'Page is rendered at: ' + new Date() + '<br/>';
    </script>
</body>
</html>

When you open it you would see something similar to the screenshot:

Deferred Loading of JavaScript

Deferred Loading of JavaScript

As you can see the JavaScript file is loaded exactly 5 seconds after the page is rendered.

You could download the sample test project with both the MSBuild task and the extension methods from here.

Summary

Simply by utilizing some techniques for loading JavaScript files you could dramatically increase the load times of your pages. Both minifying and combining several files into a single one can save significant amount of bandwidth. Deferred loading allows you to download scripts after the page has loaded thus reducing the network round trips to the server while rendering the page. There is no single golden rule that will help you achieve the best performance but when you use different techniques for your specific scenario you could really make great improvements.

ASP.NET MVC Custom Compression Action Filter

December 2, 2009 69 comments

Action filters are a powerful mechanism in ASP.NET MVC to add an additional layer of control to your action methods by attaching to the request-response pipeline. Just by decorating an action method or controller class you can perform a custom authorization based on specific rights and roles, cache and/or compress the response, localization, etc.

Implementation

In order to implement a custom action filter you need to inherit from ActionFilterAttribute – this is an abstract class that has four methods that you can override:

  • OnActionExecuting
  • OnActionExecuted
  • OnResultExecuting
  • OnResultExecuted

As their names imply a custom logic can be performed before/after an action method is executed and before/after the result is executed. Action filters have an Order property which specifies the order in which the filter is applied when multiple filters are used to decorate an action method.

Performance Optimizations

Nowadays with broadband internet a lot of people do not care about the performance of their web sites but they are wrong. Every single byte counts when you want to stand out – the end users do not care about what technology is powering up your system, they do care about performance. One of the first things that you could do to reduce the payload of your site is to do gzip or deflate compression – it will reduce the size of the server response by 60-65%. Compression is only applicable if the end user’s browser supports it – all major browsers support it so you do not need to worry. Gzip is more widely accepted and performs better than deflate, hence it should be your first choice.

Note: Do not apply compression to images and PDF files – they are already compressed and you will only waste CPU time to do so.

Compression Filter

Here is the code for the compression filter:

public class CompressionAttribute : ActionFilterAttribute
{
    public override void OnActionExecuting(ActionExecutingContext filterContext)
    {
        base.OnActionExecuting(filterContext);

        HttpRequestBase request = filterContext.HttpContext.Request;
        string acceptEncoding = request.Headers["Accept-Encoding"].ToLowerInvariant();
        if (string.IsNullOrEmpty(acceptEncoding))
            return;

        HttpResponseBase response = filterContext.HttpContext.Response;
        if (acceptEncoding.Contains("gzip"))
        {
            response.AppendHeader("Content-Encoding", "gzip");
            response.Filter = new GZipStream(response.Filter, CompressionMode.Compress);
        }
        else if (acceptEncoding.Contains("deflate"))
        {
            response.AppendHeader("Content-Encoding", "deflate");
            response.Filter = new DeflateStream(response.Filter, CompressionMode.Compress);
        }
    }
}

The Accept-Encoding header of the request shows whether the browser supports compression – if it is empty the CompressionAttribute class returns and does nothing. If the value is gzip or deflate the HttpResponseBase class’s property Filter which is of type Stream is wrapped by GZipStream or DeflateStream respectively. A Content-Encoding response header is set to the value of the compression method that is used so that the browser will know how to decompress the response.

Here is a sample usage of the Compression filter:

[Compression]
public ActionResult Index()
{
    return View();
}

Summary

Custom action filters give some extra power in the hands of developers to perform additional tasks along the ASP.NET MVC pipeline. You saw how simple it is to write a custom action filter that is applicable to real world scenarios. This is one of the performance optimization techniques that you could apply to improve the overall performance of your site.