Base page in MVC 2 - asp.net

I have just moved over to using ASP.NET MVC 2. In web forms, I normally had a BasePage class that extends from System.Web.UI.Page. And then every page extends from this BasePage. In this BasePage class I have methods that I need. How would I do this in an MVC application?
Any samples would be appreciated.
Thanks.

It is a bit different in MVC. The equivallent would be BaseController although this doesn't correlate exactly to a page in the classic ASP.NET sense. For a start, a controleler doesn't have any markup.
Into a base controller you might inject any model classes that are required by all pages and any common behaviours that have to be executed as part of all Action requests. An example might be some custom checks to go into the Controller OnActionExecuting event...
http://msdn.microsoft.com/en-us/library/system.web.mvc.controller.onactionexecuting.aspx
protected override void OnActionExecuting(ActionExecutingContext filterContext)
{
//check the filterContext for a certain condition
if (condition) {
//do something else - redirect to a different route or
//render a different view to to the default
filterContext.Result = new RedirectResult(newUrl);
}
//Otherwise, do nothing, the requested Action will execute as normal...
}

IN MVC there is a greater separation of concerns for rendering the UI, so depending on what the code did in your base page will dictate where it goes in MVC.
If your code generated HTML than you will probably be creating custom HTML helpers and reusable partials views (.ascx). If it handled input data than it will go in a model binder class, and you can create a base model binder for common code. If it talked to your services and domain model than it will go in the controller, and again you can use a base controller. Queries to the persistence layer will go in your model, and reusing code here leads to a much larger discussion of your architecture.

We also moved from base Page classes in ASP.NET and found that a combination of a base controller and a base Model (ViewData) class works well.
So ex Page properties eg: CurrentUser are available from the base Controller and also passed to the base ViewData when its initiated so you can use them on the aspx page.

Related

Filtering the output of my ASP.NET MVC views

I want to do some additional processing of the output of all my views before they get sent to the client.
I tried setting the view base class to a custom class where I override Execute, but that doesn't work because Razor will generate its own Execute in the derived class that doesn't call mine.
Is there another MVC-specific way to do it, or my only hope is to resort to the "classic" way of doing it, by setting Response.Filter in Application_BeginRequest in Global.asax?
You should implement IResultFilter. Common way to do it is by deriving from ActionFilterAttribute
void OnResultExecuted(
ResultExecutedContext filterContext
)

When is it ok to meddle in the page lifecycle an ASP.NET MVC page?

It seems that ASP.NET MVC just runs on top of ASP.NET WebForms. System.Web.Mvc.ViewPage in ASP.NET MVC inherits from System.Web.UI.Page which includes page lifecycle methods like OnRender and friends.
I have seen a couple of comments around the web to the effect that you should resist the urge to override these methods AT ALL COSTS!. Of course, this means that I find myself resisting the urge to do just that.
Is there really that much wrong with something like the following?
public class SslPage : ViewPage
{
protected override void OnPreInit(EventArgs e)
{
// Make sure we are using SSL
string url = HttpContext.Current.Request.Url.ToString();
if(url.StartsWith("http:"))
{
HttpContext.Current.Response.Redirect("https" + url.Remove(0, 4),false);
}
// Back to our regularly scheduled programming...
base.OnPreInit(e);
}
}
One could debate the purity of putting that in a "View" but it seems plenty expedient.
How dangerous/blasphemous is it to override these methods? When might it make sense?
The problem with what you describe is that the view is only rendered once the controller decides which view to render. It may seem surprising at first, but by the time your OnPreInit method is called, all of the logic of the controller has already executed.
The correct place to put this, as #Ryan says, is in a filter or a base controller.

ASP.NET MVC - Code Behind of Master Pages

