Different content for each vendor - c#

I am building a site that displays forms for different vendors.
Each vendor have some common properties, but there are some properties specific to some vendors. For instance one vendor asks for customer's Title (ie Mr, Mrs...) while others don't.
Even more, some of the properties may have different behavior. In the Title example above, one vendor could have it as a free text, while another would have it as an option select.
For this, i have a base class as a model, that holds the most common properties, and for each vendor i will create classes inheriting from the base to add the vendor specific properties, or change their behavior (like adding Data Annotations).
So, i would like to create forms specific to each vendor. What i have done and it really works, is create the generic one in the standard Views, Models, Controllers folders and each Vendor will have his own Area.
Is this really the right approach? I have seen that areas are mostly for mini sites or for localization.
Any opinion would be appreciated.

I'd say your using the wrong tool for the job here (i.e. Areas), however, you aren't far off.
Instead of using a separate area, all you need to do here is introduce separate views per "vendor" type. You could create a base view and have each specific view inherit from that. In fact, you could probably get away with a single view e.g.
public class VendorViewModel
{
...
public CustomerViewModel Customer { get; set; }
}
public class CustomerViewModel
{
public string Title { get; set; }
public IEnumerable<string> TitleOptions { get; set; }
...
}
Given the above model, your view could look like
#model VendorViewModel
...
#if (Model.Customer != null)
{
// make title selection configurable
#if (Model.Customer.TitleOptions != null)
{
#Html.DropDownListFor(m => m.Customer.Title, new SelectList(m.Customer.TitleOptions, "[Select title]"))
}
else
{
#Html.EditorFor(m => m.Customer.Title)
}
...
}
This effectively builds your view based on a particular vendors requirements e.g.
Leave the Customer property null if you don't need to capture customer info
Leave the TitleOptions property null if you want to have free-form text entry for title
This is just a simple example of how you can build up your view dynamically, and all in a single view. You could tidy it up a little by moving the customer view stuff into it's own partial view and only rendering that if required e.g.
#if (Model.Customer != null)
{
#Html.RenderPartial("CustomerView", Model.Customer)
}

Related

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

Two concurrent views with one ViewModel

I'm getting mixed answers reading through other posts, but say I have one main ViewModel, which handles two related data models
public partial class Product
{
public string ProductName { get; set; }
public int TemplateID { get; set; }
public virtual Template Template { get; set; }
}
public Template()
{
this.Products = new ObservableCollection<Product>();
}
public int TemplateID { get; set; }
public string TemplateName { get; set; }
public virtual ObservableCollection<Product> Products { get; set; }
}
Currently, have two separate Views and ViewModels, one that shows all data "byTemplates" and another that shows all the data "byProducts". Both allow CRUD operations. In order to get rid of duplicate codes and commands, I want to merge these two views into one.
Would I still require two ViewModels? Can I have both working off the same data instance? (so if I went and inserted something under the "ByTemplates" view, and switch to "ByProducts" before saving to the database, I'd still see all the changes I have?
EDIT:
I'm currently using tabs to faciliate this.
My views are here:
By Product Tab
By Templates Tab (user can select a Template, and the "Associated Products" ListView will show all prodcucts linked to "template")
What you are saying is pretty much possible, viewmodel can contain multiple models combined together acting as one parent viewmodel and it is up to view which all properties that it is interested in binding with.
Having two separate views or not is a design discussion but it is not mandatory. Neither having one viewmodel per model is required. Purpose of having view model is to get rid of direct dependency on a particular business model and merge and mold data according to UI needs. So yes you can do what you intend to do.
Please share detail xaml and existing model/viewmodel if you want in depth how to do, else you are all set.
I would tend to use a single viewmodel where both views are interconnected. An example being detail and summary view of the same data perhaps.
In the scenario you describe, if both views are leveraging the same data and methods then sure, keep them as one viewmodel. If however you are parametising each command to work on a subset then it sounds as though seperation will be better - I would look to do this by base classing the common elements to improve reuse and maintenance and then extend into specific viewmodels for each subset. That also offers better extensions later.

How to handle actions from different parts complex ViewModels in ASP.NET MVC

I have a complex form, with hierarchy of view models and I am wondering how to structure the code so that my controller will not contain handlers for all actions.
Here is a simplified example:
with the corresponding ViewModel:
public class MyPageViewModel
{
public List<TabViewModel> Tabs {get; set; }
public CustomerViewModel Customer;
}
public class TabViewModel
{
public string DisplayLabel { get; set; }
public bool Selected { get; set; }
}
class CustomerViewModel
{
public string FirstName { get; set; }
public string LastName { get; set; }
public List<Address> Addresses { get; set; }
}
public class Address
{
public string Street { get; set; }
public string City { get; set; }
}
I do know how to separate rendering of each part of the page in separate components: I am using #Html.EditorFor and #Html.DisplayFor and have a separate view for each part of the model (indicated by the red rectangles on the picture above). This works quite nice. Parts of the ViewModel (for example TabViewModel class) can also be re-used on other pages.
I am having problems with event handling logic. There are quite few actions that can be performed on this page (indicated with blue background). One possibility would be to use multiple FORM tags – each for one red rectangle on picture above. Each form would have a different action URL and would be handled by a different controller. But when using this approach, I could lose same data. For example: if the user changes First Name and then hits the Remove Address button the First Name would not be POSTed back to the server and the change would be lost.
This leaves me with one form for the whole page. That means that all actions should be processed by a single controller class. I really do not like this approach, because:
I’ll end up with big, fat controller containing action handling code for all buttons
Or I’ll have a big switch statement within my controller, which would identify the action, locate separate class, that know how to handle the action and then delegate the processing to it (yuck! This sound like writing windows messages event handling code in 1990s – WindowProc)
I’ve read about Html.ActionFor which enables you to call a separate controller from a View, but I do not think this is good approach either (it happens while view is being rendered, which is not OK).
So, to sum up, here’s the question again: Is there a way to handle the actions/events triggered from different parts of complex view model in such a way that I will not end up with a mess in my controller? What are the best practices for a real-life applications (not 101 CRUD examples that are generated by Visual studio scaffolding )
UPDATE: Please note that this is just a simplified example - in the reality, the view model is much more complex and there are many more actions, that can be performed. I am asking about a general approach for structuring the code in controller (or moving it to separate classes) in ASP.NET MVC application. The WebForms provided user controls, which enabled us to encapsulate both the View part (ASCX) and the event handlers. MVC has a good solution for encapsulating the views and I am trying to find the right way to structure the logic/event handlers.
I would add a "Save" button for the customer data fieldset and save/post all of the customer data when the user hits the Save button. This way on your Edit Post Action you will only use CustomerViewModel.
"Add new address" and "Remove this address" will add and remove the html needed for Address with javascript.
"Search for existing customer" and "Select from external DB" can show a pop up with data needed for their respectful sections in the form. Use Ajax to get the data.
This way you will have a simple Edit Post Action for the CustomerData fieldset, 2 Actions for displaying the data in in pop ups, and some javascript for manipulating the addresses section.

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