Using dictionary values in MVC model data annotations

1,852 views
Skip to first unread message

Phil Harvey

unread,
Jan 16, 2013, 12:26:22 PM1/16/13
to umbra...@googlegroups.com
Hello,

Data annotations in MVC models are nice and quick way to get form validation for free. For example this is my model...

    public class BecomeAnOrganiser
    {
        [Display(Name = "First Name")]
        [Required]
        public string FirstName { get; set; }

        [Display(Name = "Email")]
        [Required]
        [DataType(DataType.EmailAddress, ErrorMessage = "Please enter a valid email address")]
        public string Email { get; set; }
    }

Then I put this following syntax into my Razor template...

@Html.ValidationSummary()    

<div class="form-row">
        @Html.LabelFor(x => x.FirstName) *
        @Html.EditorFor(x => x.FirstName)
</div>

<div class="form-row">
        @Html.LabelFor(x => x.Email) *
        @Html.EditorFor(x => x.Email)
</div>

It's great that Umbraco allows developers to build forms in this manner with surface controllers as it's fairly standard asp.net mvc practice. However (here it comes...), I'd really like to be able to reference dictionary item values in the message strings defined in my model.

I've had a look through the code and can't see any existing implementation so I'm considering implementing this myself. I've some ideas, but I'd like to ask the community first if there's an obvious way of doing it, or precedent set elsewhere in the codebase that should dictate how we do it here.

My initial thought is to use a token syntax that gets replaced with the dictionary item when the form is rendered, then hook in the relevant bits of the MVC rendering engine to do this, for example...

        [Display(Name = "{Email Labell}")]
        [Required]
        [DataType(DataType.EmailAddress, ErrorMessage = "{Email Required Error Message}")]
        public string Email { getset; }

Thanks,

Phil


    


Niels Kühnel

unread,
Jan 16, 2013, 3:13:14 PM1/16/13
to umbra...@googlegroups.com
Hey Phil,

That's one of the things the "Localization Framework" did well with custom meta data providers and all. What it needs for v4/6 is a provider for the dictionary. If you have time, you'd be the man if you made the provider!

Cheers,
Niels K

--
You received this message because you are subscribed to the Google Groups "Umbraco development" group.
To post to this group, send email to umbra...@googlegroups.com.
To unsubscribe from this group, send email to umbraco-dev...@googlegroups.com.
To view this discussion on the web visit https://groups.google.com/d/msg/umbraco-dev/-/XtgwuFdiWpkJ.
For more options, visit https://groups.google.com/groups/opt_out.
 
 

Phil Harvey

unread,
Jan 16, 2013, 4:03:15 PM1/16/13
to umbra...@googlegroups.com
Hi Niels,


This makes sense - basically, create a new MetaDataProvider and ModelBinder that provides values from the dictionary. I can't see any reason to not use the key format you have defined - e.g,Validation.Required, ClassName.PropertyName, FooModel.Name.Required, etc.

Does this sound like the right approach to you? I need this functionality, so looks I'm going to have to implement it  :p

Phil

Niels Kühnel

unread,
Jan 16, 2013, 4:24:37 PM1/16/13
to umbra...@googlegroups.com
You don't even need to do that. Did you find the Csv/ Google Spread Sheet provider? Just implement the ITextSource interface's Get method.
Basically, you just need to feed it with key/language/value pairs, and it will do your Html.LabelFor(m=>m.HorseName) for you based on namespaces, class names etc. with the MVC stuff already there...

So cool if you pick it up! I regret that I haven't, besides using it in my personal toolbox. 
--
You received this message because you are subscribed to the Google Groups "Umbraco development" group.
To post to this group, send email to umbra...@googlegroups.com.
To unsubscribe from this group, send email to umbraco-dev...@googlegroups.com.

Phil Harvey

unread,
Jan 17, 2013, 7:32:30 AM1/17/13
to umbra...@googlegroups.com
>You don't even need to do that. Did you find the Csv/ Google Spread Sheet provider? 

I can't find this - do you have a link, I'll have a look.

Thanks,
Phil

Niels Kühnel

unread,
Jan 17, 2013, 7:38:06 AM1/17/13
to umbra...@googlegroups.com

Phil Harvey

unread,
Jan 17, 2013, 11:43:55 AM1/17/13
to umbra...@googlegroups.com
This is what I have implemented for one of our production sites thats on 4.11.x that needs this functionality:


It will look up field display values from the dictionary using the dictionary key format:

Model.FieldName for display name
Model.FieldName.Validator for error messages

