Showing posts with label AttributeUsage. Show all posts
Showing posts with label AttributeUsage. Show all posts

Friday, November 6, 2015

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 
{
..........
}

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: