C H A P T E R  6

Image

ASP.NET 4.5

Although ASP.NET MVC continues to grow in popularity, Microsoft estimates that between 80% and 90% of their customer base is still using ASP.NET Web Forms as their development platform of choice (Damian Edwards, ASP.NET program manager, Build Conference 2012).

It should thus come as no surprise that Microsoft continues to invest in the improvement of the ASP.NET Web Forms framework. ASP.NET MVC is, of course, built on top of ASP.NET Web Forms. As a result, many of these enhancements will also affect ASP.NET MVC developers—so please don’t skip this chapter!

ASP.NET 4.5 Web Forms has been influenced by its newer MVC brother, and it introduces support for strongly typed data controls and model binding. Other shiny new features include better async support, built-in minification and bundling of JavaScript and CSS files, and a new WebSockets API.

Strongly Typed Data Controls and Model Binding

Previously when working with template controls such as GridView, you would declare the item you wanted to bind to with a syntax similar to the following:

<%# DataBinder.Eval (Container.DataItem, "Price") %>

With this type of syntax, it’s very easy to make a mistake, such as a typo, since the IDE doesn’t know the type you are binding to until runtime. Additionally, if any properties in the bound class are renamed or changed, you must remember to update the binding code. Otherwise, the error will only appear at runtime.

ASP.NET 4.5 solves these issues by allowing you to specify the type that is bound to a control with the new ItemType property. Let’s see this in action:

  1. Create a new ASP.NET 4.5 Web Forms project.
  2. Add a reference to System.ComponentModel.DataAnnotations assembly. (We will need this later to demonstrate cool declarative validation features.)
  3. Create a new class called Person:
    using System.ComponentModel.DataAnnotations;

    public class Person
    {
       public int ID { get; set; }
       [Required(ErrorMessage="First name is required")]
       public string FirstName { get; set; }
       public string LastName { get; set; }
       public int Age { get; set; }
    }
  4. Create something to display the data, so open default.aspx and add the following:
       <asp:FormView ID="FormView1" ItemType="WebApplication7.Person" UpdateMethod="UpdatePeople"
    AllowPaging="true" runat="server" SelectMethod="GetPeople" DataKeyNames="ID"
    DefaultMode="Edit">
                <EditItemTemplate>
                <ol>
                   <li>
                   <%#Item.ID%>
                   </li>

                   <li>
                    <asp:TextBox ID="textFirstName" runat="server" Text='<%# BindItem.FirstName
    %>' />
                   </li>
                   <li>
                    <asp:TextBox ID="txtLastName" runat="server" Text='<%# BindItem.LastName%>'/>
                   </li>
                </ol>


                <asp:linkbutton id="UpdateButton"
                text="Update"
                commandname="Update"
                runat="server"/>


                <asp:ValidationSummary ID="ValidationSummary1" runat="server"/>
                </EditItemTemplate>
         </asp:FormView>
  5. Note the use of the new ItemType property. You might also have noticed we set two new properties: SelectMethod and UpdateMethod. SelectMethod and UpdateMethod are new methods that unsurprisingly allow us to specify the methods to bind and update data. We will complete our binding example by creating these select and update methods.
  6. We will return an IQueryable list of our person class (you can think of IQueryable as a query that hasn’t been run yet and can be modified on the fly—this is needed to enable the FormView control’s paging functionality). To do this, open default.aspx.cs and add the following code:
    public IQueryable<Person> GetPeople()
            {

                IQueryable<Person> people = new List<Person>(){
                new Person()
                {
                ID=0,
                Age=33,
                FirstName="Belinda",
                LastName="Lord"
                },

                new Person()
                {
                ID=1,
                Age=62,
                FirstName="Rhonda",
                LastName="Lord"
                },

                new Person()
                {
                ID=2,
                Age=64,
                FirstName="Gary",
                LastName="Lord"
                },


                new Person()
                {
                ID=4,
                Age=1,
                FirstName="Darcy",
                LastName="Lord"
                },



                }.AsQueryable();
                return people;
            }

            public void UpdatePeople(Person model)
            {
                var success = TryUpdateModel<Person>(model);
                if (success)
                {
                    //TODOwritebackupdate
                };
            }
  7. Run the application and you should see a highly exciting form view control bound to the list of people we created.

BindItem

BindItem is similar to Item but should be used if you want to persist changes that the user has made. To see the difference between Item and BindItem, follow these steps:

  1. Modify the textboxes in the example above to the following:
    <asp:TextBox ID="textFirstName" runat="server" Text='<%# Item.FirstName %>' /></asp:TextBox>
    <asp:TextBox ID="txtLastName" runat="server" Text='<%# BindItem.LastName %>' /></asp:TextBox>
  2. Put a breakpoint on UpdatePeople method and run the application.
  3. Make a change in both textboxes.
  4. Click the Update button and the breakpoint should be hit.

You will see only the LastName property in the submitted model has been populated with changes.

Validation

In the example above, we added a special validation attribute to our Person class:

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

This attribute, of course, specifies that the FirstName field is required. To see the effect of this attribute, run the example, remove any entry in the first name textbox, and click the Update button. ASP.NET validation will then kick in and you should then see the error message “First name is required.” This feature should look familiar to MVC users.

There is a number of different validation attributes that you can apply to your classes; ASP.NET 4.5 introduces some new ones such as e-mail address, telephone number, and credit card number. Refer to the source at http://msdn.microsoft.com/en-us/library/system.componentmodel.dataannotations(v=vs.110).aspx for more detail.

