Showing posts with label MVC. Show all posts
Showing posts with label MVC. Show all posts

Friday, 8 July 2016

Some Notes about ASP.NET Request Validation and Cross Site Scripting

ASP.NET framework has a built-in feature enabled by default to protect application against Cross Site Scripting (XSS) attack. It uses Request Validation feature that checks query string, cookie and posted form values to make sure that those inputs do not contain malicious script. It will throw an error if it encounters malicious script.


Request Validation version
For the recent version of ASP.NET framework, we should use the latest validation mode. In our web.config file, it should have something like:
<httpRuntime requestValidationMode="4.5" targetFramework="4.5" />
ASP.NET version 4.0 should use   requestValidationMode="4.0"


Turning off Request Validation feature in the application
We could also turn off Request Validation feature and only have this feature on some pages. To do this, in web.config set
<pages validateRequest="false" /> 
then set the validation feature on the pages that we would like to have it
<@ Page ValidateRequest="true" %> 


Disable Request Validation in a Controller
We also can disable Request Validation feature for a particular controller by setting [ValidateInput(false)] attribute:
[ValidateInput(false)] 
public ActionResult Index(MyModel m) 
{ 
    . . . 
} 


Disable Request Validation on a class property
To disable the feature at a more granular level, we can use [AllowHtml] attribute on a class property:
public class MyModel 
{ 
    public string MyProperty1 { get;  set; } 

    [AllowHtml] 
    public string MyProperty2 { get; set; } 

    . . . 

} 


Encoding input data
If we would like to allow input data that contains HTML or JavaScript codes, we can encode the input with HtmlEncode() function that are provided by ASP.NET framework. In ASP.NET version 4.5 or above, they have included AntiXss Library in the System.Web.Security.AntiXss namespace. This library prevents XSS better as it uses whitelisting approach compared to the default one which uses blacklisting approach. To set AntiXss Library as the default library for encoding, specify the encoderType in httpRuntime node in web.config:
<httpRuntime  . . .  encoderType="System.Web.Security.AntiXss.AntiXssEncoder" />


Sanitising data
When we need to accept HTML format data, then we should sanitise the data first from any malicious codes. The AntiXss Library 4.3.0 contains sanitiser functionalities however this has reached an end of life. The newer version that is included with ASP.NET 4.5 does not contain sanitiser.

We have some options to add sanitation functionality, a couple of those are:
- Write our own custom method using HTML Agility Pack. See this article for an example
- Use a third party library such as the open source HtmlSanitizer

Using the open source HtmlSanitizer library is easy. We can download the package from NuGet. Below is an example of a simple usage of it:
var sanitiser = new HtmlSanitizer(); 
sanitiser.Sanitize(inputString); 

If we would like to disallow some HTML tags, just use .AllowedTags.Remove() method. For example:
sanitiser.AllowedTags.Remove(“img”); 

Below is an example of a method that uses reflection to sanitise string properties of an object passed to it:
public object CleanStringsFromXSS(object data) 
        {  
            var sanitiser = new HtmlSanitizer(); 

            PropertyInfo[] properties = data.GetType().GetProperties(); 
            foreach (PropertyInfo property in properties) 
            { 
                Type propertyType = property.PropertyType; 
                if ((propertyType == typeof(string)) && (propertyType != null)) 
                { 
                    object value = property.GetValue(data); 
                    if (value != null && property.CanRead && property.CanWrite) 
                    { 
                        string sanitisedValue = sanitiser.Sanitize(value.ToString()); 
                        property.SetValue(data, sanitisedValue); 
                    } 
                } 
            } 

            return data; 
        } 


Request Validation vulnerabilities
There is a known vulnerability in Request Validation. Some types of JSON (JavaScript Object Notation) postback can bypass this feature. Therefore it is important to scan JSON input manually. The sanitation library above can be used to check or sanitise malicious codes.


References:
OWASP: ASP.NET Request Validation
Preventing XSS in ASP.NET Made Easy

Wednesday, 11 February 2015

Handling Exceptions in ASP.NET MVC Application

There are several ways to handle uncaught exceptions in ASP.NET MVC. We could use the default HandleErrorAttribute filter, extend the filter, create our own error filter, override OnException method in controller or use Application_Error method in global.asax.


Using Default MVC Error Handler
By default an MVC project applies HandleErrorAttribute filter globally in global.asax.
public static void RegisterGlobalFilters(GlobalFiltersCollection filters)
{
    filters.Add(new HandleErrorAttribute());
}
It returns the default error view (Error.cshtml) created inside Views\Shared folder.

To have this error handler working, CustomErrors must be set to 'On' in web.config:
<customErrors mode="On">
</customErrors>


Using HandleErrorAttribute Filter in Controller or Action
If we only want to apply the HandleError filter in some controllers or actions, then we need to remove HandleErrorAttribute filter addition in RegisterGlobalFilters method in global.asax. Then apply the filter on specific controllers or actions only.

We can simply use this one:
[HandleError]
This will handle all possible errors it could catch and show the default error view (Error.cshtml) located inside Views\Shared folder.

Otherwise we can specify what type of error to be handled and what view to be displayed. For example:
[HandleError(ExceptionType=typeof(ArgumentException), View="ArgumentError")]
We can also stack these filters to handle different types of error on controllers or actions.

This filter only catches errors originated from inside controller actions and other filters applied to them. It also only handles HTTP 500 Internal Server error. The filter does not do much. After catching errors, it will only show the error page.

Apart from this filter, if we want to catch other than HTTP 500 error, we can set the customErrors in the config file for a particular view to be loaded when the error happens. This is commonly used for HTTP 404 Not Found error:
<customerrors mode="On">
 <error statuscode="404" redirect="~/Error/PageNotFound">
 </error>
</customerrors>


Extending HandleErrorAttribute Filter
By extending this filter, we can add more capabilities such as to log error and handle errors generated from AJAX requests. Below is an example:
public class ExtendedHandleErrorAttribute : HandleErrorAttribute
{
    public override void OnException(ExceptionContext filterContext)
    {
        // if exception is handled already
        if (filterContext.ExceptionHandled || !filterContext.HttpContext.IsCustomErrorEnabled)
        {
            return;
        }

        // pass other HTTP exceptions to global application error handler
        if (new HttpException(null, filterContext.Exception).GetHttpCode() != 500)
        {
            return;
        }

        if (!ExceptionType.IsInstanceOfType(filterContext.Exception))
        {
            return;
        }

        // if the request is AJAX then return JsonResult else normal view
        if (filterContext.HttpContext.Request["X-Requested-With"] == "XMLHttpRequest" || ((filterContext.HttpContext.Request.Headers != null) && (filterContext.HttpContext.Request.Headers["X-Requested-With"] == "XMLHttpRequest")))
        {
            filterContext.Result = new JsonResult
                    {
                        JsonRequestBehavior = JsonRequestBehavior.AllowGet,
                        Data = new
                        {
                            error = true,
                            message = filterContext.Exception.Message
                        }
                    };
        }
        else
        {
            base.OnException(filterContext);
        }

        // log the error
        //. . .

    }
}
In this example, we are just handling HTTP 500 error (Internal Server error) to comply with HTTP standards. Other errors will be passed to global application error handler (Application_Error() method). If you'd like to return a different view, please see that part of codes in the next example (creating custom error filter).


