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

Friday, November 6, 2015

ASP.NET MVC - Customizing RequiredAttribute to display required field validation errors in a different format than the default one

Consider a scenario where you want all Required validators of your MVC application to display error messages in a different format than the default one.
As of ASP.NET MVC 5, the default error message format for required field validator is "The <<field display name>> field is required." For example, "The User name field is required." or "The Password field is required."

But instead, you want them to display in a different format, like - "Please enter value in <<field display name>>." Examples - "Please enter value in User name input box", or "Please enter value in Password input box".

One option is to set "ErrorMessage" property of Required data annotation for each and every fields where this validator is used. However, this can solve the purpose, but it will be tedious and importantly, maintenance nightmare to do so.

Perform following steps to customize default error message of Required validators, and apply them across the application.

Step - 1 Create following custom attribute (for instance, "CustomizedRequiredValidatorAdapter") inheriting from RequiredAttributeAdapter:

    public class CustomizedRequiredValidatorAdapter: RequiredAttributeAdapter
    {
        public CustomizedRequiredValidatorAdapter(ModelMetadata metadata,
                                    ControllerContext context,
                                    RequiredAttribute attribute)
            : base(metadata, context, attribute)
        {
            attribute.ErrorMessage = "Please enter value in {0}.";
        }
    }

This requires "System.Web.Mvc", and "System.ComponentModel.DataAnnotations" namespaces

Step - 2 Replace default RequiredAttribute validator by the one created in Step - 1

Add following in the Application_Start event of Global.asax.cs file:

DataAnnotationsModelValidatorProvider.RegisterAdapter(
                typeof(RequiredAttribute),
                typeof(CustomizedRequiredValidatorAdapter));

That's it! This is all you need to do. Now try running your MVC application and see the error messages on required validation failures and you should see the customized messages.

Further, if you have Globalization implemented, you can set attribute.ErrorMessageResourceType, and attribute.ErrorMessageResourceName in the custom attribute (step - 1) to get the string Error message string from resources file.

ASP.NET MVC >> Using enumerations in AuthorizeAttribute to allow the actions to be invoked by multiple roles

Consider a scenario where you need all/ some of the actions of a controller to be invoked by users having specific roles. For example, a "AdminController" which can be accessed only be users having "Admin" or "SuperUser" roles.

Now, its easy to pass multiple roles as a string in Authorize attribute as below:
[Authorize(Roles="Roles,SuperUser")]

However, this is an absolute maintenance nightmare, because if any of the roles are renamed you will need to remember to update at multiple places.

Imagine creating enum as below

    public enum Roles
    {
        User,
        Admin,
        SuperUser
    }

But as the Roles parameter in Authorize attribute is of string type, it wont allow you to pass multiple enum values there.

In order to fix this issue, we need to to create a new attribute inheriting from MVC's AuthorizeAttribute:

    [AttributeUsage(AttributeTargets.Method | AttributeTargets.Class, Inherited = true, AllowMultiple = true)]
    public class AuthorizeEnum: AuthorizeAttribute
    {
        public AuthorizeEnum(params object[] roles)
        {
            if (roles.Any(r => r.GetType().BaseType != typeof(Enum)))
                throw new ArgumentException("roles");

            this.Roles = string.Join(",", roles.Select(r => Enum.GetName(r.GetType(), r)));
        }
    }

Now, this attribute can be used to decorate the controllers and/ or actions to pass multiple roles as enum values instead of strings.

[AuthorizeEnum(Roles.User, Roles.Admin)]
public partial class AdminController 
{
..........
}

Thursday, July 17, 2014

MVC Attribute to restrict users to enter any kind of HTML tags in the input fields

By default, if a user tries to enter any HTML tags in any of the input boxes in an MVC website, it will throw an error saying "Potentially dangerous request".
This is OK, as it doesn't allow user to enter HTML tags and prevents the site from security threat.

However, the error page is not user friendly, and it is not giving a clue to the user as what was wrong there. So you may need to avoid default error page of browser, and instead your custom validation message should be displayed.

Also, there may be circumstances when you want to allow some fields to accept HTML tags (such as rich text boxes), and rest of the input fields shouldn't allow HTML. In that case, this approach will help.

In order to achieve this we need to create an attribute in MVC and then can decorate Model properties with that attribute.

