I've developed my own custom users and roles objects using ActiveRecord that do NOT extend the default Asp.Net providers and therefore I can't get the user from the HttpContext. I can create a custom htmlhelper to render menus but should my views render the menu or the master page?
If it's the master page how can I pass to the custom htmlhelper things like current user since some menu items depend on the user roles.
Also, how can I detect what controller is being viewed inside my master pages?
1) If your menu functionality is supposed to exist on multiple pages, then it makes sense to put it in the master page. If not, then the normal view.
2) A popular choice is to make all of your ViewModels inherit from a base view class, and then your Master page uses that. Example:
System.Web.Mvc.ViewMasterPage<ViewBase>
System.Web.Mvc.ViewPage<MyViewModel>
public class MyViewModel : ViewBase { }
3) You can pull out the specific controller from the route data. However, if you need specific functionality for certain controllers, I would just suggest using a different master page for those views than trying to make all of your views use the same master page.
In general, all ASP.NET controls (whether WebForms or MVC) should control their own state.
In the case of handling navigation, I'd say create a .ASCX (partial view) and place it on your master page. Let the partial view control how it is displayed based on the HttpContext.
Related
I wonder if I could get some ideas on how best to approach this.
I have a Razor Pages application. I have several areas, and each area has its own layout page and menus.
This is pretty straight forward, but I have a couple of pages I need to share with two or more areas. These shared pages will be passed an argument that indicates which area it's being used by, and I would want the layout page (menu) for that page to be the one for that area. (Ideally, the URL would also reflect the current area.)
I'm not sure if this is practical. I'd like to keep things as simple as possible. But all I come up with is some fairly complex routing stuff.
Two options I can think of:
Put the shared page in the root Pages folder and use AddPageRoute to add multiple routes to the shared page including a parameter for the area name:
options.Conventions.AddPageRoute("/SharedPage", "{areaName}/alias1");
options.Conventions.AddPageRoute("/SharedPage", "{areaName}/alias2");
You can set the layout based on the value of RouteData.Values["areaName"]. Don't use area as the parameter name. It's a reserved word as far as routing is concerned:
#{
if(RouteData.Values["areaName"] == "foo")
{
Layout = "_FooLayout";
}
if(RouteData.Values["areaName"] == "bar")
{
Layout = "_BarLayout";
}
}
Add pages to the areas that act as placeholders to generate the routes, and then extract the body of the shared page to a partial that can be placed in the top level Pages/Shared folder so that it is accessible to all other pages in the application. If you want to centralise some of the processing for the shared page, create a class that inherits from PageModel and put your processing logic there, then have the actual PageModel classes inherit from that.
You can make this by using partial views.
So, create one patial view and place it not in areas (in Common for example or other folders).
In areas folder create master view that render only your Partial view.
I'm using the typical built in view engine in mvc3 (is there a proper name for it?) for views and master pages and it's including a Razor partial view on the .aspx page. In the masterpage, there is a ContentPlaceHolder with an ID of "ScriptContent".
I want to be able to fill that ContentPlaceHolder from within the Razor partial view but I don't think this is possible. Does anyone know if it is possible and how I would go about doing that?
I already tried rendering it in the partial like so, but that didn't work.
#section ScriptContent {
... content ...
}
It would be very difficult, so much so that I'd recommend finding another way :(. I wish it was easier, but these are the complexities of integrating a new view engine into an existing legacy system.
To give you a head start if you really want to try it: You'd probably need to create a custom base class inheriting from WebViewPage for your Razor content pages, override some of the methods (honestly I'm not too familiar with that aspect so you'd need to debug to follow the pipeline) so that instead of treating the Layout property as the path to a Layout page, you treat it as a Master page. Then you'd need to instantiate the master page and somehow convert the Sections (which were transformed into calls to DefineSection by the Razor parser, and should be stored in a Dictionary somewhere on the base class) in to Content controls and stuff them in the Master Page.
If I haven't boggled your mind by this point, you may just be able to pull this off, but to be honest, I'd avoid it.
P.S. We refer to the older view engine as "ASPX", based on its file extension ;).
I have a mvc site where the master page uses RenderPartial to return different views based on user roles. One of the partial view is inherited on a "SettingsModel" type. This results in a conflict with the underlying page which takes a different model. When it tries to render the page, it says "I'm expecting "settingsModel" but the incoming model is for the page. How can I resolve this conflict?
you can use RenderAction method to render different partial pages having their own view models
this article explains difference b/w rederpartial and renderAction with pros and cons of each
I'm trying to get into MVC and currently reading the wrox professional ASP.NET MVC book.
I kind of get it so far. Instead of each URL going to a page it goes to a controller. The controller action then gets the data and decides what view to use.
I also understand that if I have a url like/product.aspx?id=100 then the controller would get the product details and merge them with the "show product" view.
Now here's the bit I don't get...
If my product page has other stuff on it, like a login box, a "top 10 products" section, list of categories etc. which may or not be used on other pages too then how would I include them and keep their code separate?
In the classic aspx model it would be simple. If my top 10 products appeared on every page then I would put it in a master page, but more likely I would make it into a user control if it was going to be used on some pages not others.
From what I understand of MVC so far, my products controller would have to get the top 10 products and so would any other controller that was producing a page with the top 10 products on it.
Confused. Please help.
From what I understand of MVC so far,
my products controller would have to
get the top 10 products and so would
any other controller that was
producing a page with the top 10
products on it.
Not necessarily. You can use Master pages with MVC, as well as Partials to compartmentalize re-usable view content.
This is a good article on using Partials.
http://jeffreypalermo.com/blog/asp-net-mvc-and-the-templated-partial-view-death-to-ascx/
Also, in your Top 10 products example, you could have that rendered by a child action:
[ChildActionOnly]
public ActionResult GetTopTenProducts()
{
var products = db.GetTopProducts(10);
return View(products);
}
You would then have a partial view (.ascx) called "GetTopProducts.ascx" that would be rendered when you call the GetTopTenProducts() action. Then in your Master page, or anywhere you wanted that Top 10 list to show up, you would call it like this:
<% Html.RenderAction("GetTopTenProducts") %>
You're close.
You're just forgetting that your controller is a class that can inherit from a base class.
You can create a base controller class that handles retrieving the top ten products, and then have any controllers that need that functionality inherit from the base class.
You then create a Master Page that uses a Partial View to render the top ten products passed to the View (from the base controller).
...and voila! No code repetition.
Please don't forget that in ASP.NET MVC you still can use MasterPage. With specific to ASP.NET MVC 2 you can display those 10 products using RenderAction which can render Action from any Controller you select.
In addition to that, you should get to know PartialView as well.
You can use master pages and in MVC partial views are synonymous with user controls. The difference being master page does not have a corresponding controller. You an solve with one of two ways.
When you use a partial view you can
pass a model in.
<%= Html.RenderPartial("PartialView",Model) %>
You can just do the work in the partial view, utilizing the code brackets <% %>.
I have an asp.net content page which is used inside of a master page (with header, menu and some links). I would like to reuse it in a different context without the master page (to not display the header and menu there), or with an empty master page if this is somehow possible. I don't want to violate DRY principle by taking the whole page and creating a standalone clone of it for obvious reasons. Is this somehow possible ?
Yes, you can set the master page dynamically in the content pages Page_PreInit method:
private void Page_PreInit(object sender, EventArgs e)
{
this.MasterPageFile = "MyMasterPage.master"
}
Set up some logic to dynamically choose which master page filename to pass in, and you are now sharing one content page with many master pages.
How about wrapping-up the shared content in a user control?
A user control is a kind of composite
control that works much like an
ASP.NET Web page—you can add existing
Web server controls and markup to a
user control, and define properties
and methods for the control. You can
then embed them in ASP.NET Web pages,
where they act as a unit.