Creating Custom Error Filter
If extending HandleErrorAttribute above is not enough then we can create our own custom error filter. The filter class will inherit from FilterAttribute and IExceptionFilter.
public class CustomHandleErrorAttribute : FilterAttribute, IExceptionFilter
{
    public void OnException(ExceptionContext filterContext)
    {
        // if exception is handled already
        if (filterContext.ExceptionHandled || !filterContext.HttpContext.IsCustomErrorEnabled)
        {
            return;
        }

        // pass other HTTP exceptions to global application error handler
        if (new HttpException(null, filterContext.Exception).GetHttpCode() != 500)
        {
            return;
        }

        /*if (!ExceptionType.IsInstanceOfType(filterContext.Exception))
        {
            return;
        }*/

        // if the request is AJAX then return JsonResult else ViewResult
        if (filterContext.HttpContext.Request["X-Requested-With"] == "XMLHttpRequest" || ((filterContext.HttpContext.Request.Headers != null) && (filterContext.HttpContext.Request.Headers["X-Requested-With"] == "XMLHttpRequest")))
        {
            filterContext.Result = new JsonResult
                        {
                            JsonRequestBehavior = JsonRequestBehavior.AllowGet,
                            Data = new
                            {
                                error = true,
                                message = filterContext.Exception.Message
                            }
                        };
        }
        else
        {
            // if we want to pass detailed error info to the view
            var controllerName = (string)filterContext.RouteData.Values["controller"];
            var actionName = (string)filterContext.RouteData.Values["action"];
            var model = new HandleErrorInfo(filterContext.Exception, controllerName, actionName);

            filterContext.Result = new ViewResult
            {
                ViewName = "theViewName",
                ViewData = new ViewDataDictionary<HandleErrorInfo>(model),
                TempData = filterContext.Controller.TempData
            };
        }

        // log the error
        //. . .

        filterContext.ExceptionHandled = true;
        filterContext.HttpContext.Response.Clear();
        filterContext.HttpContext.Response.StatusCode = 500;

        filterContext.HttpContext.Response.TrySkipIisCustomErrors = true;
    }
}
The example codes handle AJAX and normal requests, log error and return a particular view for a normal request.


Overriding OnException Method in Controller
Another way to handle error in ASP.NET MVC application is by overriding OnException method in controller. However, like the HandleErrorAttribute filter above, this method only catches errors that happen inside a controller. Other errors such as data binding or route errors will not be caught. We could also return a view by assigning a ViewResult to its ExceptionContext object's Result property. Below is an example:
protected override void OnException(ExceptionContext context)
{
    // pass other errors to global application error handler
    if (context.Exception is InvalidOperationException)
    {
        // do some error logging
        //. . .

        // if we want to pass detailed error info to the view
        var controllerName = (string)context.RouteData.Values["controller"];
        var actionName = (string)context.RouteData.Values["action"];
        var model = new HandleErrorInfo(context.Exception, controllerName, actionName);

        var result = new ViewResult
                {
                    ViewName = "theViewName",
                    ViewData = new ViewDataDictionary(model),
                    TempData = context.Controller.TempData
                };
        context.Result = result;

        // configure the response object
        context.ExceptionHandled = true;
        context.HttpContext.Response.Clear();
        context.HttpContext.Response.StatusCode = 500;
        context.HttpContext.Response.TrySkipIisCustomErrors = true;
    }
}


Using Application Global Error Handler
Lastly, we can also use Application_Error() method in global.asax. This method catches all unhandled errors and is the last resort before the yellow error screen. Many developers only use this method alone to handle all kind of errors in the application. When there is a need to handle errors (or some specific errors) at controller or action method level then the other error handlers mentioned above can be used.

Below is an example of using Application_Error() method and its related error controller and view to catch errors:
global.asax Application_Error() method:
protected void Application_Error(object sender, EventArgs e)
{
    HttpContext httpContext = ((MyApplicationName)sender).Context;
    Exception exception = Server.GetLastError();

    if (httpContext.Request["X-Requested-With"] == "XMLHttpRequest" || ((httpContext.Request.Headers != null) && (httpContext.Request.Headers["X-Requested-With"] == "XMLHttpRequest")))
    {
        // handle AJAX request

        httpContext.ClearError();
        Response.StatusCode = 500;
        Response.ContentType = "application/json";
        Response.StatusDescription = "my custom status description";    // => Response.StatusDescription maps to jqXHR or XMLHttpRequest.statusText

        // => Response.Write() maps to jqXHR or XMLHttpRequest.responseText  
#if DEBUG
        Response.Write(new System.Web.Script.Serialization.JavaScriptSerializer().Serialize(new
        {
            errorMessage = exception.ToString()
        }));
        //Response.Write(exception.ToString());
#else
        Response.Write("an application error has occurred");
#endif
    }
    else
    {
        // non AJAX request

        IController errorController = new MyWebProject.Controllers.ErrorController();
#if DEBUG
        {
            // get information to be passed to view as model
            string currentController = string.Empty;
            string currentAction = string.Empty;
            RouteData currentRouteData = RouteTable.Routes.GetRouteData(new HttpContextWrapper(httpContext));
            if (currentRouteData != null)
            {
                if (currentRouteData.Values["controller"] != null && !String.IsNullOrEmpty(currentRouteData.Values["controller"].ToString()))
                {
                    currentController = currentRouteData.Values["controller"].ToString();
                }

                if (currentRouteData.Values["action"] != null && !String.IsNullOrEmpty(currentRouteData.Values["action"].ToString()))
                {
                    currentAction = currentRouteData.Values["action"].ToString();
                }
            }

            ((Controller)errorController).ViewData.Model = new HandleErrorInfo(exception, currentController, currentAction);
        }
#else
        {
            // only show a message
            ((Controller)errorController).ViewData.Model = "error message . . .";
        }
#endif

        string action = "Error";

        if (exception is HttpException)
        {
            // get the action for different error codes
            switch (((HttpException)exception).GetHttpCode())
            {
                case 404:
                    action = "NotFound";
                    break;

                // other errors
            }
        }

        httpContext.ClearError();
        httpContext.Response.Clear();
        httpContext.Response.StatusCode = exception is HttpException ? ((HttpException)exception).GetHttpCode() : 500;

        // avoid IIS7 getting involved
        httpContext.Response.TrySkipIisCustomErrors = true;

        // execute the error controller
        RouteData routeData = new RouteData();
        routeData.Values["controller"] = "Error";
        routeData.Values["action"] = action;
        //IController errorController = new NSWHealth.ICPBS.Web.Controllers.ErrorController(); // for readability only, this is already done above 
        //((Controller)errorController).ViewData.Model = new HandleErrorInfo(exception, currentController, currentAction); // for readability only, this is already done above
        errorController.Execute(new RequestContext(new HttpContextWrapper(httpContext), routeData));
    }
}

error controller:
public class ErrorController : Controller
    {
        public ActionResult Error()
        {
            return View();
        }

        public ViewResult NotFound()
        {
            //Response.StatusCode = 404;  //could be set to 200 as well
            return View("NotFound");
        }
    }

error view:
@{
    ViewBag.Title = "Error";
    Layout = "~/Views/Shared/_Layout.cshtml";
}

<h2>Error</h2>
<div>
    @if (Html.IsDebug())
    {
        <div>
            <p>
                <b>Exception:</b> @Model.Exception.Message<br />
                <b>Controller:</b> @Model.ControllerName<br />
                <b>Action:</b> @Model.ActionName
            </p>
            <div style="overflow:scroll">
                <pre>
                @Model.Exception.StackTrace
                </pre>
            </div>
        </div>
    }
    else
    {
        <div style="min-height:460px">
            An error has occurred: @Model 
        </div>
    }
</div>


References and further reading:
Handling Errors Effectively in ASP.NET MVC
Exception Handling in ASP.NET MVC
Exception Handling in MVC

Friday, 15 August 2014

Bundling and Minification Feature in MVC

On this post we will see how to implement CSS and JavaScript files bundling and minification feature in MVC.

1. Add files
First, we need to add the files inside RegisterBundles() method of App_Start\BundleConfig.cs class. Make sure that our web project has installed Microsoft.AspNet.Web.Optimization library. If not then we can use NuGet to install it.

1.1. Adding CSS files
We use StyleBundle class to add the CSS files. First we specify the bundle name and the relative path where it is going to be generated from. Then we add the intended files to it using relative path url.
StyleBundle cssBundle = new StyleBundle("~/Styles/bundledcss");
cssBundle.Include(
 "~/Styles/mystylesheet1.css",
 "~/Styles/mystylesheet2.css",
 . . .
 );
