Asp.net mvc 5 使用“窥视”和“邮寄”时引发异常

Asp.net mvc 5 使用“窥视”和“邮寄”时引发异常,asp.net-mvc-5,glimpse,postal,Asp.net Mvc 5,Glimpse,Postal,我刚开始在我的MVC5项目中使用Gliesh,当我使用Postal发送电子邮件而不禁用Gliesh时遇到了一个问题。我已经能够将它缩小到两个软件包的一个问题——如果没有打开“一瞥”cookie,就不会发生这种情况 在《小提琴手》中,我检查了两者之间的差异。当它抛出异常时,cookie是 glimpsePolicy=On 当它工作时(一瞥关闭),有两块饼干 glimpseId=FBar; glimpsePolicy= 我得到的例外是 System.ArgumentNullException:

我刚开始在我的MVC5项目中使用Gliesh,当我使用Postal发送电子邮件而不禁用Gliesh时遇到了一个问题。我已经能够将它缩小到两个软件包的一个问题——如果没有打开“一瞥”cookie,就不会发生这种情况

在《小提琴手》中,我检查了两者之间的差异。当它抛出异常时,cookie是

glimpsePolicy=On
当它工作时(一瞥关闭),有两块饼干

glimpseId=FBar; glimpsePolicy=
我得到的例外是

