2017-02-15 5 views
5

Ich verwende Simple Injector als IoC-Container für meine .Net MVC-Projekt. Hier ist, wie ich die Dienste registriere.DI/IoC für .net mvc async/erwarten

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()) { 
    //} 
} 

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; 
    } 
} 

Mein Problem ist, dass, wenn ich async verwendet/await, das IOK fehlgeschlagen. Dann sah ich seine documentation, bekam es eine andere LifeStyle für Asynchronous Methoden. Also änderte ich die DefaultScopeLifeStyle-ExecutionContextScopeLifestyle(), es errored aus

The ICustomerService is registered as 'Execution Context Scope' lifestyle, but the instance is requested outside the context of a Execution Context Scope.

Muß ich einen Hybrid-Lebensstil implementieren für die Verwendung von asyn/erwarten sowie synchronen Methoden? Oder stimmt etwas in meinem Design nicht?

Fehler Detail (mit WebRequestLifestyle)

The asynchronous action method 'foo' returns a Task, which cannot be executed synchronously.

Description: An unhandled exception occurred during the execution of the current web request. Please review the stack trace for more information about the error and where it originated in the code.

Exception Details: System.InvalidOperationException: The asynchronous action method 'foo' returns a Task, which cannot be executed synchronously.

Source Error:

An unhandled exception was generated during the execution of the current web request. Information regarding the origin and location of the exception can be identified using the exception stack trace below.

Stack Trace:

[InvalidOperationException: The asynchronous action method 'foo' returns a Task, which cannot be executed synchronously.] System.Web.Mvc.Async.TaskAsyncActionDescriptor.Execute(ControllerContext controllerContext, IDictionary 2 parameters) +119 System.Web.Mvc.ControllerActionInvoker.InvokeActionMethod(ControllerContext controllerContext, ActionDescriptor actionDescriptor, IDictionary 2 parameters) +27 System.Web.Mvc.<>c__DisplayClass15.b__12() +56 System.Web.Mvc.ControllerActionInvoker.InvokeActionMethodFilter(IActionFilter filter, ActionExecutingContext preContext, Func 1 continuation) +256 System.Web.Mvc.<>c__DisplayClass17.<InvokeActionMethodWithFilters>b__14() +22 System.Web.Mvc.ControllerActionInvoker.InvokeActionMethodWithFilters(ControllerContext controllerContext, IList 1 filters, 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.WrappedAsyncResult 2.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.WrappedAsyncVoid 1.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.WrappedAsyncVoid 1.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.IExecutionStep.Execute() +9765121 System.Web.HttpApplication.ExecuteStep(IExecutionStep step, Boolean& completedSynchronously) +155

bearbeiten Ich habe bestätigt, es ist kein einfaches Injector Problem, es ist wirklich this. Ich habe versucht, die Lösung zu reinigen, entfernen Sie die DLLs in den Ordner bin, immer noch kein Glück mit dem gleichen Fehler. Allerdings habe ich den Controller auf einen ApiController umgestellt, der asyn hat gut funktioniert.

+0

Sie geben "Fehler aus, bevor Sie diese Zeile treffen", wenn Sie den 'WebRequestLifestyle' verwenden. Können Sie die vollständigen Ausnahmebedingungsdetails (Ausnahmetyp, Nachrichten- und Stack-Trace der Ausnahme und alle inneren Ausnahmen), die Sie erhalten, posten? – Steven

+0

@Steven fügte die vollständigen Fehlerdetails hinzu. – Quentin

+0

Hallo Quentin, das war nicht der Fehler, nach dem ich gesucht habe. Dies ist die Ausnahme, die Sie erhalten, wenn Sie den "ExecutionContextScopeLifestyle" verwenden. Ändern Sie stattdessen den "Container.Options.DefaultScopedLifestyle" in "WebRequestLifestyle", und buchen Sie die Ausnahme für diese Änderung. ps. Stellen Sie die Ausnahmedetails nicht als Bild ein, sondern als Text. Dies macht es einfacher zu lesen, zu kopieren und für andere Suchmaschinen Ihre Frage zu indexieren. – Steven

Antwort

2

Soweit ich sehen kann, ist dieses Problem nicht mit Simple Injector und seine Festlegung verbunden; Wenn Sie einen Ausführungskontextbereich um eine Webanforderung herumstreichen (was Sie mit den Ereignissen request_start und request_end erreichen können), haben Sie das gleiche Problem.

Es gibt einige Probleme auf Stackoverflow und den Rest der Interwebs, die Sie sich ansehen sollten, wie this q/a.

+0

Vielen Dank für die Eingabe. Sollte ich also 'ExecutionContextScopeLifestyle' anstelle von 'WebRequestLifestyle' verwenden, wenn es um asynchrone Methoden geht? – Quentin

+2

@Quentin: Nein, Sie können weiterhin den 'WebRequestLifestyle' in MVC verwenden. – Steven