Step 1
- Decorate HttpPost method with [ValidateInput(false)] 
Validate input is true by default, and that is why it prevents execution of any code in case if there is any HTML input values are detected in posted data.
Here, we need to set it to false" as we would like to execute code of our custom attribute       

[HttpPost]
[ValidateAntiForgeryToken]
[ValidateInput(false)]
public virtual ActionResult CreateCustomer(Customer viewModel)
{
......
}


Step 2
- Create custom attribute as below:

using System.ComponentModel.DataAnnotations;
using System.Web.Mvc;
using System.Text.RegularExpressions;
public class DenyHtmlInputAttribute: ValidationAttribute
{


protected override ValidationResult IsValid(object value, ValidationContext validationContext)
{
if (value == null)
return ValidationResult.Success;


var tagWithoutClosingRegex = new Regex(@"<[^>]+>");


var hasTags = tagWithoutClosingRegex.IsMatch(value.ToString());


if (!hasTags)
return ValidationResult.Success;

return new ValidationResult(String.Format("{0} cannot contain html tags", validationContext.DisplayName));
}


}
Step 3 
- Decorate all input fields of your Model with the attribute created above:
[DenyHtmlInput]
public string Comments { get; set; }
That's it.

This is how you can restrict Html inputs on specific fields of your MVC view.

Monday, March 31, 2014

Error 403, 403.14, 404 - After deploying ASP.NET MVC website on IIS 7, IIS 7.5

After deploying your ASP.NET MVC website on IIS 7 or IIS 7.5, you might face following errors while browsing your website:

  • 403.14 - Forbidden (The Web server is configured to not list the contents of this directory.)
  • 404 - Not Found (The resource you are looking for has been removed, had its name changed, or is temporarily unavailable)

Following are the possible causes/ fixes for this -
  • Make sure the Application pool targets correct version of .NET framework (i.e .NET Framework v4.0.30319 for .NET 4 and 4.5)
  • Make sure the Pipeline mode of IIS Application pool is "Integrated"
  • Check UrlRoutingModule-4.0 is added in the modules of that website.
  • (To do that, open list of added modules by clicking "Modules" against your website, and see if the module "UrlRoutingModule-4.0" is added or not). If not, then add a module by clicking "Add Managed Module" button, where select System.Web.Routing.UrlRoutingModule as a Module type, and give "UrlRoutingModule-4.0" as its name)
  • Make sure you have following element added in system.webServer section of website's web.config
<system.webServer>
<modules runAllManagedModulesForAllRequests="true"></modules> 
</system.webServer>

In most cases of 403.14, or 404 error, above are the possible causes and fixes. 

Tuesday, March 25, 2014

FIX: 'Model' conflicts with the declaration 'System.Web.Mvc.WebViewPage.Model'

I suddenly started receiving this error in one of my razor view. The error message was -
'Model' conflicts with the declaration 'System.Web.Mvc.WebViewPage<TModel>.Model'

This error is caused if you use "Model" instead of "model" in one or more lambda expressions (predicates) in your view.

Perform a case-sensitive search for "Model =>", and its very much possible that you may notice this in one or more lambda expressions,
For example,
@Html.EditorFor(Model => Model.BirthDate)
This should be actually, @Html.EditorFor(model => model.BirthDate)
Correcting this should fix the Model conflict error for you in your view.

Thursday, December 20, 2012

@Html.ActionLink to call action in different controller

@Html.ActionLink has many overloads (at least 17), and so sometimes it becomes confusing if the operation is not so straight-foward. 

For example, if you want to execute an Action of different controller, you must take care to use it like following:

@Html.ActionLink("Link Text", "MyAction", "MyController", new {id = item.ID}, null)
 

Its important to pass the last parameter (which is, "hostname"),
eventhough if you pass it as "null". Doing this will take up proper overload and will call the action from different controller.


Wednesday, November 21, 2012

Investigations: How to identify current path in referenced library in MVC application?


Following is the exact scenario in my application:

1) MVC application is referencing one DLL (a Class library project).
2) some code in the class library need to access folders and files from the MVC application.
Say, there is one folder named as "Templates" in root of my MVC application.
How should I able to get the path of that folder in context of execution path from any method of the class library.
If I try "~\templates" or "\templates", it looks for folder in C:\Program Files\... instead of the websites folder.
If I try "templates", it looks for folder in C:\ only.
any idea of how to achieve this


