Archives

Archives / 2008 / March
  • ASP.Net MVC Framework 2 - The Binding helper class (UI-mapper)

     

    In this post I’m going to explain the use of the ASP.Net MVC Framework’s BindingHelperExtensions class and how to use it as what I call a UI mapper (map user input fields to an object). The BindingHelperExtensions has the following five methods:

    T ReadFromRequest<T>(this Controller controller, String key)
    
    string ReadFromRequest(this Controller controller, String key)
    
    void UpdateFrom(Object value, NameValueCollection values)
    
    void UpdateFrom(Object value, NameValueCollection values, string objectPrefix)
    
    void UpdateFrom(Object value, NameValueCollection values, string[] keys)

    I will not go deep into the ReadFromRequest method, but they can be used to get a value out from the Request object, such as a QueryString or Form field. They are also extensions method to the Controller class. In this post I will write about the UpdateFrom methods which can be used to easy map a View’s user input fields to an object.


    Note: The UpdateFrom methods aren’t extension methods.


    The UpdateFrom methods can be used inside of a Controller’s action method to update an object in the Model based on input values. For example if you have a Customer object and want to fill it with values out from the Request.From, you can do the following in your Controller:

    Binding.UpdateFrom(customer, Request.Form);

    In the examples in this post I will use an alias:

    using Binding = System.Web.Mvc.BindingHelperExtensions;

    I only use it to avoid using the name of the BindingHelperExtension class to get access to the UpdateFrom methods.

    The UpdateFrom will see if there is an input field in the Request.Form collection with the same name as the property of the object passed as an argument. If there is a match, the value from input filed will be set to the value of the object’s property with the same name. For example if you have an input filed like this:

    <input type="text" name="CompanyName" .../>


    And if the Customer object you pass to the UpdateFrom method has a property with the same name; the value from the CompanyName field will be set to the Customer’s CompanyName property. If you have a View like this:

    <input type="text" name="CompanyName" />
    <input type="submit" name="City" value="Create"/>


    The value of the submit button will be set to the Customer object if it has a property with the name City. So be careful what name you set to the input elements. This can of course be handled by using one of the other two UpdateFrom methods. For example the UpdateFrom that takes a objectPrefix as an argument, can be used to pass in a prefix of the input field names which should be collected from the values argument and be set to the value argument.

    void UpdateFrom(Object value, NameValueCollection values, string objectPrefix)


    For example if you have input fields that you want to belong to a specific object in the Model, you can use an object prefix like this:

    <input type="text" name="Customer.CompanyName" />
    <input type="text" name="Customer.ContactName" />
    <input type="text" name="Product.Description" />

    Note: You can also use "_" to sepereate the prefix from the property name "Customer_CompanyName".

    When you use the UdateFrom method and you only want to map the values from the input fields with the prefix Customer to a Customer object passed to the UpdateFrom, you simply pass the “Customer” as an objectPrefix to the UpdateFrom method:

    Binding.UpdateFrom(customer, Request.Form, "Customer");


    The UpdateFrom will now only collect fields with the prefix “Customer”, and the names after the prefix will be mapped to properties of the Customer object with the same name. By using object prefix you can simply categorize input fields to be mapped to different objects. The last UpdateFrom method you can use is the one that takes an array of keys as an argument.

    void UpdateFrom(Object value, NameValueCollection values, string[] keys)


    By passing a string array with keys, only the specified keys will be collected from the values argument collection and be set to the value object’s properties. By using keys and pass a Request.Form to the values argument you can decide which input fields you want to collect.


    Note: The values argument of the UpdateFrom takes an object of type NameValueCollection, so you pass for example pass the Request.Params collection if you want to get values from both QueryStrings and Forms. You can also pass your own NameValueCollection as you probably already have figured out ;)

    To end this post I will give you a simple example how to use the UpdateFrom and with LINQ to SQL to create a new Customer to the Northwind database.

    public class CustomerController : Controller
    {
        private NorthwindDataContext dbc = new NorthwindDataContext();
    
        public void Index()
        {
           RenderView("Customer");
        }
    
        public void New()
        {
          Customer customer = new Customer();
    
          Binding.UpdateFrom(customer, Request.Form, "Customer");
    
          dbc.Customers.InsertOnSubmit(customer);
          dbc.SubmitChanges();
        }
    }

    Customer.aspx

    <%@ Page Language="C#" AutoEventWireup="true" CodeBehind="Customer.aspx.cs" Inherits="MvcUpdateInsertExample.Views.Customer.Customer" %>
    
    <!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></title>
    </head>
    <body>
        <div>
            <form action="Customer/New" method="post">
            
            Company name: <input type="text" name="Customer.CompanyName" /><br />
            Contact name: <input type="text" name="Customer.ContactName" /><br />
            
            <input type="submit" value="Create"/>
            
            </form>
        </div>
    </body>
    </html>

    I hope this post gave you some brief understanding about how you can use the BindingHelperExtensions class to easy handle user input and map it to an object in the Model.

    Read more...

  • ASP.Net MVC Framework 2 - Interception and creating a Role Action Filter

    With the ASP.Net MVC Framework Preview 2, we can use Action Filters. An Action Filter can be used to intercept actions before and after an Action method of a Controller is executed. By using Action Filters you can for example add code that will check if a user has the right permission to access a action method, or you can use it to log messaged before and action is executed, and also after. An Action Filter is easy to apply to a Controller or its Action method. Just add the ActionFilter as an attribute to the class or specific method of a Controller.

    [RoleFilter(AllowRoles="Admin,Everyone"]
    public class MyController
    {
        [MyFilter]
        public void Index()
        {
            …
            RenderView("Index");
        }
    }

    If you apply an Aciton Filter to the Controller class, it will be executed for every action method in the Controller, if you add Action Filter to a specific method, it will only be called when that specific method is executed. An Action Filter has two methods that you can override and use, OnActionExecuting and OnActionExecuted. As you probably can get out from the names, the Executing method will be called before the action method is executed, and the Executed, after the action method is executed. I will write more about the both method later in this post. You can apply several Action Filters to a Controller. One thing you need to have in mind is the order they will be executed. Reflection is used to get the Action Filters out from a Controller, Reflection can’t promise to give items in the order which they are applied. To solve this we can use the Order property of an Action Filter. By using the Order property we can specify in which order the Action Filter should be executed.

    [MyFilter(Order=1)]
    [MyFilter2(Order=2)]
    [MyFilter3(Order=3)]
    public void Index()

    The OnActionExecuting method, which is the method that will be executed before an Action method of a Controller is executed, has one argument, filterContext of type FilterExecutingContext. The FilterExecutingContext has the following properties:

    ActionMethod
    Cancel
    Controller
    HttpContext
    RouteData

    The ActionMethod is of type MemberInfo and can give you all the information needed of the Action method that are going to be executed. The Cancel property is a Boolean where you can set it to true to cancel all execution of Action Filters and avoid calling the Action method. The Controller property is of type IController and will give you access to the current Controller. The HttpContext is of type HttpContextBase and will give you access to the HttpContext. The RouteData will give you access to the current route information. The OnActionExecuted method takes an argument of type FilterExecutedContext, which have the same properties as the FilterExecutingContex except Cancel and have two other properties, Exception which can be used to get an Exception thrown inside of an Action method, ExceptionHandled can be used to specify if you have handled the exception or not. The reason why the FilterExecutedContext don’t have the Cancel property is because you can’t cancel an action method that has already been executed. If you want a common way to handle exceptions thrown from an Action method, you can use the OnActionExecuted method to log or handle the exception in your own way, instead of showing the ASP.Net yellow error page.

    The Controller base class has two methods which can also be used to handle pre and post action for every action methods of the Controller.  They have the same name and interface as the Action Filter’s OnActionExecuting and OnActionExecuted methods.

    public class MyController : Controller
    {
        public override void OnActionExecuting(FilterExecutingContext filterContext)
        {
        }
    
        public override void OnActionExecuted(FilterExecutedContext filterContext)
        {
        }
    }

    If you need to use some unique logic for a specific Controller on every action that is called, you can override the OnActionExecuting and Executed methods of the Controller, if not, it’s better to use an Action Filter, so you can reuse code among the Controllers.
    The execution of an Action method is the following when an Action filter is used:

    Controller.OnActionExecuting

    ActionFilter.OnActionExecuting

    Controller’s Action method Executed

    ActionFilter.OnActionExecuted

    Controller.OnActionExecuted

    To implement an Action Filter you need to create a class which inherits from the ActionFilterAttribute, where you override the ActionFilterAttribute’s OnActionExectuing or Executed methods or both if you want to use both pre and post actions:

    public class MyFilterAttribute : ActionFilterAttribute
    {
        public override void OnActionExecuting(FilterExecutingContext filterContext)
        {
        }
    
        public override void OnActionExecuted(FilterExecutedContext filterContext)
        {
        }
    }

    When the Action Filter is created you can simply apply the attribute to a Controller’s Class definition (if you want the pre and post action to be executed for every action method) or to methods (if you only want to make sure the pre and post action should be used on a particular method).
    The following Action Filter can be used to make sure that only a user to a specified role can execute the action method. In this code the Roles feature of ASP.Net is used:

    using System;
    using System.Web.Mvc;
    using System.Web.Security;
    using System.Security;
    
    public class RoleFilterAttribute : ActionFilterAttribute
    {
        public string Roles { get; set; }
    
    
        public override void OnActionExecuting(FilterExecutingContext filterContext)
        {
            string[] userRoles = System.Web.Security.Roles.GetRolesForUser();
    
            foreach (string definedRole in this.Roles.Split(','))
            {
                foreach (string role in userRoles)
                {
                    if (definedRole.Equals(role))
                        return;
                }
            }
    
            throw new SecurityException("Access not granted!");
        }
    
    }

    When the attribute is created, you can simply add it to the Controller.

    [RoleFilter(Roles="Admin")]
    public void ListUser()
    {
        //...
        RenderView("Users");
    }

    The only thing I want now for make it easier to add or remove interceptors, is to make it possible to set them up in a configuration file. In that way we can add or remove interceptors from a Controller without recompile our application. We can use Spring.Net’s Aspect Oriented Programming (AOP) support to add interceptors, but it would be so nice to have AOP support added to C# ;)

    Read more...

  • ASP.Net MVC Framework 2 - Define Routes in Web.config

    Something I like with ASP.Net MVC Framework Preview 2 is the RouteValueDictionary used by the Route class’s Defaults, Constraints and DataTokens property, before they use an anonymous type. Because the properties are now a specific type it’s much easier to define the routes in web.config. Before it was quite easy but some reflection was needed. I have now created a ConfigSection and a helper method to easily register routes which can be defined in the web.config for the Preview 2 version of the ASP.Net MVC Framework. I decided to use the following XML structure to define routes in web.config:

    <routeTable>
      <routes>
      
    <
    add
    name="Microsoft"
    url="{controller}/{action}/{id}"
    routeHandlerType="MyMvcRouteHandler">
    <
    defaults action="Index" id=""/> <constraints id="..."/> <dataTokens/>
    </
    add>
    <
    add name="Default" url="Default.aspx"> <defaults controller="Home" action="Index" id=""/> </add>
    </
    routes> </routeTable>

    In my solution I also decided to make sure the “name” attribute of a route <add> is required and used as a key. The two other attributes of the route <add> are “url” and “routeHandlerType”, used to specify the Url and the type of a IRouteHandler to use (by default if it's empty the MvcRouteHandler will be used). I decided to use three child elements to the <add> element, <defaults>, <constraints> and <dataTokens>. Each attribute added to those elements will be added to the property of the Route class with the same name as the element and as a key, value dictionary of type RouteValueDictionary. To make it easy to register and read the routeTable out from the web.config, I created a helper class “RouteTableManager”. By calling its static method “RegisterRoute” from Application_Start in global.asax, the routes were registered.

    RouteTableManager.RegisterRoutes(RouteTable.Routes);

    Or

    RouteTableManager.RegisterRoutes();

    The last method will use the RouteTable class internally.

    By creating a custom MvcRouteModule and override the Init method, the routes can be automatically registered without using global.asax.

    public class MyUrlRouteingModule : UrlRoutingModule
    {
        protected override void Init(HttpApplication application)
        {
            RouteTableManager.RegisterRoutes();
            base.Init(application);
        }
    }

    You can download the whole source code from here..

    Note: The code will only read the routes from the Configuration file, you can’t use it to modify or add new routes. The idea is only to define the routes in a config file instead of adding them manually in the global.asax’s Application_Start event. I also put the source code into the Model directory of the ASP.Net MVC Project, it should be separated into an own assembly, but I was lazy ;)

    Read more...