Modifying view location for partial views in ASP.NET MVC - asp.net-mvc

I would like to have both these views:
~/Views/Customer/Index.aspx
~/Views/Customer/Index.ascx
I would like to setup my MVC website so that when I call return View(viewModel) from the CustomerController.Index() action method, that it looks up the aspx file, but if I call return PartialView(viewModel) that it looks up the ascx file.
I believe the magic involves subclassing ViewEngine and ControllerFactory (so that the ViewLocator.ViewLocationFormats can be modified), but want to check that I'm not over-engineering this solution.
Does anyone have any experience with this?

Based on the comments above and the suggestion, I think my answer to a different question may provide some help - Render Partial of same name as parent View - Crashes WebDev.WebServer40.exe
The issue is that the PartialViewLocationFormats are set to be the same as the ViewLocationFormats. It does not make sense to that a partial view would be an aspx page.

override WebFormsViewEngine and reimplement ViewLocationFormats and/or PartialViewLocationFormats

Related

Adding a View without a model MVC 5

I need to create a simple view with 3 links on it ( Administration type page ), I tried adding a View called index to a Directory called Administration but when I try to navigate to it it throws a resource not found error. I am brand new to MVC coming from Web Forms so sorry if this is a stupid question ;)
Firts Add a controller which will come with Index method. Right click on Index Method and select Add View.
Add all Html you want to add in that view and your page is ready without adding a Model.
You need to have a controller to render the view.
For instance, if you had an AdminController with a method similar to something like public ActionResult Index() { return View(); } this would render the index view where you could place your html/links etc.
The view itself doesn't need a model this way as you are not supplying anything when returning the View().
You could then navigate to the page by http://xxx/Admin/Index or, 'http://xxx/Admin/'.
It is well worth looking around SO and other various websites for MVC queries!
Good luck.

Is there an MVC way of doing ASCX?

Are ASCXs still used in ASP.NET MVC or should we be using something else?
Yes, you can still use .ascx. They are often referred to as partial views.
You bet, I typically use an ascx to render a partial view for some type of ajax functionality. Although, as Jeffrey Palermo points out they don't add much value beyond the extension being a direct inclination that your are working with a partial view.
The great thing about them is that in your controller you can then use
return PartialView("MyPartialView", items);
This works great in a jQuery call when you are only interested in changing the contents of particular part of the page and not the whole page.

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

Is there an equivalent to Monorail view components for the ASP.Net MVC Framework?

I make heavy use of View Components in some of the larger applications I've built in Monorail - What is the equivalent approach in ASP.Net MVC for a view component, that can support sections etc.?
Actually you have several options to create the equivalent of a ViewComponent in ASP.NET MVC, depending in the complexity of your component. I use these two approaches which are the more mvc-ish of the options I am aware of.
1:
The simplest thing is to create a ViewUserControl and display it using Html.RenderPartial with the helper. The ViewUserControl is a simple piece of markup with no backing controller (I think you can put a codebehind file if you want).
Optionally, you can pass a model object or the entire ViewData dictionary to the view when calling RenderPartial, like this:
<% Html.RenderPartial("TopBar", model); %>
"TopBar" is an ascx page. This works anywhere, in master pages and in normal views.
2:
If you want your component to have more complicated logic or to access datasources, IoC, etc, then you can use Html.RenderAction which is an extension method found in the Microsoft.Web.Mvc assembly. I am using this out of the mvccontrib distribution. It works like this, you need to create a normal controller with all the logic you need, then create some views and all of these things become your component, for example:
public class AboutComponentController : Controller {
public IRepository Repository{ get; set; }
public ActionResult Detail() {
var lastEvent = Repository.FindAll<Auditoria>().FirstOrDefault();
return View(lastEvent);
}
}
Notice how I have a reference to an IRepository which is going to be injected with IoC (Windsor in my case) and I can do anything a normal controller would do.
Now, in any page (master or normal) where you want to use your component, import Microsoft.Web.Mvc and call Html.RenderAction with the appropriate parameters. This will create a mini mvc pipeline that creates the controller, resolves the view, etc., just like a Monorail ViewComponent. I prefer to use the lambda based variation of the method, like this:
<% Html.RenderAction<AboutComponentController>(x => x.Detail("a message"));%>
Unfortunately, the only way to pass parameters is to use the method call itself, which in turn must be unique in the controller. Still needs some work to resemble a ViewComponent.
I don't use masterpages or layouts in the views of my components since they are composition elements themselves.
Remember that when using the Webforms view engine, you can have strongly typed views if you like to have intellisense when using the Model variable in code blocks.
The beauty of this is that you can mix view engines with these approaches, I usually create the components in nvelocity and display them in aspx pages, etc.
I now there can be issues with caching of the partial views but I haven't run into any so far. I am sure there are other options (like subcontrollers in mvccontrib) but this is usually enough for simple cases. Of course you can use normal ASP.net components in your aspx view pages but that would be cheating right? hehe. I hope it helps.
Phil Haack blogged about creating areas to group controllers into sub-folders/sections similar to MonoRails.