I am newbie for ASP.NET MVC 1.0. I am converting from a classic application built up with VS2008 .NET3.5. I created a master page, and the menu must be read from the database. Now the code that generate the HTML into the appropriate menu div in classic ASP.NET3.5 VS2008 was in the code behind of the master page.
I cannot understand now where the code beind of the master page is in ASP.NET MVC 1.0?
Anyone has examples?
Thanks
In MVC there are no longer Code-Behind classes. What you want is a Partial.
You'd use it like so:
<% Html.RenderPartial("MainMenu.ascx", ViewData["Menu"]); %>
If this Menu is going to be in all of your pages you can make your controllers subclass a custom controller class that always fills the Menu data first.
If messing with the MVC inheritance hierarchy is overkill you can also make a MenuController class and use the RenderAction in your view/master:
<% Html.RenderAction<MenuController>(x => x.MainMenu()); %>
You can still have code behind if you want. In your .master file put:
<%# Master Language="C#" AutoEventWireup="true"
Inherits="Site_Master" CodeFile="Site.Master.cs" %>
Then in your .master.cs:
public partial class Site_Master : ViewMasterPage
{
protected void Page_Load(object sender, EventArgs e)
{
}
}
Your master page is now a View, and Views should be passive. In other words, they shouldn't go look up things themselves.
It would be a much more correct approach (within the context of ASP.NET MVC) to pull the required data from the Model.
Take a look at this SO question for a related discussion.
There is a great tutorial on the ASP.NET site that shows how to do exactly this.
Briefly, you pass the data to the master page through the ViewData collection. To get the data into ViewData, create an application level controller. Have the page controllers inherit from the application controller instead of the base MVC controller.
Also, if you need to do things on your master page in reaction to the page being displayed, through this application controller you can tie into the ActionExecuting event. That will provide you information about the context of the page request currently being process.
Personally, I prefer using strongly typed views and ViewModels. If your master page requires data, then create a ViewModel for it. Ensure that every page's ViewModel inherits from this base ViewModel. Similarly, create a base controller that every other controller inherits from. Using Action Filters will allow you to ensure that the master ViewModel is populated implicitly. See this for an example.

Using a Base Controller for obtaining Common ViewData

I am working on an ASP.NET MVC application that contains a header and menu on each page. The menu and header are dynamic. In other words, the menu items and header information are determined at runtime.
My initial thought is to build a base Controller from which all other controllers derive. In the base controller, I will obtain the menu and header data and insert the required information into the ViewData. Finally, I will use a ViewUserControl to display the header and menu through a master page template.
So, I'm trying to determine the best practice for building such functionality. Also, if this is the recommended approach, which method should I override (I'm guessing Execute) when obtaining the data for insertion into the ViewData.
I'm sure this is a common scenario, so any advice/best-practices would be appreciated! Thanks in advance!
EDIT:
I did find the following resources after posting this (of course), but any additional anecdotes would be awesome!
http://www.singingeels.com/Blogs/Nullable/2008/08/14/How_to_Handle_Side_Content_in_ASPNET_MVC.aspx
How do you use usercontrols in asp.net mvc that display an "island" of data?
Depends on where your information is coming from. We have standard view data that we use to generate some of the information we have on screen that we create in just this fashion. It works well and is easily maintained. We override the View method to implement strongly typed view names and use this information to retrieve some of the data that the master page requires as well.
You could write a helper extension to render the header/menu
That way you could have it show in different places in the view should you need to, but only one place for maintenance.
public static HtmlString MainMenu(this HtmlHelper helper)
Use a base controller class to implement generell filter methods. The controller class implements some filter interfaces IActionFilter, IAuthorizationFilter, IExceptionFilter and IResultFilter which are usefull to implement some common behavior for all controllers.
If the menu data is the same on all pages but different for each unique user.
Generate the menudata in an OnAuthorization or Initialize method of your controller base class. First will be called on authorization. Initialize will be called before every action method. You have access to ViewData Context. Generate the menudata there.
Put the view content for menu and header into the master page and access generated ViewData there.
I tackled a similar design challenge a couple months ago - implementing a breadcrumb feature that changes as user navigates from page to page.
I overrided the OnActionExecuting method to gather the breadcrumbs and store them in ViewData (I use the name of the action as the breadCrumb of the view). Then I updated the Master page to include a user control that takes the ViewData and renders the breadcrumbs.
One thing to be aware is that if you were using the default ASP.NET MVC error handling attribute [HandleError] and your error page is using the same Master page that attempts to read the ViewData, you will soon find out that you can't access ViewData from your error page and it will raise an exception. Depending on whether you need the ViewData for failure scenarios, the viable solution is to use a separate Master page or do this: How do I pass ViewData to a HandleError View?
I'll answer your question with another question. Will the base controller have to determine what type it really is in order to generate the proper menu data? If so, then you're defeating the purpose of polymorphism and the code to generate the data should go in each controller, perhaps in OnActionExecuting if the menu is the same for all actions. Pushing it back down into a parent class seems likely to end up with some switch statement in the parent class doing what each derived controller really ought to take care of.

