eu-*_*-ne 5 asp.net asp.net-mvc
是否有任何解决方案来访问HttpResponseBase.WriteSubstitution()方法中的TempData属性
这不起作用:
<%= Response.WriteSubstitution(x => Html.Encode(TempData["message"].ToString())) %>
Run Code Online (Sandbox Code Playgroud)
但这有效:
<%= Response.WriteSubstitution(x => DateTime.Now.ToString()) %>
Run Code Online (Sandbox Code Playgroud)
问题出在一次缓存页面的请求处理中.根据http://msdn.microsoft.com/en-us/library/system.web.httpresponse.writesubstitution.aspx:
在对页面的第一个请求中,WriteSubstitution调用HttpResponseSubstitutionCallback委托来生成输出.然后,它为响应添加一个替换缓冲区,该代码保留委托以便在将来的请求上调用.最后,它将客户端可缓存性从公共服务器降级到仅服务器,确保将来对页面的请求通过不在客户端上缓存来重新调用委托.
换句话说,委托无权访问Session属性(SessionStateTempDataProvider在会话中存储TempData),因为没有"正常"的请求生命周期.据我所知,它是在HttpApplication.ResolveRequestCache/HttpApplication.PostResolveRequestCache事件处理的,但当前状态是在HttpApplication.AcquireRequestState事件中获取的(http://msdn.microsoft.com/en-us/library/ms178473.aspx)
也许我需要某种"高级自定义TempDataProvider":)任何想法?
我找到了解决方案:
主要思想是在缓存中保存TempData的副本,并在每个请求中进行检索.该解决方案是自定义TempDataProvider和简单http模块的组合.另外还有几个助手和静态类.
这是代码:
CustomTempDataProvider:
using System;
using System.Collections.Generic;
using System.Web;
using System.Web.Caching;
using System.Web.Mvc;
public class CustomTempDataProvider : SessionStateTempDataProvider, IHttpModule
{
public void Init(HttpApplication application)
{
application.BeginRequest += new EventHandler(application_BeginRequest);
}
void application_BeginRequest(object sender, EventArgs e)
{
var httpContext = HttpContext.Current;
var tempData = httpContext.Cache[TempDataKey] ?? new Dictionary<string, object>(StringComparer.OrdinalIgnoreCase);
httpContext.Items.Add("TempData", tempData);
httpContext.Cache.Remove(TempDataKey);
}
public override void SaveTempData(ControllerContext controllerContext,
IDictionary<string, object> values)
{
HttpContext.Current.Cache.Insert(TempDataKey, values, null, DateTime.Now.AddMinutes(5), Cache.NoSlidingExpiration, CacheItemPriority.NotRemovable, null);
base.SaveTempData(controllerContext, values);
}
public static string TempDataKey
{
get
{
string sessionID = "0";
var httpContext = HttpContext.Current;
if(httpContext.Session != null)
{
sessionID = httpContext.Session.SessionID;
}
else if (httpContext.Request.Cookies["ASP.NET_SessionId"] != null)
{
sessionID = httpContext.Request.Cookies["ASP.NET_SessionId"].Value;
}
return "TempData-For-Session-" + sessionID;
}
}
public void Dispose()
{
}
}
Run Code Online (Sandbox Code Playgroud)
在web.config中注册它:
<?xml version="1.0" encoding="UTF-8"?>
<configuration>
<system.web>
<httpModules>
<add name="CustomTempDataProvider" type="CustomTempDataProvider" />
</httpModules>
</system.web>
<system.webServer>
<modules>
<remove name="CustomTempDataProvider" />
<add name="CustomTempDataProvider" type="CustomTempDataProvider" />
</modules>
</system.webServer>
</configuration>
Run Code Online (Sandbox Code Playgroud)
CustomControllerFactory:
using System.Web.Routing;
using System.Web.Mvc;
public class CustomControllerFactory : DefaultControllerFactory
{
public override IController CreateController(
RequestContext requestContext, string controllerName)
{
var controller = (Controller)base.CreateController(requestContext, controllerName);
controller.TempDataProvider = new CustomTempDataProvider();
return controller;
}
}
Run Code Online (Sandbox Code Playgroud)
在Global.asax中注册它:
protected void Application_Start()
{
RegisterRoutes(RouteTable.Routes);
ControllerBuilder.Current.SetControllerFactory(typeof(CustomControllerFactory));
}
Run Code Online (Sandbox Code Playgroud)
用于访问TempData的静态类:
using System;
using System.Collections.Generic;
using System.Linq;
using System.Web;
public static class CustomTempData
{
public static object Get(string key)
{
var tempData = HttpContext.Current.Items["TempData"] as IDictionary<string, object>;
var item = tempData.FirstOrDefault(x => x.Key == key).Value ?? String.Empty;
return item;
}
}
Run Code Online (Sandbox Code Playgroud)
用于缓存后替换的助手:
using System;
using System.Web;
using System.Web.Mvc;
public static class Html
{
public delegate object MvcResponseSubstitutionCallback(HttpContextBase context);
public static object MvcResponseSubstitute(this HtmlHelper html, MvcResponseSubstitutionCallback callback)
{
html.ViewContext.HttpContext.Response.WriteSubstitution(
context =>
HttpUtility.HtmlEncode(
(callback(new HttpContextWrapper(context)) ?? String.Empty).ToString()
)
);
return null;
}
}
Run Code Online (Sandbox Code Playgroud)
现在这成功了:
<h3><%= Html.MvcResponseSubstitute(context => CustomTempData.Get("message")) %></h3>
Run Code Online (Sandbox Code Playgroud)
如果您了解俄语,请阅读此内容
希望这可以帮助