I am using MVC3.
I have a pretty complex document class that contains many sub classes, lets call them "dog", "cat", "sheep", "cow", "goat".
I would like to use a generic controller to list, add and edit each of these classes.
Listing: I can list the relevant entity by passing in document model and iterating through the relevant class.
Edit: I need to get the id and identify the class of interest ie "dog" and then passing this as the model for editing. However next time round I may be editing a "cat" instance. Typically in MVC, as I understand it, one would ideally create a "DogController" and a "CatController". However since this document class is meant to be flexible I do not wish to hard code controllers. It may be necessary to add 2 more classes ie "horse" and "donkey".
At the moment I am using some if/else logic to ensure that the correct View is setup and called with the correct class. However this does feel as if I am breaking some MVC rules here.
Perhaps the answer lies in the use of a more formal ViewModel. Perhaps I can then have one of the properties as the subclass ("Dog"). Perhaps this can be swapped out at runtime using IOC?
Thoughts and pointers appreciated?
Thanks.
EDIT: I have tried to create 2 version of the "edit" action with different input models
[HttpPost]
public ActionResult Edit(Dog DogModel){}
[HttpPost]
public ActionResult Edit(Cat CatModel){}
I thought that due to method overloading MVC would be able to pick the correct one when the View posted, and then applied modelbinding.
Perhaps I am expecting too much or my understanding is lacking.
routes.MapRoute("Route", "{controller}/{action}/{name}/{id}", new { controller = "Animal", action = "search", name = "Home", id = 0 });
Related
Given that there is file selection widget on the view and controller need to handle event of selecting file, should I rather write controller method:
public void fileSelected(String filePath){
//process filePath
}
or
public void fileSelected(){
String filePath = view.getSelectedFilePath();
//process filePath
}
The first approach seems to introduce less coupling between C and V: C don't know what exactly data does C need while handling given event.
But it requires creating a lot of verbose methods similar to getSelectedFile on V side.
On the other hand, second approach may lead to cluttered controller methods in more complex cases than in example (much more data to pass than just filePath).
From your own experience, which approach do you prefer?
The first approach is my favourite. The only difference is I would rather use an object (like Mario suggested) to pass arguments to the method. This way method's signature will not change when you add or remove some of the arguments. Less coupling is always good :)
One more thing:
If You want to try the second solution I recommend using a ViewFactory to remove view logic from the controller.
The first approach is the way to go;
public void fileSelected(String filePath){
//process filePath
}
The Controller should not care about how the View looks like or how it's implemented. It gets much clearer for the developer as well, when creating/updating the view, to know what an action in the controller wants. Also it makes it easier for method overloading.
Though, I don't know really how String filePath = view.getSelectedFilePath(); would work. Are we talking about parsing the View code/markup?
On the other hand, second approach may lead to cluttered controller methods in more complex cases than in example (much more data to pass than just filePath).
That's when you would create a View Model class (let's say we name it MyViewModel) to store all the properties that you need to send (may it be 10 properties) and then pass that in the action: fileSelected(MyViewModel model). That's how it's intended to be used and what the *ModelBinder's in asp.net mvc are there to help you with.
I think you need to look at this from a step back.
Worry less about how it gets in, and be more concerned with validation and error raising.
Tomorrow, your requirements could change and demand that you source the information via a different architectural approach. You could refactor the setup of [inputs / an input object] into a base controller class - or one of several classes for different controller domains.
If you focus on proper validation, whether within the controller (scrubbing) or outside of it (unit tests), then you perform more thorough decoupling though duck typing.
I would go with the first approach. It's reusable and separates concerns. Even if the method of getting the filePath in the future were to change, it won't affect your method's functionality.
I find myself needing to have a View expose its Model and Controller references. Is this the smell of bad design? Or is this considered "safe" practice?
For example: I have a list (composed of a ListView, ListController, and ListModel) and many list items (composed of a ItemView, ItemController, and ItemModel).
When I create the ItemModel, ItemView, and ItemController for each list item, I pass the ItemView instance off to the ListView. But, at some later point, my ListController needs a reference to the corresponding ItemController instance.
So, would it be more proper to pass both the ItemView and the ItemController in to ListView::addItem(), or just pass in ItemView and expose an instance method such as ItemView::getController()?
Or doesn't it matter? Is each approach equally viable? If followed to their logical conclusion, does either tactic result in an anti-pattern?
But, at some later point, my ListController needs a reference to the corresponding ItemController instance
Why? If you're decoupling your classes properly, you shouldn't need this.
Controllers almost always address a functional domain. An example of such a domain might be "Sales" or "Admin." In addition, MVC also supports the use of "Areas," which provides an additional hierarchical level of organization.
Adding references to controllers from other controllers is at cross-purposes with this organizational structure. If you need to combine functionality to make your code more DRY, ordinary refactoring will accomplish that. You can also inherit controllers from a base class containing common functionality.
In the mvc pattern the users request shall be routed to a controller, say invoicecontroller, that has actions.
Lets say the default action, Index, returns a list of invoices; the controller then creates a model with a list of invoice objects, instantiates the correct view and injects the model into the view.
Now it is the views turn to do its magic. It renders the best view it can with the data it has, which may include routes to one or more controllers.
In NO instance should the view (or model) do business logic themselves.
That said, I totally agree with Jakub. Hope that helps.
Considering you are not actually showing any code at all.
In my opinion, you should change your design. A controller is not supposed to communicate with another controller (directly), MVC dictates it: reference.
If you need to invoke a controller action from another controller, consider using delegates or composition. Instead of directly invoking the controller action.
We are working on an ASP.NET MVC 3 using ext.net and EF 4.
Data model is mapped using EF4.
Views’ content is rendered from customizable XML files.
Example: Within one view, I can display fields that are related to both objects “customer” and “order”, so from this view I can modify the customer data and also add a new order.
How can we bind the view to the custom model that contains 2 objects (customer and order)? Using non strongly typed views will require a source code that will check all different possibilities (If I remove/add a field to display from the XML file, object constructor and CRUD operations parameters will change also.
We are wondering how can we handle such dynamic application?
Is this a common issue that was raised before? Or is there any solution to use dynamic views bound to custom model (object, xml, etc.)?
Your help is very appreciated, please enlighten me.
Based on what you replied to my comment, I can defenitely say that you need strongly typed views. That said, you decide what the model of your view is. If your view needs to manage users and orders at the same time, you can make a class like this:
public class MyCustomViewData
{
public IEnumerable<User> Users {get;set;}
public IEnumerable<Order> Orders {get;set;}
}
and then strongly type your view to MyCustomViewData and you're set. My example is oversimplified but I think you can get the point.
Unless I'm missing something, I believe the normal way round this would be to strongly type your view to say 'user' and then on the user object, define a property which is a collection of 'orders'.
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 am developing an application that involves a type hierarchy and started by defining the models for each type via inheritance. When it comes to writing the corresponding controllers I am not sure how to approach the whole thing in a clean way. Should I write only one controller for the base type that is able to handle derived models or should there be one controller for each subtype? How should the view-controller bindings be set up to work with the different controllers?
You might want to check out SproutCore's new experimental polymorphism support: http://groups.google.com/group/sproutcore-dev/browse_thread/thread/b63483ab66333d15
Here's some information on defining sub-classes and overriding properties and methods:
http://wiki.sproutcore.com/w/page/12412971/Runtime-Objects.
From my (limited) use of Sproutcore, I've only been able to bind 1 view to 1 controller.
As such, if you are planning to use a single view (e.g. ListView) to display your data, then I think you will only be able to bind that view to 1 controller. This means the 1 base type that is able to handle derived models seems to be the way to go.
Typically you populate the content of ArrayController instances with the results of App.store.find calls. SC.Store#find can take an SC.Query instance, which typically looks like:
MyApp.myController.set('content') = MyApp.store.find(SC.Query.local(MyApp.MyModel));
This should return all instances of MyApp.MyModel, including any instances of MyApp.MyModel's subclasses.
The first argument to SC.Query.local can either be an SC.Record subclass or a string referring to the subclass. So if you've got some intermediary SC.Record subclasses, you might want to try using them there.
Controllers should just be proxies for objects, when dealing with single instances of your model. In other words, ObjectController can proxy anything. Here is what I mean in code:
You have two objects, Person and Student.
App.Person = SC.Object.extend({
// person stuff here
})
App.Student = App.Person.extend({
// student stuff here, you have have all Person things because you are extending person.
})
You then want to define controllers:
App.personController = SC.ObjectController.create({
contentBinding: 'App.path.to.person'
})
App.studentController = SC.ObjectController.create({
contentBinding: 'App.path.to.student'
})
note that you would only bind the controller's content to something if the person/student is a result of a selection, or some other flow where bindings fire. In other words, if you set the person manually (say from a statechart, as the result of an interaction), you would still define the controller but would do
App.personController.set('content', person);
You set up the controller differently depending on whether the Person is a 'top level' object in your app, or some intermediate object that gets selected. Also, you might only need one controller, you would only have a studentController and a personController if you were acting on a person and a student at the same time. Both are just ObjectControllers, and those can proxy anything.
Finally, in your view you would bind the relevant view element to the controller:
...
nameView: SC.LabelView.design({
layout: {/* props */},
valueBinding: SC.Binding.oneWay('App.personController.name')
})
...
note that the oneway binding is if the name is not going to be changed on the view, if the view can change the name, then just do a normal binding. Also note the path here. I am not binding to
'App.personController.content.name'
Since the personController proxies the object, you bind to the
'namespace.controller.property-on-object-controller-proxies'
If you are putting a lot of business logic in your controller, you are doing it wrong. Controllers should just be for proxying objects (at least ObjectControllers should be). Business logic should be on the models themselves, and decision making logic should be in statecharts.