DI/IoC for .net mvc async/await

Que*_*tin 5 .net c# asp.net-mvc asynchronous simple-injector

我使用Simple Injector作为我的.Net MVC项目的IoC容器.这是我如何注册服务.

SimpleInjectorInitializer.cs

 public static void Initialize() {
    var container = new Container();

    container.Options.DefaultScopedLifestyle = new WebRequestLifestyle();  
    //container.Options.DefaultScopedLifestyle = new ExecutionContextScopeLifestyle(); // replace last line with this for async/await

    InitializeContainer(container);
    container.RegisterMvcControllers(Assembly.GetExecutingAssembly());
    container.Verify();
    DependencyResolver.SetResolver(new SimpleInjectorDependencyResolver(container));
}

private static void InitializeContainer(Container container) {
    container.Register<MyDbContext>(Lifestyle.Scoped);
    container.Register(typeof(IUnitOfWork<>), typeof(UnitOfWork<>), Lifestyle.Scoped);
    container.Register(typeof(IRepository<>), typeof(Repository<>), Lifestyle.Scoped);
    container.Register<ICustomerService, CustomerService>(Lifestyle.Scoped);

    //what does this do by the way?
    //using (container.BeginExecutionContextScope()) {
    //}
}
Run Code Online (Sandbox Code Playgroud)

CustomerController

public interface ICustomerService : IService<Customer> {}

public class CustomerService : BaseService<Customer, MyDbContext>, ICustomerService {
    public CustomerService(IUnitOfWork<MyDbContext> unitOfWork) : base(unitOfWork) {}
    // do stuff
}

public class CustomerController : Controller {
    private readonly ICustomerService _service;

    public CustomerController(ICustomerService service) {
        _service = service;
    }

    public ActionResult Index() {
        var foo = _service.GetById(112); // works
        // do stuff
        return View();
    }

    public async Task<int> Foo() { // error out on calling this method
        var foo = await _service.GetByIdAsync(112); 
        return foo.SomeId;
    }
}
Run Code Online (Sandbox Code Playgroud)

我的问题是每当我使用async/await时,ioc都会失败.然后我查看了它的文档,它与LifeStyle异步方法有所不同.所以我改变了DefaultScopeLifeStyleExecutionContextScopeLifestyle(),它出错了

ICustomerService注册为"执行上下文范围"生活方式,但实例是在执行上下文范围的上下文之外请求的.

我是否需要实现混合生活方式以使用asyn/await以及同步方法?或者我的设计出了什么问题?

错误细节(带WebRequestLifestyle)

异步操作方法'foo'返回一个Task,它不能同步执行.

描述:执行当前Web请求期间发生未处理的异常.请查看堆栈跟踪以获取有关错误及其源自代码的位置的更多信息.

异常详细信息:System.InvalidOperationException:异步操作方法'foo'返回一个无法同步执行的Task.

来源错误:

在执行当前Web请求期间生成了未处理的异常.可以使用下面的异常堆栈跟踪来识别有关异常的起源和位置的信息.

堆栈跟踪:

[InvalidOperationException:异步操作方法'foo'返回一个无法同步执行的Task.] System.Web.Mvc.Async.TaskAsyncActionDescriptor.Execute(ControllerContext controllerContext,IDictionary 2 parameters) +119 System.Web.Mvc.ControllerActionInvoker.InvokeActionMethod(ControllerContext controllerContext, ActionDescriptor actionDescriptor, IDictionary2 parameters)+27 System.Web.Mvc.<> c__DisplayClass15.b__12()+56 System.Web.Mvc.ControllerActionInvoker.InvokeActionMethodFilter(IActionFilter过滤器,ActionExecutingContext preContext,Func 1 continuation) +256 System.Web.Mvc.<>c__DisplayClass17.<InvokeActionMethodWithFilters>b__14() +22 System.Web.Mvc.ControllerActionInvoker.InvokeActionMethodWithFilters(ControllerContext controllerContext, IList1过滤器,ActionDescriptor actionDescriptor,IDictionary 2 parameters) +190 System.Web.Mvc.ControllerActionInvoker.InvokeAction(ControllerContext controllerContext, String actionName) +522 NotFoundMvc.ActionInvokerWrapper.InvokeActionWith404Catch(ControllerContext controllerContext, String actionName) +32 NotFoundMvc.ActionInvokerWrapper.InvokeAction(ControllerContext controllerContext, String actionName) +16 System.Web.Mvc.<>c__DisplayClass22.<BeginExecuteCore>b__1e() +23 System.Web.Mvc.Async.AsyncResultWrapper.<.cctor>b__0(IAsyncResult asyncResult, Action action) +15 System.Web.Mvc.Async.WrappedAsyncResult2.CallEndDelegate(IAsyncResult asyncResult)+16 System.Web.Mvc.Async.WrappedAsyncResultBase 1.End() +49 System.Web.Mvc.Controller.EndExecuteCore(IAsyncResult asyncResult) +36 System.Web.Mvc.Controller.<BeginExecute>b__15(IAsyncResult asyncResult, Controller controller) +12 System.Web.Mvc.Async.WrappedAsyncVoid1 .CallEndDelegate(IAsyncResult asyncResult)+22 System.Web.Mvc.Async.WrappedAsyncResultBase 1.End() +49 System.Web.Mvc.Controller.EndExecute(IAsyncResult asyncResult) +26 System.Web.Mvc.Controller.System.Web.Mvc.Async.IAsyncController.EndExecute(IAsyncResult asyncResult) +10 System.Web.Mvc.MvcHandler.<BeginProcessRequest>b__5(IAsyncResult asyncResult, ProcessRequestState innerState) +21 System.Web.Mvc.Async.WrappedAsyncVoid1.CallEndDelegate(IAsyncResult asyncResult)+29 System.Web.Mvc.Async.WrappedAsyncResultBase`1.End()+49 System.Web.Mvc.MvcHandler .EndProcessRequest(IAsyncResult asyncResult)+28 System.Web.Mvc.MvcHandler.System.Web.IHttpAsyncHandler.EndProcessRequest(IAsyncResult result)+9 System.Web.CallHandlerExecutionStep.System.Web.HttpApplication.IEx ecutionStep.Execute()+ 9765121 System.Web.HttpApplication.ExecuteStep(IExecutionStep step,Boolean&completedSynchronously)+155

编辑 我已经确认它不是一个简单的注射器问题,它就是这个.我试图清理解决方案,删除bin文件夹中的dll,仍然没有运气相同的错误.但是,我将控制器更改为ApiController,asyn运行良好.

Ste*_*ven 2

据我所知,这个问题与 Simple Injector 及其范围无关;如果您将执行上下文范围包装在 Web 请求周围(您可以通过挂钩 request_start 和 request_end 事件来完成此操作),您将面临同样的问题。

Stackoverflow 和其他互联网上有几个与此相关的问题,您应该看一下,例如这个 q/a

  • @Quentin:不,您可以继续使用 MVC 中的“WebRequestLifestyle”。 (2认同)