bundles.Add(cssBundle);

1.2. Adding JavaScript files
This time we use ScriptBundle class. The process is similar as adding CSS files above.
ScriptBundle scriptsBundle = new ScriptBundle("~/Scripts/bundlescripts"); 
scriptsBundle.Include(
 "~/Scripts/myscript1.js",
 "~/Scripts/myscript2.js",
 . . .
);
bundles.Add(scriptsBundle);
We can also use -{version} syntax when including a file. For example; ~/Scripts/jquery-{version}.js
When using this, the '.min' version will be used in release mode and normal version will be used in debug mode. The '-vsdoc' version for IntelliSense will be ignored.

In addition, wildcard character '*', can be used as well when including files to include all matching files.


2. If using Debug mode, set BundleTable.EnableOptimizations
If we want to see bundling and minification in action in debugging mode ('compilation debug="true"' is set in web.config file) then we need to set
BundleTable.EnableOptimizations = true;
otherwise each file will be called individually like before.

In my development environment, I set up a release and a debug build configurations with 'compilation debug="true"' in my web.config. In the Build section of the project properties, the debug build configuration has 'Define DEBUG constant' checked. Then I do
#if !DEBUG
BundleTable.EnableOptimizations = true;
#endif
so that I could have the bundling and minification work when I use release build configuration and off when using debug build configuration.

Below are the complete codes from the steps above.
public class BundleConfig
{
 public static void RegisterBundles(BundleCollection bundles)
 {
  StyleBundle cssBundle = new StyleBundle("~/Styles/bundledcss");
  cssBundle.Include(
   "~/Styles/mystylesheet1.css",
   "~/Styles/mystylesheet2.css",
   . . .
   );
  bundles.Add(cssBundle);

  ScriptBundle scriptsBundle = new ScriptBundle("~/Scripts/bundledscripts"); 
  scriptsBundle.Include(
   "~/Scripts/myscript1.js",
   "~/Scripts/myscript2.js",
   . . .
  );
  bundles.Add(scriptsBundle);

  #if !DEBUG
  BundleTable.EnableOptimizations = true;
  #endif
 }
}

3. Include that method in Application_Start() in Global.asax.cs
protected void Application_Start()
{
 . . .
 BundleConfig.RegisterBundles(System.Web.Optimization.BundleTable.Bundles);
 . . .
}

4. Render the bundle on the view
We render the styles bundle with Styles.Render() method and JavaScript files bundle with Scripts.Render() method, passing the same bundle name and path as when it was created.
@Styles.Render("~/Styles/bundledcss")

@Scripts.Render("~/Scripts/bundledscripts")


Files ordering
The optimisation library uses some predefined rules for ordering the files that we include. If we found that our site breaks because of the files were ordered differently from the ones we specify then we need to do a little tweak to override the default ordering. To do this, we need to implement a custom class inherited from IBundleOrderer, then just simply return the files as they are in its OrderFiles() method.
public class AsListedOrderer : IBundleOrderer
{
 public IEnumerable<BundleFile> OrderFiles(BundleContext context, IEnumerable<BundleFile> files)
 {
  return files;
 }
}
Then set the custom orderer in our bundle. For example:
public class BundleConfig
{
 public static void RegisterBundles(BundleCollection bundles)
 {
  ScriptBundle scriptsBundle = new ScriptBundle("~/Scripts/bundledscripts"); 
  scriptsBundle.Orderer = new AsListedOrderer();
  scriptsBundle.Include(
   . . .
  );
  . . .
 }
}


What about the minification?
When we are using StyleBundle or ScriptBundle type to create a bundle, the minification feature is already included in it. However if there is a syntax error in one of our files then the minification might not be applied and we could see the warning when we open the bundle uri on a browser to see the content.

If for a reason, we do not want to apply minification in our bundle, then we could use Bundle type instead. In fact, StyleBundle and ScriptBundle types inherit from Bundle type.


Bundle versioning
When the library creates a bundle, it will add calculated hash result of the files content as a querystring. For example; "/Scripts/bundledscripts?v=8mW7h5gn2CgW9MkumYwMSzClMgRORVfdSNBsizgxyoU1"
So if we make a change in our files, the generated hash value will be different. This is another good benefit for us so that we do not need to worry about our content being cached by browsers thus the latest changes will always be rendered.

Friday, 25 April 2014

Passing Objects in JSON through ViewBag

Below is an example of how to pass a collection of objects in JSON format through ViewBag.
List<Student> studentsList = new List<Student>();
studentsList = GetStudents();
ViewBag.Students = System.Web.Helpers.Json.Encode(studentsList);
We use System.Web.Helpers.Json.Encode() function to do the formatting and on the view, we just need to render the passed content like this:
@Html.Raw((String)ViewBag.Students)

A different way to do this is by passing the collection directly through ViewBag
ViewBag.Students = studentsList;
then we do the formatting on the view
@Html.Raw(Json.Encode((IList<Student>)ViewBag.Students))
However this way is less efficient than the earlier one.

Friday, 15 November 2013

Using Editor Template for Rendering DropDownList

Below is an example of how to have a dropdownlist when editing a model that has an integer type property used for foreign key property. I.e.; I have a model that has this property:
int ItemId { get; set; }
Then I want every time an instance of this model type is being edited, the field is shown as a dropdownlist. To do this, inside 'EditorTemplates' folder under the global 'Views\Shared' or a view's specific folder, I create a partial view named 'Item.cshtml' like below:
@Html.DropDownListFor(model => ViewData.TemplateInfo.FormattedModelValue, ((IEnumerable<Model.Item>)ViewBag.Items).Select(option => new SelectListItem {
                Text = option.Type.Name, 
                Value = option.ItemId.ToString(),
                Selected = (Model != null) && (option.ItemId == (int)ViewData.TemplateInfo.FormattedModelValue)
            }), "Please select")
Note that, I use ViewData.TemplateInfo.FormattedModelValue to get the value. I could also write like this by declaring the model to use:
@model int

@Html.DropDownListFor(model => model, ((IEnumerable<Model.Item>)ViewBag.Items).Select(option => new SelectListItem {
                Text = option.Type.Name, 
                Value = option.ItemId.ToString(),
                Selected = option.ItemId == Model
            }), "Please select")
Then to render the custom template on my edit view page, I do:
@Html.EditorFor(model => model.ItemId, "Item")

For more details about Editor Template or Display Template, you could see my previous post.

Friday, 25 October 2013

Inline SelectList for MVC DropDownList

Below are examples of how to write predefined SelectList items of a DropDownList inline in ASP.NET MVC view.
@Html.DropDownListFor(model => model.IsExist,
         new SelectList(new List<Tuple<bool, string>>
         {
           new Tuple<bool, string>(false, "No"),                    
           new Tuple<bool, string>(true, "Yes"),                    
         }, "Item1", "Item2"))
@Html.DropDownListFor(model => model.IsExist,
         new SelectList(new []
         {
           new {ID=false, Name="No"},
           new {ID=true, Name="Yes"},
         }, "ID", "Name"))

Friday, 27 September 2013

Data Annotations Attributes for Formatting Purpose

There are many attributes that we can use from System.ComponentModel.DataAnnotations. A few of them have just been added in the latest framework. Some of those are useful for validation and others for formatting purpose. On this post, I'd like to particularly focus on the attributes that can be used for formatting/displaying data.

However, first I will list down the ones that are useful for validation:
- Compare
- CustomValidation (this is different from creating custom validation class that derives from ValidationAttribute class)
- EmailAddress
- FileExtensions
- MaxLength
- MinLength
- Phone
- Range
- RegularExpression
- Required
- StringLength
- Url

Then the ones that are useful for formatting are below:
- Display
Specify the property name to be displayed. Also can be used to set the display order of the property. The default value is 10,000.
e.g.;
[Display(Name=”First Name”, Order=11000)]

