DataAnnotation with a configurable value? - c#

I'd like to set a DataAnnotation on a view model to a dynamic value that is configurable via the web.config. In the following example I get this error "An attribute argument must be a constant expression, typeof expression or array creation expression of an attribute parameter type". Anyone know if this is possible? Thanks
[DataType(DataType.Password)]
[RegularExpression(Properties.Settings.Default.PasswordExpression)]
public string Password { get; set; }

Attribute parameters must be constants, i.e. something whose value can be resolved at compile time. But you could write your own simple Attribute class that took the name of the the item in the appSettings, got the underlying value, and passed that on to the normal RegularExpression processing. Then your attribute would look like this:
[ConfigedRegularExpression("PasswordExpression")]
where PasswordExpression was the name of the app setting containing the actual regular expression string.
and, after writing this and doing a search (I should have done that first), I see someone's worked it out for you here:
How to write custom RegularExpressionValidator which takes the values from the config file?

Related

Using enum in data annotation

I am using a data annotation like so:
[RequiresAnyRole("Admin", "Member")]
I don't like passing strings as it can be a pain refactoring later but If I try to make an enum like so:
public enum Roles
{
Admin,
Member
}
And then try to cast the enum to string like so:
[RequiresAnyRole(Roles.Admin.ToString(), Roles.Member.ToString())]
Then I get the error:
Error CS0182 An attribute argument must be a constant expression, typeof expression or array creation expression of an attribute parameter type
My understanding of this error is that it has to be a string at compile time. I have tried to make a static dictionary with the enum as the key but that didn't work either.
What is the best way to pass these values in a way that can be refactored later i.e. not passing in a string but passing in a reference of some sort that can be updated?
This is a great opportunity to use nameof. You can keep your enum, and do:
[RequiresAnyRole(nameof(Roles.Admin), nameof(Roles.Member))]
nameof expressions are constant expressions.
Of course, if you can change the attribute's declaration, you should change it to accept your Roles enum.

Is it possible to bind Route Value to a Custom Attribute's Property in ASP.NET Core Web API?

I've a Custom Attribute which I'm using to authorize the request before it hits the Controller Action, in ASP.NET Core Web API. In the image below, "SecureMethod" is the custom attribute.
I want to add a property in the Custom Attribute, which I want to bind to one of the Route Values, please refer to the image below:
I want to bind "userIDs" route-value to one of the Custom Attribute's property ("UserIDs", this is an example attribute).
Is there any way I can bind the route-value to a custom-attribute's property?
TIA
One way you can do this is by passing the name of the route parameter to the attribute, and examining the route data in the attribute itself. For example:
[SecureMethod(PermissionRequired = AccessPermissionEnum.DeleteUsers, UserIdsKey = "userIds")]
Then something like:
public AccessPermissionEnum PermissionRequired { get; set; }
public string UserIdsKey { get; set; }
public override void OnActionExecuting(ActionExecutingContext context)
{
// Depending on how you pass your userIds to the action, you
// may need to use something else from context to get the data,
// but it's all available in there.
var userIds = context.ActionArguments[UserIdsKey];
// Do something with the ids.
base.OnActionExecuting(context);
}
Whilst this works, and in certain places it works really well, you should be aware that the filter now has intimate knowledge of the parameter being passed in. For the most part, this usually doesn't matter so much, but it's an approach you shouldn't use everywhere because it will end up adding a lot of coupling if not used well. It's a useful tool to use every now and then.
No, it is not possible.
Attribute parameters are restricted to constant values of the following types:
Simple types (bool, byte, char, short, int, long, float, and double)
string
System.Type
enums
object (The argument to an attribute parameter of type object must be
a constant value of one of the above types.)
One-dimensional arrays of any of the above types
You cannot nest attributes and you cannot pass non-constant values to attribute parameter. Even though you can declare an attribute parameter as type object, the actual argument you pass in must still be a constant string, bool, etc (declaring it as an object just means you can use any of these types each time you declare the attribute).

DataType vs UiHint

I have been using mvc2 for a while now, and when i need to set the template i use the DataType Attribute
[DataType("DropDown")]
public int Field { get; set; }
I see others using UiHint to achieve the same results
[UiHint("DropDown")]
public int Field { get; set; }
What is the difference between using these two attributes? Which attribute should I be normally using, or are they for different tasks?
DataType is generally used to make it known that this is a very specific version of a property, such as price.
The most common example of DataType is the [DataType(DataTypes.EmailAddress)] which usually is a string but we're saying that this is a very specific type of string.
They're both helpful and the UIHint overrides the DataType. So if you have a certain DataType but you want to override the editor for that specific property you can use a UIHint.
DataType attribute has two purposes
Provide additional type information for a data field. You do this by applying the DataTypeAttribute attribute to a data field in the data model and by specifying the additional type name from the DataType enumeration. Then the view engine uses the default template for displaying the property, like, a checkbox for a boolean.
If you want to override the default template, and wish to use a custom template, then it can be used to associate a custom field template with that data field. In this case you must provide a partial page[.cshtml, MVC 4] to describe the display.
The purpose of UIHint is exactly same as the second point above.
Where to use what? The answer is: context, ie., what will make more sense, what is closer to the physical problem your code is trying to solve.
What if both are applied to the same property? The answer is: UIHint has precedence, obviously. But why would you apply both?

How to use strings from Resources.resx file in dynamic data TableName attribute

Hi i am trying to find solution for using resource file with dynamic data based on EF 4.0
[TableName(Resources.Test)]
public class TestTable
....
I get an error An attribute argument must be a constant expression, typeof expression or array creation expression of an attribute parameter type.
How to do it right way?
Developer Art is right it is not supported.
The problem is what is set at compile time and what is set at run time. The Attribute is a compile time attribute. You can therefore not change the value at runtime.

How do I use ValidateDecimal attribute in Castle.ActiveRecord?

I have a class that inherits ActiveRecordValidationBase that contains the following property:
[Property]
[ValidateDecimal]
public Decimal UnitCost { get; set; }
I also have a UnitCostTextBox that accepts input for said UnitCost.
What I would like to do is perform validation once using Castle's validators. However, it seems that before I can pass UnitCodeTextBox.Text to my object, I will need to first convert it to a decimal first.
If I have an erroneous input, an exception will be thrown. So this means I still have to perform regex validations and converting the string to a decimal type before handing it over to Castle.ActiveRecord.
Doesn't this mean it's redundant to have a [ValidateDecimal] since I've already sanitized UnitCost?
I'm wondering how do you guys do it? I have googled for examples, but most of them only handle [ValidateNonEmpty] or [ValidateEmail] which are all strings anyway, not different data types
What you're missing is the binding part (actually you're doing it manually). Castle.Components.Binder and Castle.Components.Validator are used together to automatically bind and validate string input (e.g. an HTML form) into strongly typed objects.
MonoRail does this with the [DataBind] attribute and the AR-specific [ARDataBind]
In a WebForms application you'll have to implement binding+validation yourself (you can of course use Castle.Components.Binder and Castle.Components.Validator)

Categories