October 2010 - Posts

ASP.NET Web Pages Beta 1 have support for Helpers, which are methods written in C# or Visual Basic, and returns IHtmlString. They can return HTML that is displayed on the page. If you choose to create helpers that way, you would need to have your HTML in an assembly, which makes it different to modify. Because of that, the new version of Razor supports declarative Helpers that you can create directly on the page. They work in both ASP.NET MVC 3 Beta and ASP.NET Web Pages Beta 2, which is included in WebMatrix.

A declarative helper is created the same way as a method, but instead of having a return type, you set ”helper”.

Let´s say you have this code:

@{
    var text = "Hello, world!";
    <p>@text</p>
}

We want to refactor it into its own method to be able to reuse it. We can do it using a declative helper, like this:

@helper SayHello(string yadda)
{
    <p>Text: @yadda</p>
}

And if you want to use it:

@SayHello("Hello, world!")

We can also add code in the helper, such as:

@helper Calculator(int a, int b)
{
    @{
        var sum = a + b;
    }
    
    <b>@sum</b>
}

And to display the result, we use:

1 + 2 = @Calculator(1, 2)

It will display ”3” on the page, which is the sum of the numbers.

To go one step further and make it even more dynamic, we can use Lambda Expressions for the helper. If we want to be able to change how to count the result, we could use this instead:

@helper Calc(int a, int b, Func<int, int, int> calc)
{
    @{
        var sum = calc(a, b);
    }
    <p>@sum</p>
}

And if we want to multiply the letters, we use the helper this way:

@Calc(4, 4, (a, b) => a * b)

We can actually create really advanced helpers directly on the page. This is for those who are using ASP.NET Web Pages, but it can also be used in ASP.NET MVC 3 Beta.

In ASP.NET MVC 2 we got support for client validation of the model. When we activate it, a JavaScript is generated and added to the rendered view. It contains all validation rules we set up for the model, and are used to generate error massages without reloading the page.

I ASP.NET MVC 3 they have extended that support. Instead of generating a JavaScript, you can now use ”unobtrusive Jquery validation”, which uses the data-* attribute in HTML5 instead of using JavaScript.

To activate it on the page you can add this:

@Html.EnableUnobtrusiveJavaScript()

And to activate it on all pages, you can add a key to web.config:

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

New ASP.NET MVC 3 Beta projects will have this enabled as default, and upgraded projects will not have it activated as default to make sure it is backwards compatible.

To use this new validation, you will have to add references to jquery-1.4.1.js, jquery.validate.js and jquery.validate.unobtrusive.js.

To test this, I have a model, ”Customer”, which looks like this:

using System;
using System.ComponentModel.DataAnnotations;
 
namespace MyMvc3Site.Models
{
    public class Customer
    {
        [Required]
        public int CustomerId { get; set; }
 
        [Required]
        [StringLength(5)]
        public string Name { get; set; }
 
        [Required]
        public DateTime Birthday { get; set; }
    }
}

In the view, I have this:

@model MyMvc3Site.Models.Customer
 
@{
    View.Title = "Create";
}
 
<h2>Create</h2>
 
@using (Html.BeginForm()) {
    @Html.ValidationSummary(true)
 
    <fieldset>
        <legend>Fields</legend>
            
        <div class="editor-label">
            @Html.LabelFor(model => model.CustomerId)
        </div>
        <div class="editor-field">
            @Html.TextBoxFor(model => model.CustomerId)
            @Html.ValidationMessageFor(model => model.CustomerId)
        </div>
            
        <div class="editor-label">
            @Html.LabelFor(model => model.Name)
        </div>
        <div class="editor-field">
            @Html.TextBoxFor(model => model.Name)
            @Html.ValidationMessageFor(model => model.Name)
        </div>
            
        <div class="editor-label">
            @Html.LabelFor(model => model.Birthday)
        </div>
        <div class="editor-field">
            @Html.TextBoxFor(model => model.Birthday)
            @Html.ValidationMessageFor(model => model.Birthday)
        </div>
            
        <p>
            <input type="submit" value="Create" />
        </p>
    </fieldset>
 
}

Without unobtrusive jQuery validation, we will get this in the view:

<form action="/Customer/Create" id="form0" method="post"><div class="validation-summary-valid" id="validationSummary"><ul><li style="display:none"></li>
</ul></div>    <fieldset>
        <legend>Fields</legend>
            
        <div class="editor-label">
            <label for="CustomerId">CustomerId</label>
        </div>
        <div class="editor-field">
            <input id="CustomerId" name="CustomerId" type="text" value="" />
            <span class="field-validation-valid" id="CustomerId_validationMessage"></span>
        </div>
            
        <div class="editor-label">
            <label for="Name">Name</label>
        </div>
        <div class="editor-field">
            <input id="Name" name="Name" type="text" value="" />
            <span class="field-validation-valid" id="Name_validationMessage"></span>
        </div>
            
        <div class="editor-label">
            <label for="Birthday">Birthday</label>
        </div>
        <div class="editor-field">
            <input id="Birthday" name="Birthday" type="text" value="" />
            <span class="field-validation-valid" id="Birthday_validationMessage"></span>
        </div>
            
        <p>
            <input type="submit" value="Create" />
        </p>
    </fieldset>
