18

On Web Forms we have UserControls. These controls have a code-behind and can be used in different projects/solutions not depending on other things.

I want to create a control that renders some controls and would have some links that would "trigger an event". I want them not to be attached on my website, I want to be able to use the same "control" on another website. What is the equivalent in MVC? Is it possible to compile a view with a controller and use the DLL elsewhere?

BrunoLM
  • 97,872
  • 84
  • 296
  • 452
  • Related to (but not a duplicate of) these questions: [73902](http://stackoverflow.com/questions/73902/asp-net-mvc-components), [810187](http://stackoverflow.com/questions/810187/is-there-an-equivalent-to-monorail-view-components-for-the-asp-net-mvc-framework) – Daniel Schilling Feb 03 '11 at 17:48

2 Answers2

17

The closest functional equivalent to WebForms-style reusable user controls in MVC are html helpers. An html helper is a method that returns some markup. The recommended approach is to implement them in the form of extension methods off HtmlHelper or some other property of an MVC page:

public static IHtmlString MyControl(this HtmlHelper helper, string value) {
    return new HtmlString("<p>" + value + "</p>");
}

You can add this method to your MVC project directly or you can add it to a seperate class library. The only thing that the class library needs to reference is System.Web.Mvc.dll for the HtmlHelper reference (it might also need System.Web.dll if you use more types).

You usually call them from your view like so (this example uses the Razor syntax that's new in MVC 3)

@Html.MyControl("my value")

While superficially html helpers emit markup just like User Controls, there are significant differences. The most important one is that MVC views don't have the concept of the WebForms page lifecycle. This means that unlike user controls, html helpers are rendered in a single pass. There are no mulitple phases like Init, Load, Render etc in WebForms where you can hook up server-side events to interact with other controls on the page.

Depending on what specific kinds of events you are talking about there might be appropriate MVC-centric techniques to solve your task. Could you provide more detail on what you want to do? Html helpers can be quite powerful. For example the built in MVC input controls like TextBoxFor can hook up client-side validation etc.

Daniel Daranas
  • 22,454
  • 9
  • 63
  • 116
marcind
  • 52,944
  • 13
  • 125
  • 111
  • Could he also use a regular "View", render it as a "partial", and use a ViewModel as it's "Code Behind"? Since a UserControl is an ASCX, the way I see it, the nearest equivalent is a partial view with a ViewModel. – Chase Florell Jan 27 '11 at 01:06
  • 1
    @rockinthesixstring Partials don't fit the OP's requirement that the reusable components could be defined in a seperate assembly included by a few different applications (at least not without writing custom view engines or virtual path providers that would load views from assemblies etc.). – marcind Jan 27 '11 at 03:14
  • yes good call. Though I think then that UserControl is the wrong phrasing. Maybe "Custom Control" is a better fit? – Chase Florell Jan 27 '11 at 03:22
  • Wouldn't RenderAction() would be closer to user controls? – John Farrell Jan 27 '11 at 04:21
  • 2
    @jfar `RenderAction()` doesn't immediately fit for the same reasons. Basically anything that requires a view (in the form of an .aspx or .cshtml file) to be defined cannot be easily reused from multiple projects. I guess this further emphasizes that the WebForms and MVC paradigms are fundamentally different :) – marcind Jan 27 '11 at 05:18
3

Since "events" don't exist in the same sense in MVC as they do in WebForms, meeting all your requirements will be quite tricky.

For the UI layer of the UserControl equivalent, you should use a PartialView, possibly located in the Views/Shared/Templates folder depending on if you want it to be associated with a certain Model type or not.

For the back end (the "event"), you should probably implement a Controller that you could send the requests to from your links, and that supports all the behavior you need.

To use these features in various projects, you then have to copy both the controller and the template/partial view. Admittedly, it might not be as simple to re-use as a do-it-all user control from WebForms, but that is a limitation that comes with a clear separation of concerns, and that would be apparent in a well designed, layer based WebForms application as well.

Update in response to a comment on the "limitation" of separation of concerns I mentioned:
The controller can of course be distributed in a separate assembly, with it's own test assembly etc. However, including the controller assembly (or assemblies) and the partial view/template with the front end code is arguably one more thing to do (i.e. possibly fail to do) than just copying a user control with it's code-behind (that are stored next to each other).

Eric J.
  • 147,927
  • 63
  • 340
  • 553
Tomas Aschan
  • 58,548
  • 56
  • 243
  • 402
  • -1: I was going to upvote this until the "clear separation of concerns" line. What is it about separation of concerns that prevents a controller from being built into another assembly and referenced from many MVC applications? The views are HTML, more or less, and would need to be shared as such, but why shouldn't all of the .NET code be in one or more separate, testable assemblies? – John Saunders Jan 27 '11 at 00:32
  • 1
    Sure - the controller can definitely be put in a separate (testable) assembly, and shared independently of the rest of the project. I don't say it's not doable (I would even argue that it's worth the effort!), but it's definitely more complicated than just lifting a user control and it's code-behind file (if you even have one) from project to project, and it just does all the magic on it's own. *That* is limited by the clear separation of concerns - a cost I am more than willing to take. – Tomas Aschan Jan 27 '11 at 13:24