Monday, October 22, 2012

FIX: IE Document Mode changes to IE 7 while opening a remotely hosted ASP.NET (or MVC) website in Internet Explorer 8

A recent issue I faced while I deployed my ASP.NET MVC application on production server.

I hosted my MVC application on a web server having IIS 7.
While I tried to access that website on the server itself using "localhost" in URL within IE 8 browser, it was getting displayed perfectly. But when I tried to access it remotely in IE 8 browser, the layout got disturbed, and it was appearing too messy.

I did a lot of investigations, and could found this is because by default browser was opening the website under "IE 7" document mode.



In order to prevent this, I did following changes <system.webServer> section in web.config file of my application, and that successfully resolved this issue:

<system.webServer>
    <httpProtocol>
      <customHeaders>
        <clear />
        <add name="X-UA-Compatible" value="IE=edge" />
      </customHeaders>
    </httpProtocol>
  </system.webServer>

Sunday, September 30, 2012

Multiple Checkboxes in MVC 3, and Post selection to Controller Action

This article aims to explain - how to provide a multiple selection checkboxes in MVC 3 application, and the way to fetch the selection in an HttpPost contrller action.

Scenario:
A UI should have checkbox for each weekday (Mon to Sun), and when user submits the form, an HttpPost action should be able to fetch selected Weekdays by user.

We will create an Editor Template for this.
Please note this example is in C#.Net and Razor view, but you should easily be able to convert it in VB.Net and ASPX page if your application demands.

Step - 1: Create a Model (i.e. Type)

namespace MyMVC.Models
{
    public class WeekDaySelectionModel
    {
        public string WeekdDayName { get; set; }
        public bool Selected { get; set; }
    }
}

Step - 2: Create a collection of weekday names in your HttpGet action calling your view:

using System.Collections.Generic;
using MyMVC.Models;
[HttpGet]
public ActionResult EditEntry()
        {
            List<WeekDaySelectionModel> _weekDaySelection = new List<WeekDaySelectionModel>();
            _weekDaySelection.Add(new WeekDaySelectionModel { WeekdDayName = "Mon"});
            _weekDaySelection.Add(new WeekDaySelectionModel { WeekdDayName = "Tue"});
            _weekDaySelection.Add(new WeekDaySelectionModel { WeekdDayName = "Wed"});
            _weekDaySelection.Add(new WeekDaySelectionModel { WeekdDayName = "Thu"});
            _weekDaySelection.Add(new WeekDaySelectionModel { WeekdDayName = "Fri"});
            _weekDaySelection.Add(new WeekDaySelectionModel { WeekdDayName = "Sat"});
            _weekDaySelection.Add(new WeekDaySelectionModel { WeekdDayName = "Sun"});

return View("EditEntry", _weekDaySelection);              
}


Step - 3: Create an Editor Template in "..\Views\Shared\EditorTemplates" folder.

File name: WeekDaySelectionModel.cshtml (Make sure the file name is matching with the type name we created in Step 1).

@model MyMVC.Models.WeekDaySelectionModel
<span>
    @Html.HiddenFor(m => m.WeekdDayName)
    @Html.CheckBoxFor(m => m.Selected)
    @Html.LabelFor(m => m.Selected, Model.WeekdDayName)
</span>

Step - 4: Integrate this editor in your view.

File Name: EditEntry.cshtml

@model System.Collections.Generic.List<MyMVC.Models.WeekDaySelectionModel>
@for (int i = 0; i <= Model.SelectedWeekDays.Count - 1; i++)
{
    @Html.EditorFor(m => m.SelectedWeekDays[i])
}

Step - 5: Catching the selection in HttpPost controller action.

When user submits the pages, an HttpPost controller action will automatically receive the model having "Selected" property updated against each weekday name.

[HttpPost]
        public ActionResult EditEntry(System.Collections.Generic.List<WeekDaySelectionModel> _weekDayNames)
        {
            string selectedWeekDayNames = String.Empty;
            for (int i = 0; i <= _weekDayNames.Count - 1; i++)
            {
                if (_weekDayNames[i].Selected == true)
                {
                    if (String.IsNullOrEmpty(selectedWeekDayNames) == false)
                        selectedWeekDayNames += ",";
                    selectedWeekDayNames += _weekDayNames[i].WeekdDayName;
                }
            }
        }


