I've got a view model like this:
public class SignUpViewModel
{
[Required(ErrorMessage = "Bitte lesen und akzeptieren Sie die AGB.")]
[DisplayName("Ich habe die AGB gelesen und akzeptiere diese.")]
public bool AgreesWithTerms { get; set; }
}
The view markup code:
<%= Html.CheckBoxFor(m => m.AgreesWithTerms) %>
<%= Html.LabelFor(m => m.AgreesWithTerms)%>
The result:
No validation is executed. That's okay so far because bool is a value type and never null. But even if I make AgreesWithTerms nullable it won't work because the compiler shouts
"Templates can be used only with field access, property access, single-dimension array index, or single-parameter custom indexer expressions."
So, what's the correct way to handle this?
My Solution is as follows (it's not much different to the answers already submitted, but I believe it's named better):
/// <summary>
/// Validation attribute that demands that a boolean value must be true.
/// </summary>
[AttributeUsage(AttributeTargets.Property, AllowMultiple = false, Inherited = false)]
public class MustBeTrueAttribute : ValidationAttribute
{
public override bool IsValid(object value)
{
return value != null && value is bool && (bool)value;
}
}
Then you can use it like this in your model:
[MustBeTrue(ErrorMessage = "You must accept the terms and conditions")]
[DisplayName("Accept terms and conditions")]
public bool AcceptsTerms { get; set; }
I would create a validator for both Server AND Client side. Using MVC and unobtrusive form validation, this can be achieved simply by doing the following:
Firstly, create a class in your project to perform the server side validation like so:
public class EnforceTrueAttribute : ValidationAttribute, IClientValidatable
{
public override bool IsValid(object value)
{
if (value == null) return false;
if (value.GetType() != typeof(bool)) throw new InvalidOperationException("can only be used on boolean properties.");
return (bool)value == true;
}
public override string FormatErrorMessage(string name)
{
return "The " + name + " field must be checked in order to continue.";
}
public IEnumerable<ModelClientValidationRule> GetClientValidationRules(ModelMetadata metadata, ControllerContext context)
{
yield return new ModelClientValidationRule
{
ErrorMessage = String.IsNullOrEmpty(ErrorMessage) ? FormatErrorMessage(metadata.DisplayName) : ErrorMessage,
ValidationType = "enforcetrue"
};
}
}
Following this, annotate the appropriate property in your model:
[EnforceTrue(ErrorMessage=#"Error Message")]
public bool ThisMustBeTrue{ get; set; }
And Finally, enable client side validation by adding the following script to your View:
<script type="text/javascript">
jQuery.validator.addMethod("enforcetrue", function (value, element, param) {
return element.checked;
});
jQuery.validator.unobtrusive.adapters.addBool("enforcetrue");
</script>
Note: We already created a method GetClientValidationRules which pushes our annotation to the view from our model.
I got it by creating a custom attribute:
public class BooleanRequiredAttribute : RequiredAttribute
{
public override bool IsValid(object value)
{
return value != null && (bool) value;
}
}
This might be a "hack" but you can use the built in Range attribute:
[Display(Name = "Accepted Terms Of Service")]
[Range(typeof(bool), "true", "true")]
public bool Terms { get; set; }
The only problem is the "warning" string will say "The FIELDNAME must be between True and true".
[Compare("Remember", ErrorMessage = "You must accept the terms and conditions")]
public bool Remember { get; set; }
I'm just taking the best of the existing solutions and putting it together into a single answer that allows for both server side and client side validation.
The to apply to model a properties to ensure a bool value must be true:
/// <summary>
/// Validation attribute that demands that a <see cref="bool"/> value must be true.
/// </summary>
/// <remarks>Thank you <c>http://stackoverflow.com/a/22511718</c></remarks>
[AttributeUsage(AttributeTargets.Property, AllowMultiple = false, Inherited = false)]
public class MustBeTrueAttribute : ValidationAttribute, IClientValidatable
{
/// <summary>
/// Initializes a new instance of the <see cref="MustBeTrueAttribute" /> class.
/// </summary>
public MustBeTrueAttribute()
: base(() => "The field {0} must be checked.")
{
}
/// <summary>
/// Checks to see if the given object in <paramref name="value"/> is <c>true</c>.
/// </summary>
/// <param name="value">The value to check.</param>
/// <returns><c>true</c> if the object is a <see cref="bool"/> and <c>true</c>; otherwise <c>false</c>.</returns>
public override bool IsValid(object value)
{
return (value as bool?).GetValueOrDefault();
}
/// <summary>
/// Returns client validation rules for <see cref="bool"/> values that must be true.
/// </summary>
/// <param name="metadata">The model metadata.</param>
/// <param name="context">The controller context.</param>
/// <returns>The client validation rules for this validator.</returns>
public IEnumerable<ModelClientValidationRule> GetClientValidationRules(ModelMetadata metadata, ControllerContext context)
{
if (metadata == null)
throw new ArgumentNullException("metadata");
if (context == null)
throw new ArgumentNullException("context");
yield return new ModelClientValidationRule
{
ErrorMessage = FormatErrorMessage(metadata.DisplayName),
ValidationType = "mustbetrue",
};
}
}
The JavaScript to include to make use of unobtrusive validation.
jQuery.validator.addMethod("mustbetrue", function (value, element) {
return element.checked;
});
jQuery.validator.unobtrusive.adapters.addBool("mustbetrue");
"Required" is the wrong validation, here. You want something akin to "Must have the value true," which is not the same as "Required". What about using something like:
[RegularExpression("^true")]
?
My solution is this simple custom attribute for boolean values:
public class BooleanAttribute : ValidationAttribute
{
public bool Value
{
get;
set;
}
public override bool IsValid(object value)
{
return value != null && value is bool && (bool)value == Value;
}
}
Then you can use it like this in your model:
[Required]
[Boolean(Value = true, ErrorMessage = "You must accept the terms and conditions")]
[DisplayName("Accept terms and conditions")]
public bool AcceptsTerms { get; set; }
For people who are having trouble getting this working for validation on the client side (formerly me): make sure you have also
Included <% Html.EnableClientValidation(); %> before the form in the view
Used <%= Html.ValidationMessage or Html.ValidationMessageFor for the field
Created a DataAnnotationsModelValidator which returns a rule with a custom validation type
Registered the class deriving from DataAnnotationsModelValidator in the Global.Application_Start
http://www.highoncoding.com/Articles/729_Creating_Custom_Client_Side_Validation_in_ASP_NET_MVC_2_0.aspx
is a good tutorial on doing this, but misses step 4.
The proper way to do this is to check the type!
[Range(typeof(bool), "true", "true", ErrorMessage = "You must or else!")]
public bool AgreesWithTerms { get; set; }
Found a more complete solution here (both server and client side validation):
http://blog.degree.no/2012/03/validation-of-required-checkbox-in-asp-net-mvc/#comments
It's enough to add [RegularExpression]:
[DisplayName("I accept terms and conditions")]
[RegularExpression("True", ErrorMessage = "You must accept the terms and conditions")]
public bool AgreesWithTerms { get; set; }
Note - "True" must start with capital T
Related
I have developed a custom validator Attribute class for checking Integer values in my model classes. But the problem is this class is not working. I have debugged my code but the breakpoint is not hit during debugging the code. Here is my code:
public class ValidateIntegerValueAttribute : ValidationAttribute
{
protected override ValidationResult IsValid(object value, ValidationContext validationContext)
{
if (value != null)
{
int output;
var isInteger = int.TryParse(value.ToString(), out output);
if (!isInteger)
{
return new ValidationResult("Must be a Integer number");
}
}
return ValidationResult.Success;
}
}
I have also an Filter class for model validation globally in application request pipeline. Here is my code:
public class MyModelValidatorFilter: IActionFilter
{
public void OnActionExecuting(ActionExecutingContext context)
{
if (context.ModelState.IsValid)
return;
var errors = new Dictionary<string, string[]>();
foreach (var err in actionContext.ModelState)
{
var itemErrors = new List<string>();
foreach (var error in err.Value.Errors){
itemErrors.Add(error.Exception.Message);
}
errors.Add(err.Key, itemErrors.ToArray());
}
actionContext.Result = new OkObjectResult(new MyResponse
{
Errors = errors
});
}
}
The model class with validation is below:
public class MyModelClass
{
[ValidateIntegerValue(ErrorMessage = "{0} must be a Integer Value")]
[Required(ErrorMessage = "{0} is required")]
public int Level { get; set; }
}
Can anyone please let me know why the attribute integer validation class is not working.
Model validation comes into play after the model is deserialized from the request. If the model contains integer field Level and you send value that could not be deserialized as integer (e.g. "abc"), then model will not be even deserialized. As result, validation attribute will also not be called - there is just no model for validation.
Taking this, there is no much sense in implementing such ValidateIntegerValueAttribute. Such validation is already performed by deserializer, JSON.Net in this case. You could verify this by checking model state in controller action. ModelState.IsValid will be set to false and ModelState errors bag will contain following error:
Newtonsoft.Json.JsonReaderException: Could not convert string to
integer: abc. Path 'Level', ...
One more thing to add: for correct work of Required validation attribute, you should make the underlying property nullable. Without this, the property will be left at its default value (0) after model deserializer. Model validation has no ability to distinguish between missed value and value equal to default one. So for correct work of Required attribute make the property nullable:
public class MyModelClass
{
[Required(ErrorMessage = "{0} is required")]
public int? Level { get; set; }
}
I have a list of Pair of radio buttons (Yes/No):
Q1.(Y)(N)
Q2.(Y)(N)
Q3.(Y)(N)
Q4.(Y)(N)
and I have one property in my model
public string MedicalExplanation { get; set; }
My goal is to make Explanation required if any of the radio button has been set to true.
My first try was to use [Required] but it does not handle conditions.
Then I decided to use third party tool like MVC Foolproof Validation
I used it like this:
[RequiredIf("Q1", true, ErrorMessage = "You must explain any \"Yes\" answers!")]
Now the problem is I don't know how to make it required if any of the other Q2, Q3, Q4 is checked.
Please advice
In your ViewModel, create a bool property like this:
public bool IsMedicalExplanationRequired
{
get
{
return Q1 || Q2 || Q3 || Q4;
}
}
Then, use your RequiredIf attribute like this:
[RequiredIf("IsMedicalExplanationRequired", true, ErrorMessage = "You must explain any \"Yes\" answers!")]
UPDATE:
If your Q1 - Q4 properties are of type bool?, just change the IsMedicalExplanationRequired property like below:
public bool IsMedicalExplanationRequired
{
get
{
return Q1.GetValueOrDefault() || Q2.GetValueOrDefault() || Q3.GetValueOrDefault() || Q4.GetValueOrDefault();
}
}
This is how I did it:
First I created a custom validation attribute which gets a string array of fields to check passed in:
public class ValidateAtLeastOneChecked : ValidationAttribute {
public string[] CheckBoxFields {get; set;}
public ValidateAtLeastOneChecked(string[] checkBoxFields) {
CheckBoxFields = checkBoxFields;
}
protected override ValidationResult IsValid(Object value, ValidationContext context) {
Object instance = context.ObjectInstance;
Type type = instance.GetType();
foreach(string s in CheckBoxFields) {
Object propertyValue = type.GetProperty(s).GetValue(instance, null);
if (bool.Parse(propertyValue.ToString())) {
return ValidationResult.Success;
}
}
return new ValidationResult(base.ErrorMessageString);
}
}
Then I use it like this (I am using resource files to localize my error messages):
[ValidateAtLeastOneChecked(new string[] { "Checkbox1", "Checkbox2", "Checkbox3", "Checkbox4" }, ErrorMessageResourceType=typeof(ErrorMessageResources),ErrorMessageResourceName="SelectAtLeastOneTopic")]
public bool Checkbox1{ get; set; }
public bool Checkbox2{ get; set; }
public bool Checkbox3{ get; set; }
public bool Checkbox4{ get; set; }
It is only actually setting the error on the first checkbox. If you are using the built in css highlighting to highlight fields in error you will need to modify this slightly to make it look right, but I felt this was a clean solution which was reusable and allowed me to take advantage of the support for resource files in validation attributes.
I've written an If-IsRequired custom attribute to validate that a property contains a value depending on the values of some other properties in the model. Since I want to make this attribute apply to as many situations as possible, I want to allow the option for the developer leveraging the attribute to supply an infinite number of matched parameters. And lastly, I want to be able to enforce that all the parameters are matched correctly.
This is what I've written thus far. While I'm currently using arrays of strings, I'd be perfectly happy to use some sort of collection, which been unable to work. In addition, I now have a need to support the current attribute definition and create a new overload that includes the comparison operator. This will allow me to make less than, greater than, and not equal comparisons in addition to the original definition which just assumes all comparisons are done with equals.
/// <summary>
/// A custom attribute that checks the value of other properties passed to it in order to
/// determine if the property this attribute is bound to should be required.
/// </summary>
[AttributeUsage(AttributeTargets.Property, AllowMultiple = true, Inherited = true)]
public class IsPropertyRequiredAttribute : ValidationAttribute
{
private const string DefaultErrorMessage = "{0} is required.";
public string[] _selectionContextNames { get; private set; }
public string[] _expectedValues { get; private set; }
/// <summary>
/// Creates a new instance of the IsPropertyRequriedAttribute.
/// </summary>
/// <param name="SelectionContextNames">The name of the other property in the view model to check the value of.</param>
/// <param name="ExpectedValues">The expected value of the other property in the view model in order to determine if the current property the attribute is bound to should be required.</param>
public IsPropertyRequiredAttribute(string[] SelectionContextNames, string ExpectedValues)
: base(DefaultErrorMessage)
{
_selectionContextNames = SelectionContextNames;
_expectedValues = ExpectedValues;
}
public override bool IsValid(object value)
{
if (_selectionContextNames == null || _expectedValues == null)
{
if (_selectionContextNames != null || _expectedValues != null)
{
string paramName;
if (_selectionContextNames == null)
{
paramName = "ExpectedValues";
}
else
{
paramName = "SelectionContextNames";
}
throw new ArgumentException("Key/Value pairs need to match for IsPropertyRequired.", paramName);
}
}
else if (_selectionContextNames.Length != _expectedValues.Length)
{
string paramName;
if (_selectionContextNames.Length < _expectedValues.Length)
{
paramName = "ExpectedValues";
}
else
{
paramName = "SelectionContextNames";
}
throw new ArgumentException("Parameter element counts need to match for IsPropertyRequired.", paramName);
}
bool paramsValid = true;
if (_selectionContextName!= null)
{
for (int i = 0; i < _selectionContextName.Length; i++)
{
string paramValue = HttpContext.Current.Request[_selectionContextName[i]];
if (_expectedValue[i] != paramValue)
{
paramsValid = false;
}
}
if (paramsValid == true)
{
return (value != null);
}
else
{
return true;
}
}
else
{
return true;
}
}
public override string FormatErrorMessage(string name)
{
return String.Format(DefaultErrorMessage, name);
}
}
While using the attribute to decorate the property will depend on how the attribute is defined, this is what I have currently implemented (which could also probably be improved):
[IsPropertyRequired(new string[] {"prop1", "prop2", "prop3", "prop4"}, new string[] {"1", "2", "3", "4"})]
public string SomeText { get; set; }
Also, I want to prevent, as much as I can, the following decoration from happening:
[IsPropertyRequired(new string[] {"prop1", "prop2", "prop3", "prop4", "prop5withoutvalue"}, new string[] {"1", "2", "3", "4"})]
public string SomeOtherText { get; set; }
And with the new overload including comparison operators as a parameter, we could now have:
[IsPropertyRequired(new string[] {"prop1", "prop2", "prop3", "prop4"}, new string[] {"==", ">", "!=", "<="}, new string[] {"1", "2", "3", "4"})]
public string SomeComparisonText { get; set; }
Attributes in .NET are very limited in the allowed types you can specify, as mentioned on MSDN. If you want more complex data to be specified, I would recommend writing the attribute to specify an alternate location for the richer data structure.
For example, imagine an attribute with this syntax:
[ValidationRules(typeof(MyValidationRuleInfo, "MyRuleSet")]
public int SomeProperty { get; set; }
...
public static class MyValidationRuleInfo {
public static Dictionary<string, ValidationRule> MyRuleSet {
get {
return new { ... rules go here ... }
}
}
And the attribute would look up the property on the target class and get all the rules there. It's still up to you to implement all the logic of all the rules, but you get to avoid attribute soup, and you also avoid unwieldy data structures.
In fact, the xUnit.NET unit testing library does something similar with its Theory and PropertyData attributes, as shown here.
I have a controller and I want two roles to be able to access it. 1-admin OR 2-moderator
I know you can do [Authorize(Roles="admin, moderators")] but I have my roles in an enum. With the enum I can only authorize ONE role. I can't figure out how to authorize two.
I have tried something like [Authorize(Roles=MyEnum.Admin, MyEnum.Moderator)] but that wont compile.
Someone once suggested this:
[Authorize(Roles=MyEnum.Admin)]
[Authorize(MyEnum.Moderator)]
public ActionResult myAction()
{
}
but it doesn't work as an OR. I think in this case the user has to be part of BOTH roles. Am I overlooking some syntax? Or is this a case where I have to roll my own custom authorization?
Here is a simple and elegant solution which allows you to simply use the following syntax:
[AuthorizeRoles(MyEnum.Admin, MyEnum.Moderator)]
When creating your own attribute, use the params keyword in your constructor:
public class AuthorizeRoles : AuthorizeAttribute
{
public AuthorizeRoles(params MyEnum[] roles)
{
...
}
protected override bool AuthorizeCore(HttpContextBase httpContext)
{
...
}
}
This will allow you to use the attribute as follows:
[AuthorizeRoles(MyEnum.Admin, MyEnum.Moderator)]
public ActionResult myAction()
{
}
Try using the bit OR operator like this:
[Authorize(Roles= MyEnum.Admin | MyEnum.Moderator)]
public ActionResult myAction()
{
}
If that doesn't work, you could just roll your own. I currently just did this on my project. Here's what I did:
public class AuthWhereRole : AuthorizeAttribute
{
/// <summary>
/// Add the allowed roles to this property.
/// </summary>
public UserRole Is;
/// <summary>
/// Checks to see if the user is authenticated and has the
/// correct role to access a particular view.
/// </summary>
/// <param name="httpContext"></param>
/// <returns></returns>
protected override bool AuthorizeCore(HttpContextBase httpContext)
{
if (httpContext == null)
throw new ArgumentNullException("httpContext");
// Make sure the user is authenticated.
if (!httpContext.User.Identity.IsAuthenticated)
return false;
UserRole role = someUser.Role; // Load the user's role here
// Perform a bitwise operation to see if the user's role
// is in the passed in role values.
if (Is != 0 && ((Is & role) != role))
return false;
return true;
}
}
// Example Use
[AuthWhereRole(Is=MyEnum.Admin|MyEnum.Newbie)]
public ActionResult Test() {}
Also, make sure to add a flags attribute to your enum and make sure they are all valued from 1 and up. Like this:
[Flags]
public enum Roles
{
Admin = 1,
Moderator = 1 << 1,
Newbie = 1 << 2
etc...
}
The left bit shifting gives the values 1, 2, 4, 8, 16 and so on.
Well, I hope this helps a little.
I combined a few of the solutions here to create my personal favorite. My custom attribute just changes the data to be in the form that SimpleMembership expects and lets it handle everything else.
My roles enum:
public enum MyRoles
{
Admin,
User,
}
To create roles:
public static void CreateDefaultRoles()
{
foreach (var role in Enum.GetNames(typeof(MyRoles)))
{
if (!Roles.RoleExists(role))
{
Roles.CreateRole(role);
}
}
}
Custom attribute:
public class AuthorizeRolesAttribute : AuthorizeAttribute
{
public AuthorizeRolesAttribute(params MyRoles[] allowedRoles)
{
var allowedRolesAsStrings = allowedRoles.Select(x => Enum.GetName(typeof(MyRoles), x));
Roles = string.Join(",", allowedRolesAsStrings);
}
}
Used like so:
[AuthorizeRoles(MyRoles.Admin, MyRoles.User)]
public ActionResult MyAction()
{
return View();
}
Try
public class CustomAuthorize : AuthorizeAttribute
{
public enum Role
{
DomainName_My_Group_Name,
DomainName_My_Other_Group_Name
}
public CustomAuthorize(params Role[] DomainRoles)
{
foreach (var domainRole in DomainRoles)
{
var domain = domainRole.ToString().Split('_')[0] + "_";
var role = domainRole.ToString().Replace(domain, "").Replace("_", " ");
domain=domain.Replace("_", "\\");
Roles += ", " + domain + role;
}
Roles = Roles.Substring(2);
}
}
public class HomeController : Controller
{
[CustomAuthorize(Role.DomainName_My_Group_Name, Role.DomainName_My_Other_Group_Name)]
public ActionResult Index()
{
return View();
}
}
Here's my version, based on #CalebHC and #Lee Harold's answers.
I've followed the style of using named parameters in the attribute and overridden the base classes Roles property.
#CalebHC's answer uses a new Is property which I think is unnecessary, because AuthorizeCore() is overridden (which in the base class uses Roles) so it makes sense to use our own Roles as well. By using our own Roles we get to write Roles = Roles.Admin on the controller, which follows the style of other .Net attributes.
I've used two constructors to CustomAuthorizeAttribute to show real active directory group names being passed in. In production I use the parameterised constructor to avoid magic strings in the class: group names are pulled from web.config during Application_Start() and passed in on creation using a DI tool.
You'll need a NotAuthorized.cshtml or similar in your Views\Shared folder or unauthorized users will get an error screen.
Here is the code for the base class AuthorizationAttribute.cs.
Controller:
public ActionResult Index()
{
return this.View();
}
[CustomAuthorize(Roles = Roles.Admin)]
public ActionResult About()
{
return this.View();
}
CustomAuthorizeAttribute:
// The left bit shifting gives the values 1, 2, 4, 8, 16 and so on.
[Flags]
public enum Roles
{
Admin = 1,
User = 1 << 1
}
[AttributeUsage(AttributeTargets.Class | AttributeTargets.Method, Inherited = true, AllowMultiple = true)]
public class CustomAuthorizeAttribute : AuthorizeAttribute
{
private readonly string adminGroupName;
private readonly string userGroupName;
public CustomAuthorizeAttribute() : this("Domain Admins", "Domain Users")
{
}
private CustomAuthorizeAttribute(string adminGroupName, string userGroupName)
{
this.adminGroupName = adminGroupName;
this.userGroupName = userGroupName;
}
/// <summary>
/// Gets or sets the allowed roles.
/// </summary>
public new Roles Roles { get; set; }
/// <summary>
/// Checks to see if the user is authenticated and has the
/// correct role to access a particular view.
/// </summary>
/// <param name="httpContext">The HTTP context.</param>
/// <returns>[True] if the user is authenticated and has the correct role</returns>
/// <remarks>
/// This method must be thread-safe since it is called by the thread-safe OnCacheAuthorization() method.
/// </remarks>
protected override bool AuthorizeCore(HttpContextBase httpContext)
{
if (httpContext == null)
{
throw new ArgumentNullException("httpContext");
}
if (!httpContext.User.Identity.IsAuthenticated)
{
return false;
}
var usersRoles = this.GetUsersRoles(httpContext.User);
return this.Roles == 0 || usersRoles.Any(role => (this.Roles & role) == role);
}
protected override void HandleUnauthorizedRequest(AuthorizationContext filterContext)
{
if (filterContext == null)
{
throw new ArgumentNullException("filterContext");
}
filterContext.Result = new ViewResult { ViewName = "NotAuthorized" };
}
private IEnumerable<Roles> GetUsersRoles(IPrincipal principal)
{
var roles = new List<Roles>();
if (principal.IsInRole(this.adminGroupName))
{
roles.Add(Roles.Admin);
}
if (principal.IsInRole(this.userGroupName))
{
roles.Add(Roles.User);
}
return roles;
}
}
To add to CalebHC's code and answer ssmith's question about handling users who have multiple roles...
Our custom security principal returns a string array representing all the groups/roles that a user is in. So first we have to convert all the strings in the array that match items in the enum. Finally, we look for any match - if so, then the user is authorized.
Note that we're also redirecting an unauthorized user to a custom "NotAuthorized" view.
The whole class looks like this:
[AttributeUsage(AttributeTargets.Class | AttributeTargets.Method, Inherited = true, AllowMultiple = true)]
public class CustomAuthorizeAttribute : AuthorizeAttribute
{
/// <summary>
/// Add the allowed roles to this property.
/// </summary>
public Roles Is { get; set; }
/// <summary>
/// Checks to see if the user is authenticated and has the
/// correct role to access a particular view.
/// </summary>
/// <param name="httpContext"></param>
/// <returns></returns>
protected override bool AuthorizeCore(HttpContextBase httpContext)
{
if (httpContext == null)
throw new ArgumentNullException("httpContext");
if (!httpContext.User.Identity.IsAuthenticated)
return false;
var iCustomPrincipal = (ICustomPrincipal) httpContext.User;
var roles = iCustomPrincipal.CustomIdentity
.GetGroups()
.Select(s => Enum.Parse(typeof (Roles), s))
.ToArray();
if (Is != 0 && !roles.Cast<Roles>().Any(role => ((Is & role) == role)))
{
return false;
}
return true;
}
protected override void HandleUnauthorizedRequest(AuthorizationContext filterContext)
{
if (filterContext == null)
throw new ArgumentNullException("filterContext");
filterContext.Result = new ViewResult { ViewName = "NotAuthorized" };
}
}
Or you could concatenate like:
[Authorize(Roles = Common.Lookup.Item.SecurityRole.Administrator + "," + Common.Lookup.Item.SecurityRole.Intake)]
In the world of MVC I have this view model...
public class MyViewModel{
[Required]
public string FirstName{ get; set; } }
...and this sort of thing in my view...
<%= Html.ValidationSummary("Please correct the errors and try again.") %>
<%= Html.TextBox("FirstName") %>
<%= Html.ValidationMessage("FirstName", "*") %>
My question: If I submit this form without supplying a name, I get the following message "The FirstName field is required"
OK. So, I go and change my property to...
[DisplayName("First Name")]
[Required]
public string FirstName{ get; set; }
..and now get "The First Name field is required"
All good so far.
So now I want the error message to display "First Name Blah Blah". How can I override the default message to display DisplayName + " Blah Blah", wihtout annotating all the properties with something like
[Required(ErrorMessage = "First Name Blah Blah")]
Cheers,
ETFairfax
public class GenericRequired: RequiredAttribute
{
public GenericRequired()
{
this.ErrorMessage = "{0} Blah blah";
}
}
It seems that RequiredAttribute doesn't implement IClientValidatable, so if you override the RequiredAttribute it breaks client side validation.
So this is what I did and it works. Hope this helps someone.
public class CustomRequiredAttribute : RequiredAttribute, IClientValidatable
{
public CustomRequiredAttribute()
{
this.ErrorMessage = "whatever your error message is";
}
public IEnumerable<ModelClientValidationRule> GetClientValidationRules(ModelMetadata metadata, ControllerContext context)
{
yield return new ModelClientValidationRule
{
ErrorMessage = this.ErrorMessage,
ValidationType = "required"
};
}
}
Here is a way to do it without subclassing RequiredAttribute. Just make some attribute adapter classes. Here I'm using ErrorMessageResourceType/ErrorMessageResourceName (with a resource) but you could easily set ErrorMessage, or even check for the existence of overrides before setting these.
Global.asax.cs:
public class MvcApplication : HttpApplication {
protected void Application_Start() {
// other stuff here ...
DataAnnotationsModelValidatorProvider.RegisterAdapter(
typeof(RequiredAttribute), typeof(CustomRequiredAttributeAdapter));
DataAnnotationsModelValidatorProvider.RegisterAdapter(
typeof(StringLengthAttribute), typeof(CustomStringLengthAttributeAdapter));
}
}
private class CustomRequiredAttributeAdapter : RequiredAttributeAdapter {
public CustomRequiredAttributeAdapter(ModelMetadata metadata, ControllerContext context, RequiredAttribute attribute)
: base(metadata, context, attribute)
{
attribute.ErrorMessageResourceType = typeof(Resources);
attribute.ErrorMessageResourceName = "ValRequired";
}
}
private class CustomStringLengthAttributeAdapter : StringLengthAttributeAdapter {
public CustomStringLengthAttributeAdapter(ModelMetadata metadata, ControllerContext context, StringLengthAttribute attribute)
: base(metadata, context, attribute)
{
attribute.ErrorMessageResourceType = typeof(Resources);
attribute.ErrorMessageResourceName = "ValStringLength";
}
}
This example would have you create a resource file named Resources.resx with ValRequired as the new required default message and ValStringLength as the string length exceeded default message. Note that for both, {0} receives the name of the field, which you can set with [Display(Name = "Field Name")].
Just change
[Required]
to
[Required(ErrorMessage = "Your Message, Bla bla bla aaa!")]
Edit: I posted this because I was looking for this solution with [Required] attribute and had problem to find it. Creating new Q/A don't look that good, since this question already exists.
I was trying to solve the same thing and I found very simple solution in MVC 4.
First, you would probably have to store error messages in some place. I used custom resources, well described at http://afana.me/post/aspnet-mvc-internationalization.aspx.
Important is, that I can get any resource (even error message) by simply calling ResourcesProject.Resources.SomeCustomError or ResourcesProject.Resources.MainPageTitle etc. Everytime I try to access Resources class, it takes culture info from current thread and returns right language.
I have error message for field validation in ResourcesProject.Resources.RequiredAttribute. To set this message to appear in View, simply update [Required] attribute with these two parameters.
ErrorMessageResourceType - Type which will be called (in our example ResourcesProject.Resources)
ErrorMessageResourceName - Property, which will be called on the type above (In our case RequiredAttribute)
Here is a very simplified login model, which shows only username validation message. When the field is empty, it will take the string from ResourcesProject.Resources.RequiredAttribute and display this as an error.
public class LoginModel
{
[Required(ErrorMessageResourceType = typeof(Resources.Resources), ErrorMessageResourceName="RequiredAttribute")]
[Display(Name = "User name")]
public string UserName { get; set; }
}
You can write your own attribute:
public class MyRequiredAttribute : ValidationAttribute
{
MyRequiredAttribute() : base(() => "{0} blah blah blah blaaaaaah")
{
}
public override bool IsValid(object value)
{
if (value == null)
{
return false;
}
string str = value as string;
if (str != null)
{
return (str.Trim().Length != 0);
}
return true;
}
}
This is copy of RequiredAttribute from Reflector with changed error message.
using Resources;
using System;
using System.Collections.Generic;
using System.ComponentModel.DataAnnotations;
using System.Linq;
using System.Reflection;
using System.Resources;
using System.Web;
using System.Web.Mvc;
public class CustomRequiredAttribute : RequiredAttribute, IClientValidatable
{
public CustomRequiredAttribute()
{
ErrorMessageResourceType = typeof(ValidationResource);
ErrorMessageResourceName = "RequiredErrorMessage";
}
public IEnumerable<ModelClientValidationRule> GetClientValidationRules(ModelMetadata metadata, ControllerContext context)
{
yield return new ModelClientValidationRule
{
ErrorMessage = GetRequiredMessage(metadata.DisplayName),
ValidationType = "required"
};
}
private string GetRequiredMessage(string displayName) {
return displayName + " " + Resources.ValidationResource.RequiredErrorMessageClient;
}
}
App_GlobalResources/ValidationResource.resx
Now use data annotation
[CustomRequired]
This worked for me. Carefully read the comments inside the code. (Based on Chad's answer).
// Keep the name the same as the original, it helps trigger the original javascript
// function for client side validation.
public class RequiredAttribute : System.ComponentModel.DataAnnotations.RequiredAttribute, IClientValidatable
{
public RequiredAttribute()
{
this.ErrorMessage = "Message" // doesnt get called again. only once.
}
public IEnumerable<ModelClientValidationRule> GetClientValidationRules(ModelMetadata metadata, ControllerContext context)
{
yield return new ModelClientValidationRule
{
ErrorMessage = "Message", // this gets called on every request, so it's contents can be dynamic.
ValidationType = "required"
};
}
}