DataAnnotations and Resx in class library - localization

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.

Related

In asp.net-mvc, Is it wrong to move my "EditViewModel" classes outside my MVC web project?

I have an asp.net-mvc site that pretty much is a CRUD app but I also do some adds & updates outside the webview (upload from spreadsheets, etc). Based on this article, I am trying to get as much of the logic outside the MVC project into a seperate shared project so i can reuse the same code in all scenarios and I am trying to isolate and seperate my "read" viewModels that are binding to UIs for display from the "edit" viewModels that represent what is being posted to the server on a form post.
I have a number of projects in the solution (domainobjects, importexport,etc) that are shared with other solution plus the MVC project has the following directories in the MVC project
Controllers
Views
ViewModels
Scripts
EditViewModels
My ViewModels folder represents the objects that I am binding to my views (a container object that usually includes:
A domain object and
A bunch of IEnumerable of SelectListItem to populate UI dropdowns, etc
something like this:
public class OrderViewModel
{
public Order MyOrder {get;set;}
public IEnumerable<SelectListItem> OrderTypes {get;set;}
public IEnumerable<SelectListItem> Sizes {get;set;}
}
My EditViewModels folder represents the objects that i am posting from forms to the server so they are usually simpler flat objects with just primatives that i then populate a domain object with before adding or updating my database like this:
public class OrderEditViewModel
{
public int Id {get;set;}
public int OrderTypeId {get;set;}
public int SizeId {get;set;}
}
My main question is when i have a method in my Controller class that usually looks like this (simplified):
public ActionResult Update(OrderEditViewModel order)
{
var existingOrder = _repository.GetOrder(order.Id);
existingOrder.Name = order.Name;
existingOrder.Size = _repository.GetSize(order.SizeId);
existingOrder.Price = order.Price;
_repository.Save(existingOrder);
return Json( Result = "Success");
}
I am trying to figure out how to get as much code as possible outside the MVC project but that forces me to move all of my classes in the EditViewModel outside of the MVC project so those objects can be reused.
Does anyone see anything wrong with having these "Post" data structure classed outside the MVC projecdt. Given its a "viewmodel" class it feels wrong to move it away from the view but I don't see any other way to share this code outside of the MVC project. Maybe the "viewModel" name here is just wrong possibly?
Your View Models are specific to your views, and should not be relevant to anything else. They contain things which nothing else should care about, such as your select lists. As such, they should stay in your UI.
The article appears to me to be creating a situation in which the business logic depends on the UI (or at least the UI Model.. ie View Model), and I think that is the wrong approach. The UI should be able to consume the business logic without the business logic being aware what the UI is. It could be a web site, a fat client, a mobile client, a web service, etc... By making this logic depend on your view models, you now are making any future services that are not web based depend on those.
This is, however, a simple CRUD app, and in simple CRUD apps you can often take a lot of shortcuts because it's just not worth the extra engineering effort. I wouldn't normally pass a domain object to the view directly in the View Model. But in this case it's probably the best choice.
If you want to do it "right", however, then you need to create more separation of concerns. Your domain and ui layers need more separation. You create separate view and domain models, and then map between them. This prevents the business layer from knowing anything about the UI.
I would probably create a service layer that handles your logic. For instance:
_orderService.UpdateOrder(order.Id, order.Name, order.Price);
In my case, i make a difference between read(view-)models and write-models.
Read models are very specific to the view, they can contain select lists and formatted and localized content. You should not move this models outside of your ui-project. Of course you can make a separate assembly with your models, or you can make one assembly per module, but you should never consume these models from your domain layer.
Write models - in my opinion - are not that specific to your UI. Instead they represent the data that is required by the command (e.g. SaveUserCommand). They can contain validation attributes, so your domain layer can validate them easily and they can be shared by domain layer and UI. In my project I have one class per command (e.g. SaveUserCommand, EditUserCommand, DeleteUserCommand) and related models (SaveUserModel, EditUserModel). Somebody will comment, that the they also contain some UI-specific code (e.g. the IClientValidateable itnerface for attributes or the attributes itself) and at least the IClientValidateable interface is a problem that I am willing to ignore to reduce the number of models. My experience with this approach (I also tried others) shows, that these models are very easy and it very easy to bind to these models.
Sometimes you will also have the problem, that you want to show some additional information in the edit-view. Instead of adding all this information to the viewbag, I will have another model, for example:
class UserEditModel
{
string Password;
}
UserEditViewModel
{
DateTime Modified;
UserEditModel Edit;
}
So my advice:
Create write-models that have all the data and validation logic that is specific to your use cases.
Create view models that contain all data you want to display and try not to use the ViewBag.
If you have a form, add the write-model to your view model. The write-model has all the data that will be sent back to your server via POST and then directly to your domain layer.
I use four "layers" in two assemblies
{application}.app assembly with three namespaces, just a regular class library project.
1) {application}.model for domain model
2) {application}.data for data using repository pattern
3) {application}.services for all business logic
{application}.WebUI assembly for the UI, this is the MVC project
Controllers only call services and services get and update data through the repositories.
There is an services API for every operation your app has to do, i.e.
OrderServices.Update (existingOrder)
OrderServices.Approve (existingOrder)
Services layer only know domain models, and controllers just assemble the viewmodels, using the domain models gotten from services, to send them to the views and prepare the domain models using the viewmodels gotten from the views to send them to the appropiate service.
This way you can eventually create an {application}.WebAPI or whatever that uses the same {application}.app assembly reusing all of the buissiness logic and keeping viwemodels where they belong (the WebUI project)
Hope this helps.
Best regards.
You could use a service architecture of your project , where all function and db queries are in this files and which you could using just by adding this code
IOrderService<Order> service = new OrderEntityService();
and use it like
service.Create(Order) or service.Update();
Whats strange to me is you're taking care and effort to layer out your app as much as possible, but you're still letting your MVC controller contain a lot of your logic. You're trying to share the objects and models, but the logic to add a new OrderEditViewModel is not shared, its stuck within that controller.
What I try and do is create a "helper" or "logic" class for each of my controllers. That logic or helper class is then injected into my controllers and wrapped in an interface. My controller can save, edit and remove items through my helper class, but has no knowledge of how its actually doing that.
I have then shared these logic classes along with the models to other projects, allowing a lot of code re-use. The problem is just ensuring that none of the "HTTP'ness" of the controllers sneaks into your logic classes, as these must be usable in a console or winforms application. So you have to be pretty strict and wrap a lot of things like HTTPSession or HTTPContext into interfaces that can then have non HTTP implementations..
Well, I understand your situation and also tends to a DDD (Domain Driven Design) solution as #MystereMan suggests.
I have an approach that sepparates the "Models" in 3 categories:
ViewModels: Have all the information necessary to display content data in the UI
RequestModels: Have all the information necesssary to send data, post/get/etc.)
AutoBindModels: Have all the information that is injected my MVC binding model (cookies, sessions, etc..)
And the most important, for all that classes I use as DTO/POCO's, actually they have no UI dependent code just properties/calculated properties and could be easily in any other project to be referenced by an UI project.
You could also create a Controller class that act as a Service outside ASP.MVC project and extend or inject it in your MVC controller.
Hope it helps...
I never reuse (Edit)ViewModels objects (this is not entirely true, I often share one EditViewModel between Create and Update but not always).
I design my ViewModels for specific Views. Therefore, I don't have to compromise my ViewModels when the UI changes (it changes all the time).
I take this as far as creating two distinct ViewModels even if they are identical. I'm done refactoring shared ViewModels..
I would answer yes to your question.
Hope it helps.
OrderEditViewModel and OrderViewModel are both 'ViewModels' end of the day. IMO, they may stay together in the same project even in your same 'ViewModels' folder. You may though create a sub folder under ViewModels for your 'EditViewModels'.
Now as you want to clean/tidy up the controller actions, you may want to use AutoMapper or ValueInjecter. You are mapping domain entity and view models manually. That is a tiresome job. With AutoMapper you can do something like:
var customerInfo = Mapper.Map<CustomerViewModel, CustomerInfo>(customerViewModel);

