1

I'd like to keep my concrete classes separate from my views. Without using strongly typed views, I'm fine. I just use a big parameter list in the controller method signatures and then use my service layer factory methods to create my concrete objects.

This is actually just fine with me, but it got me thinking and after a little playing, I realized it was literally impossible for a controller method to accept an interface as a method parameter - because it has no way of instantiating it. Can't create a strongly-typed view using an interface through the IDE either (which makes sense actually).

So my question. Is there some way to tell the controller how to instantiate the interface parameter using my service layer factory methods?

I'd like to convert from:

[Authorize]
[AcceptVerbs(HttpVerbs.Post)]
[UrlRoute(Path = "Application/Edit/{id}")]
public ActionResult Edit(String id, String TypeCode, String TimeCode, String[] SelectedSchoolSystems,
            String PositionChoice1, String PositionChoice2, String PositionChoice3, String Reason, String LocationPreference,
            String AvailableDate, String RecipientsNotSelected, String RecipientsSelected) {

    //New blank app
    IApplication _application = ApplicationService.GetById(id);

to something like

[Authorize]
[AcceptVerbs(HttpVerbs.Post)]
[UrlRoute(Path = "Application/Edit/{id}")]
public ActionResult Edit(String id, IApplication app) {

            //Don't need to do this anymore
            //IApplication _application = ApplicationService.GetById(id);
Rake36
  • 992
  • 2
  • 10
  • 17
  • Thanks for the excellent input everyone. Huge help. – Rake36 Mar 26 '10 at 00:01
  • It's been many months, but after a lot more coding - I've come to realize that even though custom model binder is probably the correct answer, using strongly typed view models is working the best for me. The key being that the View Models are different from my database objects fairly often. – Rake36 Jul 13 '10 at 20:27

3 Answers3

2

You need view model layer.

It might make sense to abstract away business layer entities using interfaces, but it won't make much sense to abstract web app specific entities (in most cases i guess). That would allow You to code against implementations.

And trying to bind back entities from Form without accessing database will make a lot of trouble too.

Arnis Lapsa
  • 45,880
  • 29
  • 115
  • 195
  • Maybe I'm mixing architectures improperly, but I already have a data access layer and a service layer - so I'm treating the MVC site as the presentation layer and I don't want to have to create view models that are just copies of my data layer classes. Am I misguided in thinking the Interface should be good enough? – Rake36 Mar 25 '10 at 12:45
  • @Rake36 It might be enough for some cases. It always depends on context. I'm just saying that adding proper view model would resolve this particular issue easily (but would increase your code base with view models & mapping logic). – Arnis Lapsa Mar 25 '10 at 13:31
  • @Rake36 You might find useful this article - http://bit.ly/9Bxpfj I guess - `External coupling` is what makes trouble in Your case. – Arnis Lapsa Mar 25 '10 at 13:45
  • I read the article and I think I see what you mean. I'm trying too hard to maintain DRY when the View itself really may need it's own concrete class. I think it's time to write some code... I'll post back when I have something useful to share. – Rake36 Mar 25 '10 at 23:59
  • @Rake36 here's some info about view models You might find useful - http://stackoverflow.com/questions/2269144/how-to-dry-up-c-attributes-in-models-and-viewmodels/2272115#2272115 – Arnis Lapsa Mar 26 '10 at 08:29
1

Custom model binding. Just have the model binder build a instance of a derived class and return it as it's interface.

On the other hand, why? Typically, you'd use view-specific models both for the view and the controller parameters. Each view/action has specific model needs. I can understand why you might like to derive them from a common interface or abstract class -- so, for instance, your master page has a set of common information that it can use, but why would a specific action ever need to receive the data as an abstraction? Wouldn't it know exactly the kind of data that it needs and simply use the correct derived class as the parameter type?

tvanfosson
  • 524,688
  • 99
  • 697
  • 795
  • The controller has no idea which derived class to use. Only the service layer does. I had thought maybe I could go ahead and create view specific models and then use those as parameters to the service layer methods. I was trying to avoid having to perform any sort of mapping between the view models and my concrete classes. Does that make sense? – Rake36 Mar 25 '10 at 12:53
  • I understand what you are saying, but I think you're on the wrong road. I've found that things work much better when you have view models and data models. Invariably, I've found that I need to augment my data models with additional data for the view and encapsulating it in a view-specific model seems to be the best method. – tvanfosson Mar 25 '10 at 13:26
  • Thanks. I'm going to try this idea as well as the custom model binding approach. I'll post back here with my results. – Rake36 Mar 25 '10 at 23:45
1

You could write a custom model binder which will instantiate the correct type:

public class MyModelBinder: DefaultModelBinder
{
    protected override object CreateModel(
        ControllerContext controllerContext, 
        ModelBindingContext bindingContext, 
        Type modelType
    )
    {
        return // ... instantiate your model here
    }
}

And then:

public ActionResult Edit(
    string id, 
    [ModelBinder(typeof(MyModelBinder))] IApplication app
)
{
   ...
}
Darin Dimitrov
  • 1,023,142
  • 271
  • 3,287
  • 2,928