一个简图来描述下Aspnet MVC下的异步调用
{ request } / \/ -------ISS------- > work thread | | \ route - aysn controller | | \ [invoke] clr thread pool | / | / | / complete -> asyncManager | / |------asyncManager
从简图可以了解:
用户发送请求,服务器路由到控制器,控制器到action,action内部通过线程池调用新线程执行request,然后将数据返回给用户。
该简图涉及到controller的一个属性AsyncManager
asyncManagerde的作用主要体现在两点:
1. 标识异步的开始和结束,通 过 AsyncManager.OutstandingOperations.Increment/OutstandingOperations.Decrement
2. 在执行线程到结束回调过程中的参数传递 通过AsyncManager.Parameters (类型为字典,传递参数时候需要注意Key需要跟结果参数回调的参数名一致)。
asyncManager在异步调用中并不是必须的。
异步虽好,但并不是所有的场合都是适合的,一般来说如果没有长耗时和分布的需求情况下,异步是没要的
在aspnet mvc中实现异步操作有三种方式:
1.通过异步控制器AsyncController
自定义控制器通过继承AsyncController,在内部定义XXXAsync/XXXCompleted格式的action,例如:
public void IndexAsync() { } public ActionResult IndexCompleted(string parameter); //其中indexCompleted中的参数parameter //通过AsyncManager.Parameters ["parameter‘] = XX传递 //参数名和KEY要保持一致性
Async和completed定义总是成对出现了,async定义的方法用于执行异步操作,而completed定义的方法用于返回结果.
通过XXasync和XXcompeleted定义的方法,ASPNET MVC在调用时候并不是以异步的方式调用,所以真正的工作还是需要我们自己async中定义异步操作.一个简单的例子:
public class CustomAsyncController: AsyncController { public void IndexAsync() { //increment不写参数情况默认计数为1 //如果存在多个task需要添加相应的计数值,以保证结果能正确的返回 AsyncManager.OutstandingOperations.Increment(); Task.Factory.StartNew(() => { int sum = 0; for (int i = 0; i < 10000000; i++) { sum += i; } //传递参数给XXXCompleted AsyncManager.Parameters["sum"] = sum; //end AsyncManager.OutstandingOperations.Decrement();//多个任务要多次调用,调用次数一般等于increment中设置的计数 }); } public ActionResult IndexCompleted(string sum) { return Content(sum.ToString()); } }
2.通过async和await关键字
async/await关键字用于标识异步操作,我们用一个简单的例子来演示async/await的使用
a.例子我们先定义个webapi,用于返回用户信息
b.通过服务类,异步调用改用webapi接口返回用户信息
c.控制器调用服务类返回数据结果
public class UserController : ApiController { private static UserRepository _respository = new UserRepository(); [System.Web.Http.HttpGet] public IList<UserModel> GetAll() { return _respository.GetAll(); } }
public class UserService { private static UserService instance = null; public static UserService Instance { get { if (instance == null) instance = new UserService(); return instance; } } public async Task<IList<UserModel>> GetUsersAsync( CancellationToken token =default(CancellationToken)) { var uri = "http://localhost:3541/api/user/getall"; using(HttpClient client = new HttpClient()) { var response = await client.GetAsync(uri); return await response.Content.ReadAsAsync<IList<UserModel>>(); } } }
public class CustomController : Controller { public async Task<ActionResult> Index() { IList < UserModel > models = await UserService.Instance.GetUsersAsync(); return Json(models,JsonRequestBehavior.AllowGet); } }
3.直接通过返回task实现异步
最简单最直接的一种方式了
public class HomeController : AsyncController { public Task<ActionResult> Index() { return Task.Factory.StartNew(() => { return new List<UserModel> { new UserModel {Name ="visonme" }, new UserModel {Name = "visonme2" } }; }).ContinueWith<ActionResult>((task) => { return Json(task.Result, JsonRequestBehavior.AllowGet); }); } }
Aspnet MVC 异步调用