</form><script type="text/javascript">
//<![CDATA[
if (!window.mvcClientValidationMetadata) { window.mvcClientValidationMetadata = []; }
window.mvcClientValidationMetadata.push({"Fields":[{"FieldName":"CustomerId",
"ReplaceValidationMessageContents":true,"ValidationMessageId":"CustomerId_validationMessage",
"ValidationRules":[{"ErrorMessage":"The CustomerId field is required.","ValidationParameters":{},
"ValidationType":"required"},{"ErrorMessage":"The field CustomerId must be a number.",
"ValidationParameters":{},"ValidationType":"number"}]},{"FieldName":"Name",
"ReplaceValidationMessageContents":true,"ValidationMessageId":"Name_validationMessage",
"ValidationRules":[{"ErrorMessage":"The Name field is required.","ValidationParameters":{},
"ValidationType":"required"},{"ErrorMessage":"The field Name must be a string with a maximum length of 5.",
"ValidationParameters":{"max":5},"ValidationType":"length"}]},{"FieldName":"Birthday",
"ReplaceValidationMessageContents":true,"ValidationMessageId":"Birthday_validationMessage",
"ValidationRules":[{"ErrorMessage":"The Birthday field is required.","ValidationParameters":{},
"ValidationType":"required"}]}],"FormId":"form0","ReplaceValidationSummary":false,"ValidationSummaryId":"validationSummary"});
//]]>
</script>

It is a lot of JavaScript being rendered, and if we activate unobtrusive jQuery validation, we will get this instead:

<form action="/Customer/Create" method="post">    <fieldset>
        <legend>Fields</legend>
            
        <div class="editor-label">
            <label for="CustomerId">CustomerId</label>
        </div>
        <div class="editor-field">
            <input data-val="true" data-val-number="The field CustomerId must be a number." data-val-required="The CustomerId field is required." id="CustomerId" name="CustomerId" type="text" value="" />
            <span class="field-validation-valid" data-valmsg-for="CustomerId" data-valmsg-replace="true"></span>
        </div>
            
        <div class="editor-label">
            <label for="Name">Name</label>
        </div>
        <div class="editor-field">
            <input data-val="true" data-val-length="The field Name must be a string with a maximum length of 5." data-val-length-max="5" data-val-required="The Name field is required." id="Name" name="Name" type="text" value="" />
            <span class="field-validation-valid" data-valmsg-for="Name" data-valmsg-replace="true"></span>
        </div>
            
        <div class="editor-label">
            <label for="Birthday">Birthday</label>
        </div>
        <div class="editor-field">
            <input data-val="true" data-val-required="The Birthday field is required." id="Birthday" name="Birthday" type="text" value="" />
            <span class="field-validation-valid" data-valmsg-for="Birthday" data-valmsg-replace="true"></span>
        </div>
            
        <p>
            <input type="submit" value="Create" />
        </p>
    </fieldset>
</form>

Instead of JavaScript, the different elements will have a couple of new attributes instead. Jquery.validation.unobtrusive.js contains functionality that can parse these values and generates error messages based on these instead. In this way, we will get much cleaner HTML, and still have valid HTML5. The validation will work exactly like before, the only difference is what is being rendered.

When you install ASP.NET MVC 3 Beta or WebMatrix Beta 2, a new product called ”NuPack” is installed with it. NuPack makes it possible to quickly add references to third party products like Ninject, jQuery and so on. All necessary files (dll, js etc) are automatically added to the project, and necessary modifications in web.config are automatically added.

There is an existing list with packages that is used when installing NuPack, but you can create your own if you need to. You can also put all packages on a network share so you can distribute them to all developers at your company.

I am going to show you how to add packages in both Visual Studio and WebMatrix since they work differently.

NuPack in Visual Studio 2010

In Visual Studio, we have to different ways to add references, in the GUI or through a Console window, which is based on PowerShell.

In the GUI, we can get a list with all products, add them to the project and update existing references. In the console window, we can do the same, but also remove existing references.

NuPack works in both existing projects, and in new projects. I have now created a new ASP.NET MVC 3 project with no references at all. To be able to log all errors, I would like to add ELMAH, which is a really good tool that can be used to log all errors. If I was going to add it manually, I would have to go to the homepage, download the assembly, add a reference to the assembly and then make some changes in web.config. If I want to use NHibernate or some other tools, I will have to do the same with them and all dependencies.

Instead of doing this manually, I will use NuPack to add ELMAH to my project.

To add ELMAH, I right-click on References in my project, and then I click on “Add Package Reference”. This window is now opened:

mvc-1-modal

I search for ELMAH and choose to install it. What happens now is that ELMAH is downloaded and added as a reference in the project, and all necessary modifications in web.config are automatically done!

If we take a look in the folder where we have our solution, there is a new folder named ”packages”, and here we can find ”elmah 1.1” which contains all files we just downloaded. We have also got a new file in our project, “packages.config”, which contains the name and version of the package.

