I would like to separate my attribute decoration(3-4 per field) by having them someplace else so that my code looks readable.
Also the arguments passed to some attributes should come from a resource file.
EG:[Required("Cannot proceed without entering *field_Name*")]
I need just [Required]
Possible duplicate of this question(on which i couldn't resist offering a bounty) : Default resource for data annotations.
To answer your first question, you can use buddy classes. For example, if you have a "User" model, then you can create a "UserMetadata" buddy class. You can then add attributes to properties in the buddy class instead of the main class. ASP.NET MVC fully supports this, and will use your buddy class for things like validation and display name. Here is how you declare a buddy class:
[MetadataType(typeof(UserMetadata))]
public class User
{
public string Name { get; set; }
}
public class UserMetadata
{
[Required]
public object Name { get; set; }
}
Note that the property type in the buddy class can always be "object", because MVC doesn't look at the property type in buddy classes.
Note also that MetadataTypeAttribute can be found in the System.ComponentModel.DataAnnotations namespace.
For your second question, you can look at the answer that I posted here:
Default resource for data annotations in ASP.NET MVC
For the first question, maybe you could try using Fluent Validation. You can hook it up to MVC by following these instructions.
For the second question, I've posted an answer here: Default resource for data annotations in ASP.NET MVC
Related
I have the following finding received from Fortify on Demand:
ASP.NET MVC Bad Practices: Optional Submodel With Required Property
Here is a sample example of the code snippet that received the finding:
public interface IEditObjPermissionsItem : IErrorDictionary, IVrfyObject
{
string EntityType { get; }
int? foo { get; set; }
}
As the REQUIRED property was not used at all in the example, I am confused about the finding and think it may be another FP on the FoD side...
I think I answered my own question. As there is no [Required] in any of the code, it is a false positive.
The under-posting vulnerability would be if your child "submodel" contained the Required attribute.
Explanation
If a model class has required property and is the type of
an optional member of a parent model class, it may be susceptible to
under-posting attacks if an attacker communicates a request that
contains less data than is expected.
The ASP.NET MVC framework will try to bind request parameters to model
properties, including submodels.
If a submodel is optional -- that is, the parent model has a property
without the [Required] attribute -- and if an attacker does not
communicate that submodel, then the parent property will have a null
value and the required fields of the child model will not be asserted
by model validation. This is one form of an under-posting attack.
See: VulnCat
I have an N tier app in which Data, Domain and the front-end layers are in separate projects. I am using ASP.NET MVC to create the website and I am trying to add validation rules by using System.ComponentModel.DataAnnotations. Currently I have done it on the domain classes' properties.
I would like to know whether it is a good practice to apply the validation rules directly to the Domain classes? Or it is better to create ViewModels classes in the ASP.NET app and apply the validation rules to the properties of the ViewModel classes?
Hope this question fits here
I appreciate any help.
ViewModel is much better, because ViewModel should understand if it gets valid input from the user. And then you can fix all other exception during convertion using AutoMapper. I would also create a lot of custom , DataAnnotations, DataTypes, Editors, ModeMetaDataRules, and ModelBinder to go with app.
Here is parts of code for ModelFilter using custom ModelBuilder, I am going post part of it, because there is a lot of code involved, but it should get you on right track.
public interface IModelMetadataFilter
{
void TransformMetadata(ModelMetadata metadata,
IEnumerable<Attribute> attributes);
}
public class MultilineTextByNameConvention : IModelMetadataFilter
{
public void TransformMetadata(ModelMetadata metadata, IEnumerable<Attribute> attributes)
{
if ( !string.IsNullOrEmpty(metadata.PropertyName) &&
string.IsNullOrEmpty(metadata.DataTypeName) )
{
if ( metadata.PropertyName.ToLower().Contains("notes")
|| metadata.PropertyName.ToLower().Contains("description")
|| metadata.PropertyName.ToLower().Contains("comment")
)
{
metadata.DataTypeName = DataType.MultilineText.ToString();
}
}
}
}
This code looks for every ViewModel that has property name containing words 'notes', 'description', and 'comment', automatically applying Multitext DataType attribute for all that properties. This type of code can be used for a lot of other different situations. For example fields like SSN can have particular format using RexExpr DataAnnotation, and so on...
You can set attributes on partial classes of your entities and your auto generated classes will not get overridden.
For instance,
Let's say you have entity TheEntity
In a separate file with the Same namespace you can write:
namespace SameNamespaceAsEntities
{
internal sealed class TheEntityMetadata
{
//AStringInTheEntity appears twice in your project
//once in the auto gen file, and once here
[Required(ErrorMessage = "Field is required.")]
public string AStringInTheEntity{ get; set; }
}
//http://stackoverflow.com/questions/14059455/adding-validation-attributes-with-an-entity-framework-data-model
[System.ComponentModel.DataAnnotations.MetadataType(typeof(TheEntityMetadata))]
public partial class TheEntity : IEntity //you can set contracts
{
Using data annotations with the help of MetadataTypeAttribute doesn't seem to be working with ASP.NET Web API Help Page. Not even sure if the data annotations actually work with MetadataTypeAttribute, but looks like it should... based on this link. We need to specify data annotations using different classes because the primary models are being used by other portable class libraries, in which these libraries cannot use the data annotations used with ASP.NET Web API.
[MetadataType(typeof(UserInfoMetadata))]
public partial class UserInfoViewModel
{
}
public class UserInfoMetadata
{
[Required]
[Display(Name = "Email")]
public string Email { get; set; }
}
Looking at the sample model above, RequiredAttribute has been specified. That said, it should be displayed on the additional information column for the "Email" field or property. Specifying data annotations without using MetadataType attributes seem to be working fine.
I have a Generic Envelope class that i use as the common return object for the WebAPI as follows:
public class ApiEnvelope<T>
{
public bool Success { get; set; }
public Error Error { get; set; }
public Data<T> Data { get; set; }
}
Then I construct a HttpResponseMessage using:
Request.CreateResponse<ApiEnvelope<whatever>>(HttpStatusCude.OK, model);
The problem i have is that i would like the xml to be somewhat standard however the root name of the xml being returned is not standard and is coming through as ApiEnvelopeOfwhatever.
My question is how can i get the root name to be ApiEnvelope regardless of the type?
With generic class you got no chance, remove generic specification and set Data propert type to object.
I had a similar question and I got a decent answer, (I know this is old but it was a good answer): How to resolve Swashbuckle/Swagger -UI model naming issue for generics?
Now this is only part of the solution for your question, so you should look at Github repo: MakeGenericAgain. Use that to "regeneric" the resultant generated code, (big heads up: if you use this on the entire code and not just names of types, you will have a mess if you have properties name things like "NumberOfUnits" because that becomes "Number").
Sidenote:
If you want to "level up" your skills here, then use Rolsyn's SyntaxWalker to apply the renaming, and at the same time "cleanup" duplicated classes, as many design their REST-APIs with few shared "models" so a User and a Company might hace identical "Address" -properties based on identically shaped classes but it they are defined twice your NSwag -generated code will have Address and Address2, however using Roslyn, you can identify these ande rewrite the code to give a "perfect result".
I would like to be able to expose a list of users using WebAPI 2. However since I am using the new Asp.Net Authentication framework in MVC5, I can't seem to find a way to only mark specific fields as DataMembers.
Heres what I have:
[DataContract]
public class ApplicationUser : IdentityUser {
public Nullable<DateTime> birthday { get; set; }
[DataMember]
public int tolerance { get; set; }
[DataMember]
public string twitter { get; set; }
}
However, that doesn't seem to work because IdentityUser doesn't have the [DataContract] attribute. I've tried creating a custom IdentityUser, but I haven't been able to build after creating a custom copy of IdentityUser.
Any tips or work arounds here? I'd prefer not to have to create a ViewModel, unless that's the current best practice.
I know this is an old question and I stumbled upon it when I was trying to achieve the same thing. Here's what I ended up doing. You could override your properties and mark them as [JsonIgnore] so that they won't get serialised automatically.
public class ApplicationUser : IdentityUser
{
public UserType UserType { get; set; }
[JsonIgnore]
public override string PasswordHash
{
get { return base.PasswordHash; }
set { base.PasswordHash = value; }
}
}
You probably should just send a different object with the user info you need as opposed to serializing the user object.
What formatter do you want to use? I don't see any issue with default Json formatter. But for xml serializer, it requires base class to be DataContract as well.
View model is always the best practice here, although most of the samples for web api are using data entity for simplicity. The two models are separate of concerns. View model represents the contract of your api and the data model represents your domain concept. Combining two models into one can impact your design decision or even more seriously, can cause security issues. Using data entity may expose unexpected data to user. For example, different formatters have different rules to control the exposure of model. JsonIgnore doesn't work in xml formatter. It will be more complicated if you have custom formatter. Especially for the identity user entity, which has many sensitive properties like pasword hash, security stamp. I won't recommend you expose it to public.
BTW, there is many mapper tools that can help to simplify the mapping from domain model to view model. You may need them: http://www.nuget.org/packages?q=mapper