Inconsistent behavior in HtmlHelper methods retrieving model metadata - c#

I’m tracing down an unexpected behavior in MVC3, having to do with how it gets model metadata.
I had previously talked to one of my developers about using the same EditorTemplate for some data which is collected in two different areas of the system. The data fields are almost identical, except for the [Required] attribute. In one page certain fields are required, in the other page they are not. Theoretically this can be accomplished by using a base model which has the common attributes on each field, and inheriting those models, overriding the properties and adding additional validation attributes. For example:
class BaseModel
{
[Display(Name=”My Label”)]
public virtual string MyLabel { get; set ;}
}
class RequiredModel : BaseModel
{
[Required]
public override string MyLabel { get; set ;}
}
Then the View can be strongly typed to BaseModel, and calls to #Html.EditorFor(m=>m.MyLabel) in the view should pick up the correct attributes, depending on whether the actual instance of the model is a BaseModel or RequiredModel.
That’s the theory.
And in fact, it works well if you use the “old” HTML helper, e.g. #Html.TextBox(“MyLabel”). Those call ModelMetadata.FromStringExpression(field), which correctly gets the metadata from RequiredModel if the concrete model instance is RequiredModel. The newer helper methods call ModelMetadata.FromLambdaExpression(expression), which does NOT correctly get the metadata from the correct concrete instance.
Is this a bug in MVC? Intentional behavior? Is there a workaround, or a better way to address this problem?
This is of course a trivial example, the actual code we're dealing with has about 20 fields with some complex business rules and interaction, which is the same on both pages EXCEPT for which fields are required.

That's the theory.
No, that's not the theory. At least not mine.
My theory is to use separate view models for each views because the requirements of your views are different. So you would have this:
public class UpdateViewModel
{
[Display(Name = "My Label")]
public string MyLabel { get; set ;}
}
and:
public class CreateViewModel
{
[Display(Name = "My Label")]
[Required]
public string MyLabel { get; set ;}
}
Personally that's what I would do. I would totally sacrify DRY into designing view models because the requirements of my view change often and I want to have total control.
Obviously in practice I don't even bother with doing validation using declarative DataAnnotations attributes. They limit me. I use FluentValidation.NET which addresses problems like yours in a pretty elegant manner (by simply defining two different validators for the same view model - in case you decide to violate my theory and use the same view model in different views).
Now feel free to downvote my answer. I have just given my 2¢.

Related

Viewmodels vs Domain models vs entities [duplicate]

When I use Web (MVC), I always to create a separate classes layer. These classes often the same as DTO classes, but with attributes like [Display(Name = "Street")] and validation. But for web api Display attributes are not necessary, validation can be used by FluentValidation. Should Api controller returns ViewModels classes or DTO classes will be fine too?
the answer, as always is .... it depends.
If your API is serving multiple clients , apps etc, then returning DTOs is a better options.
ViewModels are specific to the MVC client and should already be prepared for display, meaning the data should already be formatted in a specific way, some fields maybe combined, they should satisfy whatever requirements the display pages have. They are called ViewNodels for a reason. The point is that they are rarely exactly the same as the data the API returns, which should be a bit more generic and follow a certain pattern to make sense to its users.
If your ViewModels are exactly the same and you only have one client then it's up to you if you want to create a set of duplicated classed just to avoid having the attributes.
Mapping from DTO to ViewModel and viceversa is not exactly complicated, but the process does introduce one more complication, one more layer.
Don't forget one thing though. API DTOs are supposed to return the data they have on any entity regardless of the requirements of any UI. Requirements can change anyway, new fields added or discarded. You're more than likely to leave the API alone when that happens and simply change your ViewModels.
Your ViewModels are specific to a UI page and should contain only the data required by that page. This means that you can end up with multiple ViewModels for the same data, it's just that the display requirements are different for each.
My vote goes towards keeping the ViewModels and DTOs separate, even if, at this point in time they are exactly the same. Thins always change and this is one of those things you can actually be ready for.
Actually it depends on application's architecture how we want to return response. In this case yes we can return DTO classes but i think that would not be the good approach because we should create a separate Resource classes that will map with DTO and then return. Just see the below example:
public class CustomerDTO
{
public int ID { get; set; }
public string Name { get; set; }
public int DepartmentId { get; set; }
}
public class CustomerResource
{
[JsonObject]
public string Name { get; set; }
[JsonObject]
public string Department { get; set; }
}
Suppose we have CustomerDTO class and we want to return response in the following json format
{
"name":"Abc xyz",
"department":"Testing"
}
So in this case we should we have separate class that will return as a response to the end user as i created CustomerResource. In this scenario we will create a mapper that will map DTO with resource object.
And also with this implementation we can test resources independently

