【问题标题】:What risks does WebApi incur when calling Request.CreateResponse() inside await block?在 await 块中调用 Request.CreateResponse() 时 WebApi 会产生什么风险?
【发布时间】:2015-09-30 12:31:30
【问题描述】:

我有一个异步 WebApi 控制器,在 await 块内调用 Request.CreateResponse(HttStatusCode.Created, result) 时会引发 StructureMapException,但仅在第一个请求期间。 StructureMap 正确解析了所有构造函数依赖项,但表现得好像在请求结束后调用了 Request.CreateResponse。在 await 块中使用 Request.CreateResponse 只是一个坏主意吗?这种策略可能会带来哪些其他风险?

我正在使用以下 NuGet 包:

  • 结构图 3.1.6.186
  • StructureMap.Web 3.1.0.133
  • StructureMap.WebApi2 3.0.4.125
  • WebActivator 2.0.5

代码如下:

public class EmailController : ApiController
{
    private readonly ISaveEmailNotification _saveEmailNotification;
    private readonly ISaveFile _saveFile;

    public EmailController(ISaveEmailNotification saveEmailNotification, ISaveFile saveFile)
    {
        _saveEmailNotification = saveEmailNotification;
        _saveFile = saveFile;
    }

    [HttpPost]
    public async Task<HttpResponseMessage> SaveEmail(NotificationRequest model)
    {
        return await Task.Run(() =>
        {
            var emailResult = _saveEmailNotification.Execute(model);
            var fileResult = _saveFile.Execute(model, emailResult);
            return Request.CreateResponse(HttpStatusCode.Created, fileResult);
        }
    }
}

这是错误:

StructureMap.StructureMapException was unhandled by user code
HResult=-2146233088
Message=You cannot use the HttpContextLifecycle outside of a web request. Try the HybridLifecycle instead.
1.) Container.GetInstance(System.Web.HttpContextBase)
2.) Container.TryGetInstance(System.Web.HttpContextBase)

Source=StructureMap.Web
Title=You cannot use the HttpContextLifecycle outside of a web request. Try the HybridLifecycle instead.
StackTrace:
   at StructureMap.Web.Pipeline.HttpContextLifecycle.findHttpDictionary() in c:\BuildAgent\work\996e173a8ceccdca\src\StructureMap.Web\Pipeline\HttpContextLifecycle.cs:line 57
   at StructureMap.Web.Pipeline.HttpContextLifecycle.FindCache(ILifecycleContext context) in c:\BuildAgent\work\996e173a8ceccdca\src\StructureMap.Web\Pipeline\HttpContextLifecycle.cs:line 20
   at StructureMap.BuildSession.ResolveFromLifecycle(Type pluginType, Instance instance) in c:\BuildAgent\work\996e173a8ceccdca\src\StructureMap\BuildSession.cs:line 102
   at StructureMap.SessionCache.GetObject(Type pluginType, Instance instance, ILifecycle lifecycle) in c:\BuildAgent\work\996e173a8ceccdca\src\StructureMap\SessionCache.cs:line 88
   at StructureMap.SessionCache.GetDefault(Type pluginType, IPipelineGraph pipelineGraph) in c:\BuildAgent\work\996e173a8ceccdca\src\StructureMap\SessionCache.cs:line 66
   at StructureMap.Container.GetInstance(Type pluginType) in c:\BuildAgent\work\996e173a8ceccdca\src\StructureMap\Container.cs:line 335
   at StructureMap.Container.TryGetInstance(Type pluginType) in c:\BuildAgent\work\996e173a8ceccdca\src\StructureMap\Container.cs:line 278
   at StructureMap.Container.TryGetInstance[T]() in c:\BuildAgent\work\996e173a8ceccdca\src\StructureMap\Container.cs:line 289
   at NotificationHubWeb.DependencyResolution.StructureMapDependencyScope.get_HttpContext() in C:\Users\Dave\Source\Workspaces\NotificationHub\Main\NotificationHubWeb\DependencyResolution\StructureMapDependencyScope.cs:line 68
   at NotificationHubWeb.DependencyResolution.StructureMapDependencyScope.get_CurrentNestedContainer() in C:\Users\Dave\Source\Workspaces\NotificationHub\Main\NotificationHubWeb\DependencyResolution\StructureMapDependencyScope.cs:line 55
   at NotificationHubWeb.DependencyResolution.StructureMapDependencyScope.DoGetInstance(Type serviceType, String key) in C:\Users\Dave\Source\Workspaces\NotificationHub\Main\NotificationHubWeb\DependencyResolution\StructureMapDependencyScope.cs:line 109
   at Microsoft.Practices.ServiceLocation.ServiceLocatorImplBase.GetInstance(Type serviceType, String key) in c:\Projects\CommonServiceLocator\main\Microsoft.Practices.ServiceLocation\ServiceLocatorImplBase.cs:line 49

【问题讨论】:

  • 也许你想要this
  • 不太合适。当控制器调用 Request.CreateResponse 时,错误发生在其中一个 nuget 包提供的 StructureMapDependencyScope 代码中,就好像每个请求容器已经由于异步问题而被清理了一样。我通过不调用 Request.CreateResponse 解决了这个问题。仍然很奇怪,它仅在 Email.SaveEmail 处理发送到 Web 应用程序的第一个请求时发生。如果我先在不同的控制器中获取一个空页面,则永远不会发生。

标签: c# asp.net-web-api async-await asp.net-web-api2 structuremap


【解决方案1】:

当我这样重写代码时,看起来在 await 块之外使用 Request.CreateResponse 确实会在首次使用时避开 StructureMapException:

[HttpPost]
public async Task<HttpResponseMessage> SaveEmail(NotificationRequest model)
{
    var taskResult await Task.Run(() =>
    {
        var emailResult = _saveEmailNotification.Execute(model);
        return _saveFile.Execute(model, emailResult);
    }

    return Request.CreateResponse(HttpStatusCode.Created, taskResult);
}

现在,这看起来像是赢家,但如果你能解释为什么将 Request.CreateReponse 移到 await 块之外可以让代码无错误地运行,我会投票支持或宣布你为回答者。

【讨论】:

  • hm 很有趣,我遇到了类似的问题,但是因为我的等待代码没有返回任何东西(只是处理),我不能使用这种方法。相反,我刚刚使用了For&lt;MyInterface&gt;().HybridHttpOrThreadLocalScoped().Use(new MyClass());
  • 但我并没有尝试使用 MyClass 或任何用户代码。访问控制器上的 Request 对象会引发异常,因此它与控制器及其 Request 属性如何被这些 Nuget 包实例化有关。一切都是自动注册的。
  • 试试看这里(代替HttpContext看能不能用HttpOrThread上下文)NotificationHubWeb.DependencyResolution.StructureMapDependencyScope.get_HttpContext() in C:\Users\Dave\Source\Workspaces\NotificationHub\Main\NotificationHubWeb\DependencyResolution\StructureMapDependencyScope.cs:line 68
  • 我读过你上面的一个 cmets,这是来自 nuget 包的代码,所以我猜你只是在他们的代码中发现了一个错误 :)
猜你喜欢
  • 2017-03-09
  • 1970-01-01
  • 2010-11-21
  • 2012-05-26
  • 2011-03-14
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2013-06-24
相关资源
最近更新 更多