技术开发 频道

为ASP.NET MVC扩展异步Action功能

  ModelBinder支持
  
  其实您到目前为止还不能使用异步Action,因为您会发现方法的AsyncCallback参数得到的永远是null。这是因为默认的Model Binder无法得知如何从一个上下文环境中得到一个AsyncCallback对象。这一点倒非常简单,我们只需要构造一个AsyncCallbackModelBinder,而它的BindModel方法仅仅是将AsyncMvcHandler.BeginProcessRequest方法中保存的AsyncCallback对象取出并返回:

public sealed class AsyncCallbackModelBinder : IModelBinder
{
    
public object BindModel(
        ControllerContext controllerContext,
        ModelBindingContext bindingContext)
    {
        
return controllerContext.Controller.GetAsyncCallback();
    }
}

  其使用方式,便是在应用程序启动时将其注册为AsyncCallback类型的默认Binder:

protected void Application_Start()
{
    RegisterRoutes(RouteTable.Routes);
    ModelBinders.Binders[
typeof(AsyncCallback)] = new AsyncCallbackModelBinder();
}

  对于asyncState参数您也可以使用类似的做法,不过这似乎有些不妥,因为object类型实在过于宽泛,并不能明确代指asyncState参数。事实上,即使您不为asyncState设置binder也没有太大问题,因为对于一个异步ASP.NET请求来说,其asyncState永远是null。如果您一定要指定一个binder,我建议您在每个Action方法的asyncState参数上标记如下的Attribute,它和AsyncStateModelBinder也已经被一并建入项目中了:

[AttributeUsage(AttributeTargets.Parameter, AllowMultiple = false, Inherited = false)]
public sealed class AsyncStateAttribute : CustomModelBinderAttribute
{
    
private static AsyncStateModelBinder s_modelBinder = new AsyncStateModelBinder();

    
public override IModelBinder GetBinder()
    {
        
return s_modelBinder;
    }
}

  使用方式如下:

[AsyncAction]
public ActionResult AsyncAction(AsyncCallback cb, [AsyncState]object state) { ... }

  其实,基于Controller的扩展方法GetAsyncCallback和GetAsyncState均为公有方法,您也可以让Action方法不接受这两个参数而直接从Controller中获取——当然这种做法降低了可测试性,不值得提倡。

0
相关文章