实现IActionResult过滤器运行时错误

时间:2013-06-27 17:24:24

标签: c# asp.net-mvc asp.net-mvc-4

我正在尝试实现此示例:

Stack Overflow

但我的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)

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

2 个答案:

答案 0 :(得分: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的第一个Action之后立即发生冲突。出于某种原因,一旦发生这种情况,就不能应用其他过滤器RequestTimingFilter工作是因为它没有对请求上下文应用过滤器,它只是一个存储在每个动作之外的定时事件。

答案 1 :(得分:2)

我非常确定您的CDN过滤器在技术上会改变您在网站上的路由。 SimpleMembership需要帐户控制器的路由在初始化时才是正确的。

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

  

默认情况下,WebSecurity.InitializeDatabaseConnection()调用位于InitializeSimpleMembershipAttribute类中,默认情况下,AccountController将使用此属性进行处理。麻烦的是必须首先调用与AccountController关联的路由,以便初始化SimpleMembershipProvider ...

Source

相关问题