views:

468

answers:

2

How can I access a controller instance from the view? E.g. I have a HomeController which then returns my Index view. Inside of that view I want to access the HomeController instance that created the view. How do I do that?

+4  A: 

ViewContext.Controller, and you'll need to cast it.

<% var homeController = ViewContext.Controller as HomeController; %>

This is covered with a few extra wrinkles in post http://stackoverflow.com/questions/151963/asp-net-mvc-how-do-i-get-virtual-url-for-the-current-controller-view.

EDIT: This is to add some meat to Mark Seemann's recommendation that you keep functionality out of the view as much as humanly possible. If you are using the controller to help determine the markup of the rendered page, you may want to use the Html.RenderAction(actionName, controllerName) method instead. This call will fire the action as though it was a separate request and include its view as part of the main page.

This approach will help to enforce separation-of-concerns because the action method redirected to can do all the heavy lifting with respect to presentation rules. It will need to return a Partial View to work correctly within your parent view.

David Andres
That's what i was looking for. Thank you David
Alex
@Alex: glad to help
David Andres
@David: RenderAction is only available in the Futures package correct?
Alex
Yes, but if your View already has access to the Model in question, you can call Html.RenderPartial instead. Also check out http://blog.codeville.net/2008/10/14/partial-requests-in-aspnet-mvc/
Iain Galloway
@Alex, this is available in the Futures library. Sorry for not including that detail.
David Andres
@Iain, you're correct. The reason I advocated for RenderAction as opposed to RenderPartial is because the need for an instance of a controller implies logic processing beyond the scope of a View. RenderPartial just moves the problem to a different View, whereas RenderAction goes a different route (to another action method, specfically).
David Andres
+4  A: 

In my opinion, you should consider a design where the View doesn't need to know about the Controller. The idea is that the Controller deals with the request, conjures up a Model and hands that Model off to the View. At that point, the Controller's work is done.

I think it is an indication of a design flaw if the View needs to know anything about the Controller. Can you share more about what it is that you are trying to accomplish?

I often find that when dealing with well-designed frameworks (such as the MVC framework), if it feels like the framework is fighting you, you are probably going about the task in the wrong way. This has happened to me a lot, and stepping back and asking myself what it is that I'm really trying to accomplish often leads to new insights.

Mark Seemann
+1 for that. If Utility Classes are needed, they should usually go either into the ViewModel or into a completely separate entity, as the Controllers life cycle should end with the "return".
Michael Stum
Mark: I've added to your argument a bit in my own post. +1
David Andres
+1 from me too. I thought about this. What I'm doing is that I have a partial view, similar to LogOnUserControl from the regular starter project for ASP.NET MVC. It displays a user name (but not coming from the Page context/IPrincipal -- it's custom). My controller already has a service which is capable of providing the user name, and so I'd rather take the instance from the controller instead of re-instantiating in the view. I'm not using the model because I'd like to take advantage of the regular return View() and not run into issues (remember, this is shared, so I'd need a VM base class etc
Alex
@Alex: This sounds to me like the use name *does* belong on the ViewModel. You could use inheritance, but you should rather *favor composition over inheritance* so in such a case I would define a 'root' ViewModel that contains a UserName property and another property that contains the page-specific ViewModel. You can then pass the value of the UserName property as the *model* parameter when you invoke the RenderPartial method.
Mark Seemann
@Mark: It adds a huge load of complexity though because now I would have to make *all* models inherit from the VM base, and change all my view returns to include this information, deal with empty strings if I don't have the information in all controllers, and so forth. Understand the pattern, but a large amount of complexity is introduced by following composition over inheritance.
Alex
@Alex: Well, it may feel like added complexity now, but is likely to enable you to keep moving forward properly. If you don't deal with the issue now, you would just be accumulating technical debt. BTW, notice that I never said anything about the UserName property being a string. If you need to deal with special cases (such as empty strings, etc.) you could encapsulate that behavior into a UserName class. That would keep you DRY.
Mark Seemann
@Alex, Mark: I second the argument for a "root" ViewModel that can change over time. Yes, it does add complexity today, but the second you need additional properties to make their way to the Model you'll have to update your view to match. This ViewModel may be shared among different Views, so this can get cumbersome.
David Andres