How do you use usercontrols in asp.net mvc that display an "island" of data?

I am trying to find out how to use usercontrols in asp.net mvc. I know how to add a usercontrol to a view and how to pass data to it. What I haven't been able to figure out is how do you do this without having to retrieve and pass the data in every single controller?
For example, if I have a user control that displays the most recent posts on several but not all the pages in the site, how do I write the Controllers so that I get data for that usercontrol and pass it to the user control from only one place in the web site instead of getting and passing data in each of the different controllers that the user control is used in?
I'm not sure if this makes sense or not. Is there a better or recommended way to handle an "island" of data that you want to display on several pages?
I'm coming from web forms where I could just write a user control that got its own data and displayed data independently from the rest of whatever page it is used on.
There are multiple ways to do it.
The basic approach is
Populate the data for the view in the BaseController (OnActionExecuting event)
Writing a custom action filter
Writing an Application Controller (the eg. is in the below links).
An example of OnActionExecuting will be
[HandleError]
public class BaseController : Controller
{
CourseService cs = new CourseService();
protected override void OnActionExecuting(ActionExecutingContext filterContext)
{
List<Tag> tags = cs.GetTags();
ViewData["Tags"] = tags;
}
}
You can use the "tags" view data on any view. This is just an example of usercontrol being rendered as side content.
<div id="sidebar_b">
<asp:ContentPlaceHolder ID="ContentReferenceB" runat="server" >
<% Html.RenderPartial("Tags"); %>
</asp:ContentPlaceHolder>
</div>
I found the following URL to be useful.
http://weblogs.asp.net/stephenwalther/archive/2008/08/12/asp-net-mvc-tip-31-passing-data-to-master-pages-and-user-controls.aspx
http://blog.matthidinger.com/2008/02/21/ASPNETMVCUserControlsStartToFinish.aspx
http://www.aaronlerch.com/blog/2008/01/26/displaying-foo-on-every-page-of-an-aspnet-mvc-application/
http://blog.wekeroad.com/2008/01/07/aspnet-mvc-using-usercontrols-usefully/
In the MVC Futures, available on codeplex , contains the RenderAction HtmlHelper extensions. This will allow you to create a controller for the ueser control and this controller will populate the ViewData used by the user control without having to resort to a base controller as was suggested.
In the View you would do
<% Html.RenderAction("Index", "UserControlController") %>
or one of the other overloads.
This will create an instance of the controller, execute the method and render the user control view into the main view. The main view controller does not need to know anything about the user control or its model/data.
Refactor the code that obtains the view data for this user control into it's own method, maybe even it's own model (class). Call this method from each controller that needs to populate the control and pass the results in the ViewData with a well-known key. You might even want to pass the type of the current controller to your method in case it needs to know what data to retrieve based on the base model for the controller.
ViewData["RecentPosts"] = RecentPosts.GetRecentPosts( this.GetType() );
In your control, retrieve the data using the well-known key.
How to Handle "Side Content" in ASP.NET MVC

Resources