For example, for this field on a model called Register...

        [Display(Name = "First Name")]
        [Required]
        public string FirstName { get; set; }

...

It would look for Register.FirstName in the dictionary to find the display name. If no dictionary item finds, it reverts to the default value (e.g. "First Name")

It would look for Register.FirstName.Required in the dictionary to find the display name for the error message for the required validator. Again, if no dictionary items are found it reverts back to the default values provides by DataAnnotationsModelMetadataProvider.

This means I can set up my model with all its messages etc specific in its attributes, then localize it at a later date.

I think this implementation is probably completely different to what you were suggesting :D

Phil

Niels Kühnel

unread,
Jan 17, 2013, 12:10:27 PM1/17/13
to umbra...@googlegroups.com
Cool, no it's exactly the same :) The localization framework also considers namespaces, so it will check:
Acme.Models.Reigster.FirstName
Register.FirstName
FirstName

in that order.

Same thing for validation, e.g. FirstName.Required, 
Required,
FirstName.StringLength, Range etc.

As you have access to the value violating a validation attribute, and the attribute's properties (Min, Max, Whatever) the messages can be reused for different settings  "The value must be greater than {Max:N0}". That's a thing you can't do with standard .NET resources.

Combined with the Umbraco dictionary or a Google Sheet the labels and validation messages for your ViewModels can be changed live.

Sadly a provider for the Umbraco dictionary is still missing :)
To view this discussion on the web visit https://groups.google.com/d/msg/umbraco-dev/-/a7qbYUls024J.

Phil Harvey

unread,
Jan 17, 2013, 12:40:15 PM1/17/13
to umbra...@googlegroups.com
Is the localization framework a 6.x feature? I couldn't find any if for it in v4.x. A Google search only returns info on v5!

Phil

Niels Kühnel

unread,
Jan 17, 2013, 1:07:47 PM1/17/13
to umbra...@googlegroups.com
Well... it was made for v5 but it ended up being completely stand-alone. 
I should probably NuGet it. Where Umbraco came/comes in is the notion of context language, fallbacks etc. It should share the same classes for language representation instead of redundant integration. It works great with Umbraco 4.x as with any other ASP.NET project, but I haven't integrated it with the dictionary.

To view this discussion on the web visit https://groups.google.com/d/msg/umbraco-dev/-/CZuctg20KPQJ.

Shannon Deminick

unread,
Jan 22, 2013, 2:59:09 PM1/22/13
to umbra...@googlegroups.com
One day it will be great to get the framework back in to the Umbraco core, it is FAR superior to what is in there already. I've been thinking about this recently for some reason too :) Might be a side project to write a converter for the current localization stuff to the new way. We currently are not using any MVC forms, etc.. in the back office which is why we haven't had a need for any model metadata provider but once we start doing that it will be required.

Floris Robbemont

unread,
Feb 18, 2013, 4:41:38 PM2/18/13
to umbra...@googlegroups.com
Niels,

We really need something like this for a project that we're doing here at our company. If all there is to write is integration with the dictionary, we could be able to write that.

Otherwise we have to build the entire thing from scratch. (we don't want multilanguage inside the viewmodels and dictionary at the same time, this should be in one place).

Can you send me an email if you're interested?

Cheers,

Floris


Op donderdag 17 januari 2013 19:07:47 UTC+1 schreef Niels Kühnel het volgende:

snie...@gmail.com

unread,
Apr 30, 2013, 11:20:14 AM4/30/13
to umbra...@googlegroups.com
I have extended the required attribute on my project so that it grabs the error message from the dictionary:

using System.Collections.Generic;
using System.ComponentModel.DataAnnotations;
using System.Web.Mvc;

public class LocalizedRequiredAttribute : RequiredAttribute, IClientValidatable
{
public override string FormatErrorMessage(string name)
{
return umbraco.library.GetDictionaryItem(this.ErrorMessage);
}
public IEnumerable<ModelClientValidationRule> GetClientValidationRules(ModelMetadata metadata, ControllerContext context)
{

yield return new ModelClientValidationRule
{
// format the error message to include the property's display name.
ErrorMessage = FormatErrorMessage(metadata.DisplayName),
// uses the required validation type.
ValidationType = "required"
};
}

}

Then, on my model I just decorate the error message:

[LocalizedRequired(ErrorMessage = "Forms.Enquiry.FirstName_Required")]


public string FirstName { get; set; }

Just posting this in case someone wants to use it without creating their own model bindings.

Reply all
Reply to author
Forward
0 new messages