Saturday, September 8, 2012

Disable Caching for a Controller Action in ASP.NET MVC

At times, we need to disable the caching for some controller actions in our MVC application.
Say for example, there is an "Add Entry" link on your view, and it has a controller action assigned to it.
Clicking on this "Add Entry" link should call an action, and that will eventually load an Entry fill-up screen/ dialog.
Now when user clicks it for the first time it will call the controller action fine. But for next consecutive clicks, it may or may not call controller action and due to which the target dialog/ entry screen will remain prefilled with old data.
This is because of caching. Under some circumstances, browser caches controller actions, and that is why the cached operation is performed rather than the controller action.

To deal with this problem, we need to disable caching of those controller actions. (Its always recommended to disable caching of controller actions that invoke Add/ Edit of entry).

Following is the walkthrough to achieve the same:

1. Create an action filter. To do that create a new class inherited  ActionFilterAttribute class.

public
class NoCache : ActionFilterAttribute
{
   
public override void OnResultExecuting(ResultExecutingContext filterContext)
   
{
        filterContext
.HttpContext.Response.Cache.SetExpires(DateTime.UtcNow.AddDays(-1));
        filterContext
.HttpContext.Response.Cache.SetValidUntilExpires(false);
        filterContext
.HttpContext.Response.Cache.SetRevalidation(HttpCacheRevalidation.AllCaches);
        filterContext
.HttpContext.Response.Cache.SetCacheability(HttpCacheability.NoCache);
        filterContext
.HttpContext.Response.Cache.SetNoStore();

       
base.OnResultExecuting(filterContext);
   
}
}

2. Decorate your controller action with the action filter class.

[NoCache]
public ActionResult EditEntry(int entryId)
{
..... the controller action code.}

This is what we need to do to disable caching of controller action in ASP.NET  MVC.

Wednesday, May 30, 2012

HTML Helper for Action image in MVC (that is, img tag with anchor tag within)

This article aims to explain how can we create and use HTML helper method for IMG html tag, to display an image, and to call a controller action while user clicks over it.

Walkthrough:

Step 1: Create new folder in your MVC structure.



