0

我正在尝试实现这个例子:

堆栈溢出

但是我的 ASP.NET MVC4 应用程序Filtering is not allowed在代码行上的第一个 Action 异常消息之后执行任何操作时都会抛出异常filterContext.RequestContext.HttpContext.Response.Filter = new CdnResponseFilter(filterContext.RequestContext.HttpContext.Response.Filter);

基于一些搜索,我尝试将过滤器移动到另一个事件函数,但它们都没有奏效。我还尝试检查过滤器是否已应用,如果是,请不要添加新过滤器。

第一个动作被正确过滤,它在执行第二个动作时引发异常。

代码

public class CDNUrlFilter : IActionFilter, IResultFilter
{
    public void OnActionExecuting(ActionExecutingContext filterContext)
    {
    }

    public void OnActionExecuted(ActionExecutedContext filterContext)
    {
        filterContext.RequestContext.HttpContext.Response.Filter = new CdnResponseFilter(filterContext.RequestContext.HttpContext.Response.Filter);
    }

    public void OnResultExecuting(ResultExecutingContext filterContext)
    { 
    }

    public void OnResultExecuted(ResultExecutedContext filterContext)
    { 
    }
}

public class CdnResponseFilter : MemoryStream
{
    private Stream Stream { get; set; }

    public CdnResponseFilter(Stream stream)
    {
        Stream = stream;
    }

    public override void Write(byte[] buffer, int offset, int count)
    {

        var data = new byte[count];
        Buffer.BlockCopy(buffer, offset, data, 0, count);
        string html = Encoding.Default.GetString(buffer);

        html = Regex.Replace(html, "src=\"/Content/([^\"]+)\"", FixUrl, RegexOptions.IgnoreCase);
        html = Regex.Replace(html, "href=\"/Content/([^\"]+)\"", FixUrl, RegexOptions.IgnoreCase);

        html = Regex.Replace(html, "src=\"/Images/([^\"]+)\"", FixUrl, RegexOptions.IgnoreCase);
        html = Regex.Replace(html, "href=\"/Images/([^\"]+)\"", FixUrl, RegexOptions.IgnoreCase);

        byte[] outData = Encoding.Default.GetBytes(html);
        Stream.Write(outData, 0, outData.GetLength(0));
    }

    private static string FixUrl(Match match)
    {
        if (match.ToString().Contains("src"))
        {
            return String.Format("{0}", match.ToString());
        }
        else if (match.ToString().Contains("href"))
        {
            return String.Format("href=\"{0}content{1}", Settings.Default.CDNDomain, match.ToString().Replace("href=\"", ""));
        }
        return match.ToString();
    }
}

这里要求的是从 Global.asax.cs 调用的 RegisterGlobalFilters:

public class FilterConfig
{
    public static void RegisterGlobalFilters(GlobalFilterCollection filters)
    {
        filters.Add(new HandleErrorAttribute());
        filters.Add(new Filters.InitializeSimpleMembershipAttribute());
        filters.Add(new Filters.RequestTimingFilter());
        if (Settings.Default.CDNEnable)
        {
            filters.Add(new Filters.CDNUrlFilter());
        }
    }
}

添加完整堆栈跟踪的另一个编辑:

Stack Trace

