I want to localize my resources (form labels, validation messages etc) using DisplayAttribute. I have my resources in the database, but looks like DisplayAttribute uses the resx files, and the class is sealed itself so I cannot derive a subclass and override the require methods/properties.
Is there any way of handling the resourcemanager used by DisplayAttribute, to get the resources from the database instead of the resx files.
And no, I can not use the resx files.
You will need to create your own ResourceProvider to get the messages from the database, and then set the <globalization> tag in Web.Config to point to your custom ResourceProvider. .Net will then use this instead of resx files.
Detailed explanation: http://msdn.microsoft.com/en-us/library/aa905797.aspx
Related
How to get all of default (English) validation messages, so I could translate them. I know I can specify resource name in validation attribute, but I just want to know all the messages.
To localize the default error messages in ASP.NET MVC you need to set the following properties in Global.asax Application_Start method,
ClientDataTypeModelValidatorProvider.ResourceClassKey = "MyResources";
DefaultModelBinder.ResourceClassKey = "MyResources";
Next, you need to create a MyResources.resx resource file and your culture specific resource file MyResources.xx.resx inside App_GlobalResources folder where you can override the following messages:
PropertyValueInvalid
FieldMustBeDate
FieldMustBeNumeric
PropertyValueRequired
I have started working on an MVC project and I came across some scenarios where I feel I am stuck. I need to convert the existing MVC3 site to work for multiple language.
I have one HeaderPage.cshtml and it has a view model bound to it by
#model IHeaderPage
And it outputs a property of this model:
<h3>#Model.HeaderName</h3>
I called this view from MainPage.cshtml
#Html.Partial("HeaderPage")
Now in the Controller's Action method I change the model's property
objHeaderPage.HeaderName="Fill your Registeration details";
And when i run the project i see the the text "Fill your Registeration details".
Now how can I change the text value, i.e. it should read from my resx file.
I have already created resx files in App_LocalResources folder.
I heard that, it can be done by Display Attribute.. but how do i do that or is there any other better way?
This should answer your question regarding the use of DisplayAttribute.
I use DisplayAttribute for every property of my ViewModel, but if you have to handle custom messages like "The record can not be saved because of an error...", or something similar, you can simply use
objHeaderPage.HeaderName = Resources.ResourceMessageName;
The framework will choose automatically the correct culture.
I prefer to put all my resources in a separate projects so I can deploy only the dll of the resources in case of need, but you can also think to deploy the resx files to edit them directly on the production machine. I guess it's up to what you prefer/need.
use System.ComponentModel.DataAnnotations Namespace in ViewModel.
[Display(Name="Fill your Registeration details")]
public string HeaderName{get;set;}
also you can use your resource file. Just review http://msdn.microsoft.com/en-us/library/system.componentmodel.dataannotations.aspx
I've been working with ASP.Net MVC (3) for some time now and i like it a lot. But one thing i find a bit annoying is having to browse between the controllers / views / model / script directory all the time. So i'm wondering if there's a way to tell MVC to look for the files in a different location?
Maybe someone can tell me how to simply group the files together by controller like:
Directory: /Membership
MembershipController
LogOnView
LogOnModel
RegisterView
RegisterModel
Kind regards
Olav
I know exactly what you're talking about. Here are the conditions where I find the default MVC folder structure to be onerous:
I'm using a model-per-view approach
My controller basically only works with that one particular view
I have some javascript that only pertains to that view
Why do I want to put each of these pieces in a different folder?
I create a folder for the view in the Views folder, so you have a folder ~/Views/MyEntityList (just like the traditional MVC approach), but I put everything that pertains to that component there:
~/Views/MyEntityList/
MyEntityListController.cs
MyEntityListModel.cs
MyEntityList.js
MyEntityList.aspx
I find this structure leads all the developers to keep views decoupled from one another. No special MVC configuration is required, except for allowing browsers to access the .js resources directly.
There are some architectural patterns where this might not be a good way to go. For a model-per-view approach (see Los Techies for more description) I really like this structure.
I think you need to get the Solution Navigator extensions via Power Tools update for VS 2010.
That way, you can display in the Solution Navigator, as opposed to the solution explorer, only the open files, for example. Makes it easier.
By the way, delete all the model folders and create a separate model project, eg:
MyApp.Domain
Any solution that is beyond basic will benefit from this.
As stated in the comments to your question, Areas will also reduce your navigation requirements.
The only "looking of files" going on is with views, everything else is just a convention, so if you want you could have:
Directory: /Membership
MembershipController
LogOnView
LogOnModel
RegisterView
RegisterModel
... but the views must be in ~/Views/Membership
It looks like you have to override some behavior in the view engine. You can See this question to get a better idea.
One way I can think of to achieve this is by writing your custom view engine. You can place all these below files in Controllers/Membership
MembershipController
LogOnView
LogOnModel
RegisterView
RegisterModel
Models will not be a problem you can simply change the namespace for the models, the only problem is with the views. For this write your custom view engine so that your mvc application knows the physical location of the view files as follows.
public class CustomViewEngine : RazorViewEngine
{
public CustomViewEngine()
{
ViewLocationFormats = new[]
{
"~/Controllers/{1}/{0}.cshtml",
};
}
}
In global.asax.cs add the ViewEngine in Application_Start() by including the following code
ViewEngines.Engines.Clear();
ViewEngines.Engines.Add(new CustomViewEngine());
You may also have to take care of various other factors like updating the Layout attribute depending on where you place the _Layout.cshtml.
In case you are using areas, add the AreaViewLocationFormats string array as well.
You can do further customization by overriding some of the methods like FileExists, CreateView, CreatePartialView.
Note: Do not forget to copy web.config in the views folder to the Membership controller. Otherwise application does not find the required mvc namespaces and it does not find the symbols like viewbag, model etc.
For my application (ASP.NET MVC 3.0 RTM, Razor View Engine), I would like to use DataAnnotations for my models. If I keep the model classes within the web project, I can have resx resources in App_GlobalResources or App_LocalResources without embedding the .resx into .resources files.
Ignoring newly spawned AppDomains and other considerations, this is ideal because changing something minor in a localized resource like a typo or incorrect translation doesn't require compilation.
However, after moving my models to a class library I don't see any way to keep .resx files as the output and still use DataAnnotations attributes. Am I missing something?
The problem lies in the way the attributes find resources. For instance, a "Name" property might look like this:
[Display(Name = "MyEntity_Name", ResourceType = typeof(Validations))]
[Required(ErrorMessageResourceName="MyEntity_Name_Required",
ErrorMessageResourceType = typeof(Validations))]
[StringLength(150, MinimumLength = 2)]
public string Name { get; set; }
This requirement for a strongly-typed resource wrapper has become the bane of my existence over the past 24 hours.
I've tried to genericize the wrapper, but it seems like the validation attributes specifically look for a property on the wrapper called MyEntity_Name for the DisplayAttribute and MyEntity_Name_Required for the RequiredAttribute. I haven't dug any deeper into the DataAnnotations code to see if there is some magic I can pull off. I was hoping someone else encountered this and had any ideas.
The Question
Is it possible to use DataAnnotations ValidationAttributes (including DisplayAttribute) in a class library without embedding the resx files into .resources files?
The Gotchas :(
In the future, I'd like to move from resx to database-driven resources with very minimal coding effort. I can't do that right now because of limited resources (no pun intended). So, I want to avoid bypassing the ResourceProvider. Also, I want to avoid rewriting or wrapping all of the attributes in the System.ComponentModel.DataAnnotations namespace.
Am I missing something?
Yes, you are missing View Models. Controller actions take/pass view models from/to views and not models. View models are classes which are specifically tailored to the needs of a given view. They contain the only the required properties and the proper formatting for the given view. A view model could be a subset of a model or an aggregation of multiple models (it depends on the requirements of the view). View models are always defined in the web project because they are very tightly coupled to views. So it is view models that you should localize/globalize with resources.
Example of workflow:
The controller action is invoked and it queries the repository to fetch a model
The controller maps the model to the corresponding view model (AutoMapper could you here)
The controller passes the view model to the view and the view displays it with the proper formating/localization.
Conclusion: models should not be formatted/localized or they become more difficult to reuse.
I can't find a way to read resource values in a controller
If you're referring to string resources stored in App_GlobalResources then you can add a
using Resources;
and access them via
Strings.<name of resource>
or use
Resources.Strings.<name of resource>