Forgive the vague title, I wasn't sure how to describe it.
If you have a generic model "Archive", how do you show different views/forms based on a user selected 'type'?
For example, the user creates a new "Archive", then gets the choice of video, book, audio etc. From there they get different forms based on the archive type.
Or would it be better to split them into different models - Video, Book, Audio?
Or can models inherit (like Video extends Archive). I guess this is basic OOP / classes, but have no idea how to apply that here.
Examples from any MVC framework are welcome!
Seems like you would not want to have the type inherit from Archive.
"Always favor encapsulation/containment over inheritance".
Why not create a class called Archive and give it a type property. The type can use inheritance to specialize for Audio, Video, etc.
It would seem that you would specialize Archive based on some other criteria. "FileSystemArchivce", "XMLArchive", "SQLArchive" and the type would not change. But the agilist in me says that this may not be necesscary at first, and you can always refactor the design later...
In terms of a controller, you probably get the biggest bang for the buck by encapsulating the differences of presentation for each type in the view. So only the view changes based on the type. Likely the semantics and rules for each one are the same and you would not need to have seperate controllers for each type. The views will be different for each type as it will have different attributes.
To actually show a different view should be easy in any MVC framework. For example, in Microsoft ASP.NET MVC you would not just return a view from a controller like the following:
return View();
but would actually state the name of the view as a parameter:
return View("VideoArchive");
which would then show the view from Views/Archive/VideoArchive.aspx
Your models Video, Book and Audio can inherit from Archive.
And each model will have a controller.
http://yourserver/Books/Edit/11
You will have to get your user to pick the type of archive they want before you create the corresponding model.
EDIT (in response to comment)
In ASP.NET MVC your model will be a class.
public class Video : Archive
{
public int Id {get;set}
public string Name {get;set;}
...
}
You will also have a controller
public class VideoController : Controller
{
public object Edit(int id)
{
Video myVideo = GetVideo(id);
return View("Edit", myVideo);
}
...
}
And you will have a view in the Views directory for example, the page which contains
public class Edit : View<Video>
{
...
}
So you can call this if you had a URL which was
http://localhost/Video/Edit/11
This was all done from memory, so there may be some mistakes, but the take-home message is that you specify the inheritance at the model. The model is just a class. In your case you want to inherit from Archive. Once you've done that the model is pass around as normal.
The Single Responsibility Principle (PDF) states that:
THERE SHOULD NEVER BE MORE THAN ONE REASON FOR A CLASS TO CHANGE.
Your Archive class violates this principle by handling multiple different types of archives. For example, if you need to update the video archive, you are also modifying the class that handles book and audio archives.
The appropriate way to handle this is to create separate classes for each different type of archive. These types should implement a common interface (or inherit a common base class) so that they can be treated interchangeably (polymorphically) by code that only cares about Archives, not specific archive types.
Once you have that class hierarchy in place, you just need a single controller and view for each model class.
For bonus points, the Single Responsibility Principle can even justify using a factory method or abstract factory for creating your model, view and controller objects (rather than new-ing them up inline). After all, creating an object and using that object are different responsibilities, which might need to be changed for different reasons.
Seems to me that one solid point in favor of MVC is that you may not need to customize the model (or the controller - of which you want only one) if all the user needs is a different view. Multiple models would appear only if the storage (persistence) architecture dictated a need for it. Some feature like data access objects (DAO) would potentially appear as another tier, between the controller and the model,should you require multiple models.
Take a look at the Apache Struts project for examples. As stated in Struts for Newbies, "To use Struts well, it's important to have a good grasp of the fundamentals. Start by reviewing the Key Technologies primer, and studying any unfamiliar topics."
For another resource, see Web-Tier Application Framework Design (Sun J2EE Blueprints)
Related
This question really has larger architectural implications and I welcome any input or suggestions on this:
I'm more of the Martin Fowler school of thought when it comes to OOP. I believe you should be able to directly render domain entities in the UI. If I have a Car entity, I should be able to render it to a webpage. The domain model is a crosscutting concern and not a layer. Treating the domain model as a layer leads to an anemic domain model. I don't believe in DTOs in an OOP architecture.
A view model for me is a way of composing the domain entities required in your view. It's not a DTO. I don't understand what the reasoning behind using a view model like DTO is though it seems like a common thing to do using automapper?
So using the metadata approach I put data annotations on my domain model to give any UI implementation hints on how to render and validate the entities. I like to have a richER domain model.
In MVC3 how can you accomplish this (specifically using the Display data annotation) with a resource file that resides in the UI layer? Is there a native implementation for this or do I need to get creative myself? Or have I gone wrong somewhere in my approach?
I disagree.
For one thing, some of the attributes you will use to specify how an entity property should be displayed on a web page come from the System.Web namespace, not the System.ComponentModel.DataAnnotations namespace. By putting these attributes on properties in your domain model, your domain model is taking a dependency on System.Web. For example, there is the [HiddenInput] attribute that tells MVC3 to render a field as input type="hidden". This is not in System.CompoenentModel.DataAnnotations.
Secondly, I don't believe you need data annotation attributes on your entity properties to have a rich domain model. A rich domain model comes from classes that wrap knowledge in a context. The client application should not need to know anything about the domain in order to use it. You achieve a rich domain model with classes, methods, and properties that describe knowledge using the ubiquitous language. DataAnnotations attributes don't lend themselves well to the ubiquitous language imo. And, your domain is more than just your entities. There are factories, services, and other patterns that you can use to build a rich domain model. A domain with only entities and metadata sounds anemic to me.
Thirdly, you may have an entity that should be rendered in different ways on your web site. When someone searches for a car, you may want to display just the make, model, year, and thumbnail photo. When someone clicks on the search result, you may want to display multiple photos, reviews, etc. If you were to use the UIHint attribute on an entity to tell the web ui how to render the car, you wouldn't be able to have different strategies for rendering the Car in different contexts.
Finally, yes, automapper is really great for DTOing your entities into viewmodels. It essentially lets you populate copies of the entity, disconnected from the domain, targeted for specific UI concerns. Here it is safe to use HiddenInput and UIHint attributes to tell MVC3 how to render data.
Response to comment 1
As far as UIHint, I mentioned it here because it has a special meaning with MVC3 EditorTemplates. In cases where a partial view involves receiving input, what is the composition of the view? Text fields, drop-down lists, and input elements that often correspond to entities and their properties in some aggregate root. You will therefore need some representation of the entities to encapsulate the data. Your DTO can be an aggregate root as well, with depth. You can have a root DTO with scalar properties (text/date/bool), navigation properties (drop-down list) and collection properties (ul/ol/table).
We create a corresponding viewmodels for many entities in an aggregate root, and implement them as views using EditorTemplates. If we ever want to switch to a different EditorTemplate, we can apply UIHint to a viewmodel property. Thus we can tell it to "render a location dto as a google map". Automapper can map navigational and collection properties to corresponding viewmodels, forming as complex a representation of your domain entities as you need for the user.
Forgive me if I misunderstand what you mean by flat dto.
Response to comment 2
A viewmodel dto can flatten out / denormalize some properties (using automapper), if your requirements call for it. For example, consider a University entity. It may have many names in many languages (translations), hinting at a UniversityName entity in the aggregate, with University having a collection of Names (1..n). Of those names, 1 may represent the OfficialName / NativeName, and another may represent the TranslatedName to the user's CurrentUICulture. Other entities in the collection may represent TranslatedNames that the user does not understand, and need not be bothered with.
If you have a view that is only interested in these 2 Names in the collection, you can promote them to first-class properties on the viewmodel:
public class UniversityViewModel
{
public string OfficialName { get; set; }
public string TranslatedName { get; set; }
// ...other properties
}
This is a case where denormalizing part of the entity when converting to a viewmodel dto can make sense. Notice how the viewmodel is anemic -- a bare container for data transfer from a controller to a view. This is perfectly fine, and in fact, encouraged.
Answer to original question
To answer your original question, it helps if you think of your domain model & entities as a layer -- more specifically, a bottom layer. Layered software is easier to understand if you think about the various concerns in an application as having dependencies on other concerns. MVC3 is a presentation / UI layer, and will have dependencies on the layers beneath it -- one of those being your domain layer.
If you want to access a resource file in the UI from the domain layer, you are going in the opposite direction. You would be making a low layer depend on a higher layer. If your domain lib depends on the UI lib for a resource, and the UI lib depends on the domain for entities, you end up with a circular dependency. I think you could probably accomplish it using reflection if you needed to, but in that case, you would be fighting against the framework. MVC and .NET in general may not be the best choice for you if that is the case.
I actually think of resource files as a cross-cutting concern. Our application has i18n sprinkled throughout, and often we find we need the same language text resources in both the domain and the UI.
There is nothing wrong with putting a Display attribute on an entity. But if you want to use resources for it, then either put that resource in the domain layer, or if you feel it doesn't belong there, in a lower layer. That way it can be accessed by both the domain and the UI.
So I ended up putting a resourse file in the domain model and added a custom HiddenFieldAttribute so that I don't have to reference the MVC assembly in the domain model.
I still fundamentally dissagree that a view model is really a DTO and that the domain model should be constructed as a layer. I feel that architecting the application in this way creates abstractions that really have no value. If the domain model was truly a layer then we would build a set of logical interfaces from which to access it, and this we don't do. It's a cross cutting concern.
Thanks to olivehour for an interesting discussion and suggesting that it's okay to place resource file(s) in to domain model assembly.
If you follow the quickstart guide provided by the official Model-Glue docs, found here:
http://docs.model-glue.com/wiki/QuickStart/2%3AModellingourApplication#Quickstart2:ModelingourApplication
It will seem like the "model" is a class that performs an application operation. In this example, they created a Translator class that will translate a phrase into Pig Latin. It's easy to infer from here that the program logic should also be "models", such as database operation classes and HTML helpers.
However, I recently received an answer for a question I asked here about MVC:
Using MVC, how do I design the view so that it does not require knowledge of the variables being set by the controller?
In one of the answers, it was mentioned that the "model" in MVC should be an object that the controller populates with data, which is then passed to the view, and the view uses it as a strongly-typed object to render the data. This means that, for the Model-Glue example provided above, there should've been a translator controller, a translator view, a PigLatinTranslator class, and a Translation model that looks like this:
component Translation
{
var TranslatedPhrase = "";
}
This controller will use it like this:
component TranslatorController
{
public function Translate(string phrase)
{
var translator = new PigLatinTranslator();
var translation = new Translation();
translation.TranslatedPhrase = translator.Translate(phrase);
event.setValue("translation", translation);
}
}
And the view will render it like this:
<p>Your translated phrase was: #event.getValue("translation").TranslatedPhrase#</p>
In this case, the PigLatinTranslator is merely a class that resides somewhere, and cannot be considered a model, controller, or a view.
My question is, is ColdFusion Model-Glue's model different than a MVC model? Or is the quickstart guide they provided a poor example of MVC, and the code I listed above the correct way of doing it? Or am I completely off course on all of this?
I think perhaps you're getting bogged down in the specifics of implementation.
My understanding of (general) MVC is as follows:
some work is needing to be done
the controller defines how that work is done, and how it is presented
the controller [does something] that ultimately invokes model processing to take place
the model processes handle all data processing: getting data from [somewhere], applying business logic, then putting the results [somewhere]
the controller then [does something] that ultimately invokes view processing to take place, and avails the view processing system of the data from the model
the view processes grab the data they're expecting and presents that data some how.
That's purposely very abstract.
I think the example in the MG docs implement this appropriately, although the example is pretty contrived. The controller calls the model which processes the data (an input is converted into an output), and then sets the result. The controller then calls the view which takes the data and displays it.
I disagree with the premise of this question "Using MVC, how do I design the view so that it does not require knowledge of the variables being set by the controller?" The view should not care where the data comes from, it should just know what data it needs, and grab it from [somewhere]. There does need to be a convention in the system somewhere that the model puts the data to be used somewhere, and the view gets the data it needs from somewhere (otherwise how would it possibly work?); the decoupling is that model just puts the data where it's been told, and the view just gets the data out from where it's been told. The controller (or the convention of the MVC system in use) dictates how that is implemented. I don't think MG is breaking any principles of MVC in the way it handles this.
As far as this statement goes "In this case, the PigLatinTranslator is merely a class that resides somewhere, and cannot be considered a model, controller, or a view." Well... yeah... all a model IS is some code. So PigLatinTranslator.cfc models the business logic here.
And this one: "In one of the answers, it was mentioned that the "model" in MVC should be an object that the controller populates with data, which is then passed to the view"... I don't think that is correct. The controller just wrangles which models and which views need to be called to fulfil the requirement, and possible interchanges data between them (although this could be done by convention, too). The controller doesn't do data processing; it decides which data processing needs to be done.
Lastly, I don't think the "strongly-typed" commentary is relevant or an apporpriate consideration in a CF environment because CF is not strongly typed. That is a platform-specific consideration, and nothing to do with MVC principles.
I think one of the common confusions around MVC is that there are multiple Views, multiple Controllers but only one Model. cfWheels has a "model" object for each persistent domain object which I think is very confusing - but of course cfWheels is drawn from Ruby on Rails which also uses "model" in that context.
In general, in MVC, "The Model" represents your business data and logic as a whole. The Model is made up of a number of domain objects (which are typically persistent) and a number of service objects (which exist to orchestrate operations across multiple domain objects). In real world applications, you typically have a data layer that manages persistence of domain objects - which may be partitioned in a number of ways.
It may also help to think of the input data that the view needs as it's "API" and it is the controller's job to satisfy that API by providing compatible data. Think of it more that the controller needs to know what type of data will satisfy the view rather than the other way around.
From inside to outside, these are our MVC app layers:
MS SQL / Tables / Views / Stored Procs
Entity Framework 4.1 (ORM) with POCO generation
Repository
Service (retrieve) and Control Functions (Save)
Routing -> Controller -> Razor View
(client) JQuery Ajax with Knockout.js (MVVM)
Everything is fine until I need to create a single ViewModel for step 5 to feed both the Razor view as well as the JSON/Knockout ViewModel:
Header that includes all Drop down list options and choices for the fields below
Items - an array of whatever we send to the client that becomes the ViewModel
Since the Controller won't have access to the Repository directly, does this mean I create a service for each and every view that allows editing content? I'll need to get the POCO from the repository plus all options for each field type as needed.
It just seems redundant to create separate services for each view. For example, a viewModel to edit an address and a separate viewModel to edit a real estate property that also has an address. We could have a dozen forms that edit the same address POCO.
To make this question easier to answer, is allowing the Controller direct access to the repositories a leaky abstraction?
Well, so are your controllers going to have code that translates POCOs from Entity Framework into separate view model objects?
If so, then you should move that code to a separate class, and follow the single-responsibility principle. Whether that class is in the "service layer" or not is up to you. And whether you use AutoMapper or not is up to you. But these kind of data mappers should not be part of the controller logic; controllers should be as dumb as possible.
OK, now let's ignore the data mapping problem, and pretend you could always use your POCOs directly as view models. Then you would still want a service layer, because it would translate between
userService.GetByUserName("bob")
in your dumb controller, and implement that in a specific manner by returning
userRepository.Users.Single(u => u.UserName == "bob")
Putting these together, your UserController ends up taking in IUserService and IUserDataMapper dependencies, and the code is super-dumb, as desired:
public ActionResult ShowUserPage(string userName)
{
var user = userService.GetByUserName(userName);
var viewModel = userDataMapper.MakeViewModel(user);
return View(viewModel);
}
You can now test the controller with stubs for both dependencies, or stub out IUserDataMapper while you mock IUserService, or vice-versa. Your controller has very little logic, and has only one axis of change. The same can be said for the user data-mapper class and the user service class.
I was reading an article this morning that you might find somewhat illuminating on these architectural matters. It is, somewhat condescendingly, titled "Software Development Fundamentals, Part 2: Layered Architecture." You probably won't be able to switch from a database application model to the persistent-ignorant model the article describes and suggests. But it might point you in the right direction.
i personally always inject the repository/repositories into the controller. i'm not sure why you would want to have a service layer between the repository and the controller. if anything you would use specifications.
once you've done that, check out automapper. its a mapper that, once properly configured, can map your domain model to your viewmodel, and back again.
Thanks to previous answers, I have now written View Models and really like this concept, however, there are points in the application where the View Model will be the exact same as the (Not sure on the term..) real model.
Now in this situation, I understand that a View Model is best as one day, I may change the application logic, and it makes the application more robust.
However, a situation I have now is where I have a multiple pages that are very closely linked to each other and all need the exact same Model. In this situation, would you use the same View Model or just create a separate identical one for each page?
Are they exactly the same? In my opinion, if they are exactly the same you should reuse the ViewModel. Why create the same ViewModels twice whose functionality is basically the same. However, you should be careful that there are no service calls being in ViewModel constructor because, you may not need the exact same service calls for all views. In that case your calls are wasted even though you do not require it. In such a case make a public method in ViewModel like :
public void DoServiceCallsForViewA()
{
ModelObj.FooA();
}
public void DoServiceCallsForViewB()
{
//your calls for view B
ModelObj.FooB();
}
Then in your viewA you can typecast the DataContext,
((YourViewModelName)DataContext).DoServiceCallsForViewA();
and in your viewB you can write :
((YourViewModelName)DataContext).DoServiceCallsForViewB();
ViewModels should be simple data vehicles between views and controller actions (just a list of properties). If they are simple lists of properties in your app you can use Automapper to make your eventual decision on this fine detail less important.
...not to evade the question, I would stick with one ViewModel definition while the views are demanding exactly the same data shuttle and be ready to create a new ViewModel when one of those views needs something ever so slightly different.
There is no need to duplicate except to make your view:action mappings obvious, but weighing the obvious mapping against violation of the DRY principle seems like a straightforward decision...
The way I see it, your Model instances should each have an associated ViewModel. That is to say, you should have a 1:1 relationship betweel Models and ViewModels. You are however free to bind multiple Views to the same ViewModel.
Say, for example, you have a Person object, and a PersonViewModel, and then two different Views relating to that Person, say a PersonEditView and a PersonDetailsView. You should put all the neccessary properties for both PersonEditView and PersonDetailsView into PersonViewModel. Then use a DataTemplateSelector to choose which View should be displayed for the ViewModel at which times.
The each ViewModel instance should be a representative for a single Model instance, and it should be the only representative for that Model instance.
I've decided to make a big push towards MVC for all new sites I make. I have a question about whether or not you can have any processing on the model level.
The case that brought up this question is a video site. I have a Video class (model) and one of the things I need to do when a user views the video I need the view to be logged in the database. I'm not sure if I need to add a query in the controller or if I can add a addView method in the Video class.
The basic underlying question for me is what kind of methods am I limited to in the models? Can it be anything or does it have to be only accessor (a.k.a getValue/setValue) methods?
Ruby on Rails has the motto skinny controller, fat model. This doesn't apply to just Rails and should be practiced with any mvc framework.
I think your model is exactly the place to handle this. Now, your model is necessarily composed of just your entity classes. Your model, in my opinion, would include your entities as well as any business logic that you need to implement. Your controller should just be handling I/O for the view, invoking model methods to accomplish the actions invoked by the user via the user interface (view).
Here how I would do this. It should be valid in pretty much any language.
The View would initiate a method call to the controller's OnView() method, then display whatever the controller spits back to it (in a controlled way, of course... I'm thinking your view is going to contain a video player component, so you're going to get a video of some kind back from the controller)
In your controller, have a method OnView() that does 3 things: instantiate the Video object (i.e. uses your data layer to get a model object), call the updateViewCount() method on the Video object, and display the video (by returning the Video object to the View, presumably).
The Video model object contains data representing your video and any houskeeping stuff you need, which includes updateViewCount(). The justification for this is that a Video has a view count (aggregation). If "view count" needs to be a complex object instead of just an integer, so be it. Your data layer that creates Video objects from their primitive representation on disk (database?) will also be responsible for loading and creating the corresponding view count object as part of the creation of the Video.
So, that's my $0.02. You can see that I've created a 4th thing (the first three being Model, View, and Controller) that is the data layer. I don't like Model objects loading and saving themselves because then they have to know about your database. I don't like Controllers doing the loading and saving directly because it will result in duplicated code across Controllers. Thus, a separate data layer that should only be directly accessed by Controllers.
As a final note, here's how I look at views: everything the user does, and everything the user sees, should go through the view. If there's a button on the screen that says "play", it shouldn't directly call a controller method (in many languages, there's no danger of doing this, but some, such as PHP, could potentially allow this). Now, the view's "play" method would just turn around and call the appropriate method on the controller (which in the example is OnView), and do nothing else, but that layer is conceptually important even though it's functionally irrelevant. Likewise, in most situations I'd expect your view to play a video stream, so the data returned by the controller to the view would be a stream in the format the view wants, which might not necessarily be your exact Model object (and adding that extra layer of decoupling may be advisable even if you can use the Video object directly). This means that I might actually make my OnView method take a parameter indicating what video format I want to get back, or perhaps create separate view methods on the controller for each format, etc.
Long winded enough for ya? :D I anticipate a few flames from the Ruby developers, who seem to have a slightly different (though not incompatible) idea of MVC.
Since you can use whatever model code you want with MVC (not just limited to LINQ) the short answer is yes. What should be done in the model is perhaps a better question. To my taste, I would add a ViewCount property (which probably maps to a column in the Video table, unless you are tracking per user in which case it would be in the UserVideo table). Then from the controller you can increment the value of this property.
With MVC, people seem to be struggling with fitting four layers into three.
The MVC paradigm does not properly address the data storage. And that's the "fourth layer". The Model has the the processing; but since it also addresses the data, programmers put SQL in there, too. Wrong. Make a data abstraction layer which is the only place that should talk to back-end storage. MVC should be DMVC.
Keep in mind, there are many variations on MVC and no real "right way" to do things. Ultimately, how you design your classes comes down to personal preference. However, since you asked for design advice, here are my two cents:
Business logic belongs in the controller. Keep it out of the model and view.
Out of the many variations on the MVC pattern, the passive view style seems to be the easiest to test. In the passive view, your classes are designed as follows:
Your controller is "smart: it makes changes to the database, updates the model, and syncronizes the view with the model. Apart from a reference to the model and view, the controller should hold as little stateful information as possible.
The model is "stupid", meaning it only holds the state of the view and no additional business logic. Models should not hold a reference to either the view or controller.
The view is "stupid", meaning it only copies information from the model to the UI, and it invokes event handlers which are handled by the controller. The view should contain no additional business logic. Views should not hold a reference to the controller or model.
If you're an MVC purist, then it would not make sense for the model to update itself or the database since those responsibilities belong to the controller, so it would not be appropriate to create an addView method to your Video class.