In my
last article , one of the possible options for protection against editing model properties in Web applications written in ASP.NET MVC was considered. This article will be devoted to the consideration of one of the options for prohibiting the reading of certain properties of the model by specific user roles.
Task
Suppose there is a class ClientViewModel.
public class ClientViewModel { public int Id { get; set; } public string Name { get; set; } public string Inn { get; set; } }
After a specific instance of the ViewModel is received in the Action method, it is passed to the View as a parameter, with all its metadata. All fields of the model are displayed on the page.

')
But what if the value of the Inn field cannot be shown to some user roles? It is necessary to develop a mechanism that would allow declaratively indicate the roles for which it is forbidden to read certain properties.
Solution idea
At the moment of transferring the model to the view, intercept it, and if the user belongs to the role that is prohibited from reading, replace the property value with the corresponding message.
Decision
Create an attribute DenyReadRolesAttribute applied to the properties of the model. It will list the list of roles that are prohibited from reading.
[AttributeUsage(AttributeTargets.Property, AllowMultiple = false)] public class DenyReadRolesAttribute : Attribute, IMetadataAware { public string Roles { get; set; } public void OnMetadataCreated(ModelMetadata metadata) { if (Roles.Split(',').Any(IsUserInRole)) metadata.Model = metadata.SimpleDisplayText = " "; } private bool IsUserInRole(string roleName) { return HttpContext.Current != null && HttpContext.Current.User != null && HttpContext.Current.User.IsInRole(roleName); } }
The attribute must implement the IMetadataAware interface to be able to modify the model metadata. In the only method of the OnMetadataCreated interface, it is determined whether at least one of the user roles belongs to the list of prohibited ones. If there is one, then the value of the property, and its string representation are replaced with the text "Reading is prohibited."
In addition, it is necessary to prohibit the transfer of protected properties to the model from the Web form at the time of linking so that the message text or user-made changes do not fall back into the model. For this, the example described in the article “Prohibiting model properties editing in ASP.NET MVC” is suitable. You need to slightly change the BindProperty method in the CustomModelBinder class as follows:
public class CustomModelBinder : DefaultModelBinder { protected override void BindProperty(ControllerContext controllerContext, ModelBindingContext bindingContext, System.ComponentModel.PropertyDescriptor propertyDescriptor) { var d = propertyDescriptor.Attributes.OfType<DenyReadRolesAttribute>().FirstOrDefault(); if (d != null && d.Roles.Split(',').Any(r => controllerContext.HttpContext.User.IsInRole(r))) return; base.BindProperty(controllerContext, bindingContext, propertyDescriptor); } }
And set it as the default binder Global.asax.cs:
protected void Application_Start() { AreaRegistration.RegisterAllAreas(); ModelBinders.Binders.DefaultBinder = new CustomModelBinder(); RegisterGlobalFilters(GlobalFilters.Filters); RegisterRoutes(RouteTable.Routes); }
It now remains to mark with a new attribute fields ViewModel, which should be hidden, indicating in it a comma-separated list of roles that are prohibited from reading.
public class ClientViewModel { [DisplayName("")] public int Id { get; set; } [DisplayName("")] public string Name { get; set; } [DisplayName("")] [DenyReadRoles(Roles = "User")] public string Inn { get; set; } }
Result
Now, when working with data, a user who is prohibited from reading the Inn property in the corresponding fields of the view, be it a page for reading or a Web form for editing, will see the text “Reading is prohibited”. Changes made to them in the form for editing, will also be ignored.