Step 2: Add a new class file "MyHelper.cs" in that folder, and create a "static" class within:
namespace MVC.Infrastructure
{
    public static class MyHelpers
.....

Step 3: Import System, and System.Web.Mvc namespaces in that class.
using System;
using System.Web.Mvc;

Step 4: Write following helper method in MyHelper.cs class.

public static MvcHtmlString ActionImage(this HtmlHelper html, string imagePath, string alt, string cssClass,
            string action, string controllerName,object routeValues)
        {
            var currentUrl = new UrlHelper(html.ViewContext.RequestContext);
            var imgTagBuilder = new TagBuilder("img"); // build the <img> tag
            imgTagBuilder.MergeAttribute("src", currentUrl.Content(imagePath));
            imgTagBuilder.MergeAttribute("alt", alt);
            imgTagBuilder.MergeAttribute("class", cssClass);
            string imgHtml = imgTagBuilder.ToString(TagRenderMode.SelfClosing);
            var anchorTagBuilder = new TagBuilder("a"); // build the <a> tag
            anchorTagBuilder.MergeAttribute("href", currentUrl.Action(action, controllerName, routeValues));
            anchorTagBuilder.InnerHtml = imgHtml; // include the <img> tag inside
            string anchorHtml = anchorTagBuilder.ToString(TagRenderMode.Normal);
            return MvcHtmlString.Create(anchorHtml);
        }

Step 5: Open your razor/ aspx view. Import namespace of above class in your view. (This example deals with razor syntax, but it will be easy for you to convert into aspx, if you are using aspx engine).

@using MVC.Infrastructure

Step 6: Use the created HTML helper to show Image in view, and to call controller action when user clicks it.

@Html.ActionImage("../../Images/logo.png", "Site Logo", "siteLogo", "About", "Home", null)
Here, "Home" is a controller name, and "About" is an action, and it does not have any routeValues so passed as null.

This is all we need to do.
Following is the HTML generated by using this HTML helper:
<a href="/Home/About"><img alt="Site Logo" class="siteLogo" src="../../Images/logo.png" /></a>

You can take advantage of this HTML helper in any view within your MVC application and it will generate HTML image and anchor tags every time for you!

Tuesday, May 1, 2012

Access Membership Configurations in ASP.NET MVC Views

We define membership configurations through membership provider settings in Web.config file in an MVC application.

For example:
<membership defaultProvider="CustomMembershipProvider">
      <providers>
        <add name="CustomMembershipProvider" type="System.Web.Providers.DefaultMembershipProvider, System.Web.Providers, Version=1.0.0.0, Culture=neutral, PublicKeyToken=31bf3856ad364e35" connectionStringName="DefaultConnection" enablePasswordRetrieval="false" enablePasswordReset="true" requiresQuestionAndAnswer="false" requiresUniqueEmail="false" maxInvalidPasswordAttempts="5" minRequiredPasswordLength="6" minRequiredNonalphanumericCharacters="0" passwordAttemptWindow="10" applicationName="MyApp" />
      </providers>
    </membership>

At times, you need to access these settings in your view in order to enforce some validation/ to display them on screen.
Its quite straight-forward to do. You can access them using @Membership object in your razor-view.
For example,

Application Name:<span>@Membership.ApplicationName</span>

will print - Application Name: MyApp in your view.

Similarly, you can access any of the configurations you have defined for Membership.

Monday, April 30, 2012

Membership in ASP.NET MVC 4 (System.Web.Providers)

ASP.NET MVC 4 came with many changes from MVC 3, and one of them was the way membership was implemented.
Membership and profiles tables in MVC 4 are reduced to a few, and they appear to be quite clean. Names like "Memberships, Profiles, Applications, Roles, etc" are for quick to identify their purpose.
Also their structure is quite simplified.

ASP.NET MVC 4 membership uses Entity Framework as its ORM.

When you create a new MVC 4 website project (as Internet application), it gets created with controller, models, and views for Logon, Registration, and all other membership functionality. By default, connectionstring is set to a local SQL Express database (as it used to be in earlier versions).

If you create an empty MVC 4 website project, you will not be able to see any of these (as you only opted it!), but still you can use MVC 4's membership features by using "System.Web.Providers" library.
Make sure, its added as a reference in your solution. (it is there in most cases).
But If not, you can add it using NuGet package manager.
For that, Go to following command in Visual Studio menu.
Tools >> Library Package Manager >> Package Manager Console
This will open up command shell at the bottom. Type in following command and press enter, and this will do all necessary changes in your project and configurations

install-package "System.Web.Providers"

Once done, go to web.config, and configure a connectionstring named "DefaultConnection" to use your remote connection (instead of default SQL Express database).
But make sure your connectionstring includes "MultipleActiveResultSets=True" configuration, otherwise it will give you an error related to "Entity framework" while performing any membership operations.

Sample DataSource settings in connectionstring:
Data Source=myPC;Initial Catalog=myTestDB;Persist Security Info=True;User ID=nirman;Password=nothing*001;MultipleActiveResultSets=True;

Once done, your application is set for membership.
And as you run your MVC application for the first time, and attempts to register a new user, it automatically will create membership tables in SQL Server database. ASP.NET MVC 4 does not use Stored Procs, etc in background for Membership, as it has used EF as its ORM. So you will see only tables got created in database. Less complicated and easily manageable, isn't it!

Wednesday, April 25, 2012

Binding two or more types of objects (models) to single view in ASP.NET MVC

This article aims to explain how we can bind two or more different types of objects to single view in ASP.NET MVC application. (Please note, the code snippets are in razor view engine, but I know its not as such difficult for you to comprehend them in ASPX engine :))

As we know, its straight-forward bind a single type of object (or collection) to a view and we can pass it from Controller action to the View.
I mean, if your need to bind a View to an object of PersonEntity type(or its collection), you can bind, pass, and post it like below:

Binding in View: 
@model MVCTutorialApp.Models.PersonEntity

Passing it from controller action:
public ActionResult PersonEdit()
{
..................
return View("EditPerson", _person);
}

HttpPost action in your controller:

        [HttpPost]

        public ActionResult PersonEdit(PersonEntity  _person)

But sometimes we need to pass multiple different types of objects to a single view.
Say, for example, you have two different types "PersonEntity", and "ContactEntity", and you need to bind them to a single view.

There are various ways to achieve them:
But two of the most ideal approaches are Wrapper class, and System.Tuple