These simple binding improvements bring us a number of advantages:

  • Since the control is strongly typed, we get “intellisense”—yea!
  • Our presentation and logic is cleanly separated, which is great for a number of reasons:
    • It’s easy to unit test the save and load methods.
    • It makes the code easier to maintain.
    • Work flow between designers and developers is simplified.
  • We can easily specify validation rules with attributes.
  • The markup in the page clearly describes what’s going on (so simple even your average project manager could work it out).

These new binding features give you some of the benefits ASP.NET MVC users have been enjoying. They could be a good starting point for upgrading existing applications to a cleaner, happier way of doing things.

HTML Encoded Databinding

While we are on the subject of databinding, I want to mention two new databinding-related features in ASP.NET 4.5:

  • HTML encoding databind expressions
  • DataGrid’s AllowCustomPaging and VirtualItemCount
HTML Encoding Databind Expressions

New to ASP.NET 4.5 is the ability to HTML encode databinding expressions by appending “:” to the end of the <%# block. For example:

<%#: BindItem.LastName %>

DataGrid’s AllowCustomPaging and VirtualItemCount

Normally when you page data with a control such as DataGrid, a data source containing every row of the data set is loaded, which can take time with large data sets.

ASP.NET 4.5 introduces a new mode that is enabled by setting AllowCustomPaging to "true". Once this is set, it tells ASP.NET that the currently bound data source doesn’t contain every row of data, and it should instead refer to the VirtualItemCount to determine the number of items to display. The user would then use the OnPageIndexChanged event to set the current page index and calculate the block of data to display.

Microsoft has an example of this at http://msdn.microsoft.com/en-us/library/system.web.ui.webcontrols.datagrid.allowcustompaging.aspx.

Value Providers

It is common in web applications to need to read from a QueryString or other posted value. ASP.NET 4.5 introduces new attributes to do this declaratively.

Let’s modify our GetPeople method to filter the list of people based on a value from the QueryString using this new approach.

  1. Open up default.aspx.cs.
  2. Add the following directive:
    using System.Web.ModelBinding;
  3. Modify the GetPeople method to the following code. Note the use of the new [QueryString] attribute on the method signature:
    public IQueryable<Person> GetPeople([QueryString] string firstName)
            {

                var people = new List<Person>(){
                    new Person(){
                        ID=1,
                        Age=31,
                        FirstName="Alex",
                        LastName="Mackey"
                    },
                    new Person(){
                        ID=2,
                        Age=33,
                        FirstName="Belinda",
                        LastName="Lord"
                    }

                }.AsQueryable();

                if (!String.IsNullOrWhiteSpace(firstName))
                {
                    return people.Where(person => person.FirstName == firstName);
                }
                else
                {
                    return people;
                }
    }
  4. Run the application.
  5. Append a parameter called firstname to the URL e.g. ?firstName=Belinda.
  6. Results should then be filtered to people who have the first name Belinda.

When applying the value type attribute, ASP.NET will match values to parameters based on name (in this case firstName from QueryString is matched to firstName in the method parameters). If this isn’t what you want, you can of course specify the value to bind to as below:

GetPeople([QueryString("nameIWantToFilterOn")] string firstName)

Binding to Other Types of Items

As well as binding to QueryString values, you can bind the variable to a number of other types of variables:

  • Control properties
  • Cookies
  • Form values
  • Profile values
  • RouteData
  • Session data
  • UserProfile data
  • ViewState (Ewww!)

… and if none of these serve your purposes, you can even create your own value providers.

Creating Your Own Value Providers

The example below demonstrates how to create your own binder. Our binder won’t do much apart from append the string echo to the requested value. (Note: This is very similar to how you would do this in ASP.NET MVC with the IValueProvider interface.)

using System.Globalization;
using System.Web.ModelBinding;

 public class TestBinderAttribute : ValueProviderSourceAttribute
    {
        private readonly string _key;
        public TestBinderAttribute()
        {
        }

        public TestBinderAttribute(string key)
        {
            _key = key;
        }

        public string Key
        {
            get
            {
                return _key;
            }
        }
        public bool ValidateInput { get; set; }

        public override string GetModelName()
        {
            return "";
        }

        public override IValueProvider GetValueProvider(ModelBindingExecutionContext
modelBindingExecutionContext)
        {
            return new TestBinderAttributeProvider();

        }

    }

    public class TestBinderAttributeProvider : IValueProvider
    {
        public bool ContainsPrefix(string prefix)
        {
            return false;
        }
        public ValueProviderResult GetValue(string key)
        {
            var result = new ValueProviderResult("Echo " + key ,key , CultureInfo.InvariantCulture);
            return result;

        }
    }

That’s it! You can then simply apply the new value provider with the attribute [TestBinder]:

public IQueryable<Person> GetPeople([TestBinder] string firstName)
{

}

HTML5 Changes

HTML5 introduces a huge number of changes, some of which have necessitated ASP.NET server controls being updated (please see the IDE chapter for a number of changes):

  • The ASP.NET textbox control has been updated to include new input types such as Email, DateTime, and so forth.
  • Validator and UpdatePanel controls work with these new element types.

File Upload Control Supports Multiple File Uploads

The file upload control now supports the multiple file upload feature (for browsers that support this).

To enable, simply set the AllowMultiple property to "true". For example,

<asp:FileUpload ID="uploadFile" runat="server" AllowMultiple="true" />

You can then iterate through the files uploaded with the PostedFiles property:

foreach (var file in uploadFile.PostedFiles) {
   file.SaveAs("");
}

Bundling and Minification