- ScaffoldColumn
Hide the property to be displayed by EditorForModel and DisplayForModel.
e.g.;
[ScaffoldColumn(false)]

- DisplayFormat
Display the property in specific format in EditorFor or DisplayFor helper. Some options are:
ConvertEmptyStringToNull, NullDisplayText, DataFormatString, ApplyFormatInEditMode and HtmlEncode.
e.g.;
[DisplayFormat(ConvertEmptyStringToNull = true, NullDisplayText = "[Null]")]
ConvertEmptyStringToNull will automatically convert passed empty string into null when binding model.
NullDisplayText is used to specify text to be displayed if the property value is null. By default an empty string will be displayed.
[DisplayFormat(ApplyFormatInEditMode=true, DataFormatString=”{0:c}”)]
ApplyFormatInEditMode by default is false because most of the time the input passed from edit form would not be able to be parsed.

- ReadOnly
Tell model binder to not set the property with a new value. EditorForModel will still enable the input to be edited however the model binder will ignore the value passed.

- DataType
Set the property to be displayed in a more specific data type. Some of the data types are; MultilineText, Password and Url. The complete list of data types and their description can be found here.
e.g.;
[DataType(DataType.Password)]

- UIHint
Used to specify custom template name to be used by EditorFor or DisplayFor helper when rendering the property. This attribute is useful when we want to use a custom template for displaying a property. The template is put under DisplayTemplates or EditorTemplates folder under Shared or a specific controller folder.

For example; if we create a new template for displaying hyperlink in a file called Hyperlink.cshtml:
<a href="@Model" target="_blank">@Model</a>
Then we can add this attribute on property that we want to be rendered using the new template. If we have put the template under Shared folder then this can be applied to any property in the project.
[UIHint("Hyperlink")]

- HiddenInput
Set the property to be rendered as an html hidden element.

Friday, 16 August 2013

Using Display Templates or Editor Templates

DisplayTemplates or EditorTemplates is used for providing custom template for a model property whether it is of a single object type or a collection of an object type. DisplayTemplates or EditorTemplates can be used to automatically render an object type in all views in the application or in all views of a particular controller. It can also only be called when needed.

To use that, first create the template (view) for the object type with this name 'object_type.cshtml' under DisplayTemplates or EditorTemplates folder under Views\Shared or a particular controller's views folder (e.g.; Views\Home). By default the framework will search under a controller views folder first then the Shared folder. If we put the template under Shared folder then it will apply to all views. Whenever a particular object type is rendered using EditorFor or DisplayFor, the framework will use the template.

For example, below is a template for a class object type called ItemViewModel:
@model ItemViewModel

@Html.DisplayNameFor(model => model.ItemId)
@Html.DisplayFor(model => model.ItemId)

@Html.DisplayNameFor(model => model.ItemName)
@Html.DisplayFor(model => model.ItemName)

Then render the property with EditorFor or DisplayFor helper method on a view.
EditorFor(model => model.Items)

That's all that we need to do. If the property is a collection of an object type then the template will be rendered multiple times for each item.

If we want the new template to be used only when we call it, then we could name the template using other name other than the object type (e.g.; MyCustomTemplate.cshtml). Then to use it we can specify the template name as the second argument on EditorFor or DisplayFor method
EditorFor(model => model.Items, "MyCustomTemplate")
or by using UIHint attribute on the object property
[UIHint("MyCustomTemplate")]
public IList<ItemViewModel> Items { get; set; }

Friday, 9 August 2013

Passing Dynamic Collection Member Manually through Html.BeginForm Method

Let's say we have a model with a collection type member that is populated dynamically on client side and we want to pass them automatically to controller by using Html.BeginForm(). We can manually add html input elements with some conventions to allow the collection to be passed.
The input element must have:
- id attribute like 'CollectionName_IndexNumber__PropertyName'
- and name attribute like 'CollectionName[IndexNumber].PropertyName'

For example, if we have:
public class InvoiceDto
{
 public int InvoiceId { get; set; }
 public string Name { get; set; }    
 public string Description { get; set; }

 public IList<ItemSellingDto> Items { get; set; }
}

public class ItemSellingDto
{
 public int ItemSellingId { get; set; }
 public int ItemId { get; set; }
 public Int16 Quantity { get; set; }     
 public decimal Price { get; set; }
 public int InvoiceId { get; set; }
}
and we would like to add each collection member (ItemSellingDto) to an html table element inside Html.BeginForm() dinamically using JavaScript (see my previous post to see the example layout), then the script would look like something like:
function addRow(response) {
 var tableRows = $('#tblItemSellings tr');
 var tr;
 tr = $('<tr/>');
 tr.append("<td>" + response.ItemName + "</td>");
 tr.append("<td>" + response.Quantity + "</td>");
 tr.append("<td>" + response.Price + "</td>");

    // the first row is for table headers
 tr.append("<td><input type='hidden' id='Items_" + (tableRows.length - 1) + "__ItemId' name='Items[" + (tableRows.length - 1) + "].ItemId' value='" + response.ItemId + "'/></td>");
 tr.append("<td><input type='hidden' id='Items_" + (tableRows.length - 1) + "__Quantity' name='Items[" + (tableRows.length - 1) + "].Quantity' value='" + response.Quantity + "'/></td>");
 tr.append("<td><input type='hidden' id='Items_" + (tableRows.length - 1) + "__Price' name='Items[" + (tableRows.length - 1) + "].Price' value='" + response.Price + "'/></td>");

 $('#tblItemSellings').append(tr);
}

Friday, 19 July 2013

Using Partial View and AJAX for Validation - with jQuery Ajax

In the previous post I wrote about using partial view for validation with Ajax.BeginForm. If we want to do the form submission manually with jQuery Ajax method we could do that as well. We only need to do minor changes on the partial view and add the jQuery script. Below is the updated partial view:
@model DTO.ItemSellingDto

<div id="result">
@using (Html.BeginForm("CreateEditPartial", "ItemSellings", FormMethod.Post, new {id="ItemSellingForm"})) {
    @Html.ValidationSummary(true)
    <fieldset>
        <legend>ItemSelling</legend>
        <span style="color: red">@ViewBag.ErrorMessage</span>
        
        <div class="editor-label">
            @Html.LabelFor(model => model.Quantity)
        </div>
        <div class="editor-field">
            @Html.EditorFor(model => model.Quantity)
            @Html.ValidationMessageFor(model => model.Quantity)
        </div>

        <div class="editor-label">
            @Html.LabelFor(model => model.Price)
        </div>
        <div class="editor-field">
            @Html.EditorFor(model => model.Price)
            @Html.ValidationMessageFor(model => model.Price)
        </div>

        . . .

        <div>
            <input id="btnCreateItemSelling" type="submit" value="Create" />
        </div>
    </fieldset>
}
</div>

<script type="text/javascript">
    $(function () {
        $('#ItemSellingForm').submit(function () {   // the form id is specified in Html.BeginForm method parameter
            $.ajax({
                url: this.action,
                type: this.method,
                data: $(this).serialize(),
                success: function (result) {
                    if (typeof result == 'object') {
                        $('#result').html('');  // this is to clear the update pane
                        addRow(result);
                    } else {
                        $('#result').html(result);  // display partial view again if input is not valid
                    }
                }
            });
            return false;  // don't forget this, otherwise the page will redirect
        });
    });
</script>
The other codes are still the same as shown here.

Tuesday, 16 July 2013

Using Partial View and AJAX for Validation - with Ajax.BeginForm

I would like to create a page that shows an update pane when a button is clicked. The pane should use Ajax so it will be displayed without page refresh. Below are how the screens will look like:



I also want some validation on the input fields on the update pane. However I prefer to have server validation so that all business rules can be put in one place. When the fields are submitted through Ajax, if there's a validation error the message should be shown. However if successful, the new record should be added to a listing table. All of this is done through Ajax so there will be no page refresh.


To be able to do this, first we need to create a Partial View that contains the input fields:
@model DTO.ItemSellingDto