Approach A: Wrapper class
Create a class that can hold instance of both "PersonEntity" and "ContactEntity".
Like, 
public class PersonContactEntity
    {
        public PersonContactEntity()
        {
        }

        public PersonEntity Person { get; set; }
        public ContactEntity Contact { get; set; }
    }

Now in your corresponding action of controller -
Create an instance of the class "PersonContactEntity".
Assign "Person" and "Contact" properties with the their respective instances.
Pass instance of "PersonContactEntity" to the view. 
public ActionResult PersonContactEdit()
{
PersonContactEntity personContact = new PersonContactEntity();
..................
personContact.Person = person object;
PersonContact.Contact = contact object;
return View("EditPersonContact",  PersonContact );
}


Create your view as strongly typed view by adding following line at top:
@model MVCTutorialApp.Models.PersonContactEntity

Once done, when you write @Model followed by dot (.) the intellisense will show you "Person" and "Contact" both, and you can  now bind your controls, or use them in your view.
Example:

@Html.TextBoxFor(m => m.Person.FullName)
Also, @Model.Contact.Email

And, also corresponding HttpPost method (controller action) can also accept PersonContactEntity when a view post data to controller action:
        [HttpPost]
        public ActionResult PersonEdit(PersonContactEntity   _personContact)

Approach B: System.Tuple
A tuple is a data structure that has a specific number and sequence of elements (Ref: MSDN)
Please visit following MSDN link to know more about tuples

Please note that, Tuple in our scenario should only be used if you do not need to do Post data from View to controller action. As tuple does not have a default constructor, it cannot be used as a parameter in HttpPost method, or you may need to find a workaround to make it possible (instead, Wrapper class (approach A) would be an easy to implement).

Coming back to using System.Tuple in our scenario:
Your controller action launching a view should be like:
public ActionResult PersonContactEdit()
{
..................
System.Tuple<PersonEntity, ContactEntity> personContactEntity = Tuple.Create(person object, contact object);
return View("EditPersonContact",   personContactEntity );
}

Create your view as strongly typed view by adding following line at top:
@model System.Tuple<LearnMVC4.Models.PersonEntity, LearnMVC4.Models.ContactEntity>

Once done, when you write @Model followed by dot (.) the intellisense will show you "Item1" and "Item2" both. Item1 corresponds to first type in tuple which is "PersonEntity", and Item2 corresponds to second type which is "ContactEntity". And you can now bind your controls, or use them in your view.
Example:

@Html.LabelFor(m => m.Item1.FullName)
Also, @Model.Item2.Email

So this is how we can pass different types of objects to single view, and can bind them.

Saturday, April 21, 2012

Implement Custom Validation in ASP.NET MVC

This article aims to explain how we can implement Custom validation (server-side) in ASP.NET MVC.

System.ComponentModel.DataAnnotations namespace provides set of predefined validations which are common in almost all scenarios (like, Required, Range, Regular Expression, etc). Click here for more information.

This namespace contains "ValidationAttribute" class which is a base class for all validation attributes.
Following are the steps to be performed in order to implement a custom validation.
1. Inherit a new validation class from ValidationAttribute base class. (A new class can be created anywhere but should have System.Component.DataAnnotations referenced.)
2. Override "IsValid" method and write our own validation. (Here, we can get the value entered by user for the corresponding field/ property, so we can validate it).
3. Apply new attribute on the field/ property of a model wherever you need that custom validation to fire.

Sample Code:
In our "Person" model, we have a "BirthDate" field. We now want to validate if the Age of a person must be 18  or above.
1. A class inherited from ValidationAttribute, and overriding of IsValid method within:



[AttributeUsage(AttributeTargets.Field | AttributeTargets.Property, AllowMultiple = false, Inherited = true)]
    public class BirthDateValidation : ValidationAttribute
    {
        public override bool IsValid(object value)
        {
            if (Convert.ToDateTime(value) >= DateTime.Now.AddYears(-18))
            {
                return false;
            }
            return true;
        }
    }


2. Applying "BirthDateValidation" attribute on Birthdate property.


[Display(Name="Birth Date")]
        [BirthDateValidation(ErrorMessage="Registration is only allowed for people above 18 years.")]
        public DateTime BirthDate { get; set; }


