Rendering multiple views from multiple controllers on a single page - asp.net-mvc

On the main page of my site, I would like to show several views which rely on their own controllers for data retrieval. I do not want to retrieve anything from the DAL in my Home controller.
For example, I want to show view listing top 5 news, a view with random quote from the database, another view with the users shopping cart contents, etc.
After Googling around, I found RenderAction method which is almost perfect, but it's not available in RC1, only in Futures, and apparently, it has some issues.
I found RenderPartial as well, but that relies on the main controller to pass data to the view.
Additional clarification:
The main reason I do not want data access logic in the Home controller is to avoid repeating the code and logic. I will use top 5 news view in several pages/controllers. I do not want to repeat data retrieval in every one of them. I already did separate a lot of logic and validation to business layer. The solution I'm after is RenderAction or UserControls as in classic ASP. I know i can use them in MVC as well, but... whats the point? I mean, if what i'm asking is too complicated or too absurd (reusable UI components), then MVC is definitely not for me, and I'd consider it seriously inferior to classic ASP.NET, because this requirement is really simple.

What you're asking is to basically not perform data access in the HomeController, this seems like a dogmatic approach. I would consider either using RenderAction from the Futures assembly (not sure what's wrong with it, I use it in a number of projects) or SubControllers from MvcContrib.

