Исключение выдается при использовании Glimpse и Postal
Я только начинаю использовать Glimpse с моим проектом MVC5 и столкнулся с проблемой, когда использую Postal для отправки электронного письма без отключения Glimpse. Я смог сузить ее до проблемы с обоими пакетами - это не происходит, если cookie Glimpse не был включен.
В Fiddler я проверил разницу между ними. Когда это бросило исключение, печенье было
glimpsePolicy=On
когда это работало (Glimpse был выключен) было два куки
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)
Я создал быстрое действие, чтобы проверить это. Код контроллера:
public void TestEmailExt()
{
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();
}
1 ответ
Причина этого заключается в том, что Почтовая библиотека создает свою собственную HttpContext
экземпляр при отображении представления электронной почты в качестве декомпилированного CreateControllerContext
метод внутри почтовых EmailViewRenderer
класс показывает:
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());
}
Это означает, что установка, которую Glimpse делает в BeginRequest
полностью удален, в то время как перехватчики все еще на месте для перехвата вызовов, связанных с MVC.
У нас была похожая проблема, где я дал аналогичный ответ, почему это не работает.
ОБНОВИТЬ:
Я упомянул выше, что подобная проблема сообщалась ранее, но, хотя я пытался найти более подходящее решение, казалось, что этот случай немного отличается в этом отношении, что другая подобная проблема фактически выполняет контроллер с использованием только что созданного контекста. в NullReferenceException
в конкретном коде Glimpse, в то время как здесь мы получаем NullReferenceException
внутри специфичного для MVC кода, хотя и запускаемого Glimpse.
System.ArgumentNullException: значение не может быть нулевым.
Имя параметра: controllerContext
в System.Web.Mvc.ChildActionValueProviderFactory.GetValueProvider(ControllerContext controllerContext)
И исключение мы получаем здесь, потому что ControllerContext
собственность на StubController
instance (создан inline) имеет значение 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;
}
Я создал проблему для этого на почтовом трекере
КОНЕЦ ОБНОВЛЕНИЯ
Я думаю, что лучшим решением на данный момент является отключение Glimpse при вызове в Postal и восстановление нормального поведения Glimpse после этого. Мы могли бы включить это так или иначе в библиотеку Glimpse Core в одном из следующих выпусков, так как кажется, что отключение Glimpse во время определенной части логики обработки запросов не кажется чем-то необычным, но пока следующий фрагмент может помочь вам (будьте осторожны, он использует внутренний ключ Glimpse, который не обязательно будет в следующем выпуске)
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();
}
}