During development, it is common to separate JavaScript and CSS files for maintainability and ease of development. Unfortunately, this division isn’t the best way to deliver the files to your users, which is where bundling and minification come in.

Bundling is the combining of files to reduce the number of requests a browser has to make. Minification is the removal of unnecessary characters (e.g., comments and spaces) to produce as tiny a file as possible.

Bundling and minification give you the following advantages:

  • The site should load quicker as there is less content to load.
  • Some browsers limit the number of HTTP requests that can be made at one time to an individual domain. Thus, reducing the number of requests means that your site should load more quickly. (You may also be interested in the concept of domain sharding, which attempts to get around this restriction by serving content from different domains.)
  • Bandwidth bills are reduced as less data is transmitted.
  • They obscure CSS and JavaScript from casual peeking. (Warning: It’s pretty trivial to unscramble a minified file—many browsers now have this functionality built in to their development tools)

Prior to VS2012, bundling and minification would have to be implemented using one of many third-party tools and libraries such as ClientDependency and JSMin.

Bundling and Minification for VS2010 Users

VS2010 users can enjoy these new features by downloading and applying the NuGet package ASP.NET Optimization (see Figure 6-1).

Image

Figure 6-1. NuGet package ASP.NET Optimization

App_Start and Bundling/Minification Configuration

So, how do we configure the files to bundled and minified? This configuration is done in BundleConfig.cs, which is located in a new directory called App_Start. App_Start is used to contain programmatic configuration for ASP.NET applications (by default bundles/minification in ASP.NET and other items such as Routing in ASP.NET MVC).

BundleConfig has one static method called RegisterBundles, which lists all the files to be minified/bundled. This is called in the global.asax.cs App_Start method. There is no reason you have to stick with this convention, but I can’t see an immediate problem with it so I suggest using it.

Let’s take a look at what is going on in the RegisterBundles method. The following example (code removed for brevity) shows the creation of two types of bundles: a ScriptBundle containing two Microsoft AJAX JavaScript files and a StyleBundle containing site.css.

public static void RegisterBundles(BundleCollection bundles)
{
  bundles.Add(new ScriptBundle("~/bundles/MsAjaxJs").Include(
                "~/Scripts/WebForms/MsAjax/MicrosoftAjax.js",
                "~/Scripts/WebForms/MsAjax/MicrosoftAjaxWebForms.js"));

    bundles.Add(new StyleBundle("~/Content/css").Include("~/Content/site.css"));
}

I think it’s pretty self-explanatory how this API works—the only parameters you may be wondering about are the "~/bundles/MsAjaxJs" and "~/Content/css" values. These provide a path that your bundle should be referenced at. When you want to use your bundles, you simply reference the bundles as in the following (note MVC has a similar syntax):

<%: Styles.Render("~/Content/css", "~/Content/moreCss") %>
<%: Scripts.Render("~/bundles/MsAjaxJs") %>

But there is one more thing to be aware of—the use of minified and bundled files can make debugging harder, so files will only be bundled and minified when you are not running in debug mode. This can be modified in web.config as shown here:

<compilation debug="true"></compilation>

Or you can also use the BundleTable.EnableOptmizations API if you need programmatic control.

It would be tedious to add each file in a directory, so the Bundles API also has an IncludeDirectory method. But you may be wondering in what order ASP.NET will bundle your scripts and CSS files? By default, files are bundled alphabetically. ASP.NET does, however, understand the dependencies for some popular libraries—the bundler is smart enough to know that jQuery needs to be bundled before jQueryUI.

The bundler even understands common naming conventions and will always place reset.css and normalize.css first when combining CSS files.

Creating Your Own Transforms

If you want to use your own bundling or minification mechanism, the Optimization extensions allow you to do this too by implementing the IBundleTransform interface.

