人么总说事件会改变一切,当实际上你必须自己动手去改变一切——Andy Warhol
对输入请求进行路由
在软件中,URI(统一资源标识符)是指通过一个位置或者名称来引用资源。
当URI通过位置来识别资源是,就叫做URL(统一定位符)
当URI通过名称标志资源时,就叫做URN(统一资源名称)
ASP.NET MVC 旨在处理更通用的URI,ASP.NET Web Forms只要处理位置感知的物理资源
模拟ASP.NET MVC运行时
1 | public void ProcessRequest(HttpContext context) |
controller类中
1 | namespace _0101 |
这个简单的例子模拟了ASP.NET MVC使用的基本机制,处理请求的组件是控制器类,通过request的url映射到专门的控制器类进行处理
应用程序路由
url模式与路由
路由:代表URL绝对路径的模式匹配字符串,即没有协议,IP地址,端口号的url字符串
比如:http://localhost:3462/home/test ==> /home/test
路由可以是常量也可以是占位符,mvc系统默认的路由是{controller}/{action}/{id},它可以匹配如Home/Index/1子类的路由
定义应用程序路由
mvc中路由是在Global.asax
下被注册
1 | public class MvcApplication : System.Web.HttpApplication |
对应的类在App_Start/RouteConfig.cs
1 | public class RouteConfig |
路由集合routes添加路由一般通过MapRoute
进行配置,但如果你的路由有MapRoute
不支持的参数可以使用
1 | var route = newRoute(..); |
进行添加,maproute
里面的参数:
name:路由名
url:url匹配模式
defaults:该url默认值对象
如http://localhost:3462/并没有输入controller/action但处理程序会匹配到默认值,导航到http://localhost:3462/Home/Index下
处理路由
ASP.NET url路由模块总是根据注册的顺序进行匹配,所以前一项设置默认值会导致后一项永远得不到匹配
路由同时可以添加约束列表,MapRoute的一个重载
1 | public static Route MapRoute(this RouteCollection routes, string name, string url, object defaults, object constraints); |
可以利用正则表达式将不正确的url拒之门外
1 | routes.MapRoute( |
路由处理程序
路由处理程序实现了IRouteHandler
的接口
1 | public interface IRouteHandler |
RequestContext
中封装了路由的相关信息,MVC框架并没有提供很对内置的路由处理程序,因为自定义路由的需求并不普遍
处理物理文件的请求
在RouteConfig.cs
下添加routes.RouteExistingFiles = true;
1 | public static void RegisterRoutes(RouteCollection routes) |
阻止已定义的路由
相同地方
1 | routes.IgnoreRoute("{resource}.axd/{*pathInfo}"); |
控制器类
编写控制器类
1 | public class HomeController : Controller |
[NonAction]
阻止action绑定到About方法上
[ActionName("About")]
指定Qunimalegebi方法的绑定action name
操作和http动词
1 | [AcceptVerbs(HttpVerbs.Get|HttpVerbs.Post)] |
通过AcceptVerbs
特性绑定http请求方式,httpverbs
枚举类型值
1 | public enum HttpVerbs |
利用“|”可以响应多个请求方式
处理输入数据
获取request对象中的输入数据
request中包含form,querystring,cookie,header
等数据
从路由中获取输入数据
路由和上面得一致,controller中
1 | var str = RouteData.Values["locale"]; |
url:http://localhost:4426/home/1111/en-ed?data=11
str为en-ed,所以routedata捕获的是定义好的路由值,同时根据上述路由会匹配到第一个时直接结束,所以str2位null
1 | var str2 = RouteData.Values["id"]; |
利用valueprovider
字典获取所有来源的值
1 | var str6 = ValueProvider.GetValue("locale").AttemptedValue;//路由的值 |
ValueProvider.GetValue("data")
会有两个属性
RawValue
Object类型原始值
AttemptedValue
string 强转成string类型的值
产生操作结果
controller类中大部分方法返回的都是ActionResult
类型,下面就看看ActionResult
类是什么
actionresult构造
1 | public abstract class ActionResult |
actionresult
类是抽象类,定义了一个方法为ExecuteResult。该方法为具体派生类执行时触发的一系列动作
一些派生类
- ContentResult
- EmptyResult
- FileResult
- HttpUnauthorizedResult
- JavaScriptResult
- JsonResult
- RedirectResult
- RedirectToRouteResult
- ViewResultBase
FileResult
派生
FilePathResult
: 直接将一个文件发送给客户端
可以通过更改报文头实现直接下载,不用浏览器解析
1 | public ActionResult GetFile() |
FileContentResult
: 返回byte字节给客户端(比如图片)FileStreamResult
: 返回流
深入执行操作结果的机制
控制器中我添加了以下方法
1 | public ActionResult GetScript() |
可以看到返回的是JavaScript(script);转到controller类定义可以看到
1 | protected internal virtual JavaScriptResult JavaScript(string script) |
所以JavaScript(script)不过就是controller类的一个帮助方法而已,充当JavaScriptResul
t的对象工厂的角色,类似的如View(),大家都知道View参数默认值是View文件夹下面控制器名文件夹下面的index,所以不传参数并不代表没有参数,JavaScriptResult
实现
1 | public class JavaScriptResult : ActionResult |
可以看到JavaScriptResult
里面仍然是调用的response.ContentType,response.write
注意:
- 如果控制器没有返回
ActionResult
,不会抛出异常,mvc框架会将return中的任何值封装成ContentResult
对象序列化返回,没有返回值会映射成EmptyResult
- mvc中只dotNet 4.5 之后可以使用
async/await
语法执行异步操作响应界面