<div id="result">
@using (Ajax.BeginForm(new AjaxOptions(){UpdateTargetId="result", HttpMethod="Post", 
    Url=Url.Action("CreateEditPartial","ItemSellings"), OnSuccess="addRow"})) {
    @Html.ValidationSummary(true)
    <fieldset>
        <legend>ItemSelling</legend>
        <span style="color: red">@ViewBag.ErrorMessage</span>
        
        <div class="editor-label">
            @Html.LabelFor(model => model.Quantity)
        </div>
        <div class="editor-field">
            @Html.EditorFor(model => model.Quantity)
            @Html.ValidationMessageFor(model => model.Quantity)
        </div>

        <div class="editor-label">
            @Html.LabelFor(model => model.Price)
        </div>
        <div class="editor-field">
            @Html.EditorFor(model => model.Price)
            @Html.ValidationMessageFor(model => model.Price)
        </div>

        . . .

        <div>
            <input id="btnCreateItemSelling" type="submit" value="Create" />
        </div>
    </fieldset>
}
</div>
Note that in this case I use Ajax.BeginForm to help with the form submission. We could have used jQuery method $.ajax as well (I will write about this on the next post). Some of the AjaxOptions properties that I have used are:
- UpdateTargetId: this is the target element that will be updated after submission to the server side
- HttpMethod: POST or GET
- Url: this should point to the controller action to process the form
- OnSuccess: we can specify a javascript function to call after the form is successfully submitted.
There are some other options such as LoadingElementId, OnBegin, OnComplete and OnFailure. Please see this page for more details.
We also need a submit type element for the form. Also note that on the first line, we could use a model as well like a normal view.

To show this partial view when the button on the main view is clicked, add a placeholder somewhere on the main page and call the jQuery load function when the button is clicked.
// in this case the button id is 'btnAddItemSelling' 
// and I use a div with id 'itemSellings' for the placeholder
$("#btnAddItemSelling").click(function () {
 $("#itemSellings").load("@Url.Action("CreateEditPartial","ItemSellings")");
});
The url passed in the function parameter is the url used by GET controller action for displaying the partial view that we will create next.

Then we create the controller actions. We have two controller actions, one for displaying the partial view (GET) and the other for receiving the form data after submitted (POST). Note that the actions return partial view type when displaying and when the validation is failed. Also on line 9, we could pass a model as a parameter to the method from the Ajax form.
public ActionResult CreateEditPartial()
{
 // prepare and populate required data for the input fields
 // . . .

 return PartialView("CreateOrEdit");
}

[HttpPost]
public ActionResult CreateEditPartial(ItemSellingDto itemSellingDto)
{
 if (!ModelState.IsValid)
 {
  // prepare and populate required data for the input fields
  // . . .

  return PartialView("CreateOrEdit");
 }
 else
 {
  return Json(itemSellingDto);
 }
}
For the validation, in this case I just simply used Data Annotation but we could use other alternative such as a custom method, etc. I simply used   ModelState.IsValid   to check whether the inputs passed are fine. Then also put   @Html.ValidationMessageFor(...)   for each input field on the view. Note also that I enclosed the Ajax.BeginForm inside a div (please see line 3 and 34 on the partial view file above) and assign the Id to UpdateTargetId (one of the AjaxOptions properties) so that when input is not valid then the partial view content will be automatically put into the target element.

Next, include these two javascript references; jQuery and jQuery Unobtrusive Ajax on the main page. Do NOT put jQuery Unobtrusive Ajax on the partial page as this will cause the page to be submitted multiple times instead of once. Also write the javacript function that will be called when the validation from server side is successful. In this case, the code returns an object if validation is successful then the javascript function checks the data passed, if it is an object then add it to the listing table.



function addRow(response) {
 if(typeof response =='object')
 {
  // append object to table
  . . .
 }
}

Thursday, 31 January 2013

Basic Usage of Unity for Dependency Injection in MVC 4 Project

First, we need to install Unity Application Block library. If you use NuGet:
PM> install-package Unity.Mvc3
Yes, that is the correct version even for MVC 4 (at least at the time of writing).

Bootstrapper.cs file will be created in the project.

Next, inside Applicaton_Start() in Global.asax.cs, put this code:
Bootstrapper.Initialise();

Then register our components inside BuildUnityContainer() method in Bootstrapper.cs. For example:
        . . .
        container.RegisterType<IColourRepository, ColourRepository>();
        container.RegisterType<IInvoiceRepository, InvoiceRepository>();
        . . .

Calling container.RegisterControllers() in order to register controllers is no longer required in recent version.

Saturday, 30 June 2012

xUnit Examples of Testing Controller Actions

We will see some examples of unit tests using xUnit testing framework to test controller actions. Let say we have these controller actions:
public ViewResult Add()
{            
    return View("Add", new StuffViewModel());
}


[HttpPost]
public ActionResult Add(StuffViewModel stuffViewModel)
{
    if (ModelState.IsValid)
    {
        Stuff stuff = mappingService.Map<StuffViewModel, Stuff>(stuffViewModel);
        stuffRepository.InsertOrUpdate(stuff);
        return RedirectToAction("List");
    }
    return View("Add", stuffViewModel);
}
As you can see both actions use same view. The first action is for displaying the view (HTTP GET) and the other is for handling submission from the view (HTTP POST).

Then below are the unit tests to cover both actions functionalities:
public class Add
{
    private Mock<IStuffRepository> stuffRepository;
    private Mock<IMappingService> mappingService;
    private StuffsController controller;

    public Add()
    {
        stuffRepository = new Mock<IStuffRepository>();
        mappingService = new Mock<IMappingService>();
        controller = new StuffsController(stuffRepository.Object, mappingService.Object);
    }


    [Fact]
    public void GET_should_return_add_view()
    {
        // Arrange

        // Act
        var result = controller.Add();

        // Assert
        var viewResult = Assert.IsType<ViewResult>(result);
        Assert.Equal("Add", viewResult.ViewName);
    }

    [Fact]
    public void GET_should_have_StuffViewModels()
    {
        // Arrange

        // Act
        var result = controller.Add();

        // Assert
        //Assert.IsAssignableFrom<StuffViewModel>(result.ViewData.Model); 
        Assert.IsType<StuffViewModel>(result.ViewData.Model);
    }

    [Fact]
    public void POST_should_save_to_database_if_model_is_valid()
    {
        // Arrange
        StuffViewModel stuffViewModel = new StuffViewModel { StuffID = 1 };
        Stuff stuff = new Stuff { StuffID = 1};
        mappingService.Setup(m => m.Map<StuffViewModel, Stuff>(It.IsAny<StuffViewModel>()))
                        .Returns(stuff);
                
        // Act
        controller.Add(stuffViewModel);

        //Assert
        stuffRepository.Verify(o => o.InsertOrUpdate(stuff), Times.Once());
    }

    [Fact]
    public void POST_should_redirect_to_list_view_after_saving()
    {
        // Arrange
        StuffViewModel stuffViewModel = new StuffViewModel { StuffID = 1 };
        Stuff stuff = new Stuff { StuffID = 1 };
        mappingService.Setup(m => m.Map<StuffViewModel, Stuff>(It.IsAny<StuffViewModel>()))
                        .Returns(stuff);

        // Act
        var result = controller.Add(stuffViewModel);

        // Assert
        var redirectToRouteResult = Assert.IsAssignableFrom<RedirectToRouteResult>(result);
        Assert.Equal("List", redirectToRouteResult.RouteValues["action"]);
    }

    [Fact]
    public void POST_if_not_valid_should_not_save_into_database()
    {
        // Arrange
        StuffViewModel stuffViewModel = new StuffViewModel { StuffID = 1 };
        Stuff stuff = new Stuff { StuffID = 1 };
        mappingService.Setup(m => m.Map<StuffViewModel, Stuff>(It.IsAny<StuffViewModel>()))
                        .Returns(stuff);
        controller.ModelState.AddModelError("key", "error");

        // Act
        var result = controller.Add(stuffViewModel);

        // Assert
        stuffRepository.Verify(o => o.InsertOrUpdate(stuff), Times.Never());
    }

