是否可以在Umbraco SurfaceController(和UmbracoApiController)中使用异步操作
我尝试了以下代码
public async Task< ActionResult> HandleLogin(LoginViewModel model)
{
await Task.Delay(1000);
return PartialView("Login", model);
}
虽然在调用动作时它正确编译,但是一旦命中await,动作似乎就会返回,并返回一个字符串
System.Threading.Tasks.Task`1 [System.Web.Mvc.ActionResult]
控制器当然继承自 SurfaceController ,我想知道这是不是问题?
如果无法做到这一点,是否有任何解决方法可以实现异步操作行为?
感谢任何帮助!
答案 0 :(得分:10)
Umbraco中的SurfaceControllers最终来自 System.Web.Mvc.Controller 但是它们具有自定义动作调用程序( RenderActionInvoker )集。
RenderActionInvoker 继承自 ContollerActionInvoker 。为了处理异步操作,它应该来自 AsyncContolkerActionInvoker 。 RenderActionInvoker 仅覆盖findaction方法,因此更改为从 AsyncContolkerActionInvoker 派生很容易。
一旦我通过此更改重新编译Umbraco.Web,异步操作就可以正常工作。
我猜你可以在每个班级上指定一个新的actioninvoker,而不是重新编译整个项目
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");
}
}
但是,Haven没有测试过这种做事方式。
答案 1 :(得分:4)
仅供参考我为跟踪器添加了一个问题: http://issues.umbraco.org/issue/U4-5208
虽然有一项工作:
创建自定义异步渲染操作调用(如上所述):
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;
}
}
创建自定义渲染mvc控制器:
public class FixedAsyncRenderMvcController : RenderMvcController
{
public FixedAsyncRenderMvcController()
{
this.ActionInvoker = new FixedAsyncRenderActionInvoker();
}
}
创建自定义渲染控制器工厂:
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;
}
}
创建一个umbraco启动处理程序,并用上面的自定义部分替换必要的部分:
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);
}
}