.NET MVC中各种Result的本质原理
在使用.net mvc时发现在Controller中返回一个View()便能达到页面的渲染,返回一个Json()便能返回json格式的数据,返回一个Content()便能返回一个string格式的数据。那我们又没有想过mvc框架是怎么实现的呢,今天我们就带着疑惑,去探寻mvc框架中result的奥妙
一.Content()
protected internal virtual ContentResult Content(string content, string contentType, Encoding contentEncoding) { ContentResult contentResult = new ContentResult(); contentResult.Content = content; contentResult.ContentType = contentType; contentResult.ContentEncoding = contentEncoding; return contentResult; //在这里返回了一个ContentResult对象 } public class ContentResult : ActionResult { public string Content { get; set; } public Encoding ContentEncoding { get; set; } public string ContentType { get; set; } public override void ExecuteResult(ControllerContext context) //重写父类的方法,本质都是返回一个ActionResult { if (context == null) { throw new ArgumentNullException("context"); } HttpResponseBase response = context.HttpContext.Response; //重点在这里,返回了一个HttpResponseBase if (!string.IsNullOrEmpty(ContentType)) //若是ContentType不为空了就赋值,为空了就是默认返回string { response.ContentType = ContentType; } if (ContentEncoding != null) { response.ContentEncoding = ContentEncoding; } if (Content != null) { response.Write(Content); //写入输出流,完成http请求的返回 } } }
通过源码分析,得到所有的Content()方法本质都是返回 Content(string content, string contentType, Encoding contentEncoding)这个重载的版本。在这个方法里面返回一个ContentResult对象,通过对ContentResult的源码解析,重写父类的ExecuteResult的方法,用Response.Write(Content)写入输出流,完成http请求的返回
二.JavaScript()
protected internal virtual JavaScriptResult JavaScript(string script) { JavaScriptResult javaScriptResult = new JavaScriptResult(); javaScriptResult.Script = script; return javaScriptResult; //返回一个JavaScriptResult 对象 } public class JavaScriptResult : ActionResult //都是继承了ActionResult { public string Script { get; set; } public override void ExecuteResult(ControllerContext context) { if (context == null) { throw new ArgumentNullException("context"); } HttpResponseBase response = context.HttpContext.Response; response.ContentType = "application/x-javascript"; //奥秘在这里,通过修改Response.ContentType来控制返回的类型,别的部分大致都相同 if (Script != null) { response.Write(Script); } } }
通过JavaScript()方法可以直接返回一个javascript,这就是我们常见的有的请求没有后缀名,但依然能执行javascript的奥秘。其本质就是将Response.ContentType的值修改为application/x-javascript并通过response.Write()方法输出,完成相应的实现
三.Json()
protected internal virtual JsonResult Json(object data, string contentType, Encoding contentEncoding, JsonRequestBehavior behavior) { JsonResult jsonResult = new JsonResult(); jsonResult.Data = data; jsonResult.ContentType = contentType; jsonResult.ContentEncoding = contentEncoding; jsonResult.JsonRequestBehavior = behavior; return jsonResult; //返回一个JsonResult对象 } public class JsonResult : ActionResult { public Encoding ContentEncoding { get; set; } public string ContentType { get; set; } public object Data { get; set; } public JsonRequestBehavior JsonRequestBehavior { get; set; } public int? MaxJsonLength { get; set; } public int? RecursionLimit { get; set; } public JsonResult() { JsonRequestBehavior = JsonRequestBehavior.DenyGet; } public override void ExecuteResult(ControllerContext context) { if (context == null) { throw new ArgumentNullException("context"); } if (JsonRequestBehavior == JsonRequestBehavior.DenyGet && string.Equals(context.HttpContext.Request.HttpMethod, "GET", StringComparison.OrdinalIgnoreCase)) //默认是不支持Get请求,我们可以使用JsonRequestBehavior.AllowGet来允许Get返回 { throw new InvalidOperationException(MvcResources.JsonRequest_GetNotAllowed); } HttpResponseBase response = context.HttpContext.Response; if (!string.IsNullOrEmpty(ContentType)) { response.ContentType = ContentType; } else { response.ContentType = "application/json"; //定义返回格式为application/json } if (ContentEncoding != null) { response.ContentEncoding = ContentEncoding; } if (Data != null) { JavaScriptSerializer javaScriptSerializer = new JavaScriptSerializer(); //加载JavaScriptSerializer 这个序列化对象,我们也可以用Newtonsoft来进行对象的序列化 if (MaxJsonLength.HasValue) { javaScriptSerializer.MaxJsonLength = MaxJsonLength.Value; } if (RecursionLimit.HasValue) { javaScriptSerializer.RecursionLimit = RecursionLimit.Value; } response.Write(javaScriptSerializer.Serialize(Data)); //序列化对象并返回 } } }
mvc中的Json()跟Content()类似,都是有多个重载的版本,但本质上都是调用的Json(object data, string contentType, Encoding contentEncoding, JsonRequestBehavior behavior)这个版本,返回一个JsonResult对象,通过对源码的分析,我们发现JsonResult中通过判断,默认Get请求是不会让我们返回的。所以我们要通过JsonRequestBehavior.AllowGet来完成Get请求的返回。最后还是老套路,通过response.Write(javaScriptSerializer.Serialize(Data))序列化对象,并执行返回
总结
通过对源码的解析,我们不难发现各种Result的本质区别就是修改ContentType的值来控制返回的数据类型。各种Result都继承了ActionResult,通过重写父类的ExecuteResult的方法,来完成相应的返回操作,当然viewresult()是个例外,它是将cshtml转换为一个cs文件,通过页面渲染,最终达到呈现视图的效果