Best Practice for Binding ItemsControl in MVVM

What is the best practice for binding a list of items to an ItemsControl when using the MVVM pattern?
1. Bind a list of ViewModels
Load the items from the database, create the models and all viewmodels and then bind a list of viewmodels to the ItemsControl.ItemsSource:
public class MyMainViewModel
{
public List<PersonViewModel> Persons { get; set; }
}
2. Bind a list of Models
Load the items from the database, create the models and then bind a list of those models directly to the ItemsControl.ItemsSource:
public class MyMainViewModel
{
public List<Person> Persons { get; set; }
}
I think the answer here is really it depends.
Firstly, you need to assess whether your view needs to interact with your model in such a way that it would make sense for a view model to be wrapped around a particular model. Let's look at an example:
public class WebsiteModel
{
public string URL { get; set; }
}
Here I have a very simple model which represents a website, nothing too fancy. I can create a view model which will encompass all websites, like a one to many relationship:
public class WebsitesViewModel
{
//A list of websites.
public List<WebsiteModel> Websites { get; set; }
//The command I will use to navigate, where the object parameter will be the WebsiteModel.
public ICommand NavigateCommand { get; set; }
...
public void Navigate(WebsiteModel model)
{
...
}
Here I want my view to be able to navigate to the URL using the browser. My view model holds a list of models and my command takes care of navigation.
The next method I can create a view model to represent a single model, I would say this is a SOLID approach:
public class WebsiteViewModel
{
//The website model
public WebsiteModel Website { get; set; }
//The command I will use to navigate, no parameters needed.
public ICommand NavigateCommand { get; set; }
...
public void Navigate()
{
...
}
In this scenario, I'll need another view model which will expose a list of WebsiteViewModel to my view.
public List<WebsiteViewModel> Websites { get; set; }
The truth is there isn't really a best practice. Neither method really trumps the other. There are benefits to each method, however the method to choose really depends on the implementation. In this scenario, method 2, I would say is overcomplicated. However it's not uncommon for a view model to become very large very quickly, and the need to separate concerns will force you to create smaller classes, and even view models to wrap your models inside, making method 2 a viable option.
So to wrap up. Neither method is best practice.
The only "correct" way to do it, is to use ViewModels all the way.
While initially more work, it gives you more flexibility and less bugs later on.
Don't for get, when you a model should only be valid in it's bounded context and when you bind your ViewModel to the view, you have a leaky abstraction. The View becomes aware of model and each change to the model, will affect your View.
Further more, refactoring doesn't work within XAML. So if you name a model property via refactoring, your XAML will still bind to the old property. This doesn't give you a compile error and your bounded element will just remain empty (in best case) or crash (in worst case).
This can be quite hard to figure out and fix. Also as Scroog1 commented, it introduces memory leaks. May not be noticeable in small applications, but ones working with big data sets it can lead to out of memory exceptions.
You should utilize an automapping library to map from Model to ViewModel in cases that allows it, this will reduce some boilerplate code. But remember to avoid ViewModel to Model automappings, as it's discouraged.
You want to avoid that a change in your model influences code in a different bounded context, i.e. you don't want to expose every database or model change in a rest service, even if the change do not influence the given rest action.
The same strategy can be applied to the n-layer model (View, ViewModel, (Domain) Model layer, Services and Infrastructure)
I think there is no correct way, using models is the pragmatic and simpler way, using view models is more time consuming but more decoupled...
You should have a look at this article:
http://blog.alner.net/archive/2010/02/09/mvvm-to-wrap-or-not-to-wrap.aspx
also: http://www.codeproject.com/Articles/61147/MVVM-Creating-ViewModel-Wrap-your-business-object

ASP.NET MVC: Custom Validation by DataAnnotation depending on configuration

I'm using DataAnnotation for client and server validation of my view model. I would like to ask you about the best practices of using custom validation.
I have two forms, which use the same view model:
public class RecipientViewModel
{
[Required]
public string Address1 { get; set; }
public string Address2 { get; set; }
}
What I want to achieve, it is that the first form should validate the Address2 field, but the second form did not. Of course my view model is much bigger and I want to do it generic as much as possible.
Is there any possibility to pass a list of fields to be validated and how? For example view could pass it to view model somehow?
Please clarify your question or show more code.
In general the Annotations are very good to check expected structures or a certain kind of expected data. Like length, presence, type.
For other more complicated, complex business cases. Good implementation will have a business layer or a domain design which handles these use cases.
So define your use cases and think about an layer between controller and data model. Maybe something like a validation Services which gets injected into the viewmodel.
HTH
EDIT: You probably want to take a look at - Validating with a Service Layer from the ASP.NET site - http://www.asp.net/mvc/overview/older-versions-1/models-(data)/validating-with-a-service-layer-cs] which shows some of the conepts - the technology might have changed slightly since the article is from 2009 but you got the idea.

Change name the For helper methods create

I am making a form with MVC and am using the [ControlType]For([expression]) helper methods (EG Html.TextBoxFor(...))
To bind the data to the controls I am using the following ViewModel:
public class UserViewModel
{
//The Model that will be used to bind data to the elements
public UserModel User { get; set; }
//Used to bind selectable options to DropDownLists
public SelectList DescentTypes { get; set; }
public SelectList GenderTypes { get; set; }
}
When using this the name of the controls get set to name="Property.SubProperty" (EG name="User.Id") but I would rather it show as name="Id" on my html form.
Is it possible to do this without having to write a lot of custom code so the framework can translate it back to the ViewModel (UserViewModel) or just the Model (User) itself?
I'd advise leaving the default naming in place unless you have a very good reason to alter it. IDs (which it appears your question is leaning towards) are more flexible.
Changing IDs
IDs aren't submitted with a form, so you can set them as desired without breaking model binding. By default, they are hierarchical, but you can override them inline:
#Html.TextBoxFor( o => o.UserName, new { id = "foo" } )
Of course, this is manual work.
If the big concern is external JS/CSS, I'd suggest using class names and data-* attributes in your (CSS/jQuery/whatever) selectors rather than IDs.
#Html.TextBoxFor( o => o.User.UserName, new { data_role="grand-total" } )
It's still manual, but it's descriptive and independent of an ID.
Sometimes I use a snippet of script in my views to initialize a larger JS class with data that is most easily available directly within the view. This lets the bulk of the script reside in an external file while allowing dynamic values to be used to initialize it. This is useful for more than just IDs.
Altering Generated Markup and Binding
For reference, let's say you wanted to change ID and name.
Write your own HtmlHelper extension methods to create the markup you want. You could probably wrap the existing methods that do not take an expression and pass explicit values to them to indicate the name that you want.
Write your own ModelBinder to map the raw form collection.
Determine a strategy for dealing with hierarchical objects (which is the main reason the naming convention exists in the first place).
Item #3 could be addressed by decorating properties to indicate how the naming should be performed and how model binding should map. This could become complicated quickly.
public class UserViewModel
{
// use this metadata to determine how to handle properties on this member
[Flatten]
public UserModel User { get; set; }
public SelectList DescentTypes { get; set; }
public SelectList GenderTypes { get; set; }
}
Alternatives
Flatten your view model by adding User's properties directly to it. It looks like your are composing your view model from domain model(s). This isn't usually a good idea. I'd suggest reading the pros/cons of binding directly to domain models.
Leave the naming alone. It really isn't hurting anything and it makes life easy. You can avoid ever directly working with names/IDs in your client code by using helper methods.
For example:
// JavaScript + Razor
var name = "#Html.NameFor( o => o.User.Id )";
alert(name);

ASP.NET MVC: Populating Derived Strongly Typed View with Base Strongly Typed View

In my application I have different pages: Contact Us, About Us, Home
They all have the same base elements that needs to populate the view:
Page Title
Meta Description
User Information
However on each page, they have some elements that are different:
Contact Us
Contact Information Model
Contact Form Model
About Us
Extended User Information Model
Home
Home Page Text Property
They are all routed to the same Controller Action Method because most of the functionality is similar other than populating the "extra" information dependent on page type.
So far I have done something where:
PageDetailViewData pageDetailViewData = new PageDetailViewData {Title = title, Desc = desc....}
and following this I have:
switch ((PageType)page.PageType)
{
case (PageType.Contact):
return View("ContactUsDetails", pageDetailViewData);
default:
return View(pageDetailViewData);
}
The question is how do I populate the "extra" information? I am not sure if I am going about doing this the right way. Any insight to better structure the logic flow would be appreciated.
The answer of using interfaces to imply some commonality between your view models is certainly going to help to answer some of the points in your questions.
I would however ask how wise it is to "refactor" your Action to support multiple views of differing data structures.
MVC controller actions typically represent the minimum amount of code required to gather the specific data required to generate the intended view. It's not completely uncommon for a single action to return different views of the same model data (Html view or Mobile view for example) but by varying both the structure of the data and view that will generated you introduce a few problems.
In particular you violate common best practices like the Single Responsibility Principle and make your code much more complicated to test - and Pain free testing and TDD are part of the big win with ASP.Net MVC after all.
Personally I would have a separate Action.
As far as your view models are concerned, how would you do it if this was a database?
You would have separate queries for separate data right?
A user's profile information would be queried separately from the page meta data information. This would be done for a number of reasons that could include the ability to cache certain parts of the data but not others for example.
So with the above suggestions your code might look like this (Warning: this code wasn't written in Visual Studio and is probably full of syntax issues):
public interface IMetaDataViewModel
{
PageMetaData MetaData{get; set;}
}
public class HomeViewModel : IMetaDataViewModel
{
public PageMetaData MetaData{get; set;}
public string HomePageText{get; set;}
}
//other view models go here....
public class CommonPagesController : Controller
{
private MetaDataProvider _metaProvider = new MetaDataProvider();
private PageDataProvider _pageDataProvider = new PageDataProvider();
private ContactDataProvider _contactDataProvider = new ContactDataProvider();
public ActionResult Home()
{
var viewModel = new HomeViewModel
{
MetaData = _metaProvider.GetPageMeta();
HomePageText = _pageDataProvider.GetPageData();
};
return View(viewModel);
}
public ActionResult Contact()
{
var viewModel = new ContactViewModel
{
MetaData = _metaProvider.GetPageMeta();
ContactFormData = _contactDataProvider.GetData();
};
return View(viewModel);
}
//you get the picture...
}
There are several ways you could also refactor out the generation of the view model code but thats one possible pattern.
I appreciate that this answer does have a certain amount of opinion in it but I would consider having separate actions to be best practice.
Hope that helps.
The title of your question almost gives you the answer. You can use some form of polymorphism to accomplish this. You could define a base class with the shared properties, or alternatively an interface like this:
public interface ICommonPage
{
string Title { get; }
string MetaDescription { get; }
string UserInformation { get; }
}
Then define three strongly typed ViewModel classes that all implement this interface (or derive from the base class):
ContactUsViewModel : ICommonPage
AboutUsViewModel : ICommonPage
HomeViewModel : ICommonPage
On each of those ViewModel classes, you add the extra properties that you need for those Views.
In your Controller Action, you will need to switch on PageType to select the correct ViewModel and populate it with data.
You will also need to creat three different Views (.aspx) that are strongly typed to each ViewModel class.
If you have shared rendering for the common data, you can extract that into a strongly typed UserControl (.ascx) that is typed to ICommonPage.

Categories

Resources