Model layer dependency on MVC attributes

We have an MVC3 project that uses nHibernate; there is a separate model project that contains all the model classes which is used by the repository and service layers. The models make use of data annotations like DisplayAttribute and RequiredAttribute from System.ComponentModel.DataAnnotations.
There are also attributes such as RemoteAttribute that are contained in System.Web.Mvc.
This of course means that the model project now has a dependency to a particular front end technology.
Assuming the solution could have other front ends what would be the best way to handle this dependency link?
RemoteAttribute does not belong in the model, since it specifies a controller/action to validate the property on the server, and the model shouldn't have knowledge of concepts like controller, action or route. The presentation layer depends on the model, not the other way around.
I would create a view model that inherits the model, overrides the property (must be virtual) and adds the RemoteAttribute. This way you can avoid duplication and mapping, although that's also an alternative.
To reduce dependency between database model and frontend technology, you can use special view model for validation qnd other front end actions in controller and put data from viewmodel to database entity after it.

how to do Localization for one of the #Model property in mvc3

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

How to implement a custom view engine in ASP.Net MVC that (sorta) isn't file-based?

I've created a fairly generic view engine that I created initially without aiming toward ASP.Net MVC. Now though, I think it would be a good idea to have it to where it can at least be easily used by MVC projects. I'm wondering if my project would map well to the ASP.Net MVC style though.
The problem I'm having is that my view engine generates everything at compile-time via T4 templates. This means that everything is statically typed for the most part. Most of MVC seems to be a bit loosely typed however.
So for some view you might have this code generated:
class MyView{
public string Foo{get;set;}
public int Bar{get;set;}
public string Render(){
return "This is my view: "+Foo+(string)Bar;
}
}
And because of how it works, even if there is a views/FooView.html file, it may get processed into a class named MyView.
So how exactly is the best way to assign ViewData to say Foo and Bar of MyView? Should I just impose the limitation that you can only use a single field in the views(basically being a ViewData) or?
The other major problem I see is that MVC is almost completely file based. When you say RenderView("MyView",data); it will look in /views/ for a file named MyView.aspx or whatever(you can change where it looks and the file extension of course). The problem is that MyView could have been compiled from a file named FooView.html. Should I basically just generate a huge list for every view available with their mappings from class name to filesystem name? Or is there a better way?
Note: Because I generate all the views(and possibly could generate the MVC view engine) from a T4 template, this means I could write huge lists and other extremely tedious or bad code. But I feel like there is a better way than a huge list in this case, and that there will be underlying problems with only keeping a list.
You may extend my T4 based view engine to create your class file from your model, compile it in memory and cache it, and pass your view model to the compiled assembly via reflection.
http://mvct4viewengine.codeplex.com/

Changing ASP.Net MVC directory structure

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.

Resources