    [Fact]
    public void POST_if_not_valid_should_return_to_add_view()
    {
        // Arrange
        StuffViewModel stuffViewModel = new StuffViewModel { StuffID = 1 };
        Stuff stuff = new Stuff { StuffID = 1 };
        mappingService.Setup(m => m.Map<StuffViewModel, Stuff>(It.IsAny<StuffViewModel>()))
                        .Returns(stuff);
        controller.ModelState.AddModelError("key", "error");

        // Act
        var result = controller.Add(stuffViewModel);

        // Assert
        var viewResult = Assert.IsType<ViewResult>(result);
        Assert.Equal("Add", viewResult.ViewName);
    }

    [Fact]
    public void POST_if_not_valid_should_return_view_with_StuffViewModel()
    {
        // Arrange
        StuffViewModel stuffViewModel = new StuffViewModel { StuffID = 1 };
        Stuff stuff = new Stuff { StuffID = 1 };
        mappingService.Setup(m => m.Map<StuffViewModel, Stuff>(It.IsAny<StuffViewModel>()))
                        .Returns(stuff);
        controller.ModelState.AddModelError("key", "error");

        // Act
        var result = controller.Add(stuffViewModel);

        // Assert
        var viewResult = Assert.IsType<ViewResult>(result);
        Assert.IsType<StuffViewModel>(viewResult.ViewData.Model);
    }
}

Thursday, 21 June 2012

Mocking AutoMapper in Unit Testing

This post will show how to mock AutoMapper with Moq in unit testing. Unit testing that has dependency to AutoMapper would require all of the mapping configurations be specified and run first before the actual mapping takes place (Mapper.Map(...) is called). These configurations would be burdensome and should not be included in unit testing. A unit test for a feature should only test that particular feature the developer has written. It should not test other services or functionalities. This is where the concept of mocking come up.

To be able to mock AutoMapper, we can use Dependency Injection to inject a mapper interface to the constructor of the calling code's class rather than using AutoMapper directly. Below is an example of such interface:
public interface IMappingService
{
    TDest Map<TSrc, TDest>(TSrc source) where TDest : class;
}

Then create an implementation class for the interface. Note on line 5 that for this class we specify AutoMapper directly.
public class MappingService : IMappingService
{
    public TDest Map<TSrc, TDest>(TSrc source) where TDest : class
    {
        return AutoMapper.Mapper.Map<TSrc, TDest>(source);
    }
}

Next, bind the interface with the concrete class. Below is an example of how to do it with Ninject:
kernel.Bind<IMappingService>().To<MappingService>();

Then whenever we want to do mapping, we call the interface's Map method instead of using the AutoMapper's Mapper.Map() method.
public ViewResult List()
{
    IEnumerable<Stuff> stuffs = stuffRepository.All;

    List<StuffViewModel> model = mappingService.Map<IEnumerable<Stuff>, List<StuffViewModel>>(stuffs);

    return View("List", model);
}
Please remember that mapping configurations need to be specified first before we could do any mapping. You can see this post to see how to set up the configurations.

Now we can mock the mapper in our unit test. In the example below I use xUnit testing framework. As you can see; first we create a mock instance from the interface, setup what the Map method will return and then pass the mock object to the class constructor of the feature to be tested (line 6, 25 and 28).
[Fact]
public void ListPageReturnsStuffViewModels()
{
    // Arrange
    Mock<IStuffRepository> stuffRepository = new Mock<IStuffRepository>();
    Mock<IMappingService> mappingService = new Mock<IMappingService>();

    List<Stuff> stuffs = new List<Stuff>();
    stuffRepository.Setup(r => r.All).Returns(stuffs.AsQueryable());

    var viewModelStuffs = new List<StuffViewModel> {
        new StuffViewModel { StuffID = 1/*,
                                Name= "Bip",
                                Description= "Colourful baby bip",
                                DateAdded = DateTime.Now,
                                UserID = 1 */
        },
        new StuffViewModel { StuffID = 2/*,
                                Name= "Socks",
                                Description= "Winter socks with animal figures",
                                DateAdded = DateTime.Now,
                                UserID = 1 */
        }
    };
    mappingService.Setup(m => m.Map<IEnumerable<Stuff>, List<StuffViewModel>>(It.IsAny<IEnumerable<Stuff>>()))
                    .Returns(viewModelStuffs);

    var controller = new StuffsController(stuffRepository.Object, mappingService.Object);


    // Act
    var result = controller.List() as ViewResult;
    //var model = result.ViewData.Model as List<StuffViewModel>;


    // Assert
    var model = Assert.IsType<List<StuffViewModel>>(result.ViewData.Model);
    Assert.Equal(2, model.Count);                
}

Thursday, 17 May 2012

Using Remote Attribute Validator in ASP.NET MVC 3

In the past I have written a few posts about validation in ASP.NET MVC 3. One of them is about creating custom client side validation. There is another way to do client validation in MVC 3. This one is easier to implement for standard/common validation functions. It is the new RemoteAttribute. This attribute allows us to have client side validation that calls controller action on the back end.

To use the attribute, first we need to prepare an action method:
[HttpPost]
public ActionResult CheckFirstName(string firstname)
{
    return Json(firstname.Equals("firstname"));
}

Then specify the attribute on a field of a model:
[Remote("CheckFirstName", "Account", HttpMethod = "Post", ErrorMessage = "First name is not valid")]
public string FirstName { get; set; }
In this case we pass the action method name, controller name, HTTP method used by the action and a default error message. Notice also that the action method must accept an input parameter which would be the field's value. When specifying the Remote attribute we could also use a route name or action, controller and area names.

Let us look at another example. Here we have another action method:
[HttpPost]
public ActionResult CheckFullName(string fullName, string firstname, string lastname)
{
    return Json(fullName.Equals(string.Format("{0} {1}", firstname, lastname)));
}

Then on the model class:
[Remote("CheckFullName", "Account", HttpMethod="Post", AdditionalFields="FirstName,LastName", ErrorMessage = "Full name is not valid")]
public string FullName { get; set; }

This time we pass additional fields to the validation method. Notice the AdditionalFields parameter and also on the action method there are extra parameters passed.

One important thing to remember, to avoid the validation result being cached by the browser, we need to include this attribute on the controller action:
[OutputCache(Location = OutputCacheLocation.None, NoStore = true)]

Reference:
The Complete Guide To Validation In ASP.NET MVC 3 - Part 1

Friday, 30 March 2012

Client Side Custom Annotation Validation in ASP.NET MVC 3

On this post, we will see how to implement client side custom data annotation validation in ASP.NET MVC 3. I wrote about server side custom validation on my previous post.

There are a few steps that need to be done to implement client side custom validation:

1. Make our custom validation class (see my previous post for the codes example) inherits from IClientValidatable and implement its GetClientValidationRules method.
public class SumIntegers : ValidationAttribute, IClientValidatable
{
    . . .

    public IEnumerable<ModelClientValidationRule> GetClientValidationRules(ModelMetadata metadata, 
          ControllerContext context)
    {
        ModelClientValidationRule rule = new ModelClientValidationRule();

        //specify a name for the custom validation
        rule.ValidationType = "sumintegers";

        //pass an error message to be used
        rule.ErrorMessage = FormatErrorMessage(metadata.GetDisplayName());

        //pass parameter(s) that need to be used when validating
        rule.ValidationParameters.Add("sum", _sum);

        yield return rule;
    }
}
To do this we need to add a reference to System.Web.Mvc namespace in the class file.

Below is the html generated from the ModelClientValidationRule properties set above.
<input type="text" value="" name="CSVInput" id="CSVInput" 
data-val-sumintegers-sum="20" 
data-val-sumintegers="custom error message for CSVInput" 
data-val="true" class="text-box single-line valid">
As we can see, the properties are put into data-val attributes. The attribute data-val-[validation_name] contains the error message, where [validation_name] is the ValidationType property's value we set above. Each passed parameter is put into data-val-[validation_name]-[parameter_name] attribute.


