Maarten Balliauw {blog}

ASP.NET MVC, Microsoft Azure, PHP, web development ...

NAVIGATION - SEARCH

Ordering fields in ASP.NET MVC 2 templated helpers

Ever worked with the templated helpers provided by ASP.NET MVC 2? Templated helpers provide a way to automatically build UI based on a data model that is marked with attributes defined in the System.ComponentModel.DataAnnotations namespace. For example, a property in the model can be decorated with the attribute [DisplayFormat(DataFormatString = "{0:c}")], and the templated helpers will always render this field formatted as currency.

If you have worked with templated helpers, you must agree: they can be useful! There’s one thing which is impossible in the current version: ordering fields.

kick it on DotNetKicks.com

Take the following class and the rendered form using templated helpers:

ASP.NET MVC EditorForModel()

[code:c#]

public class Person
{
    public string Email { get; set; }
    public string FirstName { get; set; }
    public string LastName { get; set; }
}

[/code]

Nice, but I would rather have the field “Email” displayed third. It would be nice if the field order could be applied using the same approach as with the System.ComponentModel.DataAnnotations namespace: let’s build us an attribute for it!

Building the OrderAttribute

Assuming you have already built an attribute once in your life, let’s go over this quickly:

[code:c#]

[global::System.AttributeUsage(AttributeTargets.Property, Inherited = true, AllowMultiple = false)]
public sealed class OrderAttribute : Attribute
{
    readonly int order;

    public OrderAttribute(int order)
    {
        this.order = order;
    }

    public int Order
    {
        get { return order; }
    }
}

[/code]

The OrderAttribute can be applied to any property of a model, and needs exactly one parameter: order. This order will be used to sort the fields being rendered. Here’s how our Person class may look like after applying the OrderAttribute:

[code:c#]

public class Person
{
    [Order(3)]
    public string Email { get; set; }

    [Order(1)]
    public string FirstName { get; set; }

    [Order(2)]
    public string LastName { get; set; }
}

[/code]

Speaks for itself, no? Now, before you stop reading: this will not work yet. The reason is that the default ModelMetadataProvider from the ASP.NET MVC framework, which provides the templated helpers all information they need about the model, does not know about this OrderAttribute. Let’s see what we can do about that…

Building the OrderedDataAnnotationsModelMetadataProvider

In order for the ASP.NET MVC framework to know and use the OrderAttribute created previously, we’re going to extend the default DataAnnotationsModelMetadataProvider provided with ASP.NET MVC 2. Here’s the code:

[code:c#]

public class OrderedDataAnnotationsModelMetadataProvider : DataAnnotationsModelMetadataProvider
{
    public override IEnumerable<ModelMetadata> GetMetadataForProperties(
        object container, Type containerType)
    {
        SortedDictionary<int, ModelMetadata> returnValue =
            new SortedDictionary<int, ModelMetadata>();

        int key = 20000; // sort order for "unordered" keys

        IEnumerable<ModelMetadata> metadataForProperties =
            base.GetMetadataForProperties(container, containerType);

        foreach (ModelMetadata metadataForProperty in metadataForProperties)
        {
            PropertyInfo property = metadataForProperty.ContainerType.GetProperty(
                metadataForProperty.PropertyName);

            object[] propertyAttributes = property.GetCustomAttributes(
                typeof(OrderAttribute), true);

            if (propertyAttributes.Length > 0)
            {
                OrderAttribute orderAttribute = propertyAttributes[0] as OrderAttribute;
                returnValue.Add(orderAttribute.Order, metadataForProperty);
            }
            else
            {
                returnValue.Add(key++, metadataForProperty);
            }
        }

        return returnValue.Values.AsEnumerable();
    }
}

[/code]

By overriding the GetMetadataForProperties, we’re hooking into the DataAnnotationsModelMetadataProvider’s moment of truth, the method where all properties of the model are returned as ModelMetadata. First of all, we’re using the ModelMetadata the base class provdes. Next, we use a little bit of reflection to get to the OrderAttribute (if specified) and use it to build a SortedDictionary of ModelMetadata. Easy!

One small caveat: non-decorated properties will always come last in the rendered output.

One thing left…

One thing left: registering the OrderedDataAnnotationsModelMetadataProvider with the ModelMetadataProviders infrastructure offered by ASP.NET MVC. Here’s how:

[code:c#]

protected void Application_Start()
{
    AreaRegistration.RegisterAllAreas();

    RegisterRoutes(RouteTable.Routes);

    ModelMetadataProviders.Current = new OrderedDataAnnotationsModelMetadataProvider();
}

[/code]

I guess you know this one goes into Global.asax.cs. If all works according to plan, your rendered view should now look like the following, with the e-mail field third:

image

kick it on DotNetKicks.com

Vote to help me speak at the MIX 2010 conference!

Everybody knows the Microsoft MIX event, right? The one in Las Vegas? The one with all the fancy web-related stuff? Rings a bell? Ok, great. In the beginning of December 2009, Microsoft did an open call for speakers, which I answered with some session proposals. Who doesn’t want to go to Vegas, right?

The open call proposals have been processed (150+ sessions submitted, wow!) and a voting has started. Yes, you hear me coming: please go ahead and vote for a session I submitted. Voting ends January 15th, 2010.

Since I could not decide which color of the voting banner matched best with my blog’s theme, I decided to put them all three online:

image

Thanks in advance!

Maarten

PS: There's also Elijah Manor, Justin Etheredge, K. Scott Allen, and many others who submitted good looking sessions.

kick it on DotNetKicks.com

Microsoft Web Development Summit 2009

PHP at Microsoft Being in the US for 2 times in a month (PDC09 and Web Development Summit) is fun, tiring and rewarding. The WDS09 was an invite-only event organized by Microsoft, focusing on interaction between Microsoft and the PHP community. I must say: the event has been helpful and interesting for both parties!

  • The Heathman Hotel in Kirkland is a nice hotel!
  • Traveling towards the US is far more productive than flying back: I did PHPMEF traveling westbound, I crashed (half sleep/half awake) on the eastbound flight…
  • If you just traveled over 26 hours: do NOT go shopping immediately when you arrive home! It’s really frustrating and tiring.
  • Did a session on Windows Azure SDK for PHP, PHPExcel and PHPLinq.
  • Did an interview for the Connected Show
  • Met a lot of people I knew from Twitter and e-mail, and met a lot of new people, both Microsoft and PHP community. Nice to meet you all!
  • Event focus was on feedback between Microsoft and PHP community, overall I think the dialogue was respectful and open and helpful to both parties.

Standing at the Microsoft logo

This was actually my first time at the WDS which has been around for 5 years already. The Interop team invited me there, and I want to thank them for doing that: it was a great trip, a great event and I got the chance to meet lots of new people.

Attendees were mostly people from the PHP community, like Cal Evans, Rafael Doms, Chris Cornutt, Romain Bourdon (WAMP server anyone?), Alison “snipe” Gianotto, … Next to that, lots of Microsoft people came by during various sessions. Some of them even reserved the whole week and were attending all sessions to make sure they were in the feedback loop all the time.

We’ve seen Microsoft sessions on IIS, Web Platform Installer, Silverlight, SQL Server, Bing, Powershell (sorry, Scott Hanselman, for disturbing your presentation with a tweet :-)). Interesting sessions with some info I did not know. PHP community sessions were also available: Wordpress, Joomla, Drupal, the PHP community perspective, feedback sessions, PHPLinq, PHPExcel, interoperability bridges, … A good mix of content with knowledgeable speakers and good communication between speakers, product groups and audience. Well done!

Supporting multiple submit buttons on an ASP.NET MVC view

Multiple buttons on an ASP.NET MVC view A while ago, I was asked for advice on how to support multiple submit buttons in an ASP.NET MVC application, preferably without using any JavaScript. The idea was that a form could contain more than one submit button issuing a form post to a different controller action.

The above situation can be solved in many ways, one a bit cleaner than the other. For example, one could post the form back to one action method and determine which method should be called from that action method. Good solution, however: not standardized within a project and just not that maintainable… A better solution in this case was to create an ActionNameSelectorAttribute.

Whenever you decorate an action method in a controller with the ActionNameSelectorAttribute (or a subclass), ASP.NET MVC will use this attribute to determine which action method to call. For example, one of the ASP.NET MVC ActionNameSelectorAttribute subclasses is the ActionNameAttribute. Guess what the action name for the following code snippet will be for ASP.NET MVC:

[code:c#]

public class HomeController : Controller
{
    [ActionName("Index")]
    public ActionResult Abcdefghij()
    {
        return View();
    }
}

[/code]

That’s correct: this action method will be called Index instead of Abcdefghij. What happens at runtime is that ASP.NET MVC checks the ActionNameAttribute and asks if it applies for a specific request. Now let’s see if we can use this behavior for our multiple submit button scenario.

kick it on DotNetKicks.com

The view

Since our view should not be aware of the server-side plumbing, we can simply create a view that looks like this.

[code:c#]

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

<!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>Create person</title>
    <script src="<%=Url.Content("~/Scripts/MicrosoftAjax.js")%>" type="text/javascript"></script>
    <script src="<%=Url.Content("~/Scripts/MicrosoftMvcAjax.js")%>" type="text/javascript"></script>
</head>
<body>

    <% Html.EnableClientValidation(); %>
    <% using (Html.BeginForm()) {%>

        <fieldset>
            <legend>Create person</legend>
            <p>
                <%= Html.LabelFor(model => model.Name) %>
                <%= Html.TextBoxFor(model => model.Name) %>
                <%= Html.ValidationMessageFor(model => model.Name) %>
            </p>
            <p>
                <%= Html.LabelFor(model => model.Email) %>
                <%= Html.TextBoxFor(model => model.Email) %>
                <%= Html.ValidationMessageFor(model => model.Email) %>
            </p>
            <p>
                <input type="submit" value="Cancel" name="action" />
                <input type="submit" value="Create" name="action" />
            </p>
        </fieldset>

    <% } %>

    <div>
        <%=Html.ActionLink("Back to List", "Index") %>
    </div>

</body>
</html>

[/code]

Note the two submit buttons (namely “Cancel” and “Create”), both named “action” but with a different value attribute.

The controller

Our controller should also not contain too much logic for determining the correct action method to be called. Here’s what I propose:

[code:c#]

public class HomeController : Controller
{
    public ActionResult Index()
    {
        return View(new Person());
    }

    [HttpPost]
    [MultiButton(MatchFormKey="action", MatchFormValue="Cancel")]
    public ActionResult Cancel()
    {
        return Content("Cancel clicked");
    }

    [HttpPost]
    [MultiButton(MatchFormKey = "action", MatchFormValue = "Create")]
    public ActionResult Create(Person person)
    {
        return Content("Create clicked");
    }
}

[/code]

Some things to note:

  • There’s the Index action method which just renders the view described previously.
  • There’s a Cancel action method which will trigger when clicking the Cancel button.
  • There’s a Create action method which will trigger when clicking the Create button.

Now how do these last two work… You may also have noticed the MultiButtonAttribute being applied. We’ll see the implementation in a minute. In short, this is a subclass for the ActionNameSelectorAttribute, triggering on the parameters MatchFormKey and MatchFormValues. Now let’s see how the MultiButtonAttribute class is built…

The MultiButtonAttribute class

Now do be surprised of the amount of code that is coming…

[code:c#]

[AttributeUsage(AttributeTargets.Method, AllowMultiple = false, Inherited = true)]
public class MultiButtonAttribute : ActionNameSelectorAttribute
{
    public string MatchFormKey { get; set; }
    public string MatchFormValue { get; set; }

    public override bool IsValidName(ControllerContext controllerContext, string actionName, MethodInfo methodInfo)
    {
        return controllerContext.HttpContext.Request[MatchFormKey] != null &&
            controllerContext.HttpContext.Request[MatchFormKey] == MatchFormValue;
    }
}

[/code]

When applying the MultiButtonAttribute to an action method, ASP.NET MVC will come and call the IsValidName method. Next, we just check if the MatchFormKey value is one of the request keys, and the MatchFormValue matches the value in the request. Simple, straightforward and re-usable.

kick it on DotNetKicks.com

MSDN - Converting an existing ASP.NET application to Windows Azure

Back from PDC 2009 with a lot of information on Windows Azure, I did an MSDN Live Meeting on ASP.NET and Windows Azure today. Here's the slide deck and demo code.

Abstract: "Put your stuff in the cloud! Windows Azure allows you to take advantage of cloud computing infranstructure for hosting, computing, and storage of your applications. In this demo filled session we take an existing ASP.Net Application and move it to be hosted in Windows Azure, while taking advantage of Windows Azure storage."

Example code can be downloaded here: MSDN - Converting an existing ASP.NET application to Windows Azure.zip (2.01 mb)

If you want more info about Windows Azure and how to develop, architect or benefit from the platform as a whole, register freely at the Azure User Group Belgium.

Before you get started, you need to have a Windows Azure token. Request a token by completing the application here. Tokens are generally issued within a few hours. Once you have received your token, redeem it at http://windows.azure.com. Afterwards, you can deploy your application using the interface at http://windows.azure.com or by issuing a right-click -> Publish... in your Visual Studio solution.

Windos Azure Developer Portal

Thank you for attending!

kick it on DotNetKicks.com

Microsoft PDC09 keynote highlights

Finally found some time to write a short blog post on the announcements this morning at PDC 2009.Microsoft PDC keynote highlights Ray Ozzie started the keynote this morning, focusing on Microsoft’s “three-screen” vision for the future. There will be three screens connected to the cloud: TV, (handheld) devices and of course good old PC. This vision is driven by some key players: Windows 7, Internet Explorer, Silverlight and Windows Azure. Make sure to have a look at these four if you want to play in this future.

Some announcements were made as well:

Had a great day yesterday, driving trough the city of Los Angeles and looking at various places in town. Conference day one was also very interesting, lots of good sessions. Currently missing a session slot though, waiting for a Channel9 interview on the Windows Azure SDK for PHP. Stay tuned!

Localize ASP.NET MVC 2 DataAnnotations validation messages

Living in a country where there are there are three languages being used, almost every application you work on requires some form of localization. In an earlier blog post, I already mentioned ASP.NET MVC 2’s DataAnnotations support for doing model validation. Ever since, I was wondering if it would be possible to use resource files or something to do localization of error messages, since every example that could be found on the Internet looks something like this:

[code:c#]

[MetadataType(typeof(PersonBuddy))]
public class Person
{
    public string Name { get; set; }
    public string Email { get; set; }
}

public class PersonBuddy
{
    [Required(ErrorMessage = "Name is required.")]
    public string Name { get; set; }

    [Required(ErrorMessage = "E-mail is required.")
    public string Email { get; set; }
}

[/code]

Yes, those are hardcoded error messages. And yes, only in one language. Let’s see how localization of these would work.

1. Create a resource file

Add a resource file to your ASP.NET MVC 2 application. Not in App_GlobalResources or App_LocalResources, just a resource file in a regular namespace. Next, enter all error messages that should be localized in a key/value manner. Before you leave this file, make sure that the Access Modifier property is set to Public.

Access modifier in resource file

2. Update your “buddy classes”

Update your “buddy classes” (or metadata classes or whatever you call them) to use the ErrorMessageResourceType and ErrorMessageResourceName parameters instead of the ErrorMessage parameter that you normally pass. Here’s the example from above:

[code:c#]

[MetadataType(typeof(PersonBuddy))]
public class Person
{
    public string Name { get; set; }
    public string Email { get; set; }
}

public class PersonBuddy
{
    [Required(ErrorMessageResourceType = typeof(Resources.ModelValidation), ErrorMessageResourceName = "NameRequired")]
    public string Name { get; set; }

    [Required(ErrorMessageResourceType = typeof(Resources.ModelValidation), ErrorMessageResourceName = "EmailRequired")]
    public string Email { get; set; }
}

[/code]

3. See it work!

After creating a resource file and updating the buddy classes, you can go back to work and use model binders, ValidationMessage and ValidationSummary. ASP.NET will make sure that the correct language is used based on the thread culture info.

Localized error messages

kick it on DotNetKicks.com

Upcoming sessions on Azure, PHP and ASP.NET

It’s going to be a filled end of 2009… There’s Microsoft PDC which I will be attending and will probably cause me some sleepless nights (both due to jetlag and due to all the new stuff that will be released). Next to that, I’ll also be doing some sessions in the next few weeks. Here’s a list…

Date

Event

28 october 2009

PHPBenelux Meeting: PHP and Microsoft technologies

I’ll be doing two sessions here:

· PHP and Silverlight, together with Kevin Dockx
“This session covers the basics of Microsoft Silverlight and demonstrates how PHP developers can benefit from developing rich client-side components that run in the web browser using Silverlight and PHP.”

· Make Web not War, together with Katrien De Graeve
“Microsoft will present the array of initiatives in the company to better support and integrate with PHP and give you an introduction on Windows Azure and its support for PHP in the cloud.”

More info? www.phpbenelux.eu

4 november 2009

First Azure User Group Belgium (AZUG.be) meeting

I’ll be doing an introductory session to Microsoft’s Azure platform. Yves Goeleven and Kurt Claeys will be showing off .NET services and provide more info on the AZUG.be. All of this followed by an open discussion.

Register now on www.azug.be!

24 november 2009

MSDN Live Meeting (Dutch)

Een ASP.NET-applicatie overbrengen naar Windows Azure
“Zet alles over naar the cloud! Met Windows Azure kunt u voordeel halen uit de cloud computing-infrastructuur voor hosting, computing en storage van uw applicaties. De sessie bevat talrijke demo’s, we brengen een bestaande ASP.Net-applicatie over naar hosting in Windows Azure en maken gebruik van Windows Azure storage”

More info on the MSDN pages!

Looking forward to see you at one of these events!

Recording of my session at Remix 2009 - ASP.NET MVC

On September 29, I did a session on ASP.NET MVC at Remix 2009 Belgium. All session recordings are now online, check the Remix09 site. Slides and code for my talk can be found in a previous blog post. The video material can be found below. Enjoy! And feel free to leave some comments!

kick it on DotNetKicks.com

ASP.NET MVC Wisdom

Abstract: "Building a Twitter clone in 60 minutes, featuring what's new in ASP.NET MVC 2 preview 1 and focusing on some of the core ASP.NET MVC features like security and routing."

Let me Bing that for you

Have you ever been bugged with stupid questions? Do you get tired of people asking stuff that is only one search engine query away? Chances are you answered both of these questions with “yes!”. Together with Phil Haack and Juliën Hanssens, I created LetMeBingThatForYou.com, a website that generates a search engine query for people who ask you questions they could easily answer by themselves.

Yes, the idea is a copy of LetMeGoogleThatForYou.com. However, we thought Bing deserved something similar. We even got Bing’s picture of the day working. How cool is that?

Find Chuck Norris

One last note: this project is not associated with Microsoft nor Bing. We’re doing this project for fun.

kick it on DotNetKicks.com