一、前言
在之前的一篇随笔中已经讲述过控制器,而今天的随笔是作为之前的扩展。
二、正文
1.自定义动作方法
相信大家在开发过程一定会遇到动作方法的重名问题,虽然方法的名称和参数一样,但是里面的逻辑是不一样的,因为你设置了对应的注解属性可以确定调用哪个动作方法。这个时候你就需要将动作的名称与方法的名称区别开来,那么你就可以使用ActionName注解属性。比如我们要求一个页面在本地访问与非本地访问时呈现不同的页面,但是你又想用不同的方法区分开来写,那么这个时候你就可以使用这个注解属性了,比如下面的代码:
1 [ActionName("Index")] 2 public ActionResult LocalIndex() 3 { 4 return View(); 5 } 6 7 public ActionResult Index() 8 { 9 return View(); 10 }
虽然第一个方法的名称叫做LocalIndex,但是最终页面的名称还是按照ActionName中设置的名称去查询,所以读者千万不要还是按照方法的名称去新建视图,这样是错的。
2.非动作方法
从开始学到现在,大家都一定发现只要写在控制器中的公开方法最后都是一个动作方法(简单说就是对应一个页面),但是我们有时需要一个公开的方法,但是它又不是一个动作方法,仅仅只是为了便于单元测试,那么我们该怎么办?ASP.NET MVC一样还是想到了这些,为我们提供了NonAction注解属性,因为使用很简单所以就不单独举例了。
3.自定义动作方法选择器
上面的第一节介绍了动作方法可以是同一个名字,并且参数也可以完全一样,那么控制器如何去判断执行哪个动作方法呢?其中一个就是根据动作方法选择器(就是动作方法的注解属性)的返回值去过滤匹配的动作方法,ASP.NET MVC现成的有HttpPost等,当然我们也可以自定义,只要实现下面这个抽象类中的IsValidForRequest方法即可:
1 [AttributeUsage(AttributeTargets.Method, AllowMultiple = false, Inherited = true)] 2 public abstract class ActionMethodSelectorAttribute : Attribute 3 { 4 protected ActionMethodSelectorAttribute(); 5 6 public abstract bool IsValidForRequest(ControllerContext controllerContext, MethodInfo methodInfo); 7 } 8 9 其中MethodInfo 中包含的关于动作方法的信息。 10 11 下面是笔者的一个示例,可以根据form表单的值决定是否执行该动作方法: 12 public class LoginAttribute : ActionMethodSelectorAttribute 13 { 14 bool _isFirst; 15 16 public LoginAttribute(bool isFirst) 17 { 18 _isFirst = isFirst; 19 } 20 21 public override bool IsValidForRequest(ControllerContext controllerContext, System.Reflection.MethodInfo methodInfo) 22 { 23 24 string obj = controllerContext.HttpContext.Request.Form["loginType"]; 25 if (obj != null) 26 { 27 if (_isFirst) 28 { 29 if (obj.Equals("true")) 30 return true; 31 } 32 else 33 { 34 if (obj.Equals("false")) 35 return true; 36 } 37 } 38 return false; 39 } 40 }
4.异步控制器
相信从事ASP.NET的人一定会知道异步这个概念,这个概念不仅仅只是在ASP.NET中即使在ASP.NET MVC中也一样存在,只是稍有变化,如果这个控制器中含有异步的方法,那么我们就需要继承AsyncController类,并且需要异步的动作方法要分成两个部分,第一个执行异步操作的方法,命名需要为 动作方法名+Async,当异步操作执行完成之后将调用 动作方法名+Completed方法,特别注意方法的规范,如果名称不对可能就无法看到异步控制器的正确执行结果,笔者有一个简单的示例:
1 namespace MvcStudy.Controllers 2 3 { 4 5 [SessionState(System.Web.SessionState.SessionStateBehavior.Disabled)] 6 7 public class TestController : AsyncController 8 9 { 10 11 [NoAsyncTimeout] 12 13 public void IndexAsync() 14 15 { 16 17 AsyncManager.OutstandingOperations.Increment(); 18 19 Task.Factory.StartNew(() => 20 21 { 22 23 Thread.Sleep(2000); 24 25 AsyncManager.Parameters["data"] = "test"; 26 27 AsyncManager.OutstandingOperations.Decrement(); 28 29 }); 30 31 } 32 33 34 35 public ActionResult IndexCompleted(string data) 36 37 { 38 39 ViewBag.Data = data; 40 41 return View(); 42 43 } 44 45 } 46 47 }
这里我们使用Increment方法开启一个异步操作(该方法可以传递数字表示要开启几个异步操作),然后就是利用StartNew开始我们的一个异步操作,在异步操作完成之后将数据放入Parameters中,这样我们就可以通过IndexCompleted的参数中获得,异步操作最后调用Decrement方法标识一个异步操作完成。IndexAsync动作方法上还存在一个注解属性(NoAsyncTimeout),标识该异步操作没有超时限制,如果你需要设置一个超时可以用AsyncTimeout,并传入一个以毫秒为单位的时间,如果异步操作的执行超时则会产生TimeOutException类型的异常。
读者一定会疑惑SessionState这个注解属性是干什么的,大家一定会熟悉ASP.NET中的一般处理程序,默认都是不可以访问Session其目的就是提高性能,那么在ASP.NET MVC中我们就可以通过SessionState使该控制器不需要维护Session,当然我们也就无法在这个控制器中访问Session了,但是却可以得到性能的提升。