I have a simple class and corresponding properties. I would like to add some validation rules (to a web property). I want to check that the web address is valid. What are the types of conditions I would need to check for?
My thinking:
I have to require this format www.example.sometext
Should I check for valid .sometext endings (i.e. .com, .org, etc.) Problem is there are basically unlimited of these now.
So my question who would I add a validation rule on the class level to handle this?
public string WebAddress { get; set; }
You can use Uri.IsWellFormedUriString method. It will return true if the string was well-formed, if not it will return false.
Link to MSDN: IsWellFormedUriString
Related
I am wanting to validate that a property value is set to a specific text. I came across [validation] (https://www.tutorialsteacher.com/mvc/implement-validation-in-asp.net-mvc) and saw how there are many options such as Required which is very helpful. But I do not see one to ensure that a property has a specific value. Is there a way I can do that using data annotations? Is regular expression for that?
i.e.
ClassName property must be set to "science". Is there a data annotation for property values? Is regular expression for that?
public class Student{
[DataAnnotation("science")]
public string ClassName{ get; set; }
}
I have searched over a few articles and still cannot find the solution to my problem. Would like to know if this is possible with data annotations?
You need to Use CustomValidationAttribute. Please refer below
https://learn.microsoft.com/en-us/previous-versions/aspnet/cc668224(v=vs.100)
https://www.codeproject.com/Tips/5257153/How-to-Create-Custom-Validation-Attribute-in-Cshar
https://learn.microsoft.com/en-us/dotnet/api/system.componentmodel.dataannotations.customvalidationattribute?view=netframework-4.8
Basically, these attributes will have Isvalid function. In you case you can put the validation as Property value == science
I'm a bit confused about C#'s use of attributes. At first I thought it was simply used to give program code additional information through the use of the [Obsolete] attribute. Now I find that [Dllimport] can be used to import a dynamic linked library and its functions. Can attributes import .exe files and other kind of files?
A last question, for programmers working in C# every day, how much do you use attributes, and do you use it for anything else than extending information and importing dll's?
Simply said, attributes are just metadata attached to classes or methods, at the very base.
The compiler, however, reads through your code, and runs specific actions for specific attributes it encounters while doing so, hardcoded into it. E.g., when it finds a DllImportAttribute on a method, it will resolve it to an external symbol (again, this is a very simplified explanation).
When it finds an ObsoleteAttribute, it emits a warning of deprecation.
Your own attributes (which you can create with a class inheriting from the Attribute base class) will not have an effect on the default compiler. But you (or other libraries) can also scan for them at runtime, opening up many possibilities and leading to your second question:
I typically use them to do meta programming. For example, imagine a custom network server handling packets of a specific format, implemented in different classes. Each packet format is recognized by reading an integer value. Now I need to find the correct class to instantiate for that integer.
I could do that with a switch..case or dictionary mapping integer -> packet which I extend every time I add a packet, but that is ugly since I have to touch code possibly far away from the actual Packet class whenever I add or delete a packet. I may not even know about the switch or dictionary in case the server is implemented in another assembly than my packets (modularity / extensibility)!
Instead, I create a custom PacketAttribute, storing an integer property set via the attribute, and decorate all my Packet classes with it. The server only has to scan through my assembly types at startup (via reflection) and build a dictionary of integer -> packet pairs automatically. Of course I could scan my assembly every time I need a packet, but that's probably a bit slow performance-wise.
There are APIs which are much more attribute heavy, like controllers in ASP.NET Core: You map full request URLs to methods in handler classes with them, which then execute the server code. Even URL parameters are mapped to parameters in that way.
Debuggers can also make use of attributes. For example, decorating a class with the DebuggerDisplayAttribute lets you provide a custom string displayed for the instances of the class when inspecting them in Visual Studio, which has a specific format and can directly show the values of important members.
You can see, attributes can be very powerful if utilized nicely. The comments give some more references! :)
To answer the second part of your questions, they are also used, for example, in setting validation and display attributes for both client and server side use in a web application. For example:
[Display(Name = "Person's age")]
[Required(ErrorMessage = "Persons's age is required")]
[RangeCheck(13, 59, ErrorMessage = "The age must be between 13 and 59")]
public int? PersonsAgeAtBooking { get; set; }
Or to decorate enums for use in display
public enum YesNoOnlyEnum
{
[Description("Yes")]
Yes = 1,
[Description("No")]
No = 2
}
There are many other uses.
I just took over a fairly large project. One of my tasks is to modify the code that gets rate quotes from FedEx. Currently, in order to get a set of rate quotes for a shipment that includes quotes for each "ServiceType" (Ground, 2-day, overnight, etc.) the code makes one call for each type. FedEx offers a web service that is used to get this information. After doing a little research, it looks like this web service can return multiple ServiceType quotes with a single round-trip. To do this, I'm supposed to "leave the service type out of the request." (Here's the question that pointed me in that direction.)
So I know that I can exclude the service type property from the serialization by decorating the property with, [System.Xml.Serialization.XmlIgnoreAttribute()]. But how can I do that only when I want results for all the ServiceType values and still be able to pass a single service type for the cases where I know what shipping method the user wants?
EDIT: FedEx's documentation indicates that this field is optional. Some basic testing shows that excluding it from the request with the XmlIgnoreAttribute does return data for multiple ServiceTypes.
If you implement a public bool ShouldSerializeXXX() function alongside the XXX property being serialized, XmlSerializer will ignore the corresponding XXX property when the function returns false. You'll have to have some basis for setting this (maybe the XXX property can be null? or you can grab some other state to make the decision.)
So, something along these lines:
public class MyClass
{
public ServiceType? ServiceType { get; set; }
public bool ShouldSerializeServiceType() { return ServiceType.HasValue; }
}
I am working on a MVC 4 project. I am having an issue with multiple custom validation attribute on single property. Suppose I have 3 custom validation attribute for single property such as:
public class Test
{
[customAttribute1]
[customAttribute2]
[customAttribute3]
public string property1 { get; set; }
}
Currently when I post he form than all three custom validations are performed on the property (no matter whether first validation pass or fail).
What I want is if customAttribute1 validation fails than no need to validate the property with next next custom attribute. How can i achieve this?
The point of this behaviour is to return back (to the UI) all the errors in the Model, so the user can fix all the errors at the same time...
Let's say you want you password to be minimum 8 chars and have at least an uppercase and a number. The way you want your validation to run is to stop if the password is not long enough without checking the rest. Typical use case scenario:
User sets password "foo" -> submit
error - Password too short
User sets it to "foofoofoo"
error - Password must have an uppercase
User sets it to "FooFooFoo"
error - Password must have a number
User goes away frustrated...
So, if the 3 attributes are to be validated together, my suggestion is to keep this behaviour. If the 3 are exclusive then do as others suggested and combine them into a single attribute.
Ordering or executing conditionally is not supported AFAIK.
The best bet is to have all these 3 validations in the same attribute.
If you are badly in need of this kind of validation, then Fluent Validation can do it for you.
Suppose if I have an Annotation like the following
[DisplayFormat(DataFormatString = "{0:#.00#}", ApplyFormatInEditMode = true)]
It works great. But suppose I want to replace the DataFormatString in real time i.e. some times like this {0:#.00#} and sometimes {0:#.000#} based on some application settings the user chooses. Is there a way to do that?
I tried storing the format string in a global variable, but it gives me the following error.
An attribute argument must be a constant expression, typeof expression
or array creation expression of an attribute parameter type
If I make the global variable constant it works but then the purpose is lost. Any advice on a work around?
Basically I would like to give the users an option to set the decimal spaces universally with out having to implement the feature on a per View/Controller basis.
I know I can put the culture using NumberFormat.CurrencyDecimalDigits. But this will ignore Zeros after the decimal.
Attribute requires constant string, you can't change that. Also this attribute does not provide ability to provide resource name. So, I think best way to you is creating DisplayTemplate and EditorTemplate for this property.
[UIHint("Bar")]
public decimal Bar { get; set; }
And in Bar template you can change format based on some application settings chosen by user:
#model decimal
#Model.ToString(HttpContext.Current.Session["format"].ToString())
There is a good library called MvcExtensions, one of it's feature is fluent metadata configuration. It allows you to construct model metadata fluently instead of DataAnnotations.
Using this library, you may accomplish your task:
Configure(x => x.Payment)
.Format(() => ConfigurationManager.DataFormatString)