2. Write a jQuery validation adapter.
The adapter is used to retrieve the data-val attributes with their values and translate them into a format that jQuery validation can understand. So this adapter is helping us to easily implement our unobtrusive client side validation.

The adapter has several methods that we can use:
- addBool - creates an adapter for a validation rule that is 'on' or 'off', it requires no additional parameters
- addSingleVal- creates an adapter for a validation rule that needs to retrieve a single parameter value
- addMinMax - creates an adapter that maps to a set of validation rules, one that checks for a minimum value and the other checks for a maximum value
- add - used to create a custom adapter if we cannot use one of the methods above. We can use this if the adapter requires additional parameters or extra setup code.

In our case, addSingleVal is the best one to use.
// first parameter is the adapter name which should match with the value of ValidationType 
//    property of ModelClientValidationRule set on the server side
// second parameter is the parameter name added to ValidationParameters property of 
//    ModelClientValidationRule on the server side
$.validator.unobtrusive.adapters.addSingleVal("sumintegers", "sum");


3. Write the jQuery validator.
We do this through a method called addMethod that belongs to jQuery validator object.
// first parameter is the validator name which should match with the adapter name 
//    (which is also the same as the value of ValidationType)
// second parameter is the validation function to be invoked
$.validator.addMethod("sumintegers", 

  // the validation function's first parameter is the input value, second is the input element 
  //    and the third one is the validation parameter or an array of validation parameters passed
  function (inputValue, inputElement, sum) {

    var returnValue = true;
    if (inputValue) {
        var total = 0;

        try {
            $.each(inputValue.split(','), function () {
                total += parseInt(this);
            });
        }
        catch (err) {
            returnValue = false;
        }

        if (total != sum) {
            returnValue = false;
        }
    }
    return returnValue;

});

Say we put the scripts from step two and three in a single file called CustomScripts.js. Below is all the scripts that we have written:
/// <reference path="jquery-1.4.4.js" />
/// <reference path="jquery.validate.js" />
/// <reference path="jquery.validate.unobtrusive.js" />

if ($.validator && $.validator.unobtrusive) {

    $.validator.unobtrusive.adapters.addSingleVal("sumintegers", "sum");

    $.validator.addMethod("sumintegers", function (inputValue, inputElement, sum) {
        var returnValue = true;
        if (inputValue) {
            var total = 0;

            try {
                $.each(inputValue.split(','), function () {
                    total += parseInt(this);
                });
            }
            catch (err) {
                returnValue = false;
            }

            if (total != sum) {
                returnValue = false;
            }
        }
        return returnValue;
    });

}
The first three lines are references put to have IntelliSense works in our codes. Make sure the paths are correct.


4. Finally, include jquery.validate, jquery.validate.unobtrusive and our custom scripts files on the page to render.
<script src="@Url.Content("~/Scripts/jquery.validate.min.js")" type="text/javascript"></script>
<script src="@Url.Content("~/Scripts/jquery.validate.unobtrusive.min.js")" type="text/javascript"></script>
<script src="@Url.Content("~/Scripts/CustomScripts.js")"></script>