System.ArgumentNullException: Value cannot be null.
Parameter name: controllerContext
   at System.Web.Mvc.ChildActionValueProviderFactory.GetValueProvider(ControllerContext controllerContext)
   at Castle.Proxies.Invocations.ValueProviderFactory_GetValueProvider.InvokeMethodOnTarget()
   at Castle.DynamicProxy.AbstractInvocation.Proceed()
   at Glimpse.Core.Extensibility.ExecutionTimer.Time(Action action)
   at Glimpse.Core.Extensibility.AlternateMethod.NewImplementation(IAlternateMethodContext context)
   at Castle.DynamicProxy.AbstractInvocation.Proceed()
   at Castle.Proxies.ValueProviderFactoryProxy.GetValueProvider(ControllerContext controllerContext)
   at System.Web.Mvc.ValueProviderFactoryCollection.GetValueProvider(ControllerContext controllerContext)
   at System.Web.Mvc.ControllerBase.get_ValueProvider()
   at Glimpse.Mvc.Message.ActionMessageExtension.AsActionMessage[T](T message, ControllerBase controller)
   at Glimpse.Mvc.AlternateType.ViewEngine.FindViews.PostImplementation(IAlternateMethodContext context, TimerResult timerResult)
   at Glimpse.Core.Extensibility.AlternateMethod.NewImplementation(IAlternateMethodContext context)
   at Castle.DynamicProxy.AbstractInvocation.Proceed()
   at Castle.Proxies.IViewEngineProxy.FindView(ControllerContext controllerContext, String viewName, String masterName, Boolean useCache)
   at System.Web.Mvc.ViewEngineCollection.<>c__DisplayClass6.<FindView>b__4(IViewEngine e)
   at System.Web.Mvc.ViewEngineCollection.Find(Func`2 lookup, Boolean trackSearchedPaths)
   at System.Web.Mvc.ViewEngineCollection.Find(Func`2 cacheLocator, Func`2 locator)
   at Postal.EmailViewRenderer.Render(Email email, String viewName)
   at Postal.EmailService.Send(Email email)
   at System.Dynamic.UpdateDelegates.UpdateAndExecuteVoid1[T0](CallSite site, T0 arg0)
   at System.Web.Mvc.ActionMethodDispatcher.<>c__DisplayClass1.<WrapVoidAction>b__0(ControllerBase controller, Object[] parameters)
   at System.Web.Mvc.ReflectedActionDescriptor.Execute(ControllerContext controllerContext, IDictionary`2 parameters)
   at System.Web.Mvc.ControllerActionInvoker.InvokeActionMethod(ControllerContext controllerContext, ActionDescriptor actionDescriptor, IDictionary`2 parameters)
   at System.Web.Mvc.Async.AsyncControllerActionInvoker.<BeginInvokeSynchronousActionMethod>b__36(IAsyncResult asyncResult, ActionInvocation innerInvokeState)
   at System.Web.Mvc.Async.AsyncResultWrapper.WrappedAsyncResult`2.CallEndDelegate(IAsyncResult asyncResult)
   at Castle.Proxies.Invocations.AsyncControllerActionInvoker_EndInvokeActionMethod.InvokeMethodOnTarget()
   at Castle.DynamicProxy.AbstractInvocation.Proceed()
   at Glimpse.Mvc.AlternateType.AsyncActionInvoker.EndInvokeActionMethod.NewImplementation(IAlternateMethodContext context)
   at Castle.DynamicProxy.AbstractInvocation.Proceed()
   at Castle.Proxies.AsyncControllerActionInvokerProxy.EndInvokeActionMethod(IAsyncResult asyncResult)
   at System.Web.Mvc.Async.AsyncControllerActionInvoker.AsyncInvocationWithFilters.<InvokeActionMethodFilterAsynchronouslyRecursive>b__3c()
   at System.Web.Mvc.Async.AsyncControllerActionInvoker.AsyncInvocationWithFilters.<>c__DisplayClass45.<InvokeActionMethodFilterAsynchronouslyRecursive>b__3e()
   at System.Web.Mvc.Async.AsyncControllerActionInvoker.<>c__DisplayClass30.<BeginInvokeActionMethodWithFilters>b__2f(IAsyncResult asyncResult)
   at System.Web.Mvc.Async.AsyncControllerActionInvoker.<>c__DisplayClass1e.<>c__DisplayClass28.<BeginInvokeAction>b__19()
   at System.Web.Mvc.Async.AsyncControllerActionInvoker.<>c__DisplayClass1e.<BeginInvokeAction>b__1b(IAsyncResult asyncResult)

失败的原因是,Postal库在将电子邮件视图呈现为Postal的
EmailViewRenderer
类中的反编译
CreateControllerContext
方法时创建了自己的
HttpContext
实例,显示:

private ControllerContext CreateControllerContext()
{
  HttpContextWrapper httpContextWrapper = new HttpContextWrapper(new HttpContext(new HttpRequest("", this.UrlRoot(), ""), new HttpResponse(TextWriter.Null)));
  RouteData routeData = new RouteData();
  routeData.Values["controller"] = (object) this.EmailViewDirectoryName;
  return new ControllerContext(new RequestContext((HttpContextBase) httpContextWrapper, routeData), (ControllerBase) new EmailViewRenderer.StubController());
}
这意味着Spile在
BeginRequest
上所做的设置被完全删除,而钩子仍然在拦截MVC相关调用

我们有一个问题,我解释了为什么这不起作用

更新:

我在上文中提到,之前也曾报道过类似的问题,但在我试图找到更合适的解决方案时,在这一点上,这种情况似乎略有不同,因为另一个类似的问题实际上使用新创建的上下文执行控制器,从而在特定于一瞥的代码中产生
NullReferenceException
,而在这里,我们在特定于MVC的代码中得到
NullReferenceException
,尽管是由一瞥触发的

System.ArgumentNullException:值不能为null

参数名称:controllerContext
位于System.Web.Mvc.ChildActionValueProviderFactory.GetValueProvider(ControllerContext ControllerContext)

我们在这里得到的例外是因为
StubController
实例(内联创建)上的
ControllerContext
属性为null,这通常在执行控制器时设置(这里不是这种情况)

因此,我在下面提出的解决方法仍然适用,但如果稍微修改上面的
CreateControllerContext()
的代码,就可以避免:

private ControllerContext CreateControllerContext()
{
  HttpContextWrapper httpContextWrapper = new HttpContextWrapper(new HttpContext(new HttpRequest("", this.UrlRoot(), ""), new HttpResponse(TextWriter.Null)));
  RouteData routeData = new RouteData();
  routeData.Values["controller"] = (object) this.EmailViewDirectoryName;
  // MODIFIED
  var stubController = new EmailViewRenderer.StubController();
  var controllerContext = new ControllerContext(new RequestContext(httpContextWrapper, routeData), stubController);
  stubController.ControllerContext = controllerContext;
  return controllerContext;
}
我已经在网站上为此创建了一个问题

更新结束

我认为目前最好的解决方案是在打电话到邮局时禁用窥视功能,然后再恢复正常的窥视行为。在即将发布的某个版本中,我们可能会以这种或那种方式将其包含到Spile核心库中,因为在请求处理逻辑的特定部分禁用Spile似乎并不少见,但现在下面的代码片段可能会对您有所帮助(注意,它使用的是一瞥内部密钥,但不保证在即将发布的版本中存在该密钥)

然后可以在控制器操作方法中使用,如下所示:

public void TestEmailExt()
{
    using (new GlimpseSuppressionScope(System.Web.HttpContext.Current))
    {
        var confirmationToken = "ConfirmationToken";
        var Phone1 = "**********";
        dynamic email = new Email("RegEmail");
        email.To = "**@gmail.com";
        email.UserName = "UserName";
        email.ConfirmationToken = confirmationToken;
        email.Phone = Extensions.Right(Phone1, 4);
        if (email.To.Contains("@mydomain"))
            email.From = INTERNAL_EMAIL_FROM;
        else
            email.From = EXTERNAL_EMAIL_FROM;
        email.Send();
    }
}
public class GlimpseSuppressionScope : IDisposable
{
    private const string GlimpseRequestRuntimePermissionsKey = "__GlimpseRequestRuntimePermissions";
    private readonly HttpContext currentHttpContext;
    private readonly RuntimePolicy? currentRuntimePolicy;
    private bool disposed;

    public GlimpseSuppressionScope(HttpContext currentHttpContext)
    {
        if (currentHttpContext == null)
        {
            throw new ArgumentNullException("currentHttpContext");
        }

        this.currentHttpContext = currentHttpContext;
        this.currentRuntimePolicy = this.currentHttpContext.Items[GlimpseRequestRuntimePermissionsKey] as RuntimePolicy?;
        this.currentHttpContext.Items[GlimpseRequestRuntimePermissionsKey] = RuntimePolicy.Off;
    }

    ~GlimpseSuppressionScope()
    {
        this.Dispose(false);
    }

    public void Dispose()
    {
        this.Dispose(true);
        GC.SuppressFinalize(this);
    }

    private void Dispose(bool disposing)
    {
        if (!this.disposed)
        {
            if (disposing)
            {
                if (this.currentHttpContext != null)
                {
                    this.currentHttpContext.Items.Remove(GlimpseRequestRuntimePermissionsKey);
                    if (this.currentRuntimePolicy.HasValue)
                    {
                        this.currentHttpContext.Items[GlimpseRequestRuntimePermissionsKey] = this.currentRuntimePolicy.Value;
                    }
                }
            }

            this.disposed = true;
        }
    }
}
public void TestEmailExt()
{
    using (new GlimpseSuppressionScope(System.Web.HttpContext.Current))
    {
        var confirmationToken = "ConfirmationToken";
        var Phone1 = "**********";
        dynamic email = new Email("RegEmail");
        email.To = "**@gmail.com";
        email.UserName = "UserName";
        email.ConfirmationToken = confirmationToken;
        email.Phone = Extensions.Right(Phone1, 4);
        if (email.To.Contains("@mydomain"))
            email.From = INTERNAL_EMAIL_FROM;
        else
            email.From = EXTERNAL_EMAIL_FROM;
        email.Send();
    }
}