3. Last thing, as it is a server-side validation (just like, Required, Range, etc), dont forget to relaunch the view from corresponding HttpPost action in your controller, in case if ModelState.IsValid is False. (indicating, a validation failed)

[HttpPost] 
       public ActionResult PersonEdit(Person person)
        {
            if (ModelState.IsValid == false)
            {
                return View("PersonEdit",  person);
            }
            else
            {
             //Write code to define actions on success
            }            
        }


That's all we need to implement this validation:

Screenshot:


Simple client-side Validations using ASP.NET MVC

This article aims to demonstrate how we can apply simple validations at view (page) level in ASP.NET MVC.

Say, you have a "Person" model, that you pass in the view to and fro controller action.

A Person model is having many fields, one of them is "PersonName" (Label: Person Name) and you want to make it required when user inputs data in corresponding view of this model.

In order to achieve this, first decorate PersonName field in Person model with "Required" attribute.
"Required" attribute is a part of System.ComponentModel.DataAnnotations namespace. So this must be imported in your model (using System.ComponentModel.DataAnnotations)

System.ComponentModel.DataAnnotations contain various attributes that can be applied on a model field. Along with that it has all necessary validators (like, Required, Range, MaxLength, MinLength, Regular Expression, Custom validator, etc).

For our case, we should write - 

[Required(ErrorMessage="Please Enter Person Name!")]
[Display(Name="Person Name")]
public string PersonName { get; set; }

This will automatically handle required validation for Person Name field input.
Now, in the view (.aspx, or .cshtml), we need to put ValidationSummary in order to display error message in case validation fails.
@Html.ValidationSummary(false, "Please correct following errors and try again!")

The last thing is to add a condition in HttpPost method to relaunch the view with latest inputs and error messages, in case if validation(s) fail.

[HttpPost]
        public ActionResult PersonEdit(Person person)
        {
            if (ModelState.IsValid == false)
            {
                return View("PersonEdit",  person);
            }
            else
            {
             //Write code to define actions on success
            }            
        }

Now, when the view is launched with person model, it will have same inputs as well as validation errors, so that they will get displayed in ValidationSummary control in view to let users know about the errors.

NOTE: Also, remember to put @Html.ValidationSummary control before @Html.BeginForm block, otherwise it will always show you validation messages even before HttpPost.

Thursday, April 19, 2012

Investigation: Values do not retain in model while posting it from view to controller action in MVC

Scenario: My controller action is passing a model to the view, and displaying the fields on my view.
There are few fields which are non-editable (like, ID, etc), and are only for display purpose, so I have placed them directly on view.
There are few fields in that model which are not required to be displayed at all on view, so I have not placed them on view.
The problem is that, when a user clicks Submit to post the view to controller action, the model does not contain their original value for those fields.
How to fix it?

Fix: When you bind a model by passing it from control action to view, you should bind each and every field of the model in view. This will retain their values during HttpPost.

So if there are some fields you want to display them as read-only, or if you do not want to display them at all, then you should still bind them within view. Its necessary if you are posting the view to a controller action (using HttpPost)

The best way is to use hidden tag, using @Html.HiddenFor helper, if you do not want to display the field.
Or use @Html.DisplayFor helper, if you want to display the field in read-only mode.

Data Binding to RadioButton in a View in MVC

This article is to provide information for how to do a data binding of a RadioButton (or group of them) in the View.

For example, you have Gender field in your model with two obvious options - Male, and Female.

What we really want to achieve is -
a. when a controller action invokes a view (with its model), it should correctly select the appropriate radio button from underlying model,
b. when a user changes the selection of radio button it should correctly update underlying model.

This is for what binding is needed.
For controls, such as TextBox, Label, etc, binding is quite straightforward using TextBoxFor, LabelFor, etc helpers.
But for controls such as RadioButton, CheckBox, etc, it's little bit different as below:

The below example is using RazorView engine.

@Html.RadioButtonFor(m => m.Gender, "Male", Model.Gender == "Male" ? new { Checked = "checked"} : null )
Male


@Html.RadioButtonFor(m => m.Gender, "Female", Model.Gender == "Female" ? new { Checked = "checked"} : null )
Female

Here, Checked is an HtmlAttribute for Checked state of RadioButton/ CheckBox
@Html.RadioButtonFor will show only RadioButton without its label, and for that purpose we have written Male, and Female after each Helpers.