0

So I just came across an extension method built into ASP.NET MVC: ChildActionExtensions.RenderAction(...). This invokes an action method using the given parameters and renders the result inline in the view.

This surprised me because I thought the MVC architecture had the controller setting up the model and passing it into the view, such that all the data needed by the view would be in the model by the time the view is called. This action lets the view turn around and say "by the way, controller, I need a bunch more information to render." How is this compatible with the MVC architecture? Not only is it possible in ASP.NET MVC, but it's built into the framework which would suggest that it's been approved by people who know what they're doing. So could someone tell me why it makes sense for the view to do this?

  • Question, does RenderPartial(...) confuse you? – Berin Loritsch Jun 11 '18 at 13:19
1

This surprised me because I thought the MVC architecture had the controller setting up the model and passing it into the view, such that all the data needed by the view would be in the model by the time the view is called.

The M in MVC is not the View Model (as it appears in ASP.NET), its the Domain Model (the business logic layer - assuming that the domain logic is more involved then just "fetch or write some data"). The idea behind MVC is to decouple the view and the controler from the domain model (with the direction of the dependencies poining towards the domain model). The view models you pass to the view (which is, in this case, essentially an HTML template for generating final HTML) are most often just data bags that are used to transfer some data (that ultimately originates) from the domain model, to the view, without explicitelly depending on the implementation details of the domain (the types of the domain). That's more or less it - MVC itself doesn't mandate that the views cannot request additional data at a later time in the page lifecycle. Now, whether this is a good practice or not, could be up for some debate - the point is, it doesn't go against MVC, strictly speaking.

  • The "M" in MVC is simply "The Model." It makes no distinctions between view models, domain models, DTOs or any other kind of data container. The "M" in MVC is "data, data access, business rules and stuff" --- stuff that doesn't belong in a "V" or "C". The M should stand for Miscellaneous, because that's the architecture you get if you are only thinking in terms of M's, V's and C's. – Greg Burghardt Jun 11 '18 at 15:52
  • The M in (Web) MVC is (roughly) the same M that's in MVP, and the Model in the previous "Application Model". In the original MVC (not how we think of it anymore) where each control had a View, a Controller, and a Model, each model was a little piece of business logic. To add to the confusion, the VM in MVVM pattern (which is a variant of MVP), is not the model, as it belongs to the presentation component, and is not the same as the view models used in (Web) MVC, which are just an implementation detail of the interfaces between components and are not really part of the pattern itself. – Filip Milovanović Jun 11 '18 at 17:28
  • I think the main thing I disagree on is stating that the "M" in MVC is the Domain Model. The design pattern does not specify this. In fact, it does not specify a buzzword beyond the word "Model". – Greg Burghardt Jun 11 '18 at 19:09
0

The short answer is no it does not incompatible with MVC. In fact it helps.

Your view can be composed of related and unrelated data. There are different tools available to help you build up your screen in a way that applies the Single Responsibility Principle (SRP) and understandable. I found a good summary of why you would choose one over the other.

Let's say we are developing a blog. We have our main article with comments underneath. In this case it would be reasonable to use RenderPartial() for the comments. Example:

public ActionResult Display(int id)
{
    Model = Articles.Find(id);

    if (Model == null) return NotFound();
}

In the View you would have something like this:

<article>
    <header>@Model.Title</header>
    <div class="blog-content">
        @RawHtml(Model.Content)
    </div>
    <div class="blog-comments>
        @foreach(var comment in Model.Comments)
        {
            RenderPartial("_Comment", comment);
        }
    </div>
</article>

So far so good. It's all within what you are expecting. However, what if you also want to list the categories on the same page? or possibly the top 5 articles? That's where you would use RenderAction(). The logic of what you want to display has nothing to do with the content you just set up. It's also something that would be less than desirable to include in the Display() method.

<section id="top-five">
    @RenderAction("TopFive")
</section>
<section id="categories">
    @RenderAction("Categories")
</section>

This allows the framework to push on the action method call to the stack and render the results directly to the same output. When the output is rendered the framework pops off that context to return you to the main page. That lets you embed unrelated content in the same page because it's good for users, but still maintain an understandable codebase.

  • But why do this as a controller action and set up all the overhead of an internal web request to get the content? Why not just have a helper class that returns the markup? – Jez Jun 11 '18 at 15:01
  • 1
    @Jez: rendering a child action does not incur an "internal web request" but it does delegate to the routing framework. You incur the cost of a little more class reflection for the benefit of increasing the modularity of your views, and preventing the addition of a "Top 5" list on multiple pages resulting in a mass refactoring job of multiple controllers, view models and perhaps even factory objects. – Greg Burghardt Jun 11 '18 at 15:56
  • Why would adding a helper class to return the markup results in a mass refactoring? – Jez Jun 11 '18 at 15:57
  • @Jez, what makes you think it's doing an internal web request? MVC has a certain way of doing things, and RenderAction() preserves that way of doing things, but it is not making any web requests. Also, consider the example I gave. To support the new content on the page I didn't have to change one line of controller code. That allows me to have one place to define what the "TopFive" is and how that is filtered, as well as which categories I display. Without RenderAction I would have to repeat those calls in my Display() and Index() actions. – Berin Loritsch Jun 11 '18 at 17:04
  • What I meant was not to use a helper class in the controller, but use a helper class (maybe with HtmlHelper extension methods) from the View, then you don't need to use a controller action at all (which you have to decorate to make sure the action isn't called from the web server). It's not doing an internal request, but it has some overhead ("The RenderAction method builds a new request context and fills it up with the same HTTP context of the parent request and a different set of route values"), see: itprotoday.com/software-development/… – Jez Jun 11 '18 at 19:18

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service, privacy policy and cookie policy

Not the answer you're looking for? Browse other questions tagged or ask your own question.