This took a few seconds to do, which is going to save us a lot of time compared to doing this manually (downloading files, adding references, reading instructions etc).

We also have a concole window for NuPack, which can be used the same way.

mvc-2-console

We can use commands like:

· Add-Package name – Adding the package ”name”

· Remove-Package name – Removing the package ”name”

· List-Package – Displays a list with all packages

· Update-Package name – Updating the package ”name” to the latest version

If we want to remove ELMAH, which we just added we can write:

Remove-Package ELMAH

All references are deleted, and the changes in web.config are restored.

If we install MvcScaffold we will get new PowerShell commands to use, such as Add-MvcView, which adds a new view to the project.

ASP.NET Web Pages

If we want to use NuPack with ASP.NET Web Pages, we can use a website instead.

If we want to display the site, go to /_Admin in the browser. The first time we go here, we will have to set the admin password:

wm1-Admin

When we have entered the password, we will get to the next step where we can see a list with all available packages:

wm2-packages

The packages available for ASP.NET Web Pages contain different helpers, such as a Bing-helper which can be used to search on our site using Bing. There are also some other helpers here. If we choose to install Microsoft-web-helpers 1.0, the package will be downloaded and we will get this:

wm3-binginstalled

We can now use the helper on our site by writing:

@Bing.SearchBox(”http://www.minsida.com”)

This is the result:

wm4-searchbox

The first time we logged in on the site, we had to create a password. This password is hashed and then saved in a text file on the server:

wm5-Passwordtxt

It may look bad and insecure to store it in clear text, but you can´t actually open that file in the browser:

wm6-hiddensegment

Summary

Thanks to NuPack, we can quickly and easy add functionality to our site without doing anything but click on some buttons. Since we can create our own packages, we can use it internally on the company to easily distribute assemblies and settings to our colleagues.

Microsoft just released ASP.NET MVC 3 Beta, which came with some news. Among other things, we now have a new project dialog box, an updated version of Razor, support for helpers from ASP.NET Web Pages, new interfaces for Dependency Injection, unobtrusive jQuery validation and more. A new beta of WebMatrix has also been released.

New project dialog

When we created new ASP.NET MVC project in CTP's that came before, there were different project types for the Web Forms and Razor syntax. In ASP.NET MVC Beta we have a single project type called ASP.NET MVC 3 Web Application. If we choose to create a new project, we get a new window, where we can choose View Engine, type of ASP.NET MVC 3-projects and if we want a test project:

1-newproject

Updated version of Razor

Unfortunately, we still don´t have syntax highlighting and intellisense for Razor, but for syntax highlighting, you can use either WebMatrix, or this plugin for Visual Studio 2010:

http://bit.ly/a0Jkqv

However, there are some new features for Razor in ASP.NET MVC 3, like a new way to specify the model, as well as support for declarative helpers.

Helpers from ASP.NET Web Pages

When ASP.NET Web Pages came with WebMatrix, we got a couple of different helpers like one which is used to show a table, with support for sorting and paging. It can now be used in asp.net MVC 3.

New interfaces for Dependency Injection

ASP.NET MVC 3 CTP came with enhanced support for Dependency Injection, by IMvcServiceLocator. In the new beta, we can use the IDependencyResolver insttead, which is smaller and contains just what we need to inject code in ASP.NET MVC.

There is also a new interface called IControllerActivator, which is used to create an instance of an already existing instance of a controller, i.e. as that the Activator class. Unlike the IControllerFactory it is not used to locate the correct controller.

Unobtrusive jQuery Validation

ASP.NET MVC 2 supports validation on the client. In ASP.NET MVC 3 Beta has been updated to provide a cleaner way to validate. Instead of the JavaScript with validation rules directly on the page it now takes advantage of the data-* attribute from HTML5 on the elements. This means that the rendered HTML looks much better, while we still have a validated page (if we validate against HTML5). However, developers can disable it if they want to continue to use the JavaScript as before.

Updated ValidateInputAttribute

When we try to post HTML from the client, we will, by default, get an error message that says that potentially dangerous code has been posted. This came in ASP.NET 1.1, and can be turned off in WebForms by setting the ValidateRequest to false.

In ASP.NET MVC, we instead insert a ValidateInput attribute on the controller or action method and set the parameter to false. What´s new in ASP.NET MVC 3 Beta and WebMatrix Beta 2 is that we now can define specific fields you may post HTML, while all others are protected. This provides increased security when we usually do not want to allow HTML in all fields.

NuPack

A very exciting new feature, and which are included in both ASP.NET MVC 3 Beta and WebMatrix Beta 2 is NuPack. It is a new package manager which makes it possible to download and install modules with just a few clicks. This means that we can get the Ninject, jQuery, ELMAH, and more without having to go to each page and download them manually.

With ASP.NET MVC 3 Beta, we can either use a dialog window in Visual Studio to add packages, or we can use a new command window. With WebMatrix we visit a specific page instead to get access to the modules.

More information

I will mention all the new features in separate blog posts for more in-depth information, but you can already download both ASP.NET MVC 3 and WebMatrix here:

http://www.microsoft.com/web/gallery/install.aspx?appid=MVC3

More Posts