passing viewdata to asp.net mvc masterpages

I'm trying to pass ViewData to my asp.net mvc masterpage for an mvc usercontrol that I keep on a masterpage. For example, I created a dropdownlist of names as an mvc usercontrol and I put that in my masterpage.
The problem I am running into is passing the ViewData to the masterpage. I found this article from Microsoft which has a decent solution but I was wondering if there are other "better" solutions out there. The thing I don't like about the solution in the link is that I have to change every controller to inherit from a new controller class.
http://www.asp.net/learn/MVC/tutorial-13-cs.aspx
Edit: The problem I am looking at is the fact that if I place a user control in my masterpage that relies on ViewData, I have to REPEATEDLY include that ViewData for every single page that uses said masterpage. It's possible the solution in the link above is the best solution but I was hoping there were other alternatives.
The master page already has access to the ViewData. If you want strongly typed access to it, you need to do two things:
Put the master page stuff in a base class (e.g. CommonViewData)
Have you master page inherit from the generic ViewMasterPage<> class:
" %>
Could you possibly use the OnActionExecuting method on a base controller class and populate the view data there?
Something like:
protected override void OnActionExecuting(ActionExecutingContext context)
{
context.Controller.ViewData.Model = GetDataForControl();
}
I haven't tried it so it's just a thought...
For what it's worth, I am using the method from that tutorial in a current project and it works very well.
What you can also do, if it is data that is somewhat static (like a menu that doesn't change much), is to put the object on the cache so your database isn't called for every controller initialisation.
I usually use an abstract controller class for my MasterPage, it is the best solution, because the MasterPage is like an "abstract view". But I override the MasgerPageController View() method to include the viewdata.
protected override ViewResult View(string viewName, string masterName, object model)
{
this.ViewData["menu"] = this.PagesRepository.GetPublishPages();
return base.View(viewName, masterName, model);
}
I don't quite get your problem...
The problem I am looking at is the fact that if I place a user control in my masterpage that relies on ViewData, I have to REPEATEDLY include that ViewData for every single page that uses said masterpage.
Well yeah... of course you do. If you have a usercontrol in your master page then of course you're going to have to pass the required data for that usercontrol for every action & view that uses that masterpage.
It's not like you have to repeat yourself if you are just inheriting from a base controller.
Is your issue the fact that some controllers have actions that both do and don't call views that derive from that particular masterpage? So therefore if you are implementing a base controller, the actions that don't use that particular masterpage will still have the viewdata for it...? (If all that makes sense ;-)
I think the solution suggested does work but not the ideal solution. If we put the code in the BaseController constructor it is going to be called even for Action methods which does not have a MasterPages (e.g Post methods and Ajax methods).
I think a better solution(not ideal) is to call Html.Action method in the Master page.

Resources