Tips: at the first time this validation will fire after the input lost focus but after that it will fire after each key press. This is the default behaviour of other built-in validators. If you are not happy with this and would like the validation to always fire only when the input lost focus then you need to add one of these scripts:
// if only for the specific input field
$(document).ready(function () {
    $("input#CSVInput").keyup(function () {
        return false;
    });
}

// or for all input fields
//    never put this inside document ready function
$.validator.setDefaults({
    onkeyup: false
})

Reference:
Professional ASP.NET MVC 3 - Jon Galloway, Phil Haack, Brad Wilson, K. Scott Allen

Friday, 16 March 2012

Server Side Custom Annotation Validation in ASP.NET MVC 3

On this post we will see an example of server side custom data annotation validation in ASP.NET MVC 3. I will write the client side one on my next post.

Let's say we would like to create a custom validation using data annotation to check the sum of a list of comma separated integers. If the sum is equal to the sum parameter supplied then the value is valid otherwise an error message will be displayed.

To begin, we need to create a class that derived from ValidationAttribute. This class is used by other built in validation annotations. We also need to add reference to System.ComponentModel.DataAnnotations namespace in our class file.

When implementing ValidationAttribute class, we need to override its IsValid method (line 12 and 13 of the codes below). This method has two parameters; the first one is the value to be validated and the second one provides more information about the field (context) where the value comes from. This method is where we put our validation logic.

Because we want to pass the sum amount to be checked against as a parameter, in other words we would like to use the validation attribute as something like [SumIntegers(20)], then we need to create a constructor accepting the parameter (line 6-10).

On line 27, we return a hard coded error message when an exception has occurred. We could also have a custom error message when using the validation attribute. We do this through ErrorMessage property of the ValidationAttribute. Say we would like to use our validation attribute as something like [SumIntegers(20, ErrorMessage="custom error message for {0}")]; to do this we call FormatErrorMessage method, pass the context display name to the method, then return the message as ValidationResult type (line 21-22).

We also provide a default error message (line 7), passing it to the base constructor. If we do not specify a default error message and somehow we forget to provide one on the validation attribute then the error message returned will be 'The field [fieldname] is invalid.'

Notice also that on the first line there are some attributes for the validation class. This is the default one used if we do not specify any. So in this case we may not need to specify it. To know more about System.AttributeUsage you can see http://msdn.microsoft.com/en-us/library/tw5zxet9%28v=VS.100%29.aspx

[System.AttributeUsage(System.AttributeTargets.All, AllowMultiple = false, Inherited = true)]
public class SumIntegers : ValidationAttribute
{
    private readonly int _sum;

    public SumIntegers(int sum)
        :base("The sum of integers of {0} are not equal to the one specified.")
    {
        _sum = sum;
    }

    protected override ValidationResult IsValid(
        object value, ValidationContext validationContext)
    {
        if (value != null)
        {
            try
            {
                if (value.ToString().Split(',').Select(n => int.Parse(n.Trim())).Sum() != _sum)
                {
                    var errorMessage = FormatErrorMessage(validationContext.DisplayName);
                    return new ValidationResult(errorMessage);
                }
            }
            catch (Exception ex)
            {
                return new ValidationResult("Input is not valid");
            }
        }

        return ValidationResult.Success;
    }
}

Finally, the usages:
[SumIntegers(50)]
public string CSVInput { get; set; }

[SumIntegers(20, ErrorMessage="custom error message for {0}")]
public string Numbers { get; set; }

Monday, 5 December 2011

Calling Controller Action Method with HTTP GET Ajax Request

In this post, we will see how to do Ajax request using HTTP GET method with JSON in ASP.NET MVC3. HTTP GET method to retrieve data in JSON format should never be used for getting sensitive information, the POST method should be used instead. For more information of how to use the POST method, you can read my previous post; Ajax with jQuery and JSON in ASP.NET MVC 3 or Passing Object in JSON to Controller.

First we prepare our controller method that will respond to the Ajax call:
public JsonResult GetDetailsUsingHttpGet(int id)
{
    Team team = teamRepository.Find(id);
    var anonymousTeam = new { TeamId = team.TeamId, Name = team.Name };

    //'JsonRequestBehavior.AllowGet' must be set, otherwise we will get an error message '500 error'
    return Json(anonymousTeam, JsonRequestBehavior.AllowGet);
}
Since MVC version 2, a controller method that is responding to a GET request is not allowed to return JSON format data for security reason. We need to explicitly state that this operation is allowed by setting 'JsonRequestBehavior.AllowGet' in the returning Json() method.

Then our JavaScript codes:
$(document).ready(function () {
    $("#ajaxBtnGetOne").click(function (event) {
        $.ajax({
            type: "GET",
            url: "/Teams/GetDetailsUsingHttpGet/1",
            contentType: "application/json; charset=utf-8",
            dataType: "json",
            success: AjaxGETSucceeded,
            error: AjaxFailed
        });
    });  
});
function AjaxGETSucceeded(objdata) {
    alert('success');
    alert(objdata.TeamId + ' - ' + objdata.Name);
    $('#ajaxDiv').html(objdata.TeamId + ' - ' + objdata.Name);
}
function AjaxFailed(result) {
    alert('an error has occured: ' + result.status + ' ' + result.statusText);
    alert(result.responseText);
}
Note that in the Ajax function we pass a parameter through its 'url' setting; in this example is '1' that will be passed as an 'id' parameter.

Monday, 28 November 2011

Passing Object in JSON to Controller

In this post, we will see how to pass object(s) in JSON from a jQuery Ajax function to a controller method in ASP.NET MVC 3. For more detailed explanation about the jQuery function and receiver controller method, you may want to see my previous post.

First we prepare our class which structure will be similar as the structure of the object(s) in JSON that is going to be passed. This class will also be the data type of the object(s) received by the receiver method through its parameter:
public class TeamViewModel
{
    public int TeamId { get; set; }
    public string Name { get; set; }
}

Then our JavaScript codes (jQuery version used at the time of writing is 1.5.1):
$(document).ready(function () { 
    //pass an object 
    $("#ajaxBtnPostTwo").click(function (event) {
        $.ajax({
            type: "POST",
            url: "/Teams/ProcessObjectUsingHttpPost",
            data: "{ 'TeamId':'10', 'Name':'TopTeam' }",
            contentType: "application/json; charset=utf-8",
            dataType: "json",
            success: ObjectWithAjaxSucceeded,
            error: AjaxFailed
        });
    });

    //pass a collection of objects
    $("#ajaxBtnPostThree").click(function (event) {
        var teamlist = [ { TeamId: 5, Name: 'Team Five'},
                            { TeamId: 6, Name: 'Team 6'},
                            { TeamId: 7, Name: 'Team seven'} ]

        $.ajax({
            type: "POST",
            url: "/Teams/ProcessListObjectsUsingHttpPost",
            data: JSON.stringify(teamlist),
            contentType: "application/json; charset=utf-8",
            dataType: "json",
            success: ObjectWithAjaxSucceeded,
            error: AjaxFailed
        });
    });
});

function ObjectWithAjaxSucceeded(data) {
    alert('success');
    //write content to a div
    $('#ajaxDiv').html(data);
}
function AjaxFailed(result) {
    alert('an error has occured: ' + result.status + ' ' + result.statusText);
    alert(result.responseText);
}
Note that the first ajax function is passing an object while the second one is passing a collection of objects. On the first method, the object is specified directly in the JSON string. While on the second method, JSON.stringify() method is used to convert the JavaScript objects into JSON string.

Finally, our controller methods:
[AcceptVerbsAttribute(HttpVerbs.Post)]
public JsonResult ProcessObjectUsingHttpPost(TeamViewModel team)
{
    return Json(String.Format("{0} -processed- <br/> {1} -processed-",
                            team.TeamId, team.Name));
}

[AcceptVerbsAttribute(HttpVerbs.Post)]
public JsonResult ProcessListObjectsUsingHttpPost(List<TeamViewModel> teams)
{
    StringBuilder sb = new StringBuilder();
    foreach (TeamViewModel team in teams)
    {
        sb.AppendFormat("{0} -processed- , {1} -processed <br />", team.TeamId, team.Name);
    }
    return Json(sb.ToString());
}
The first one receives a single object while the second one receives a collection of objects. The framework automatically serialize the JSON data into the data type (class) that we have specified above; ie. TeamViewModel.

On the next post we will see how to do Ajax call with HTTP GET method.

Monday, 21 November 2011

Ajax with jQuery and JSON in ASP.NET MVC 3

In this article, we'll see how to do Ajax request using HTTP POST method in ASP.NET MVC 3. The recent MVC framework allows this to be done easily.

First we prepare our html controls.
<input id="ajaxBtnPostOne" value="Ajax Button Post 1" param="1" type="button" />
<div id='ajaxDiv'></div>

Then the javascript codes. Make sure you have jQuery library in the application. In this article, I use jQuery 1.5.1.
$(document).ready(function () {
    $("#ajaxBtnPostOne").click(function (event) {
        $.ajax({
            type: "POST",
            url: "/Teams/GetDetailsUsingHttpPost", 
            data: "{ 'id':'" + $('#ajaxBtnPostOne').attr('param') + "'}",
            contentType: "application/json; charset=utf-8",
            dataType: "json",
            success: AjaxSucceeded,
            error: AjaxFailed
        });
    });
});

function AjaxSucceeded(data) {
    alert('success');
    //write content to a div
    $('#ajaxDiv').html(data);
}

function AjaxFailed(result) {
    alert('an error has occured: ' + result.status + ' ' + result.statusText);
    alert(result.responseText);
}
Note that we use jQuery function $.ajax() to bind to the 'on clicked' event of the html button we have above.
The settings on this method:
- type: we want use HTTP POST.
- url: this is the url where the Ajax call will be posted to. In this case is the location of the server side method 'GetDetailsUsingHttpPost' that we are going to create below.
- data: this is the data that will be passed to the method.
- dataType: we want to use JSON in this case.
- success: what to do when the Ajax call is returned successfully, in this case we execute a method.
- error: what to do if an error occurred, in this case we execute a method.

Then we have the server side receiver method. In MVC, we can simply use a controller method to handle an Ajax call. No extra configuration is needed.
[AcceptVerbsAttribute(HttpVerbs.Post)]
public JsonResult GetDetailsUsingHttpPost(int id)
{
    Team team = teamRepository.Find(id);
    return Json("Team Name = " + team.Name);
}
Note that '[AcceptVerbsAttribute(HttpVerbs.Post)]' attribute is used so that the method will only respond to a POST method. When Ajax call is used with JSON to query sensitive information, it is recommended to use POST method. Please see http://haacked.com/archive/2009/06/25/json-hijacking.aspx for more details.

Also notice that the method accept an integer parameter however the passed data is a string; the framework does the conversion automatically. Note that the variable name ('id') used in the 'data' setting of the javascript function is the same as the one accepted by the method.

To return JSON data, we just need to put the data to be returned inside Json() method and specify the controller method's return type as JsonResult.

Say now we want to return an object instead of a string. To do this, we can simply use an anonymous type or a class. If we choose to use a class then prepare our class, eg. TeamViewModel:
public class TeamViewModel
{
    public int TeamId { get; set; }
    public string Name { get; set; }
}
No extra configuration is needed to return an anonymous type or a class' object to the Ajax call. Here is our modified controller method:
/*modified to return an object instead of string data*/
[AcceptVerbsAttribute(HttpVerbs.Post)]
public JsonResult GetDetailsUsingHttpPost(int id)
{
    Team team = teamRepository.Find(id);
    TeamViewModel teamVM = new TeamViewModel();
    teamVM.TeamId = team.TeamId;
    teamVM.Name = team.Name;
    return Json(teamVM);

    // we could also have used an anonymous type instead
    //var anonymousTeam = new { TeamId = team.TeamId, Name = team.Name, City = "sydney" };
    //return Json(anonymousTeam);
}
We need to change the js function that is called when the Ajax call is successful:
function AjaxSucceeded(objdata) {
    alert('success');
    alert(objdata.TeamId + ' - ' + objdata.Name);
    $('#ajaxDiv').html(objdata.TeamId + ' - ' + objdata.Name);
}
Notice that the received object has similar structure as the returned object's type from the controller method; ie. it has 'TeamId' and 'Name' members. It also preserve the case sensitivity of the properties; if we use small case letters 'objdata.teamid' instead of 'objdata.TeamId', this will be rendered as 'undefined'.

On the next post, we will see how to pass object(s) in the Ajax function.