Let’s create a simple custom bundler that replaces a string in JavaScript files to demonstrate how to do this:

  1. Create a new class called TestTransform and add the following code:
    using System.Web.Optimization;

    public class TestTranform : IBundleTransform
        {
            public void Process(BundleContext context, BundleResponse response)
            {
                response.Content = response.Content.Replace("replace me", "Yep your custom bundler
    works!");
                response.ContentType = "text/css";
            }
        }
  2. Now open Global.asax and register the new transform:
    var testBundle = new Bundle("~/bundles/testMinify").Include("~/scripts/test.js");
    testBundle.Transforms.Add(new TestTranform());
    bundles.Add(testBundle);
  3. Reference your bundle and transform with a script tag in our aspx or master file as shown below:

       <%: Scripts.Render("~/bundles/testMinify") %>

  4. Finally, create a new JavaScript file in the root of the script directory and add the following code:

    alert('replace me'),

  5. Now open the site and an alert box should be shown with the replaced text.

More Useful Possibilities of Bundling/Minification

Custom bundlers and minifiers can be used for any pre-processing you might want to do on JavaScript or CSS files. For example, at the Build 2012 conference, Mads Kristensen (Microsoft Web Platform Program Manager) showed a creative example of overriding the minification process to compile CoffeeScript to JavaScript. For further information on this, please refer to http://channel9.msdn.com/Events/BUILD/BUILD2012/SAC-837T.

Validation and XSS Changes

XSS (cross-site scripting) is a well-known attack where unvalidated user input is directly output onto a web page, unencoded, and run. For example, imagine if the following script were submitted to a forum site and then output unencoded (it would be run for each user that visited the site!):

<script>alert('do something bad')</script>

Or even the much worse:

<script>window.location='http://www.justinbiebermusic.com/'</script>

XSS attacks can, however, be much more serious as they can be used to hijack another user’s session cookie, and as a result, allow the attacker to make requests in the context of another user.

For more information on XSS, please refer to www.owasp.org/index.php/Cross-site_Scripting_(XSS) and www.blackhat.com/presentations/bh-usa-09/VELANAVA/BHUSA09-VelaNava-FavoriteXSS-SLIDES.pdf.

ASP.NET Validation

By default, ASP.NET will try to validate submitted requests for potential attacks such as XSS. At some point, you have probably seen this kick in and a screen similar to the one shown in Figure 6-2.

Image

Figure 6-2. Potentially dangerous request submitted

You could be forgiven for thinking that ASP.NET will prevent all XSS attacks. Unfortunately, this isn’t the case.

Image Warning  Attempting to circumvent ASP.NET protection on live web sites is very probably illegal, so don’t do it!

Unfortunately, ASP.NET’s protection mechanisms are fairly easily circumvented (see www.procheckup.com/vulnerability_manager/documents/document_1258758664/bypassing-dot-NET-ValidateRequest.pdf), and there is a mind-blowing number of ways to format input and produce an XSS attack. (See http://ha.ckers.org/xss.html.) Thus, it is vital that you never trust any input from a user and always make sure you encode any output.

Other Issues with ASP.NET Validation

ASP.NET validation can also sometimes get in the way if users want to be able to enter certain characters such as “<” or “>”. As an example, I worked on a medical system where staff would often use characters such as “<” and “>” to denote ranges of laboratory values. In certain combinations, the characters “<” and “>” will cause ASP.NET’s validation checks to fail, which led to some unhappy medical staff not being able to enter data how they wanted!

Prior to ASP.NET 4.5, if you wanted to ensure staff could always enter data in this format, you had little choice but to turn validation off at a page or site level.

So now we that we know the issues with the existing model, let’s see how ASP.NET 4.5 improves things.

New Shiny ASP.NET 4.5 Validation Mode!

ASP.NET 4.5 validation mode is enabled by default in ASP.NET 4.5 sites and in web.config with the following key:

<httpRuntime requestValidationMode="4.5" />

When operating in 4.5 validation mode, a number of new features are enabled such as lazy validation, the ability to access raw unvalidated data without triggering the validation mechanisms, and new integrated AntiXSS functionality!

Lazy Validation

When the validation mode is set to 4.5, submitted data using Server Controls (standard HTML form elements will still trigger failure) will only be validated when and if it’s actually used. Consequently, if a submitted data contains potentially dangerous values but you never actually use it, then ASP.NET will not throw a nasty, potentially dangerous, request error.

Raw Unvalidated Data

ASP.NET 4.5 provides the ability for you to access the raw form, cookies, QueryString, and URL data without triggering validation with the new unvalidated collections:

Request.Unvalidated.Cookies["myValue"]
Request.Unvalidated.QueryString["myValue"]
Request.Unvalidated.Form["myValue"]

Image Warning  When you use this method, you are on your own and must remember to perform your own checks!

ValidateRequestMode

Validation can now be disabled at control level with the ValidateRequestMode property:

<asp:TextBox ValidateRequestMode="Disabled" runat="server"></asp:TextBox>

AntiXSS

ASP.NET 4.5 has beefed up protection against XSS attacks by incorporating a more advanced protection mechanism based on the open source AntiXSS libraries. The AntiXSS libraries provide superior encoding and protection by using a whitelist-based model (specifying the values that are allowed rather than those that are not allowed), and they contain additional security and encoding features.

ASP.NET 4.5 sites and applications use AntiXSS encoding by default by specifying the following option in web.config:

<httpRuntime ...
  encoderType="System.Web.Security.AntiXss.AntiXssEncoder, System.Web,
    Version=4.0.0.0, Culture=neutral, PublicKeyToken=b03f5f7f11d50a3a" />

AntiXSS routines are now used by default for the following methods in ASP.NET 4.5:

  • CssEncode
  • HtmlEncode
  • HtmlFormUrlEncode
  • HtmlAttributeEncode
  • XmlAttributeEncode
  • XmlEncode
  • UrlEncode
  • UrlPathEncode (new)

You can also, of course, use the various AntiXSS methods individually if you need more control. For example:

<%=System.Web.Security.AntiXss.AntiXssEncoder.HtmlEncode("<script>alert('I wont run as im
encoded!'),</script>", false)%>

Let’s talk to Barry Dorrans, the original developer of AntiXSS and author of Wrox’s Beginning ASP.NET Security, about AntiXSS and XSS attacks.

Barry Dorrans and AntiXSS

AntiXSS was originally developed as a separate open source project, wasn’t it?

Yes. And it still is. The open source project provides more encoding options—the core encoders were taken into the framework (Alex: Barry also mentioned AntiXSS has additional VBScript, Javascript, and the two LDAP encoders that are not present in the framework version). AntiXSS will be updated and enhancements pulled from .NET 4.5, and .NET will take enhancements from AntiXSS as well for the code encoders.

Any general advice on how to protect against XSS attacks?

Don’t trust input. This doesn’t just mean data from forms, but data from your database, as there’s a risk it may have been compromised, or data from a request such as cookies or headers. All of these can be changed by an attacker, and all should be validated and encoded before output. Additionally, encode correctly. If you’re outputting to JavaScript, use the JavaScript encoder. If your JavaScript is going to insert HTML, then you need to HTML encode first, then JavaScript encode, before outputting it into your page.

Any new features in AntiXSS that you would like to highlight to readers?

AntiXSS now supports .NET 4.0’s encoder swapping, so you can switch between the original .NET encoder and the AntiXSS encoder (either the built-in 4.5 version or the stand-alone version) with the flick of a config setting.

You are known to have some strong opinions on individuals with red hair—any comment?

All male gingers should be rounded up and sent to Tasmania, then the island surrounded with mines and other deterrents to stop them making an escape.

Hmm … time to move on to unobtrusive validation …

Unobtrusive Validation

ASP.NET 4.5’s unobtrusive validation significantly reduces the amount of JavaScript that is generated inline when using ASP.NET’s validation controls.

Let’s see this in action by comparing the two modes. First, add a textbox and validation control to a page:

<asp:TextBox ID="txtFirstname" runat="server"></asp:TextBox>
        <asp:RequiredFieldValidator runat="server" ControlToValidate="txtFirstname"
ErrorMessage="Required"></asp:RequiredFieldValidator>

Check out all the funky validation code this small addition generates:

<script type="text/javascript">
//<![CDATA[
var Page_Validators =  new Array(document.getElementById("ctl02"));
//]]>
</script>
<script type="text/javascript">
//<![CDATA[
var ctl02 = document.all ? document.all["ctl02"] : document.getElementById("ctl02");
ctl02.controltovalidate = "txtFirstname";
ctl02.errormessage = "Required";
ctl02.evaluationfunction = "RequiredFieldValidatorEvaluateIsValid";
ctl02.initialvalue = "";
//]]>
</script>

<script type="text/javascript">
//<![CDATA[

var Page_ValidationActive = false;
if (typeof(ValidatorOnLoad) == "function") {
    ValidatorOnLoad();
}

function ValidatorOnSubmit() {
    if (Page_ValidationActive) {
        return ValidatorCommonOnSubmit();
    }
    else {
        return true;
    }
}
        //]]>
</script>
And
<script type="text/javascript">
//<![CDATA[
function WebForm_OnSubmit() {
if (typeof(ValidatorOnSubmit) == "function" && ValidatorOnSubmit() == false) return false;
return true;
}
//]]>
</script>

Ugh—and this is the slightly cut-down version! Luckily, we can reduce this in ASP.NET 4.5 by enabling the new unobtrusive validation mode (enabled by default in 4.5 sites and applications). When unobtrusive validation is enabled, additional HTML5 data attributes are added to controls to hold the meta information about how validation should work and the generated script is much reduced:

<input name="txtFirstname" type="text" id="txtFirstname" />
        <span data-val-controltovalidate="txtFirstname" data-val-errormessage="Required"
id="ctl02" data-val="true" data-val-evaluationfunction="RequiredFieldValidatorEvaluateIsValid"
data-val-initialvalue="" style="visibility:hidden;">Required</span>

If for some reason you don’t want to use the new validation mode, you can turn it off in a number of places.

  • Web.config:

    <add name="ValidationSettings:UnobtrusiveValidationMode" value="None" />

  • Programmatically:
    ValidationSettings.UnobtrusiveValidationMode =
                            UnobtrusiveValidationMode.WebForms;
  • At page level:

    Page.UnobtrusiveValidationMode = System.Web.UI.UnobtrusiveValidationMode.WebForms;

Async

One of the big themes in ASP.NET 4.5 is better support for asynchronous scenarios with the introduction of Await and Async keywords. It’s worth noting that previous versions of ASP.NET contain async functionality such as async pages and interfaces for writing async handlers and modules (although their examples and documentation are a bit lacking).

For more information, please refer to http://msdn.microsoft.com/en-us/magazine/cc163463.aspx.

Async in ASP.NET 4.5

ASP.NET 4.5 contains several new APIs and changes that allow you to utilize async functionality in your web applications. But first, some of you may be wondering why you might want async support at all.

By default, ASP.NET has access to a (configurable) number of threads to services site requests. If all of these threads are doing something (e.g., awaiting a response from a remote server), then your web server won’t be able to respond to new requests and probably will start throwing Server Unavailable messages, leaving your users to look up amusing cat videos on YouTube.

Many ASP.NET applications function marvelously until they hit a certain number of requests, and then performance can degrade very quickly. Apart from throwing more hardware at the problem or optimizing code, we can try to be more efficient in utilizing resources.

If you have certain types of requests that have to wait on an external resource, you can essentially give back the thread to service other requests (until a response is received).

Of course, you could still end up with a situation where you tie up all the threads on a machine waiting for requests. In which case, you may want to consider other possibilities such as a non-blocking message/queue-based system.

When to Use Async to Improve Performance in ASP.NET

There are no hard and fast rules for determining when async functionality should be used, and it is vital that when making any changes, you measure their effect by benchmarking your application before and after changes are made. As a rough guide, you can consider implementing async functionality when the following situations are true:

  • Your users are getting server unavailable errors.
  • You have task(s) that are not CPU intensive and wait on a remote resource such as a service or database.
  • The task being performed is not really short—the overhead of maintaining the async model and context switching could actually make things worse for very fast tasks.

So now that we have a (simplified) view of why you might want to do this, let’s see how ASP.NET 4.5 can help us out.

Async HttpModule

It was possible in previous versions of ASP.NET to develop async modules and handlers, but documentation and examples were very scarce. ASP.NET 4.5 makes this much easier.

The example below shows how to create an asynchronous HttpModule that will call the Digg REST API (http://developers.digg.com/version2/digg-getall) asynchronously and output a string of JSON onto each web page the user requests:

using System.Threading.Tasks;
using System.Net;

public class TestHttpModule:IHttpModule
{

        public void Init(HttpApplication context)
        {
            EventHandlerTaskAsyncHelper helper = new
EventHandlerTaskAsyncHelper(ScrapeHtmlPage);
            context.AddOnPostAuthorizeRequestAsync(helper.BeginEventHandler,
helper.EndEventHandler);
        }

        private async Task ScrapeHtmlPage(object caller, EventArgs e)
        {
            WebClient client = new WebClient();
            var result = await
client.DownloadStringTaskAsync("http://services.digg.com/2.0/digg.getAll");
            //process here
            System.Web.HttpContext.Current.Response.Write(result);
        }


        public void Dispose()
        {

        }
    }

Note how we used the new EventHandlerTaskAsyncHelper class to wrap the Begin and End methods out of a task object, which avoided the need to worry about any implementation detail.

If you are playing with this example, remember to register the module in web.config:

<system.webServer>
    <modules>
      <add name="WebApplication4.TestHttpModule" type="WebApplication4.TestHttpModule"/>
    </modules>
  </system.webServer>

HttpTaskAsyncHandler

Previously if you wanted to develop an async handler, you would have to implement the IHttpAsyncHandler interface (see http://madskristensen.net/post/How-to-use-the-IHttpAsyncHandler-in-ASPNET.aspx). ASP.NET 4.5 introduces a new abstract class called HttpTaskAsyncHandler that hides a lot of the complexity from you.

HttpResponse, BeginFlush, and EndFlush

If you are sending a very large response to a user, it is necessary to periodically call the HttpResponse.Flush to stop memory usage becoming too high. ASP.NET 4.5 augments the HttpResponse class with new BeginFlush and EndFlush methods to allow you to perform blocks of flushing and not overuse OS resources.

GetBufferlessInputStream

ASP.NET 4 introduced a method called GetBufferlessInputStream to retrieve a stream object from a request. (See http://george2giga.com/tag/file-upload/ for an example.) This method, however, was synchronous and would occupy a thread for the entire request. ASP.NET 4.5 adds BeginRead and EndRead methods to the GetBufferlessInputStream method to allow chunked reading and releasing of resources between read calls.

GetBufferedInputStream

New to ASP.NET 4.5 is the GetBufferedInputStream, which is similar to GetBufferlessInputStream but also saves a copy of the request internally (the same place that Form, Files data is kept). This is cool as it allows you to use results in downstream pages, modules, and handlers.

WebSockets

Web applications are becoming increasingly sophisticated, and it is common to need to communicate with various services.

There are a number of options to accomplish this task with, probably the most popular being to continually poll a server with XHR requests. Other alternatives exist that delay disconnections. These can be tricky to implement and don’t scale well (sometimes worse than polling as they keep a connection open), so they aren’t used as much.

HTTP isn’t really an ideal protocol for performing frequent requests for the following reasons:

  • It’s not optimized for speed, and it utilizes a lot of bandwidth for every request with various headers, and the like, sent with each request.
  • To keep an application up-to-date, many requests must be sent.
  • It provides limited cross-domain support (relying on workarounds such as JSONP http://remysharp.com/2007/10/08/what-is-jsonp/).
  • Firewalls and proxies sometimes buffer streaming / long-polling solutions, increasing latency.
  • Long-polling and streaming solutions are not very scalable.

WebSockets is a new technology that attempts to resolve some of these limitations by:

  • Sending the minimum amount of data necessary
  • Making more efficient usage of bandwidth
  • Providing cross-domain support
  • Still operating over HTTP so it can transverse firewalls and proxies
  • Working with some load balancers (TCP l4)
  • Providing support for binary data (Note: some JavaScript implementations don’t currently support this.)
  • Providing a full duplex communication channel

When would WebSockets be a suitable protocol for your application? You might want to consider using WebSockets in the following scenarios:

  • Games
  • Real-time data
  • Chat applications
  • News tickers

There is a nice set of demos at www.html5rocks.com/en/tutorials/websockets/basics/ and an interesting article that compares a WebSockets and polling solution in terms of latency and throughput at http://websocket.org/quantum.html.

WebSockets Pitfalls

WebSockets is a relatively new protocol that has already undergone a number of versions as various issues are addressed. Addressing these problems is important as support across browsers varies.

At the time of writing, WebSockets (in some form) can be used by the following browsers (check http://caniuse.com for the most up to date information):

  • IE10
  • Chrome 13+
  • Firefox 7
  • Safari 5+
  • Opera 11+

Earlier implementations of WebSockets had some security issues, so your connections may work but they are not secure. (Firefox disabled support in Firefox 4 and 5 for this reason.)

The other issue that you may encounter is that some older proxy servers don’t support the HTTP upgrade system that WebSockets uses to connect, so some clients may be unable to connect.

ASP.NET 4.5 WebSockets Support

ASP.NET 4.5 introduces a number of APIs for working with WebSockets. If you find you need more control than the ASP.NET API’s offers, then look into WCF because it has also been updated.

Before we begin, there are a couple of requirements for using ASP.NET WebSockets API:

  • Application must be hosted on IIS 8 (available only with some version of Windows 8—please note IIS Express currently does not work).
  • WebSockets protocol feature must be installed (IIS option).
  • ASP.NET 4.5 must be in use.
  • A compatible browser on the client must be present. (IE10 or Chrome will work fine at time of writing.)
  • It would help if your Chinese birth animal were the horse.

Currently, Microsoft has no plans to release WebSockets support for earlier versions of IIS. Consequently, if you plan to run it on Windows Server 2008, you are going to have to look at other options such as http://superwebsocket.codeplex.com/. Alternatively you could look at the SignalR library from Microsoft, which is designed for developing async applications and providing WebSockets (and fallback) support: https://github.com/SignalR/SignalR/wiki/WebSockets.

Hello, WebSockets Example!

I am going to assume that you are already working with some version of Windows 8 that has IIS and ASP.NET 4.5 installed. The other thing we are going to need to do is make sure IIS has the WebSockets protocol feature installed (this is in the add/remove programs bit):

  1. First, create a new empty ASP.NET project called WebSockets.
  2. Add the NuGet package Microsoft.Websockets.
  3. Pull down the latest jQuery library and put it in a scripts directory (I am using 1.7.2). Note: jQuery isn’t necessary; it just saves a bit of tedious event and manipulation code.
  4. Now add a file called index.htm and enter the following code:
    <!doctype html>

    <head>

    <script src="Scripts/jquery-1.7.2.min.js" type="text/javascript"></script>

    <script type="text/javascript">

    $(document).ready(function () {

    var name = prompt('what is your name?:'),

    var url = 'ws://' + window.location.hostname + window.location.pathname.replace('index.htm',
    'ws.ashx') + '?name=' + name;

    alert('Connecting to: ' + url);

    ws = new WebSocket(url);

    ws.onopen = function () {
    $('#messages').prepend('Connected <br/>'),

    $('#cmdSend').click(function () {

    ws.send($('#txtMessage').val());

    $('#txtMessage').val(''),

    });

    };

    ws.onmessage = function (e) {

    $('#chatMessages').prepend(e.data + '<br/>'),

    };

    $('#cmdLeave').click(function () {

    ws.close();

    });

    ws.onclose = function () {

    $('#chatMessages').prepend('Closed <br/>'),

    };

    ws.onerror = function (e) {

    $('#chatMessages').prepend('Oops something went wront <br/>'),

    };

    });

    </script>

    </head>

    <body>

    <input id="txtMessage" />

    <input id="cmdSend" type="button" value="Send" />

    <input id="cmdLeave" type="button" value="Leave" />

    <br />
    <div id="chatMessages" />

    </body>

    </html>
  5. To create an HttpHandler, add a new generic handler to the project called ws.ashx and enter the following code:
    using System;

    using System.Collections.Generic;

    using System.Linq;

    using System.Web;

    using Microsoft.Web.WebSockets;

    namespace WebSockets

    {

    public class ws : IHttpHandler

    {

    public void ProcessRequest(HttpContext context)

    {

    if (context.IsWebSocketRequest)

    context.AcceptWebSocketRequest(new TestWebSocketHandler());

    }

    public bool IsReusable

    {

    get

    {

    return false;

    }

    }
    }

    }
  6. Finally, you need to create something to handle the WebSockets connection (TestWebSocketHandler, that is created in the AcceptWebSocketRequest method). Create a new class called TestWebSocketHandler and enter the following code:
    using System;

    using System.Collections.Generic;

    using System.Linq;

    using System.Threading;

    using System.Web;

    using Microsoft.Web.WebSockets;

    namespace WebSockets

    {

    public class TestWebSocketHandler : WebSocketHandler

    {

    private static WebSocketCollection clients = new WebSocketCollection();

    private string name;

    public override void OnOpen()

    {

    this.name = this.WebSocketContext.QueryString["name"];

    clients.Add(this);

    clients.Broadcast(name + " has connected.");

    }

    public override void OnMessage(string message)

    {

    clients.Broadcast(string.Format("{0} said: {1}", name, message));

    }
    public override void OnClose()

    {

    clients.Remove(this);

    clients.Broadcast(string.Format("{0} has gone away.", name));

    }

    }

    }
  7. That’s all you need. Now you can compile the project and run it in a compatible browser (IE10 or the latest Chrome will do fine), making sure you are hosting your project from IIS (project properties if you are not) and the site/application is operating in integrated pipeline mode.
  8. Once you have run it up, you will be prompted to provide a name. An alert box will then indicate the end point of your application (ws://localhost/.. Note: The secure HTTPS version is wss://.)
  9. Now open up a different browser via WebSockets (see Figure 6-3).
Image

Figure 6-3. WebSockets example running

Performance Improvements

Microsoft says that combined use of ASP.NET 4.5 and Windows 8 can improve web application startup time by up to 35 percent (www.asp.net/vnext/overview/whitepapers/whats-new#_Toc_perf).

A number of performance enhancements have been made that will affect ASP.NET applications performance:

  • Shared assemblies
  • Multi core JIT compilation
  • Precompilation
  • Optimized GC
  • Prefetcher

Shared Assemblies (ASP.NET 4 & VS2012)

If you have a number of web sites hosted on a server, it’s quite likely that many of them also use the same libraries. For example, several sites may reference NHibernate assemblies. When a web server first starts up, having many copies of the same libraries slows everything down as each one must be individually processed, read, and loaded.

VS2012 introduces a new command line tool that replaces individual assemblies with a link to a single copy of an assembly, making this process much quicker. If a site references a specific version of an assembly, the symbolic link will be replaced by the actual assembly.

To use the shared assemblies, you must use the command-line tool aspnet_intern.exe, which comes as part of the VS2012 SDK, to process assemblies on the server (you can also use this feature within ASP.NET 4 if you apply the following update: http://support.microsoft.com/kb/2468871).

When aspnet_intern is run, it will, by default, process assemblies that appear in more than three places. (This is configurable using the minrefcount option.)

Let’s see this in action now:

  1. Open a command prompt and go to C:Program Files (x86)Microsoft SDKsWindowsv8.0AinNETFX 4.0 Tools.
  2. Use the following command to look at all aspnet_interns options: aspnet_intern /?
  3. Run the following command to get a report of assemblies that would benefit from interning without actually interning:
    aspnet_intern -mode analyze -sourcedir
    "C:WindowsMicrosoft.NETFrameworkv4.0.30319Temporary ASP.NET Files" > c:internReport.txt
  4. Run the following command to intern assemblies to the folder C:CommonASP:
    aspnet_intern -mode exec -sourcedir
    "C:WindowsMicrosoft.NETFrameworkv4.0.30319Temporary ASP.NET
    Files" -interndir C:CommonASP

Microsoft suggests setting up a weekly scheduled task to do this.

Multi Core JIT Compilation (4.5)

When a site first starts up, individual assemblies must be JIT compiled by the framework. ASP.NET 4.5 speeds up this work by dividing compilation across multiple cores. This feature is enabled by default in ASP.NET 4.5, but it may be turned off in web.config as shown below:

<system.web>
    <compilation profileGuidedOptimizations="None"  />
</system.web>

GC Compilation Optimized for Memory

To a certain extent, previous versions of ASP.NET allowed you to configure and tweak how the garbage collector worked (http://learn.iis.net/page.aspx/50/aspnet-20-35-shared-hosting-configuration/).

ASP.NET 4.5 introduces a new profile setting for those running servers, hosting many sites that groups these tweaks together. To enable this setting, copy the following setting to the aspnet.config file at WindowsMicrosoft.NETFrameworkv4.0.30319aspnet.config:

<configuration>
  <runtime>
    <performanceScenario value="HighDensityWebHosting"  />

Prefetcher (Windows 8 and ASP.NET 4.5 only)

Recent versions of Windows include a technology known as Prefetcher (http://en.wikipedia.org/wiki/Prefetcher), which reduces disk-read time by maintaining an index of recently used files.

Until now, Prefetcher was not available in server editions of Windows because it was mainly aimed at client applications. Prefetching, however, can reduce launch time for individual sites. To enable Prefetching for individual sites, run the following command from a Visual Studio command prompt:

sc config sysmain start=auto
reg add "HKEY_LOCAL_MACHINESYSTEMCurrentControlSetControlSession ManagerMemory
ManagementPrefetchParameters" /v EnablePrefetcher /t REG_DWORD /d 2 /f
reg add "HKEY_LOCAL_MACHINESoftwareMicrosoftWindows NTCurrentVersionPrefetcher" /v
MaxPrefetchFiles /t REG_DWORD /d 8192 /f
net start sysmain

You must then add the following switch to your web site:

<configuration>
  <system.web>
    <compilation enablePrefetchOptimization="true" />
  </system.web>
</configuration>

Precompile

VS2012 allows you to precompile a web site before deployment or publishing to reduce startup time. To enable this option, right-click on Project, select Properties, and then go to the Package/Publish Web tab and select the checkbox that reads “Precompile this application before publishing.”

Miscellaneous Changes

You should also be aware of the following changes in VS2012 affecting ASP.NET users.

IIS Express

In VS2012, IIS Express is now the default web server for testing your applications. IIS Express has all the main features of its bigger brother, but it doesn’t require administrator rights for most tasks, it is not run a service, and it can be used by multiple users on the same machine. Refer to http://learn.iis.net/page.aspx/868/iis-express-overview/ for more information.

Enable CDN Fallback

The Script Manager control will now fall back to a local version of referenced scripts if they are not loaded successfully from the CDN. For more information on the EnableCDN feature, please refer to http://weblogs.asp.net/infinitiesloop/archive/2009/11/23/asp-net-4-0-scriptmanager-improvements.aspx.

Routing Changes

An update was made to IIS 7 to natively enable routing functionality on Windows 7 SP1. Previously it was necessary to add a setting called runAllManagedModulesForAllRequests to your web.config file to enable this. The new web site templates in Visual Studio 12 do not include this setting, which means that it is false by default. Thus, if you run one of the new project templates on a machine without the aforementioned update applied, then routing won’t work. To resolve this problem, simply add the setting to web.config:

<configuration>
  <system.webServer>
    <modules runAllManagedModulesForAllRequests="true">
    </modules>
  </system.webServer>
</configuration>

HttpRequest.Abort

HttpRequest.Abort is a new method that forcibly terminates an HTTP connection.

New APIs for Better Async Support

A number of new APIs have been introduced for better Async support such as HttpResponse.ClientDisconnectedToken, HttpRequest.TimedOutToken, and HttpContext.ThreadAbortOnTimeout. These APIs allow you to be notified of client disconnection or timeout and control the time before ASP.NET aborts a request. Unfortunately there is no information on these at the time of writing.

New APIs for Extending Web Forms Compilation

Microsoft has also introduced new APIs for customizing how ASP.NET works. Again, very little information is available on these APIs, but I wanted to make you aware of them. A new class called ControlBuilderInterceptor has been created that should allow you to customize Web Forms output to some degree, and a new method called TemplateParser.ParseTemplate will allow the creation of a template instance from ASPX markup.

AN INSIDER’S OPINION

Conclusion

ASP.NET 4.5 contains a number of useful features. Probably the biggest game changer is support for model and declarative binding. New async support and improvements to validation are also very welcome and will benefit all users.

..................Content has been hidden....................

You can't read the all page of ebook, please click here login for view all page.
Reset
3.144.222.185