I've been reading 'ASP.NET-MVC Tutorials' to learn how to generate data for the 'masterpage' view in an ASP.NET MVC application. It suggests the pattern of using a 'base-controller' and generating the data in its constructor.
My issue is that I wish to store the application data in the application cache rather than the viewdata dictionary. The application cache doesn't exist in the controller constructors as its set later, how can开发者_C百科 I store data for the masterpage view in application cache?
Figured it out. Well.... a version that works. I needed to add the applciation data to the cache when the ControllerActionInvoker's 'InvokeAction' method fires. To do this I had to create a new ActionInvoker as below.
public class ContextActionInvoker : ControllerActionInvoker
{
public const string testMessageCacheAndViewDataKey = "TESTMESSAGE";
private const int testListLifetimeInMinutes = 10;
public ContextActionInvoker(ControllerContext controllerContext) : base() { }
public override bool InvokeAction(ControllerContext context, string actionName)
{
// Cache a test list if not already done so
var list = context.HttpContext.Cache[testMessageCacheAndViewDataKey];
if (list == null)
{
list = new SelectList(new[] {
new SelectListItem { Text = "Text 10", Value = "10" },
new SelectListItem { Text = "Text 15", Value = "15", Selected = true },
new SelectListItem { Text = "Text 25", Value = "25" },
new SelectListItem { Text = "Text 50", Value = "50" },
new SelectListItem { Text = "Text 100", Value = "100" },
new SelectListItem { Text = "Text 1000", Value = "1000" }
}, "Value", "Text");
context.HttpContext.Cache.Insert(testMessageCacheAndViewDataKey, list, null, DateTime.Now.AddMinutes(testListLifetimeInMinutes), TimeSpan.Zero);
}
context.Controller.ViewData[testMessageCacheAndViewDataKey] = list;
return base.InvokeAction(context, actionName);
}
}
Once this was done I needed to create a custom controllerfactory that would make sure the correct ActionInvoker method was called. I did this by doing...
public class ContextControllerFactory : DefaultControllerFactory
{
protected override IController GetControllerInstance(RequestContext requestContext, Type controllerType)
{
IController controller = base.GetControllerInstance(requestContext, controllerType);
Controller contextController = controller as Controller;
if (contextController != null)
{
var context = new ControllerContext(requestContext, contextController);
contextController.ActionInvoker = new ContextActionInvoker(context);
}
return controller;
}
}
I then had to tell the MVC application which controllerfactory to use. I did this by changing Global.asax.cs a bit...
public class MvcApplication : System.Web.HttpApplication
{
...
protected void Application_Start()
{
...
ControllerBuilder.Current.SetControllerFactory(typeof(ContextControllerFactory));
...
}
...
}
Then on the masterpage I used the dropdownlist HTML helper method, by doing...
<%: Html.DropDownList(MVC_MasterPage_data_set_in_cache.Controllers.ContextActionInvoker.testMessageCacheAndViewDataKey) %>
If you override the Initialize
method in your base controller, you have access to the Cache
. Initialize
will execute before any action is executed on any request for an action in the controller.
protected override void Initialize(RequestContext requestContext)
{
base.Initialize(requestContext);
var list = requestContext.HttpContext.Cache[testMessageCacheAndViewDataKey];
if (list == null) { ... }
}
精彩评论