While I can understand the desire not to replicate functionality in multiple controllers, I don't understand the reluctance to have your Home controller interact with the DAL. I think the partial view is definitely the way to go. My solution to not replicating the functionality would be to push the code that generates the data for the various views into your business or data layer. You could then reference it from each of the required controller actions that use the partial views. Putting it in the business layer could isolate the controller from your data layer, if that's what you desire, but I still think it's the proper job of the controller action to obtain and provide the data to the view.
Another potential solution would be to populate the view generated by your Home controller via Ajax callbacks to the various controller actions that generate the required view components. The drawback to this is that it doesn't fail gracefully in the absence of javascript in the browser.
EDIT
Based on your clarification, I would suggest implementing a base controller that fills the ViewData for the shared controls in ActionExecuted (so that it's done only when the action succeeds). Derive your other controllers from the base controller when you want to inherit this behavior.

If you really don't want to use RenderAction, then the only other option you have is to load the necessary data pieces with action filters. Your home controller could then look like this:
public class HomeController : Controller
{
[RequireNews]
[RequireQuotes]
[RequireCart]
public ActionResult Index()
{
return View();
}
}
These action filters could be re-used where they are needed. You might also choose to place these on the controller class itself.

Related

how to manage logic in the _Layout.cshtml

I am currently working with an mvc site where I have a fairly extensive main layout page. It is dependent on data from the database which in turns includes inherent logic as what to include etc on the layout.
Most of my controller actions are rendered within this layout. I am not sure of how to work this. Being used to master pages in web forms, all the logic resides in the master page. I have a couple mechanisms to achieve the common layout logic but looking for the best practise way of achieving such.
Options are:
Replicate logic in all controller actions (not really an option)
Extract the logic in to another class and call it from the controller actions
All controllers inherit from a base controller which as overrides the OnActionExecuting method and us this to perform logic and return the necessary data in the TempData
Use "RenderAction" in the cshtml to call necessary controller actions and extract the layout in to smaller partial views
Any other options open to me or recommendations?
If I understand you correctly, I would use an action partial
#Html.Action("{ActionName}", "{Controller}", new { roleName= "Admin" })
Action Partials call dedicated controller action methods of type
[ChildActionOnly]
public ActionResult _TopNav(string roleName)
This way you can design recurring logic that will propagate throughout your application without replicating.
Even better, if your _Layout handles privilege based link generating, you can pass role id's and control what the end user sees and what their navigation buttons point to.

Developing ASP.NET MVC web applications the right way

I'm starting to develop a new ASP.NET MVC application, and I'd like to make sure that my understanding about the way of developing applications under MVC pattern is correct.
Question 1: Suppose that I have some main views (MainView1, MainView2, ...) with some partial views in it (PartialView1, PartialView2, PartialView3, ...). From what I have understood about MVC, I should define a Model for each view. e.g. I have to define PartialModel, PartialModel2, ... and also define my main models which are containers of the partial models which have been used in them:
public class MainModel1
{
public PartialModel1 Partial1 {get;set}
public PartialModel2 Partial2 {get;set}
public PartialModel3 Partial3 {get;set}
}
This way when I want to redirect to MainView, I can initialize the models used in that view by using this Model. Is my understanding of MVC correct? Or should communication between Views and Models be in another form in MVC?
Question 2: If the above is correct, Then suppose I have a partial view in some of my main view pages. This partial view has a submit button which calls an action method. This action method should somehow return the main page's view with the right viewmodels for views. Is there any recommendation about how to get/set viewmodels of other views in a partial view's action?
Thanks.
You understanding is correct. Each view (no matter whether it is main or partial) should have a corresponding view model (unless in the very rare case where this view contains only static html of course). And following this logic a main view that has to render other partial views will have a view model which itself will have reference (maybe as properties) to view models that are required by those partial views.
There is another technique which is using the Html.Action helper. In this case the partial is rendered through another controller/action than the main one. So you don't need to reference the partial view model in the main view model. They will be completely distinct. Take a look at the following blog post to learn more about Html.Action.
Your understanding is perfectly fine. This is what you can also refer to ViewModel in Asp.net MVC.
So, What basically is an Asp.net MVC ViewModel ?
In ASP.NET MVC, ViewModels allow you to shape multiple entities from one or more data models or sources into a single object, optimized for consumption and rendering by the view. The below image illustrates the concept of a ViewModel:
The purpose of a ViewModel is for the view to have a single object to render, alleviating the need for UI logic code in the view that would otherwise be necessary. This means the only responsibility, or concern, of the view is to render that single ViewModel object, aiding in a cleaner separation of concerns (SoC). Concerns are distinct aspects of the application that have a particular purpose (i.e., concern), and keeping these aspects apart means your application is more organized, and the code more focused. Putting data manipulation code in its own location away from the view and controller, enforces SoC.
Using ViewModels in MVC for finer granularity and better SoC leads to more easily maintainable and testable code. Remember, unit testing is about testing small units.
Along with better coding practices, there are many business reasons demonstrating why you might consider using ViewModels:
Incorporating dropdown lists of lookup data into a related entity
Master-detail records view
Pagination: combining actual data and paging information
Components like a shopping cart or user profile widget
Dashboards, with multiple sources of disparate data
Reports, often with aggregate data

When should we implement a custom MVC ActionFilter?

Should we move logic that supposes to be in Controller (like the data to render the partial view) to ActionFilter?
For example, I'm making a CMS web site. There should be a advertisement block to be rendered on several pages but not all the pages. Should I make an ActionFilter attribute like [ShowAd(categoryId)] and decorate the action methods with this attribute?
The implementation of this controller would include service calls to retrieve information from database, buildup view models and put in the ViewData. There would be a HtmlHelper to render the partial view using the data in ViewData if it exists.
That just seems yucky to me.
When I'm trying to figure out whether I need an ActionFilter, the first question I have is, Is this a cross-cutting concern?. Your particular use-case doesn't fit this, at first blush. The reason is, is that an ad is just another thing to render on a page. There's nothing special about it that makes it cross-cutting. If you replaced the word 'Ad' with 'Product' in your question, all the same facts would be true.
So there's that, and then there's the separation of concerns and testability. How testable are your controllers once you have this ActionFilter in place? It's something else you've got to mock out when testing, and what's worse is that you have to mock out those dependencies with every controller you add the ActionFilter to.
The second question I ask is, "How can I do this in a way that seems most idiomatic in the platform I'm using?"
For this particular problem, it sounds like a RenderAction and an AdController is the way to go.
Here's why:
An Ad is its own resource; it normally isn't closely tied to anything else on the page; it exists in its own little world, as it were.
It has its own data-access strategy
You don't really want to repeat the code to generate an Ad in every place you could use it (which is where a RenderPartial approach would take you)
So here's what such a beast would look like:
public AdController : Controller
{
//DI'd in
private AdRepository AdRepository;
[ChildActionOnly]
public ActionResult ShowAd(int categoryId)
{
Ad ad = Adrepository.GetAdByCategory(categoryId);
AdViewModel avm = new AdViewModel(ad);
return View(avm);
}
}
Then you could have a custom partial view that is set up around this, and there's no need to put a filter on every action (or every controller), and you don't have try to fit a square peg (an action filter) in a round hole (a dynamic view).
Adding an Ad to an existing page then becomes really easy:
<% Html.RenderAction("ShowAd", "Ad" new { categoryId = Model.CategoryId }); %>
If your ad system is simple enough, there is no reason you could/should not use an action filter to insert enough info into the view data to generate the ad in your view code.
For a simple ad system, say.. a single ad of a specific category shows up in the same place in the layout on every page and that's it, then there is no real argument of a better way except to prepare for future changes to the system. While those concerns may be legitimate, you may also have it on good authority that requirement will never change. But, even if requirements do change, having wrapped all the code that generates ads in one place is the most important aspect and will save you much more time up front than a more robust solution might. Obviously there are more than a few ways to wrap this code in a single place.
As for the way you are choosing to do it, I would keep your action filter cleaner to only have it insert the category into the view data and have all the magic happen inside your html helper which would take the category in as a parameter. Building up view models to shove into the view data is going to require a bit of extra work, and put code all over the place when it doesn't need to be there. Keep it simple and do all of the html generation inside of the html helper which is responsible for...building html.

ASP.NET MVC: How to handle model data that must go to every view?

So if there is some global state that every view of an MVC app will need to render ... for example: IsUserLoggedOn and UserName ... whats the appropriate way of getting that information to every view?
I understand that that part of the view should be in the master page or in a partial view thats added to the other views. But whats a good way to make sure the 'global' model data is passed to the view every time from all the relevant controllers and actions?
After asking this, I found this good blog post by Steve Sanderson:
http://blog.stevensanderson.com/2008/10/14/partial-requests-in-aspnet-mvc/
He suggests three different approaches:
Use a base controller class or ActionFilter to add the relevant model to the ViewData[] collection every time. I think a few people have suggested that sort of thing already.
Use Html.RenderAction() in the view ... and as he says:
If someone tells you that internal
subrequests are bad because
it “isn’t MVC”, then just bite them on
the face immediately. Also ask them
why they’re still willing to use Ajax,
and even <IMG> tags for that matter,
given that both are a form of
subrequest.
Use 'Partial Requests' (he provides the code for this on his blog) which allow one controller to nest calls to other controllers into a sortof nested ViewData structure.
codeulike - see the answer to a similar question asked at exactly the same time as this:
ASP.NET MVC displaying user name from a Profile
in a nutshell, basically create a base controller that's inherited by all your other controllers. the base controller then has an override function that carries thro' to all 'child' controllers. rather than duplicate the code, take a look at my answer above and give it a try..
cheers...
You could create base class for viewmodel which contains shared information and inherit that for each viewmodel.
public class ViewModelBase
{
// shared data
}
public class Page1ViewModel : ViewModelBase
{
// page 1 data
}
In masterpage you could use that base class
Inherits="System.Web.Mvc.ViewMasterPage<ViewModelBase>"
and in each view use those derived classes
Inherits="System.Web.Mvc.ViewPage<Page1ViewModel>"

Where to apply logic for a sidebar control in ASP.NET MVC

Take the example of wanting to have a "Latest news items" sidebar on every page of your ASP.NET MVC web site. I have a NewsItemController which is fine for pages dedicating their attention to NewsItems. What about having a news sidebar appear on the HomeController for the home page though? Or any other controller for that matter?
My first instinct is to put the logic for selecting top 5 NewsItems in a user control which is then called in the Master Page. That way every page gets a news sidebar without having to contaminate any of the other controllers with NewsItem logic. This then means putting logic in what I understood to be the presentation layer which would normally go in a Controller.
I can think of about half a dozen different ways to approach it but none of them seem 'right' in terms of separation of concerns and other related buzz-words.
I think you should consider putting it in your master page. Your controller can gather data (asynchronously, of course), store it in a nice ViewModel property for your view (or in TempData) and then you can call RenderPartial() in your master page to render the data.
The keeps everything "separate"
http://eduncan911.com/blog/html-renderaction-for-asp-net-mvc-1-0.aspx
This seems to address the question - even using the instance of a sidebar - but using a feature not included with MVC 1 by default.
http://blogs.intesoft.net/post/2009/02/renderaction-versus-renderpartial-aspnet-mvc.aspx
This also indicates the answer lies in RenderAction.
For anyone else interested, here's how I ended up doing it. Note you'll need to the MVC Futures assembly for RenderAction.
Basically you'd have something like this in your controller:
public class PostController
{
//...
public ActionResult SidebarBox()
{
// I use a repository pattern to get records
// Just replace it with whatever you use
return View(repoArticles.GetAllArticles().Take(5).ToList());
}
//...
}
Then create a partial view for SidebarBox with the content you want displayed, and in your Master Page (or wherever you want to display it) you'd use:
<% Html.RenderAction<PostController>(c => c.SidebarBox()); %>
Not so hard after all.
You can create a user control (.ascx) and then call RenderPartial().
Design a method in your controller with JsonResult as return type. Use it along with jQuery.
Use RenderAction() as suggested by elsewhere.
News section with ASP.NET MVC

Resources