how to manage logic in the _Layout.cshtml - asp.net-mvc

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.

Related

MVC controller vs. out-of-box Sitecore Controller

I've been reading a lots of blogs on MVC provided here:
http://www.sitecore.net/Community/Technical-Blogs/John-West-Sitecore-Blog.aspx
However, I am not being able to explain/convience myself/team:
When to use custom control vs. out of box site core controller?
When does the Out of Box Controller gets invoked?
Benifit of custom control vs. out of box controllers?
If we go with out of box, should we include all business logic on Views. Is this testable?
I also looked at below and still not certain:
https://bitbucket.org/demoniusrex/launch-sitecore-mvc-demo
Any help will be appreciated.
Whilst I broadly agree with Kevin Obee's statement I think it's worth reminding ourselves that controllers are being used in two distinct roles in Sitecore:
Page level controller (invoked by item route)
Component level controller (invoked by redering mechanism)
When to use: Custom controller / default Sitecore controller
Page level controller
Any route that matches an item path will by default use the Index action on the Sitecore.Mvc.Controllers.SitecoreController. This action will return a ViewResult based on the layout configuration of the item.
If you have a need for changing this behaviour (e.g. something that impacts the entire page) you can specify a custom controller and action on the item (or the Standard Values for the item). For the custom controller you can either roll your own or subclass the default controller.
Component level controller
For ViewRendering Sitecore renders the Razor views without the need for a specific controller (well I guess it's the page level controller that is in play - but just imagine that Sitecore provides a default controller that gets the model using the mvc.getModel pipeline and feeds it to the Razor view).
For ControllerRendering you provide a custom controller that can execute logic (see Kevin's answer) and provide a model for the view. There is no benefit from subclassing Sitecore.Mvc.Controllers.SitecoreController.
When are controllers invoked
Page level controller
The action on the page level controller is invoked by the routing engine.
Component level controller
The action on a ControllerRendering is invoked as the page view renders.
Benefit of using: Custom controller / default Sitecore controller
The benefit of a custom controller over the default Sitecore controller is that you are in control of the logic. The benefit of using the default Sitecore controller is that Sitecore provides the logic for you.
Should we include all business logic on Views
No. (See Kevin's answer)
My personal view is that the business logic should go in command and query classes that are invoked from the controller class. From these calls you can assemble a strongly typed view model which gets passed to a dumb razor view for rendering.
Ensure that any services that the controller relies on are passed into it via constructor injection using contracts (interfaces) instead of concrete classes and you should end up with solution that is unit testable.

Logic for Partial Views Used Across an App

How do I associate a PartialView which will be used across the app with a Child Action? For example the PartialView could be a login bar at the top of the page which will need to have some associated logic (loading the model etc) which I would normally put in a ChildAction.
However, I don't know what Controller will be used. I think I could create a base Controller class with the ChildAction and then inherit from that but I was hoping there would be a more elegant solution.
The RenderAction method allows for selecting the controller:
http://msdn.microsoft.com/en-us/library/ee839451.aspx

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

Rendering multiple views from multiple controllers on a single page

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.

Where to put master page's code in an MVC application?

I'm using a few (2 or 3) master pages in my ASP.NET MVC application and they must each display bits of information from the database. Such as a list of sponsors, current fundings status etc.
So my question was, where should I put these master-page database calling code?
Normally, these should goes into its own controller class right? But then that'd mean I'd have to wire them up manually (e.g. passing ViewDatas) since it is out of the normal routing framework provided by the MVC framework.
Is there a way to this cleanly without wiring ViewData passing/Action calls to master pages manually or subclassing the frameworks'?
The amount of documentation is very low... and I'm very new to all this including the concepts of MVC itself so please share your tips/techniques on this.
One way to do this is to put in the masterpage view the hook for the ViewData and then you define a BaseController : Controller (or multiple base classes) where you do all the db calls you need.
What you wanna do is quite the same thing described in this articles.
I hope this helps!
Regards
Great question. You have several options available to you.
Have a jQuery call on your masterpage that grabs the data you need from a controller and then populate your fields using jQuery again.
Your second option is to create user controls that make their own calls to the controller to populate their information.
I think the best choice is creating controls for the region of your masterpage that has data that needs to be populated. Thus leaving your masterpage to strictly contain design elements. Good luck.
If you don't mind strongly typed view data, you can put all the master page data in a common base class for viewData. You can set this data in the base class's constructor. All your views requiring additional data will then need strongly typed viewdata that inherits from this base class.
To allow a call to View() in your controllers without any explicit viewdata you can override View in your ControllerBase:
protected override ViewResult View(string viewName, string masterName, object model)
{
if (model == null)
{
model = new ViewDataBase();
}
return base.View(viewName, masterName, model);
}

Resources