2014-04-11 6 views
9

Ist es möglich, eine Asynchron-Vorgang innerhalb einer Umbraco SurfaceController (und UmbracoApiController)Async-Controller Aktion mit Umbraco 7 liefert String

Ich habe versucht, den folgenden Code

public async Task< ActionResult> HandleLogin(LoginViewModel model) 
{ 
    await Task.Delay(1000); 
    return PartialView("Login", model); 
} 

und obwohl es korrekt kompiliert zu verwenden, wenn die Aktion ist die Aktion aufgerufen scheint, sobald die await zurückzukehren getroffen wird, und gibt einen String

System.Threading.Tasks.Task`1 [System.Web.Mvc.ActionResult]

der Controller erbt natürlich von SurfaceController und ich frage mich, ob das das Problem ist?

Wenn dies nicht möglich ist, gibt es Problemumgehungen, um asynchrones Aktionsverhalten zu erreichen?

Jede Hilfe wäre dankbar erhalten!

+1

Ich bin nicht vertraut mit Umbraco, aber die Tatsache, dass Die Umwandlung von 'Task ' in eine Zeichenfolge zeigt an, dass sie 'asynchrone' Methoden nicht versteht. Möglicherweise müssen Sie sich direkt an die Umbraco-Community wenden und/oder eine Funktion anfordern. –

+0

Danke, ja ich dachte, es könnte so etwas sein. Habe auch eine Frage auf unserem .umbraco gestellt. Wird hier aktualisiert, wenn eine Rückmeldung! –

+0

Ich habe ein ähnliches Problem auf http://stackoverflow.com/questions/30166566/umbraco-7-asp-net-mvc-async-controller-returning-system-threading-tasks-task1 mit einem RenderMvcController gepostet - mit etwas Glück mit Dies?? Es ist ein Jahr später, aber immer noch das gleiche Problem! Fehle ich etwas? – legas

Antwort

10

Die SurfaceControllers in Umbraco ableiten letztlich von System.Web.Mvc.Controller aber sie benutzerdefinierte Aktion Aufrufer (RenderActionInvoker) gesetzt haben.

RenderActionInvoker erbt von ContollerActionInvoker. Um asynchrone Aktionen zu verarbeiten, sollte es stattdessen von AsyncContolkerActionInvoker abgeleitet werden. RenderActionInvoker überschreibt nur die findaction-Methode, so dass die Änderung von abgeleitet wird. AsyncContolkerActionInvoker ist einfach.

Sobald ich Umbraco.Web mit dieser Änderung neu kompiliert, funktioniert async Aktionen gut.

Anstatt das gesamte Projekt neu zu kompilieren, ich denke, Sie einen neuen actioninvoker auf jeder Klasse angeben konnte

public class RenderActionInvokerAsync : System.Web.Mvc.Async.AsyncControllerActionInvoker 
{ 

    protected override ActionDescriptor FindAction(ControllerContext controllerContext, ControllerDescriptor controllerDescriptor, string actionName) 
    { 
     var ad = base.FindAction(controllerContext, controllerDescriptor, actionName); 

     if (ad == null) 
     { 
      //check if the controller is an instance of IRenderMvcController 
      if (controllerContext.Controller is IRenderMvcController) 
      { 
       return new ReflectedActionDescriptor(
        controllerContext.Controller.GetType().GetMethods() 
         .First(x => x.Name == "Index" && 
            x.GetCustomAttributes(typeof(NonActionAttribute), false).Any() == false), 
        "Index", 
        controllerDescriptor); 

      } 
     } 
     return ad; 
    } 

} 

public class TestController : SurfaceController 
{ 

    public TestController() { 
     this.ActionInvoker = new RenderActionInvokerAsync(); 
    } 

    public async Task<ActionResult> Test() 
    { 
     await Task.Delay(10000); 
     return PartialView("TestPartial"); 

    } 
} 

nicht auf diese Weise, Dinge zu tun, obwohl getestet haben.

+1

Danke Pete. Ihre Antwort hat mir geholfen, mein eigenes Problem mit diesem Problem zu lösen (allerdings nicht mit Umbraco). In MVC5 hat meine 'ControllerFactory' einen alten' ActionInvoker' angehängt, um sich in ELMAH einzuklinken, der von 'ControllerActionInvoker' geerbt wurde. Als ich dies in AsyncControllerActionInvoker änderte, wurde das Problem gelöst. – Hanshan

3

Gerade FYI habe ich ein Problem an den Tracker für diese hinzugefügt: http://issues.umbraco.org/issue/U4-5208

Es ist eine Arbeit um, obwohl:

Erstellen Sie eine benutzerdefinierte Asynchron-Aktion aufrufen machen (gemäß oben):

public class FixedAsyncRenderActionInvoker : System.Web.Mvc.Async.AsyncControllerActionInvoker 
{ 
    protected override ActionDescriptor FindAction(ControllerContext controllerContext, ControllerDescriptor controllerDescriptor, string actionName) 
    { 
     var ad = base.FindAction(controllerContext, controllerDescriptor, actionName); 

     if (ad == null) 
     { 
      //check if the controller is an instance of IRenderMvcController 
      if (controllerContext.Controller is IRenderMvcController) 
      { 
       return new ReflectedActionDescriptor(
        controllerContext.Controller.GetType().GetMethods() 
         .First(x => x.Name == "Index" && 
            x.GetCustomAttributes(typeof(NonActionAttribute), false).Any() == false), 
        "Index", 
        controllerDescriptor); 

      } 
     } 
     return ad; 
    } 

} 

erstellen Sie eine benutzerdefinierte machen Mvc Controller:

public class FixedAsyncRenderMvcController : RenderMvcController 
{ 
    public FixedAsyncRenderMvcController() 
    { 
     this.ActionInvoker = new FixedAsyncRenderActionInvoker(); 
    } 
} 

Erstellen Sie eine benutzerdefinierte Render-Controller Fabrik:

public class FixedAsyncRenderControllerFactory : RenderControllerFactory 
{ 
    public override IController CreateController(RequestContext requestContext, string controllerName) 
    { 
     var controller1 = base.CreateController(requestContext, controllerName); 
     var controller2 = controller1 as Controller; 
     if (controller2 != null) 
      controller2.ActionInvoker = new FixedAsyncRenderActionInvoker(); 
     return controller1; 
    } 
} 

einen umbraco Startup-Handler erstellen und die erforderlichen Teile mit den oben genannten Zeichnungsteile ersetzen:

public class UmbracoStartupHandler : ApplicationEventHandler 
{ 
    protected override void ApplicationStarting(UmbracoApplicationBase umbracoApplication, ApplicationContext applicationContext) 
    { 
     DefaultRenderMvcControllerResolver.Current.SetDefaultControllerType(typeof(FixedAsyncRenderMvcController)); 

     FilteredControllerFactoriesResolver.Current.RemoveType<RenderControllerFactory>(); 
     FilteredControllerFactoriesResolver.Current.AddType<FixedAsyncRenderControllerFactory>(); 

     base.ApplicationStarting(umbracoApplication, applicationContext); 
    } 
} 
Verwandte Themen