at System.Web.HttpResponse.set_Filter(Stream value) 
at POSGuys.Filters.CDNUrlFilter.OnActionExecuted(ActionExecutedContext filterContext) in c:\Users\skatir\Documents\BitBucket\posguys\Filters\CDNUrlFilter.cs:line 20 
at System.Web.Mvc.Async.AsyncControllerActionInvoker.<>c__DisplayClass4f.b__49() 
at System.Web.Mvc.Async.AsyncControllerActionInvoker.<>c__DisplayClass4f.b__49() 
at System.Web.Mvc.Async.AsyncControllerActionInvoker.<>c__DisplayClass4f.b__49() 
at System.Web.Mvc.Async.AsyncControllerActionInvoker.<>c__DisplayClass37.b__36(IAsyncResult asyncResult) 
at System.Web.Mvc.Async.AsyncControllerActionInvoker.<>c__DisplayClass25.<>c__DisplayClass2a.b__20()
at System.Web.Mvc.Async.AsyncControllerActionInvoker.<>c__DisplayClass25.b__22(IAsyncResult asyncResult) 
at System.Web.Mvc.Controller.<>c__DisplayClass1d.b__18(IAsyncResult asyncResult) 
at System.Web.Mvc.Async.AsyncResultWrapper.<>c__DisplayClass4.b__3(IAsyncResult ar) 
at System.Web.Mvc.Controller.EndExecuteCore(IAsyncResult asyncResult) 
at System.Web.Mvc.Async.AsyncResultWrapper.<>c__DisplayClass4.b__3(IAsyncResult ar) 
at System.Web.Mvc.Controller.EndExecute(IAsyncResult asyncResult) 
at System.Web.Mvc.MvcHandler.<>c__DisplayClass8.b__3(IAsyncResult asyncResult) 
at System.Web.Mvc.Async.AsyncResultWrapper.<>c__DisplayClass4.b__3(IAsyncResult ar) 
at System.Web.Mvc.MvcHandler.EndProcessRequest(IAsyncResult asyncResult) 
at System.Web.Mvc.HttpHandlerUtil.ServerExecuteHttpHandlerWrapper.<>c__DisplayClass4.b__3() 
at System.Web.Mvc.HttpHandlerUtil.ServerExecuteHttpHandlerWrapper.Wrap[TResult](Func`1 func) 
at System.Web.HttpServerUtility.ExecuteInternal(IHttpHandler handler, TextWriter writer, Boolean preserveForm, Boolean setPreviousPage, VirtualPath path, VirtualPath filePath, String physPath, Exception error, String queryStringOverride)


Target Site

Void set_Filter(System.IO.Stream)

在尝试解决这个问题时,我偶然发现了一些非常奇怪的事情,那就是如果我将 OnActionExecute 中的 Response.Filter 的设置包装在 try{}catch{} 中,会阻止页面正确使用过滤器呈现。这让我觉得系统的其他一些部分被尝试过滤掉,而不应该过滤掉。我将在调试器中做一些工作,看看我是否不能从这里缩小范围。

4

2 回答 2

2

我通过在过滤器注册期间将过滤器移动到列表顶部解决了这个问题。如果有人知道为什么会这样,我很想知道,但这是我的解决方案:

public class FilterConfig
{
    public static void RegisterGlobalFilters(GlobalFilterCollection filters)
    {
        if (Settings.Default.CDNEnable)
        {
            filters.Add(new Filters.CDNUrlFilter());
        }
        filters.Add(new HandleErrorAttribute());
        filters.Add(new Filters.InitializeSimpleMembershipAttribute());
        filters.Add(new Filters.RequestTimingFilter());
    }
}

在初始化 SimpleMembership 的第一个操作之后立即发生冲突。由于某种原因,一旦发生这种情况,就无法应用其他过滤器。RequestTimingFilter 之所以起作用,是因为它不对请求上下文应用过滤器,它只是一个存储在每个操作之外的计时事件。

于 2013-06-27T22:08:00.610 回答
2

我很确定您的 CDN 过滤器在技术上改变了您在网站上的路由。SimpleMembership 需要 Account 控制器的路由在它初始化时是正确的。

这篇文章就是让我得出这个结论的原因。

默认情况下,WebSecurity.InitializeDatabaseConnection() 调用在 InitializeSimpleMembershipAttribute 类中,默认情况下,AccountController 使用此属性。问题在于,必须首先调用与 AccountController 关联的路由才能初始化 SimpleMembershipProvider...

来源

于 2013-06-27T22:27:42.770 回答