Using Data Annotations with Resources.Messages C# - c#

i'm a student and beginner developer.
I'm on a project on my workplace.. and I'm using Data Annotations for validation... but I need to use Resources.Messages to implement dynamic error messages. Here goes an example of what I'm trying to do:
[Required (ErrorMessage = (string.Format(Messages.MissingParameter, Messages.Ad)))]
[Range(0, long.MaxValue)]
public long? Ad { get; set; }
In this scenario, missing parameter is the follow string "The parameter {0} is required" and Messages.Ad is a string with the internacionalized field.
Soo, if I use Data Annotation, there's a few solutions, like using the ErrorResource... (like this RegularExpressions example -> Why can't I use resources as ErrorMessage with DataAnnotations?)
But these don't contemplate the issue of passing strings that use parameters to deliver the final string (as illustrated on string.format)
So, my question is: How to use complex internationalization string's with data Annotations.

You can't because you have to use specific values that are able to be used as attribute parameters.
From MSDN - Attributes Tutorial C# :
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

Related

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).

Is there an model validation attribute to check parameter types without using custom code?

I have a webapi where I want to validate if the used parameter is of type int. I know of the attribute DataTypesAttribute but it doesn't support the simple types. I do not want to create a custom attribute for this.
Take a look at here, as mentioned when you desalinize from a json string to object the value type must be int, if not the desalinization will fail. model validation as it's name suggests is mostly for domain driven and business related validations not type specific.

DataAnnotation with a configurable value?

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?

Creating DescriptionAttribute on Enumeration Field using System.Reflection.Emit

I have a list of strings which are candidates for Enumerations values. They are
Don't send diffs
500 lines
1000 lines
5000 lines
Send entire diff
The problem is that spaces, special characters are not a part of identifiers and even cannot start with a number, so I would be sanitizing these values to only chars, numbers and _
To keep the original values I thought of putting these strings in the DescriptionAttribute, such that the final Enum should look like
public enum DiffBehvaiour
{
[Description("Don't send diffs")]
Dont_send_diffs,
[Description("500 lines")]
Diff_500_lines,
[Description("1000 lines")]
Diff_1000_lines,
[Description("5000 lines")]
Diff_5000_lines,
[Description("Send entire diff")]
Send_entire_diff
}
Then later using code I will retrieve the real string associated with the enumeration value, so that the correct string can be sent back the web service to get the correct resource.
I want to know how to create the DescriptionAttribute using System.Reflection.Emit
Basically the question is where and how to store the original string so that when the Enumeration value is chosen, the corresponding value can be retrieved.
I am also interested in knowing how to access DescriptionAttribute when needed.
Ok, if you really want to use reflection:
DiffBehvaiour value = DiffBehvaiour.Dont_send_diffs;
FieldInfo enumField = value.GetType().GetField(value.ToString());
DescriptionAttribute attribute = (DescriptionAttribute)enumField.
GetCustomAttributes(typeof(DescriptionAttribute), true)[0];
Console.WriteLine(attribute.Description);
$> Don't send diffs
Obviously there is no error handling, etc, but the basic idea is there.
Update
I now think I see the point of your question, which myself and the other people that answered actually missed.
You want to decorate an enum with attributes at runtime i.e. add attributes to a type at runtime. Adding attributes to a type at runtime is not possible.
However these is support in the .Net for a type metadata engine via : TypeDescritor:
MSDN http://msdn.microsoft.com/en-us/library/system.componentmodel.typedescriptor.aspx
Example http://geekswithblogs.net/abhijeetp/archive/2009/01/10/dynamic-attributes-in-c.aspx
The TypeDescritor framework allows you to dynamically provide type information rather than actually dynamically decorating types directly - it is a layer of indirection.
You may be able to bend this mechanism to support what you want to do, but at the end of the day you will need to maintain a lookup for your enum members to provide the description strings. Using a lookup structure to maintain a mapping between your enum members and description string was my first answer and the first answer to this question...
You could write a generic method like this:
class EnumExtensions
{
public static string GetDescription<TEnum>(TEnum value)
// inexpressible generic constraint TEnum : System.Enum
{
// reflection lookup of this value per #chibacity answer
}
public static IDictionary<TEnum,string> GetDescriptions<TEnum>()
// inexpressible generic constraint TEnum : System.Enum
{
// do the reflection lookups once and build a dictionary
var result = new Dictionary<TEnum, string>();
foreach(string name in Enum.GetNames(typeof(TEnum))
{
var value = (TEnum)Enum.Parse(typeof(TEnum), name);
var description = GetDescription(value);
result.Add(value, description);
}
return result;
}
}

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