0

We need to resolve dataAnnotations at runtime for the nature of the project and configuration. Apparently one of the options (without using custom attributes preferably) is to subclass DataAnnotationsModelValidatorProvider and override its GetValidators method. Later in the global.axax.cs the new class in added as ModelValidatorProviders.Providers.Add(new CustomCoolProvider());

Question: Is this still valid for MVC 5?

The idea behind this implementation is to replace some formatted values set as data annotations, for example: [Display(Name="COOL.VALUE")] will be understood and replace for some other value: metadata.DisplayName = "Some super cool value"

Here someone wrote an example for a prev version of MVC. DataAnnotations dynamically attaching attributes

Help is appreciated.

Community
  • 1
  • 1
user1791567
  • 1,388
  • 1
  • 16
  • 29
  • 2
    If you read the last answer in that article, it explicitly says that DisplayAttribute doesn't work with that method, because it only works with ValidationAttribute's. DataAttributes are compiled into the application at compile time, and cannot be changed at runtime. The only reason the ValidationAttribute technique works is because ValidationAttributes have a hook built into them to allow for it, other attributes don't have this. – Erik Funkenbusch Aug 05 '14 at 03:48
  • So, how can I overwrite the display.name value? – user1791567 Aug 05 '14 at 04:04
  • You can't. This is one of the major limitations of DataAttributes. – Erik Funkenbusch Aug 05 '14 at 04:06
  • Ok, will a custom attribute do it? How do you build i18n in MVC? – user1791567 Aug 05 '14 at 04:10
  • Can the resource strings be stored in the database? – user1791567 Aug 05 '14 at 04:13
  • Well, certainly you can do the same thing ValidationAttributes do, and build a hook into your attribute. MVC already supports localization though... Including the DisplayAttribute... What is wrong with the existing localization support? – Erik Funkenbusch Aug 05 '14 at 04:14
  • Yes, of course they can be stored in a database. MVC uses the standard asp.net resource system, and you can simply create a ResourceProvider that loads resources from the database. Set the Resource type and name, create your resource provider and configure it in web.config, and you're good to go. – Erik Funkenbusch Aug 05 '14 at 04:19
  • Let us [continue this discussion in chat](http://chat.stackoverflow.com/rooms/58652/discussion-between-user1791567-and-erik-funkenbusch). – user1791567 Aug 05 '14 at 04:20
  • See http://weblogs.asp.net/thangchung/extending-resource-provider-for-soring-resources-in-the-database – Erik Funkenbusch Aug 05 '14 at 04:21
  • The problem is, I have an MVC app that does not have access to the db. It communicates back and forth using WebAPI. There are multiple models which are POCOS... and these POCOS (all under same assembly) are the shared between the two pieces.. so, data from the MVC application will always come from a WebAPI call – user1791567 Aug 05 '14 at 04:29
  • That isn't a problem, you just customize your Resource provider to use WebApi instead the database. There's an example of making a Database provider here http://www.west-wind.com/presentations/wwDbResourceProvider/ which you could customize to use WebApi instead. – Erik Funkenbusch Aug 05 '14 at 04:35
  • Ok, I will give it a try tomorrow morning and let you know. Thanks man! – user1791567 Aug 05 '14 at 04:40
  • I went with this implementation and so far runs well http://www.codeproject.com/Tips/514321/A-Simple-and-Effective-Way-to-Localize-ASP-Net-MVC – user1791567 Aug 05 '14 at 13:55

1 Answers1

0

This is what we used to process data annotations. In your global.asax.cs file.

protected void Application_Start() {
    ...
    ModelMetadataProviders.Current=new MyMetadataProvider();
    ...
}

private class MyMetadataProvider:DataAnnotationsModelMetadataProvider {
    protected override ModelMetadata CreateMetadata(IEnumerable<Attribute> attributes,Type containerType,Func<object> modelAccessor,Type modelType,string propertyName) {
        var metadata = base.CreateMetadata(attributes,containerType,modelAccessor,modelType,propertyName);

        //Automatically replace underscores with spaces and remove the "id" from the end of column names
        if(metadata.DisplayName==null&&propertyName!=null) {
            metadata.DisplayName=propertyName.Replace('_',' ');
            if(metadata.DisplayName.ToLower().EndsWith(" id"))
                metadata.DisplayName=metadata.DisplayName.Remove(metadata.DisplayName.Length-3);
        }

        //Automatically attribute multiline for anything 500 chars and above (or strings with no length defined)
        if(modelType==typeof(string)&&!(attributes.OfType<StringLengthAttribute>()?.FirstOrDefault()?.MaximumLength<500))
            metadata.DataTypeName="MultilineText";

        //Automatically attribute dates (not datetime)
        if(attributes.OfType<ColumnAttribute>()?.FirstOrDefault()?.TypeName?.ToLower()=="date") {
            metadata.DataTypeName="Date";
            metadata.EditFormatString="{0:yyyy-MM-dd}";
        }

        return metadata;
    }
}
Carter Medlin
  • 11,857
  • 5
  • 62
  • 68