Logo

Maarten Balliauw {blog}

ASP.NET, ASP.NET MVC, Azure, PHP, OpenXML, VSTS, ...

About the author

Maarten Balliauw is currently employed as .NET Technical Consultant at RealDolmen. His interests are mainly web applications developed in ASP.NET (C#) or PHP and the Windows Azure cloud platform.
More about me More about me
Send mail E-mail me


ASP.NET MVC Quickly Subscribe to my RSS feed Follow me on Twitter! View Maarten Balliauw's profile on LinkedIn
View Maarten Balliauw's MVP profile

Search

Latest Twitter

    Follow me on Twitter...

    My projects

    Disclaimer

    The opinions expressed herein are my own personal opinions and do not represent my employer's view in any way.

    © Copyright Maarten Balliauw 2010

    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:

    [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; }
    }

    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:

    [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; }
    }

    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


    Categories: ASP.NET | C# | General | MVC

    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


    Categories: ASP.NET | C# | General | MVC

    Leveraging ASP.NET MVC 2 futures “ViewState”

    Let’s start this blog post with a confession: yes, I abused a feature in the ASP.NET MVC 2 futures assembly to fire up discussion. In my previous blog post, I called something “ViewState in MVC” while it is not really ViewState. To be honest, I did this on purpose, wanting to see people discuss this possibly new feature in MVC 2. Discussion started quite fast: most people do not like the word ViewState, especially when it is linked to ASP.NET MVC. As Phil Haack pointed out in a comment on my previous blog post, I used this foul word where it was not appropriate.

    (…) I think calling it ViewState is very misleading. (…) what your serializing is the state of the Model, not the View. (…)

    That’s the truth! But… how should we call this then? There is already something called ModelState, and this is something different. Troughout this blog post, I will refer to this as “Serialized Model State”, or “SMS” in short. Not an official abbreviation, just something to have a shared meaning with you as a reader.

    So, SMS… Let’s use this in a practical example.

    kick it on DotNetKicks.com

    Example: Optimistic Concurrency

    Concurrency between old train and updated train. Every developer who has worked on a business application will definitely have come to deal with optimistic concurrency. Data retrieved from the database has a unique identifier and a timestamp, used for optimistic concurrency control. When editing this data, the identifier and timestamp have to be associated with the client operation, requiring a persistence mechanism. This mechanism should make sure the identifier and timestamp are preserved to verify if another user has updated it since it was originally retrieved.

    There are some options to do this: you can store this in TempData, in a Cookie or in Session state. A more obvious choice, however, would be a mechanism like “SMS”: it allows you to persist the model state on your view, allowing to retrieve the state of your model whenever data is posted to an action method. The fact that it is on your view, means that is linked to a specific request that will happen in the future.

    Let’s work with a simple Person class, consisting of Id, Name, Email and RowState properties. RowState will contain a DateTime value when the database record was last updated. An action method fetching data is created:

    [HttpGet]
    public ActionResult Edit(int id)
    {
        // Simulate fetching Person from database
        Person initialPersonFromDatabase = new Person
        {
            Id = id,
            FirstName = "Maarten",
            LastName = "Balliauw",
            Email = "",
            RowVersion = DateTime.Now
        };
        return View(initialPersonFromDatabase);
    }

    The view renders an edit form for our person:

    <h2>Concurrency demo</h2>

    <% Html.EnableClientValidation(); %>
    <%= Html.ValidationSummary("Edit was unsuccessful. Please correct the errors and try again.") %>

    <% using (Html.BeginForm()) {%>
        <%=Html.Serialize("person", Model)%>

        <fieldset>
            <legend>Edit person</legend>
            <%=Html.EditorForModel()%>
            <p>
                <input type="submit" value="Save" />
            </p>
        </fieldset>

    <% } %>

    Let’s have a look at this view markup. <%=Html.EditorForModel()%> renders an editor for our model class Person. based on templates. This is a new feature in ASP.NET MVC 2.

    Another thing we do in our view is <%=Html.Serialize("person", Model)%>: this is a HtmlHelper extension persisting our model to a hidden form field:

    <input name="person" type="hidden" value="/wEymwIAAQAAAP
    ////8BAAAAAAAAAAwCAAAARE12YzJWaWV3U3RhdGUsIFZlcnNpb249MS4wL
    jAuMCwgQ3VsdHVyZT1uZXV0cmFsLCBQdWJsaWNLZXlUb2tlbj1udWxsBQEA
    AAAbTXZjMlZpZXdTdGF0ZS5Nb2RlbHMuUGVyc29uBAAAABo8Rmlyc3ROYW1
    lPmtfX0JhY2tpbmdGaWVsZBk8TGFzdE5hbWU+a19fQmFja2luZ0ZpZWxkFj
    xFbWFpbD5rX19CYWNraW5nRmllbGQbPFJvd1ZlcnNpb24+a19fQmFja2luZ
    0ZpZWxkAQEBAA0CAAAABgMAAAAHTWFhcnRlbgYEAAAACEJhbGxpYXV3BgUA
    AAAAqCw1nBkWzIgL"
    />

    Yes, this looks ugly and smells like ViewState, but it’s not. Let’s submit our form to the next action method:

    [HttpPost]
    public ActionResult Edit([Deserialize]Person person, FormCollection form)
    {
        // Update model
        if (!TryUpdateModel(person, form.ToValueProvider()))
            return View(person);

        // Simulate fetching person from database
        Person currentPersonFromDatabase = new Person
        {
            Id = person.Id,
            FirstName = "Maarten",
            LastName = "Balliauw",
            Email = "maarten@maartenballiauw.be",
            RowVersion = DateTime.Now
        };

        // Compare version with version from model state
        if (currentPersonFromDatabase.RowVersion > person.RowVersion)
        {
            // Concurrency issues!
            ModelState.AddModelError("Person", "Concurrency error: person was changed in database.");

            return View(person);
        }
        else
        {
            // Validation also succeeded
            return RedirectToAction("Success");
        }
    }

    Let’s see what happens here…The previous model state is deserialized from the hidden field we created in our view, and passed into the parameter person of this action method. Edited form values are in the FormCollection parameter. In the action method body, the deserialized model is updated first with the values from the FormCollection parameter. Next, the current database row is retrieved, having a newer RowVersion timestamp. This indicates that the record has been modified in the database and that we have a concurrency issue, rendering a validation message.

    Conclusion

    “ViewState” (or “SMS” or whatever it will be called) is really a useful addition to ASP.NET MVC 2, and I hope this blog post showed you one example usage scenario where it is handy. Next to that, you are not required to use this concept: it’s completely optional. So if you still do not like it, then do not use it. Go with Session state, Cookies, hidden fields, …

    kick it on DotNetKicks.com


    Categories: ASP.NET | C# | General | MVC

    Exploring the ASP.NET MVC 2 futures assemby

    The future is cloudy! The latest preview of ASP.NET MVC 2, preview 2, has been released on CodePlex last week. All features of the preview 1 version are still in, as well as some nice novelties like client-side validation, single project areas, the model metadata model, … You can read more about these here, here and here.

    Sure, the official preview contains some great features of which I’m already a fan: the model and validation metadata model is quite extensible, allowing the use of DataAnnotations, EntLib, NHibernate or your own custom validation logic in your application, while still being able to use standard model binders and client-side validation. Next to all this, a new version of the MVC 2 futures assembly was released on CodePlex. And oh boy, there’s some interesting stuff in there as well! Let’s dive in…

    Quick note: the “piece de resistance” is near the end of this post. Also make sure to post your thoughts on this “piece”.

    kick it on DotNetKicks.com

    Controls

    There’s not much that has changed here since my previous blog post on the MVC futures. Want to use a lightweight TextBox or Repeater control? Feel free to do so:

    <p>
        TextBox: <mvc:TextBox Name="someTextBox" runat="server" /><br />
        Password: <mvc:Password Name="somePassword" runat="server" />
    </p>
    <p>
        Repeater:
        <ul>
        <mvc:Repeater Name="someData" runat="server">
            <EmptyDataTemplate>
                <li>No data is available.</li>
            </EmptyDataTemplate>
            <ItemTemplate>
                <li><%# Eval("Name") %></li>
            </ItemTemplate>
        </mvc:Repeater>
        </ul>
    </p>

    Asynchronous controllers

    Yes, I also blogged about these before. Basically, asynchronous controllers allow you to overcome the fact that processing-intensive action methods may consume all of your web server’s worker threads, making your webserver a slow piece of software while it is on top-notch hardware.

    When using asynchronous controllers, the web server schedules a worker thread to handle an incoming request. This worker thread will start a new thread and call the action method on there. The worker thread is now immediately available to handle a new incoming request again.

    Get some REST!

    Again: I already blogged on this one: REST for ASP.NET MVC SDK. This SDK now seems to become a part of the ASP.NET MVC core, which I really think is great! The REST for ASP.NET MVC SDK adds “discovery” functionality to your ASP.NET MVC application, returning the client the correct data format he requested. From the official documentation:

    1. It includes support for machine-readable formats (XML, JSON) and support for content negotiation, making it easy to add POX APIs to existing MVC controllers with minimal changes.
    2. It includes support for dispatching requests based on the HTTP verb, enabling “resource” controllers that implement the uniform HTTP interface to perform CRUD (Create, Read, Update and Delete) operations on the model.
    3. Provides T4 controller and view templates that make implementing the above scenarios easier.

    Let’s come down to business: the REST SDK is handy because you do not have to care about returning a specific ActionResult: the SDK will automatically check whether a ViewResult, JsonResult, XML output or even an Atom feed is requested by the client. ViewData will automatically be returned in the requested format. Result: cleaner code, less mistakes. As long as you follow conventions of course.

    Other stuff…

    Yeah, I’m lazy. I also blogged on this one before. Check my previous blog post on the MVC futures for nice stuff like more action method selectors (like [AcceptAjax] and others), more HtmlHelper extensions for images, mailto links, buttons, CSS, … There’s more action filters as well, like [ContentType] which specifies the content-type headers being sent out with an action method.

    There’s also donut caching, allowing you to cache all output for an action method except a specific part of the output. This allows you to combine cached views with dynamic content in quite an easy manner.

    More new stuff: the CookieTempDataProvider, allowing you to turn of session state when using TempData. There’s also the [SkipBinding] attribute, which tells the ModelBinder infrasructure to bind all action method parameters except the ones decorated with this attribute.

    ViewState!

    ViewState gone evil! Got you there, right? The ASP.NET MVC team has been screaming in every presentation they gave in the past year that there was no such thing as ViewState in ASP.NE MVC. Well, there is now… And maybe, i will be part of the future MVC 2 release as well. Let’s first have a look at it and afterwards discuss this all…

    On every view, a new HtmlHelper extension method named “Serialize” is present. This one can be used to create a hidden field inside a HTML form, containing a serialized version of an object. The extension method also allows you to pass a parameter specifying how the object should be serialized. The default option, SerializationMode.PlainText, simply serializes the object to a string and puts it inside of a hidden field. When using SerializationMode.Encrypted and/or SerializationMode.Signed, you are really using ASP.NET Webforms ViewState under the covers.

    The call in your view source code is easy:

    <% using (Html.BeginForm()) {%>
        <%Html.Serialize("person", Model); %>
        <fieldset>
            <legend>Edit person</legend>
            <p>
                <%=Html.DisplayFor(p => Model.FirstName)%>
            </p>
            <p>
                <%=Html.DisplayFor(p => Model.LastName)%>
            </p>
            <p>
                <label for="Email">Email:</label>
                <%= Html.TextBox("Email", Model.Email) %>
                <%= Html.ValidationMessage("Email", "*") %>
            </p>
            <p>
                <input type="submit" value="Save" />
            </p>
        </fieldset>
    <% } %>

    When posting this form back to a controller action, a new ModelBinder can be used: The DeserializeAttribute can be placed next to an action method parameter:

    [HttpPost]
    public ActionResult Edit([Deserialize]Person person, string Email)
    {
        // ...
    }

    There you go: Person is the same object as the one you serialized in your view. Combine this with the RenderAction feature (yes, check my previous blog post on the MVC futures), and you have a powerful model for creating something like controls, which still follows the model-view-controller pattern mostly.

    Now release the hounds: I think this new “ViewState” feature is cool. There are definitely situations where you may want to use this, but… Will it be a best practice to use this? What is your opinion on this?

    kick it on DotNetKicks.com


    Categories: ASP.NET | C# | General | MVC

    Remix 2009 session - Slides and code

    As promised during the session at Remix 2009, here’s my example code and slide deck.

    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."

    Example code can be downloaded here: ASP.NET MVC Wisdom - ReMix.zip (8.91 mb)

    Thank you for attending!


    Categories: ASP.NET | C# | Events | General | MVC | Presentations | Testing

    ASP.NET MVC MvcSiteMapProvider 1.0 released

    image Back in March, I blogged about an experimental MvcSiteMap provider I was building. Today, I am proud to announce that it is stable enough to call it version 1.0! Download MvcSiteMapProvider 1.0 over at CodePlex.

    Ever since the source code release I did back in March, a lot of new features have been added, such as HtmlHelper extension methods, attributes, dynamic parameters, … I’ll leave most of them up to you to discover, but there are some I want to quickly highlight.

    kick it on DotNetKicks.com

    ACL module extensibility

    By default, MvcSiteMap will make nodes visible or invisible based on [Authorize] attributes that are placed on controllers or action methods. If you have implemented your own authentication mechanism, this may no longer be the best way to show or hide sitemap nodes. By implementing and registering the IMvcSiteMapAclModule interface, you can now plug in your own visibility logic.

    public interface IMvcSiteMapAclModule
    {
        /// <summary>
        /// Determine if a node is accessible for a user
        /// </summary>
        /// <param name="provider">The MvcSiteMapProvider requesting the current method</param>
        /// <param name="context">Current HttpContext</param>
        /// <param name="node">SiteMap node</param>
        /// <returns>True/false if the node is accessible</returns>

        bool IsAccessibleToUser(MvcSiteMapProvider provider, HttpContext context, SiteMapNode node);
    }

    Dynamic parameters

    Quite often, action methods have parameters that are not really bound to a sitemap node. For instance, take a paging parameter. You may ignore this one safely when determining the active sitemap node: /Products/List?page=1 and /Products/List?page=2 should both have the same menu item highlighted. This is where dynamic parameters come in handy: MvcSiteMap will completely ignore the specified parameters when determining the current node.

    <mvcSiteMapNode title="Products" controller="Products" action="List" isDynamic="true" dynamicParameters="page" />

    The above sitemap node will always be highlighted, whatever the value of “page” is.

    SiteMapTitle action filter attribute

    In some situations, you may want to dynamically change the SiteMap.CurrentNode.Title in an action method. This can be done manually by setting  SiteMap.CurrentNode.Title, or by adding the SiteMapTitle action filter attribute.

    Imagine you are building a blog and want to use the Blog’s Headline property as the site map node title. You can use the following snippet:

    [SiteMapTitle("Headline")]
    public ViewResult Show(int blogId) {
       var blog = _repository.Find(blogIdId);
       return blog;
    }

    You can also use a non-strong typed ViewData value as the site map node title:

    [SiteMapTitle("SomeKey")]
    public ViewResult Show(int blogId) {
       ViewData["SomeKey"] = "This will be the title";

       var blog = _repository.Find(blogIdId);
       return blog;
    }

    HtmlHelper extension methods

    MvcSiteMap provides different HtmlHelper extension methods which you can use to generate SiteMap-specific HTML code on your ASP.NET MVC views. Here's a list of available HtmlHelper extension methods.

    • HtmlHelper.Menu() - Can be used to generate a menu
    • HtmlHelper.SiteMap() - Can be used to generate a list of all pages in your sitemap
    • HtmlHelper.SiteMapPath() - Can be used to generate a so-called "breadcrumb trail"

    The MvcSiteMap release can be found on CodePlex.

    kick it on DotNetKicks.com


    Categories: ASP.NET | C# | General | MVC | Projects

    Book review: Beginning ASP.NET MVC 1.0

    image It sure looks like August 2009 is the month in which I found multiple books on my doormat for review. Last week I did ASP.NET 3.5 CMS Development, this time I’ll be reviewing a competitor to my own book on ASP.NET MVC, ASP.NET MVC 1.0 Quickly: Simone Chiaretta and Keyvan Nayyeri’s “Beginning ASP.NET MVC 1.0”.

    Let’s start with the “official book overview”, which I usually copy-paste from Amazon. This book will learn you:

    • The intricacies of the Model View Controller (MVC) pattern and its many benefits
    • The fundamentals of ASP.NET MVC and its advantages over ASP.NET Web Forms
    • Various elements in ASP.NET MVC including model, view, controller, action filters, and routing
    • Unit testing concepts, Test-Driven Development (TDD), and the relationship between unit testing and the MVC pattern
    • How to unit test an ASP.NET MVC application
    • Details about authentication, authorization, caching, and form validation in ASP.NET MVC
    • The ins and outs of AJAX and client-side development in ASP.NET MVC
    • Ways to extend ASP.NET MVC

    After doing some reading over the weekend, I can say this book is great! It follows a different path than most of the ASP.NET MVC books out there today: of course it offers the basic introduction to ASP.NET MVC, it talks about models, controllers, views, …, however: it also covers more advanced topics like dependency injection (using NInject).

    Near the end of the book, some case studies are discussed: first a blog engine is built from ground up. The second case study is about building a photo gallery application.

    If you need a book which gives you the basics and some more advanced topics, Beginning ASP.NET MVC 1.0 is really for you. I liked reading it, and Simone and Keyvan have done a great job in explaining all there is to the great ASP.NET MVC framework. Looking forward to read more books by these guys! And to make sure my own sales figures do not drop: if you are a fan of a quick-start book on ASP.NET MVC, go buy ASP.NET MVC 1.0 Quickly :-)

    Oh and by the way, a sample chapter is also available at the publisher’s site.


    Categories: ASP.NET | Book review | Books | C# | General | MVC

    ASP.NET MVC Chained Controller Factory

    My last post on the REST for ASP.NET MVC SDK received an interesting comment… Basically, the spirit of the comment was: “There are tons of controller factories out there, but you can only use one at a time!”. This is true. One can have an IControllerFactory for MEF, for Castle Windsor, a custom one that creates a controller based on the current weather, … Most of the time, these IControllerFactory  implementations do not glue together… Unless you chain them!

    kick it on DotNetKicks.com

    Chaining IControllerFactory

    The ChainedControllerFactory that I will be creating is quite easy: it builds a list of IControllerFactory instances that may be able to create an IController and asks them one by one to create it. The one that can create it, will be the one that delivers the controller. In code:

    public class ChainedControllerFactory : IControllerFactory
    {
        const string CHAINEDCONTROLLERFACTORY = "__chainedControllerFactory";

        protected List<IControllerFactory> factories = new List<IControllerFactory>();

        public ChainedControllerFactory Register(IControllerFactory factory)
        {
            factories.Add(factory);
            return this;
        }

        public IController CreateController(RequestContext requestContext, string controllerName)
        {
            IController controller = null;
            foreach (IControllerFactory factory in factories)
            {
                controller = factory.CreateController(requestContext, controllerName);
                if (controller != null)
                {
                    requestContext.HttpContext.Items[CHAINEDCONTROLLERFACTORY] = factory;
                    return controller;
                }
            }

            return null;
        }

        public void ReleaseController(IController controller)
        {
            IControllerFactory factory =
                HttpContext.Current.Items[CHAINEDCONTROLLERFACTORY] as IControllerFactory;
            if (factory != null)
                factory.ReleaseController(controller);
        }
    }

    We have to register this one as the default IControllerFactory in Global.asax.cs:

    protected void Application_Start()
    {
        ChainedControllerFactory controllerFactory = new ChainedControllerFactory();
        controllerFactory
            .Register(new DummyControllerFactory())
            .Register(new OnlyHomeControllerFactory())
            .Register(new DefaultControllerFactory());

        ControllerBuilder.Current.SetControllerFactory(controllerFactory);

        RegisterRoutes(RouteTable.Routes);
    }

    Note: the DummyControllerFactory and the OnlyHomeControllerFactory are some sample, stupid IControllerFactory implementations.

    Caveats

    There is actually one caveat to know when using this ChainedControllerFactory: not all controller factories out there follow the convention of returning null when they can not create a controller. The ChainedControllerFactory expects null to determine if it should try the next IControllerFactory in the chain.

    Download source code

    You can download example source code here: MvcChainedControllerFactory.zip (244.37 kb) (sample uses MVC 2, code should work on MVC 1 as well)

    kick it on DotNetKicks.com


    REST for ASP.NET MVC SDK

    REST - Representational State Transfer Earlier this week, Phil Haack did a post on the newly released REST for ASP.NET MVC SDK. I had the feeling though that this post did not really get the attention it deserved. I do not have the idea my blog gets more visitors than Phil’s, but I’ll try to give the SDK some more attention by blogging an example. But first things first…

    kick it on DotNetKicks.com

    What is it?

    “REST for ASP .NET MVC is a set of capabilities that enable developers building a website using ASP .NET MVC to easily expose a Web API for the functionality of the site. “

    Ok then. Now you know. It will get more clear after reading the next topic.

    When should I use this?

    There are of course features in WCF that enable you to build REST-ful services, but…

    In many cases, the application itself is the only reason for development of the service. In other words, when the only reason for the service’s existence is to service the one application you’re currently building, it may make more sense  would stick with the simple case of using ASP.NET MVC. (Phil Haack)

    Quickly put: why bother setting up a true WCF service layer when the only reason for that is the web application you are building?

    Let me add another statement. Add a comment if you disagree:

    In many cases, you are building an ASP.NET MVC application serving HTML, and building a WCF layer exposing XML and/or JSON using REST, so you can use this in your Ajax calls and such. Why build two or three things displaying the same data, but in another format?

    This is where the REST for ASP.NET MVC SDK comes in handy: it adds “discovery” functionality to your ASP.NET MVC application, returning the client the correct data format he requested. From the official documentation:

    1. It includes support for machine-readable formats (XML, JSON) and support for content negotiation, making it easy to add POX APIs to existing MVC controllers with minimal changes.
    2. It includes support for dispatching requests based on the HTTP verb, enabling “resource” controllers that implement the uniform HTTP interface to perform CRUD (Create, Read, Update and Delete) operations on the model.
    3. Provides T4 controller and view templates that make implementing the above scenarios easier.

    An example…

    … a simple ASP.NET MVC application!

    Let’s say you have an application where you can create, read, update and delete your own name and firstname. We have a simple model for that:

    public class Person
    {
        public int Id { get; set; }
        public string FirstName { get; set; }
        public string LastName { get; set; }
    }

    We can do CRUD operations on this in our ASP.NET MVC application, using the action methods in our PersonController:

    public class PersonController : Controller
    {
        protected List<Person> Data
        {
            get
            {
                if (Session["Persons"] == null)
                {
                    Session["Persons"] = new List<Person>();
                }
                return (List<Person>)Session["Persons"];
            }
        }

        //
        // GET: /Person/

        public ActionResult Index()
        {
            return View(Data);
        }

        //
        // GET: /Person/Details/5

        public ActionResult Details(int id)
        {
            return View(Data.FirstOrDefault(p => p.Id == id));
        }

        //
        // GET: /Person/Create

        public ActionResult Create()
        {
            return View(new Person());
        }

        //
        // POST: /Person/Create

        [AcceptVerbs(HttpVerbs.Post)]
        public ActionResult Create(Person person)
        {
            try
            {
                person.Id = Data.Count + 1;
                Data.Add(person);

                return RedirectToAction("Index");
            }
            catch
            {
                return View();
            }
        }

        //
        // GET: /Person/Edit/5


        public ActionResult Edit(int id)
        {
            return View(Data.FirstOrDefault(p => p.Id == id));
        }

        //
        // POST: /Person/Edit/5

        [AcceptVerbs(HttpVerbs.Post)]
        public ActionResult Edit(int id, FormCollection collection)
        {
            try
            {
                Person person = Data.FirstOrDefault(p => p.Id == id);
                UpdateModel(person, new string[] { "FirstName", "LastName" }, collection.ToValueProvider());
                return RedirectToAction("Index");
            }
            catch
            {
                return View();
            }
        }
    }

    Any questions on this? Read the book :-)

    … get some REST for FREE!

    Like all “free” things in life, there’s always at least a little catch. “Free” in this case means:

    1. Adding a reference to System.Web.Mvc.Resources.dll provided by the REST for ASP.NET MVC SDK
    2. Registering another controller factory in Global.asax.cs (more on that later)
    3. Adding the [WebApiEnabled] to every controller and/or action method you want to expose via REST.

    The first step is quite straightforward: get the bits from CodePlex, compile, and add it as a reference in your MVC project. Next, open Global.asax.cs and add the following in Application_Start:

    protected void Application_Start()
    {
        // We use this hook to inject our ResourceControllerActionInvoker
        // which can smartly map HTTP verbs to Actions

        ResourceControllerFactory factory = new ResourceControllerFactory();
        ControllerBuilder.Current.SetControllerFactory(factory);

        // We use this hook to inject the ResourceModelBinder behavior
        // which can de-serialize from xml/json formats

        ModelBinders.Binders.DefaultBinder = new ResourceModelBinder();

        // Regular register routes
        RegisterRoutes(RouteTable.Routes);
    }

    What we do here is tell ASP.NET MVC to create controllers using the ResourceControllerFactory provided by the REST for ASP.NET MVC SDK.

    Next: add the [WebApiEnabled] to every controller and/or action method you want to expose via REST. And that’s about it. Here’s what I get in my application if I browse to http://localhost:2681/Person:

    image

    Nothing fancy here, just a regular ASP.NET MVC application. But wait, let’s now browse to http://localhost:2681/Person?format=Xml:

    image

    Cool, no? And we only added 4 lines of code. But there’s more! I can also browse to http://localhost:2681/Person?format=Json and get JSON data returned. But that’s not all. There’s more!

    • You can add custom FormatHandler classes and, for example, provide one that handles RSS data.
    • There’s no need to always add the query string variable “format”: you can also specify the type of content you want in your HTTP request, by setting the HTTP “Accept” header. For example, if I set the Accept header to “application/json,text/xml”, REST for ASP.NET MVC will provide me with JSON if possible, and if not, it will send me XML. This approach is particularly useful when working with AJAX calls on your view.

    Downloads

    Here’s a list of downloads:

    kick it on DotNetKicks.com


    Categories: ASP.NET | C# | General | MVC | XML