Is there a way to have OutputCache ignore the master page in asp.net mvc? - asp.net-mvc

I have an action that returns a view with a master page with a logon user control at the top. When I set outputcache, it caches the entire output including the current user, so everybody would see whoever was the last person to hit the page to refresh the cache as the current user. Is there a way to prevent the master page from being included in the cache?
I am using the following code:
[OutputCache(Duration=3000, VaryByParam={params})]
public ActionResult {actionName}({params})
{
{codeGoesHere}
}

There was a concept of "donut caching" (excluding parts of a page from the output cache) but it didn't made it in asp.net MVC 1. For solution to your problem you can try this workaround.

Output cache is associated with the controller, not the view. A controller may return different views, based on the passed parameters. Caching may also be done by parameters (like you have in your example). When the result of a controller is cached, that cached value is the view's generated html (including the master page if any). So, the short answer is, no, you can't exclude the master page from the cache.

Related

Persistent data across internal pipelines / requests

Basically I have a webpage structure where common parts of the page (header, side bar, etc) are generated in a separate controller filled with child actions outputting partial views. I then call these actions (using RenderAction()) from the layout page of the website.
So (if I'm right in saying this), There are multiple internal mvc pipelines (header/sidebar internal requests) including the original request pipeline to for the specific webpage. How/Where can I initialize some data from the original pipeline request and have that data accessible from the other internal mvc pipeline requests?
Summary of what I want to accomplish (with example)
Request for website comes in.
MVC starts pipeline for "Home" controller, "index" action.
Before the Action gets executed, some data needs to be created that can later be accessible.
From the layout page, several "RenderAction" Methods get executed creating sub pipelines for interal requests (e.g. "Shell" controller, "DisplayHeaderBar" action
"DisplayHeaderBar" needs to access some data that was set in step 3 before rendering partial view
Hopefully this makes sense...
What you're looking for are child actions. You simply create an action in some controller that returns a partial view. For example, you could handle your site navigation via:
[ChildActionOnly]
public ActionResult SiteNavigation()
{
// get the data for your nav
return PartialView("_SiteNavigation", yourSiteNavModel);
}
The ChildActionOnly attribute ensures that this action can only be called as a child action, making it inaccessible via typing a URL in a browser's navigation bar.
Then, you create a view in Views\Shared\_SiteNavigation.cshtml:
#model Namespace.To.ClassForSiteNavigation
<!-- render your site navigation using the model -->
Finally, in your layout:
#Html.Action("SiteNavigation", "ControllerWhereThisExists")
I think you could use Tempdata for that. Tempdate gets deleted after you access it, so if you want to use the data more then once use Tempdata.Peek or Tempdata.Keep.
Here is a link with some explanation how you can pass data in asp.net mvc.
https://msdn.microsoft.com/en-us/library/dd394711%28v=vs.100%29.aspx
If tempdata doesn't do it then you could use cache.

pass value to renderpartial in master page from user control

Is it possible to have a master page that has a renderpartial it in and supply a value to be passed to that partial before it is rendered.
For example we have a common menu structure across our site, I would like to put this as a partial in the master page, the problem comes in that depending on what area in the page you are we need to set a value for the selected tab so it gets highlighted and you can see where you are.
Currently the render partial is on ever page and passes in a value for the selected tab, I would like this to be in the master page and just have some way to pass the value to the master page.
I have a feeling this might be possible with the changes introduced with razor but I'm not sure, in any case we are using asp.net mvc 2 (although I'm still interested in things that would apply to more recent versions)
You could use RouteData property to get currently called page using the following:
ViewContext.ParentActionViewContext.RouteData.Values["controller"]
ViewContext.ParentActionViewContext.RouteData.Values["action"]
// OR
ViewContext.RouteData.Values["controller"]
ViewContext.RouteData.Values["action"]
Either in the controller associated with the menu or in the view itself (if it's partial). Then you can filter the output upon the current route.

MVCDonutCaching - Issues with child action when parent is not donut cached

I am using the awesom MVCDonutCaching package from Nuget in order to cache entire pages while leaving certain portions uncached. The process is simple and everything works as it should:
I am caching as follows:
[DonutOutputCache(CacheProfile = "FiveMins")]
public ActionResult Index()
{
return View();
}
For the section of my page I do not wish to cache I am doing the following:
#Html.Action("HeaderLinks","Home", true)
This works as it should and indeed the bulk of the page is cached but my header links - context sensitive links displaying a log on button if the user is not logged in, their username if they are, etc. - is not cached. So far everything works.
The problem that I am having is that the headerlinks belong to a master/layout page and are used across the board - regardless of whether an Action has a DonutOutputCache attribute set or not. When I create another action, let's call it 'about us', without a donut caching attribute I do not see my header links at all
public ActionResult AboutUs()
{
return View();
}
Looking at the source code I see the following
<!--Donut#
<ActionSettings xmlns="http://schemas.datacontract.org/2004/07/DevTrends.MvcDonutCaching" xmlns:i="http://www.w3.org/2001/XMLSchema-instance">
<ActionName>HeaderLinks</ActionName>
<ControllerName>Home</ControllerName>
<RouteValues xmlns:a="http://schemas.microsoft.com/2003/10/Serialization/Arrays">
<a:KeyValueOfstringanyType>
<a:Key>Area</a:Key>
<a:Value i:type="b:string" xmlns:b="http://www.w3.org/2001/XMLSchema"/>
</a:KeyValueOfstringanyType>
</RouteValues>
</ActionSettings>
#-->
Obviously in the above example, which is generated by the donut caching library - the links section is replaced by some commented XML.
My question in a nutshell is: is it possible with this library to reuse the same child action regardless of whether the parent action is using donut caching or not?
Any help would be appreciated.
Currently you are required to use the Html.Action together with the DonutOutputCache action filter in order to get the donut hole to render. If you use the Html.Action without the DonutOutputCache, you will see the placeholder comment that you have outlined above.
This is an oversight though and will be addressed in the next release.
see http://mvcdonutcaching.codeplex.com/workitem/2388

Shared 'per request' storage for ASP.NET MVC controllers

In a standard ASP.NET webforms project, if I have a several user controls on a page that require the same data I'd tend to have the first user control put the data in the HttpContext.Current.Items collection so it was available for all the others.
What's the nearest equivalent to this for a ViewResult on an MVC controller that's used multiple times on the same page?
Thanks
Edit:
Basically the ViewReults here are content areas which appear more than once on a page, so I was looking to query the database once to get a collection of all the content for the page (when the first content area is laoded) rather than a separate query for each content area. Thought it would speed things up.
Further info:
Just to make it clear, the content controller action is used repeatedly as a 'RenderAction' from within pages that are served by an additional 'main' controller. Consequently I don't think I can use ViewData (or any other property on the controller class itself) as it's not shared between different instantiations of the same controller.
I think I'm going to have to fall back on the HttpContext after all using a method such as this one.
"Multiple times on the same page" means the same request meaning you can still use the HttpContext.Current.Items collection.
Why don't you just put this content in your ViewModel and have all the controls use that? This is a pretty standard usage of a View's model.

Post/Redirect/Get: Redirect to specific route

I have the following scenario:
I have an edit page, which can be called from different pages. These pages could be the detail view for the current entity, or the list view for the entities (with or without a search in the route).
HOW do I cleanly redirect to the original calling page using the MVC framework? Of course I could simply pass the HttpContext.Request.Url value by holding it in my TempData, but that sort of smells, in my eyes (or, err, nose). It's on a lower level than the rest of the code.
Is there a way to get the routevalues for the previous page in a controller context? If I have that, I could store that temporarily and pass that to the redirect.
Do not use TempData when not redirecting. One AJAX request from your edit page, and the TempData will go away.
Tomas is right that a hidden element or query string parameter is the way to go. But make sure you sanitize the value submitted. You don't want to redirect any old site on the web; you need to ensure that the page to which you redirect is part of your sites.
you can always have a hidden form element telling the controller where to redirect when posting a form. when using a get request, you could use a querystring in a similar way. it might not be the most beautiful solution, but it's quite a lot safer than trusting httpreferrer or other headers that could easily be changed (or ommitted) by the browser.

Resources