加入收藏 | 设为首页 | 会员中心 | 我要投稿 李大同 (https://www.lidatong.com.cn/)- 科技、建站、经验、云计算、5G、大数据,站长网!
当前位置: 首页 > 编程开发 > asp.Net > 正文

ASP.NET MVC“Donut caching”和TempData

发布时间:2020-12-16 06:56:05 所属栏目:asp.Net 来源:网络整理
导读:是否有任何解决方案来访问HttpResponseBase.WriteSubstitution()方法中的TempData属性 这不起作用: %= Response.WriteSubstitution(x = Html.Encode(TempData["message"].ToString())) % 但这有效: %= Response.WriteSubstitution(x = DateTime.Now.ToStri
是否有任何解决方案来访问HttpResponseBase.WriteSubstitution()方法中的TempData属性

这不起作用:

<%= Response.WriteSubstitution(x => Html.Encode(TempData["message"].ToString())) %>

但这有效:

<%= Response.WriteSubstitution(x => DateTime.Now.ToString()) %>

问题出在一次缓存页面的请求处理中.根据http://msdn.microsoft.com/en-us/library/system.web.httpresponse.writesubstitution.aspx:

On the first request to the page,the WriteSubstitution calls the HttpResponseSubstitutionCallback delegate to produce the output. Then,it adds a substitution buffer to the response,which retains the delegate to call on future requests. Finally,it degrades client-side cacheability from public to server-only,ensuring future requests to the page re-invoke the delegate by not caching on the client.

换句话说,委托无权访问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()
    {
    }
}

在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>

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;
    }
}

在Global.asax中注册它:

protected void Application_Start()
{
    RegisterRoutes(RouteTable.Routes);

    ControllerBuilder.Current.SetControllerFactory(typeof(CustomControllerFactory));
}

用于访问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;
    }
}

用于缓存后替换的助手:

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;
    }
}

现在这成功了:

<h3><%= Html.MvcResponseSubstitute(context => CustomTempData.Get("message")) %></h3>

如果您了解俄语,请阅读this

希望这可以帮助

(编辑:李大同)

【声明】本站内容均来自网络,其相关言论仅代表作者个人观点,不代表本站立场。若无意侵犯到您的权利,请及时与联系站长删除相关内容!

    推荐文章
      热点阅读