ASP.NET MVC . Controller
2010-11-03 16:13
295 查看
Controller 提供了众多的方法让我们返回各种类型的 ActionResult。
1. View
最常用的一种,用于返回一个 "标准" 页面。
这个页面默认是 ViewPage,也可以是我们自己定义的其它模板引擎页面。
MVC 还提供了强类型的 ViewPage<TModel>。
Index.aspx
在 WebForm 时代,我们就已经习惯了将一个页面分解成多个 UserControl,现在我们依然可以这么做。htmlHelper 专门提供了 RenderPartial 扩展方法,从当前视图目录(Views\xxx)下载入 .ascx 页面。
RenderPartialInternal 调用 FindParitialView 从视图引擎中载入 .ascx,同时将当前的环境参数传递给它。也就是说 RenderPartial 只是一种视图级别的行为,并不会再次触发 Controller Action 操作,这点要和 Controller.PartialView() 区别开来。
Index.aspx
Part.ascx
2. Content
Content 用于输出(Response.Write) "静态" 片段。
看看和 jQuery 的配合使用。
Index.aspx
3. PartialView
Controller.PartialView() 和 HtmlHelper.RenderPartial() 的不同之处在于前者是再次执行 ActionInvoke 并返回一个 ActionResult 结果,后者只是使用现有的 ViewContext 显示一个视图片段。而与 Controller.Content() 的区别是 PartialView() 使用视图引擎输出一个 "动态" 的 ascx 结果。
和 Content() 一样,我们通常将其和 jQuery 等 Ajax 框架配合使用。
Index.aspx
Part.ascx
4. Redirect / RedirectToAction / RedirectToRoute
Controller 提供了几种方式,让我们在不同的 Action 之间进行跳转。
方法1:
Redirect() 直接用 Response.Redirect() 完成 url 跳转。
相关细节:
方法2:
RedirectToAction() 直接使用 Action Name 进行跳转。
如果目标 Action 不在当前 Controller 类,则可以指定目标 Controller Name。
相关细节:
可以看到 RedirectToRouteResult.ExecuteResult 中使用 Route 相关信息拼接成目标 Url 后进行跳转。
方法3:
RedirectToRoute() 则是直接用 MapRoute 时定义的 Route Name 进行跳转。
相关细节:
执行过程和 RedirectToAction() 相同。
5. Json
Json() 在编写 Ajax 时非常有用,可以将 Entity 等对象序列化成 JSON 格式供 Javascript 使用。
Index.aspx
很好用,不是吗?看看相关细节。
使用 System.Web.Script.Serialization.JavaScriptSerializer 完成 JSON 序列化操作,也就是说我们还可以用 ScriptIgnoreAttribute 排除某些属性。
6. Javascript
某些时候,我们需要根据一些逻辑判断来载入执行不同的 Javascript 代码。
Index.aspx
只是这种做法,似乎将 View 和 Controller 的耦合加大了…… 还不如直接用 Javascript 来处理这些。
7. File (Download / Upload)
File() 提供了 Download 功能。
当我们在浏览器请求 "/Test/Download/1" 是就会打开下载窗口,同时给出了保存文件名。
文件上传是另一个常用的 Web 应用。
Index.aspx
MVC 提供了一个 HttpPostedFileBaseModelBinder 将 Request.Files 的信息直接映射给 Action 同名参数。
看看一次上传多个文件的演示。
Index.aspx
[最后修改
1. View
最常用的一种,用于返回一个 "标准" 页面。
protected internal virtual ViewResult View(string viewName, string masterName, object model){ if (model != null) { base.ViewData.Model = model; } return new ViewResult { ViewName = viewName, MasterName = masterName, ViewData = base.ViewData, TempData = base.TempData };}public class ViewResult : ViewResultBase{ protected override ViewEngineResult FindView(ControllerContext context) { ViewEngineResult result = ViewEngineCollection.FindView(context, ViewName, MasterName); if (result.View != null) { return result; } ... }}
这个页面默认是 ViewPage,也可以是我们自己定义的其它模板引擎页面。
MVC 还提供了强类型的 ViewPage<TModel>。
public class User{ public string Name { get; set; } public int Age { get; set; }}public class TestController : Controller{ public ActionResult Index() { ViewData["message"] = "Hello, World!"; var model = new User { Name = "Tom", Age = 13 }; return View(model); }}
Index.aspx
<%@ Page Language="C#" Inherits="System.Web.Mvc.ViewPage<Learn.MVC.Controllers.User>" %><html xmlns="http://www.w3.org/1999/xhtml"><head runat="server"> <title>Index</title></head><body> Name: <%= Model.Name %>; Age: <%= Model.Age %></body></html>
在 WebForm 时代,我们就已经习惯了将一个页面分解成多个 UserControl,现在我们依然可以这么做。htmlHelper 专门提供了 RenderPartial 扩展方法,从当前视图目录(Views\xxx)下载入 .ascx 页面。
public static class RenderPartialExtensions{ public static void RenderPartial(this HtmlHelper htmlHelper, partialViewName, model, viewData) { htmlHelper.RenderPartialInternal(partialViewName, viewData, model, ViewEngines.Engines); }}public class HtmlHelper{ internal virtual void RenderPartialInternal(string partialViewName, ViewDataDictionary viewData, object model, ViewEngineCollection viewEngineCollection) { ... ViewDataDictionary newViewData = null; if (model == null) { if (viewData == null) newViewData = new ViewDataDictionary(ViewData); else newViewData = new ViewDataDictionary(viewData); } else { if (viewData == null) newViewData = new ViewDataDictionary(model); else newViewData = new ViewDataDictionary(viewData) { Model = model }; } ViewContext newViewContext = new ViewContext(ViewContext, ViewContext.View, newViewData, ViewContext.TempData); IView view = FindPartialView(newViewContext, partialViewName, viewEngineCollection); view.Render(newViewContext, ViewContext.HttpContext.Response.Output); } internal static IView FindPartialView(viewContext, partialViewName, viewEngineCollection) { ViewEngineResult result = viewEngineCollection.FindPartialView(viewContext, partialViewName); if (result.View != null) { return result.View; } ... }}
RenderPartialInternal 调用 FindParitialView 从视图引擎中载入 .ascx,同时将当前的环境参数传递给它。也就是说 RenderPartial 只是一种视图级别的行为,并不会再次触发 Controller Action 操作,这点要和 Controller.PartialView() 区别开来。
Index.aspx
<%@ Page Language="C#" Inherits="System.Web.Mvc.ViewPage<Learn.MVC.Controllers.User>" %><html xmlns="http://www.w3.org/1999/xhtml"><head runat="server"> <title>Index</title></head><body> Name: <%= Model.Name %>; Age: <%= Model.Age %> <br /> <% Html.RenderPartial("Part"); %></body></html>
Part.ascx
<%@ Control Language="C#" Inherits="System.Web.Mvc.ViewUserControl<Learn.MVC.Controllers.User>" %><%= ViewData["message"] %> <br /><%= Model.Name %>
2. Content
Content 用于输出(Response.Write) "静态" 片段。
protected internal virtual ContentResult Content(content, contentType, contentEncoding){ return new ContentResult { Content = content, ContentType = contentType, ContentEncoding = contentEncoding };}public class ContentResult : ActionResult{ public string Content { get; set; } public override void ExecuteResult(ControllerContext context) { ... HttpResponseBase response = context.HttpContext.Response; if (!String.IsNullOrEmpty(ContentType)) { response.ContentType = ContentType; } if (ContentEncoding != null) { response.ContentEncoding = ContentEncoding; } if (Content != null) { response.Write(Content); } }}
看看和 jQuery 的配合使用。
public class TestController : Controller{ public ActionResult Index() { return View(); } public ActionResult Part() { return Content("<a href=\"http://www.rainsts.net\">Q.yuhen</a>"); }}
Index.aspx
<%@ Page Language="C#" Inherits="System.Web.Mvc.ViewPage" %><html xmlns="http://www.w3.org/1999/xhtml"><head runat="server"> <title>Index</title> <script src="http://www.cnblogs.com/Scripts/jquery-1.3.1.min.js" type="text/javascript"></script> <script type="text/javascript"> $(function() { $("#div1").load("/test/part"); }); </script></head><body> <div id="div1"> </div></body></html>
3. PartialView
Controller.PartialView() 和 HtmlHelper.RenderPartial() 的不同之处在于前者是再次执行 ActionInvoke 并返回一个 ActionResult 结果,后者只是使用现有的 ViewContext 显示一个视图片段。而与 Controller.Content() 的区别是 PartialView() 使用视图引擎输出一个 "动态" 的 ascx 结果。
protected internal virtual PartialViewResult PartialView(string viewName, object model){ if (model != null) { ViewData.Model = model; } return new PartialViewResult { ViewName = viewName, ViewData = ViewData, TempData = TempData };}public class PartialViewResult : ViewResultBase{ protected override ViewEngineResult FindView(ControllerContext context) { ViewEngineResult result = ViewEngineCollection.FindPartialView(context, ViewName); if (result.View != null) { return result; } ... }}
和 Content() 一样,我们通常将其和 jQuery 等 Ajax 框架配合使用。
public class TestController : Controller{ public ActionResult Index() { return View(); } public ActionResult Part() { ViewData["time"] = DateTime.Now; var model = new User { Name = "Tom", Age = 13 }; return PartialView(model); }}
Index.aspx
<%@ Page Language="C#" Inherits="System.Web.Mvc.ViewPage" %><html xmlns="http://www.w3.org/1999/xhtml"><head runat="server"> <title>Index</title> <script src="http://www.cnblogs.com/Scripts/jquery-1.3.1.min.js" type="text/javascript"></script> <script type="text/javascript"> $(function() { $("#div1").load("/test/part"); }); </script></head><body> <div id="div1"> </div></body></html>
Part.ascx
<%@ Control Language="C#" Inherits="System.Web.Mvc.ViewUserControl<Learn.MVC.Controllers.User>" %><%= ViewData["time"] %> <br /><%= Model.Name %>; <%= Model.Age %>
4. Redirect / RedirectToAction / RedirectToRoute
Controller 提供了几种方式,让我们在不同的 Action 之间进行跳转。
public class MvcApplication : System.Web.HttpApplication{ public static void RegisterRoutes(RouteCollection routes) { ... routes.MapRoute ( "Test2", "Test/T2/{name}/{age}", new { controller = "Test", action = "T2", name = "", age = 0 } ); ... }}
方法1:
Redirect() 直接用 Response.Redirect() 完成 url 跳转。
public class TestController : Controller{ public ActionResult Index() { return Redirect("/Test/T2/Tom/23"); } public ActionResult T2(User user) { return Content(user.Name); }}
相关细节:
protected internal virtual RedirectResult Redirect(string url){ ... return new RedirectResult(url);}public class RedirectResult : ActionResult{ public override void ExecuteResult(ControllerContext context) { ... string destinationUrl = UrlHelper.Content(Url, context.HttpContext); context.HttpContext.Response.Redirect(destinationUrl, false /* endResponse */); }}
方法2:
RedirectToAction() 直接使用 Action Name 进行跳转。
public class TestController : Controller{ public ActionResult Index() { return RedirectToAction("T2", new { name = "Tom", age = 23 }); } public ActionResult T2(User user) { return Content(user.Name); }}
如果目标 Action 不在当前 Controller 类,则可以指定目标 Controller Name。
return RedirectToAction("T2", new { controller="Test2", name = "Tom", age = 23 });
相关细节:
protected internal virtual RedirectToRouteResult RedirectToAction(string actionName, string controllerName, RouteValueDictionary routeValues){ RouteValueDictionary mergedRouteValues; if (RouteData == null) { mergedRouteValues = RouteValuesHelpers.MergeRouteValues(actionName, controllerName, null, routeValues, true /* includeImplicitMvcValues */); } else { mergedRouteValues = RouteValuesHelpers.MergeRouteValues(actionName, controllerName, RouteData.Values, routeValues, true /* includeImplicitMvcValues */); } return new RedirectToRouteResult(mergedRouteValues);}public class RedirectToRouteResult : ActionResult{ public override void ExecuteResult(ControllerContext context) { ... string destinationUrl = UrlHelper.GenerateUrl(RouteName, null /* actionName */, null /* controllerName */, RouteValues, Routes, context.RequestContext, false /* includeImplicitMvcValues */); ... context.HttpContext.Response.Redirect(destinationUrl, false /* endResponse */); }}
可以看到 RedirectToRouteResult.ExecuteResult 中使用 Route 相关信息拼接成目标 Url 后进行跳转。
方法3:
RedirectToRoute() 则是直接用 MapRoute 时定义的 Route Name 进行跳转。
public class TestController : Controller{ public ActionResult Index() { return RedirectToRoute("Test2", new { name = "Tom", age = 23 }); }}
相关细节:
protected internal virtual RedirectToRouteResult RedirectToRoute(string routeName, RouteValueDictionary routeValues){ return new RedirectToRouteResult(routeName, RouteValuesHelpers.GetRouteValues(routeValues));}
执行过程和 RedirectToAction() 相同。
5. Json
Json() 在编写 Ajax 时非常有用,可以将 Entity 等对象序列化成 JSON 格式供 Javascript 使用。
public class TestController : Controller{ public ActionResult Index() { return View(); } public ActionResult GetUser(string name) { var user = new User { Name = name, Age = 23 }; return Json(user); }}
Index.aspx
<%@ Page Language="C#" Inherits="System.Web.Mvc.ViewPage" %><html xmlns="http://www.w3.org/1999/xhtml"><head runat="server"> <title>Index</title> <script src="http://www.cnblogs.com/Scripts/jquery-1.3.1.min.js" type="text/javascript"></script> <script type="text/javascript"> $(function() { $("#btnTest").click(function() { $.getJSON ( "/Test/GetUser", { name: "Tom" }, function(json) { alert(json.Name + ";" + json.Age); } ); }); }); </script></head><body> <input type="button" id="btnTest" value="Test" /></body></html>
很好用,不是吗?看看相关细节。
protected internal virtual JsonResult Json(object data, string contentType, Encoding contentEncoding){ return new JsonResult { Data = data, ContentType = contentType, ContentEncoding = contentEncoding };}public class JsonResult : ActionResult{ public override void ExecuteResult(ControllerContext context) { ... if (Data != null) { JavaScriptSerializer serializer = new JavaScriptSerializer(); response.Write(serializer.Serialize(Data)); } }}
使用 System.Web.Script.Serialization.JavaScriptSerializer 完成 JSON 序列化操作,也就是说我们还可以用 ScriptIgnoreAttribute 排除某些属性。
6. Javascript
某些时候,我们需要根据一些逻辑判断来载入执行不同的 Javascript 代码。
public class TestController : Controller{ public ActionResult Index() { return View(); } public ActionResult GetJs(int id) { switch (id) { case 1: return JavaScript("alert('Hello, C#!');"); case 2: return JavaScript("alert('Hello, MVC!');"); default: return null; } }}
Index.aspx
<%@ Page Language="C#" Inherits="System.Web.Mvc.ViewPage" %><html xmlns="http://www.w3.org/1999/xhtml"><head runat="server"> <title>Index</title> <script src="http://www.cnblogs.com/Scripts/jquery-1.3.1.min.js" type="text/javascript"></script> <script type="text/javascript"> $(function() { $("#btnTest").click(function() { var id = $("#txtId").val(); $.getScript("/Test/GetJs/" + id); }); }); </script></head><body> <input type="text" id="txtId" value="1" /> <input type="button" id="btnTest" value="Test" /></body></html>
只是这种做法,似乎将 View 和 Controller 的耦合加大了…… 还不如直接用 Javascript 来处理这些。
protected internal virtual JavaScriptResult JavaScript(string script){ return new JavaScriptResult { Script = script };}public class JavaScriptResult : ActionResult{ public override void ExecuteResult(ControllerContext context) { ... HttpResponseBase response = context.HttpContext.Response; response.ContentType = "application/x-javascript"; if (Script != null) { response.Write(Script); } }}
7. File (Download / Upload)
File() 提供了 Download 功能。
public class TestController : Controller{ public ActionResult Index() { return View(); } public ActionResult Download(int id) { var filename = String.Format("~/Content/Download/{0}.rar", id); var fileDownloadName = String.Format("{0}.rar", id); return File(filename, "application/octet-stream", fileDownloadName); }}
当我们在浏览器请求 "/Test/Download/1" 是就会打开下载窗口,同时给出了保存文件名。
protected internal virtual FileContentResult File(byte[] fileContents, contentType, fileDownloadName){ return new FileContentResult(fileContents, contentType) { FileDownloadName = fileDownloadName };}public abstract class FileResult : ActionResult{ public override void ExecuteResult(ControllerContext context) { ... HttpResponseBase response = context.HttpContext.Response; response.ContentType = ContentType; ... WriteFile(response); } protected abstract void WriteFile(HttpResponseBase response);}public class FileContentResult : FileResult{ protected override void WriteFile(HttpResponseBase response) { response.OutputStream.Write(FileContents, 0, FileContents.Length); }}
文件上传是另一个常用的 Web 应用。
public class TestController : Controller{ public ActionResult Index() { return View(); } public ActionResult Upload(HttpPostedFileBase file) { var filename = Server.MapPath("~/Content/Upload/" + Path.GetFileName(file.FileName)); file.SaveAs(filename); return null; }}
Index.aspx
<%@ Page Language="C#" Inherits="System.Web.Mvc.ViewPage" %><html xmlns="http://www.w3.org/1999/xhtml"><head runat="server"> <title>Index</title></head><body> <form action="/Test/Upload" enctype="multipart/form-data" method="post"> <input type="file" name="file" /> <input type="submit" name="upload" /> </form></body></html>
MVC 提供了一个 HttpPostedFileBaseModelBinder 将 Request.Files 的信息直接映射给 Action 同名参数。
public class HttpPostedFileBaseModelBinder : IModelBinder{ public object BindModel(ControllerContext controllerContext, ModelBindingContext bindingContext) { ... HttpPostedFileBase theFile = controllerContext.HttpContext.Request.Files[bindingContext.ModelName]; // case 1: there was no <input type="file" ... /> element in the post if (theFile == null) { return null; } // case 2: there was an <input type="file" ... /> element in the post, but it was left blank if (theFile.ContentLength == 0 && String.IsNullOrEmpty(theFile.FileName)) { return null; } // case 3: the file was posted return theFile; }}
看看一次上传多个文件的演示。
public class TestController : Controller{ public ActionResult Index() { return View(); } public ActionResult Upload(HttpPostedFileBase file1, HttpPostedFileBase file2) { var html = String.Format("{0}:{1}<br />{2}:{3}", file1.FileName, file1.InputStream.Length, file2.FileName, file2.InputStream.Length); return Content(html); }}
Index.aspx
<%@ Page Language="C#" Inherits="System.Web.Mvc.ViewPage" %><html xmlns="http://www.w3.org/1999/xhtml"><head runat="server"> <title>Index</title></head><body> <form action="/Test/Upload" enctype="multipart/form-data" method="post"> <input type="file" name="file1" /> <input type="file" name="file2" /> <input type="submit" name="upload" /> </form></body></html>
[最后修改
相关文章推荐
- ASP.NET MVC框架之控制器Controller(四)
- ASP.NET MVC 入门4、Controller与Action
- ASP.NET MVC中Controller与View之间的数据传递总结 (来自网络)
- ASP.NET MVC系列:Controller/Action
- 在ASP.NET MVC 中获取当前URL、Controller、Action(集)
- ASP.NET MVC Controller的激活
- ASP.NET MVC之Controller学习2
- ASP.NET MVC 重点教程一周年版 第三回 Controller与View
- ASP.NET MVC 设置 Route 使 URL 中不显示 controller 名
- asp.net mvc 中的 controller和asp.net web api 的apicontroller有什么区别?(转)
- 从零开始学习 ASP.NET MVC 1.0 (三) Controller/Action 深入解析与应用实例 【转】
- how to get all controller attribute action and parameter in asp.net mvc
- Asp.Net MVC学习总结(二)——控制器与动作(Controller And Action)
- ASP.NET MVC 5 Web编程3 -- Controller的应用及扩展
- ASP.NET MVC中Controller的使用Demo
- Asp.net MVC 学习笔记 (3) --Controller 与View 之间的数据传递
- Asp.net Mvc Framework 三 (Controller与View)
- ASP.NET MVC Controller激活系统详解
- 004. Asp.Net Routing与MVC 之二: 请求如何激活Controller和Action
- 返璞归真 asp.net mvc (7) - asp.net mvc 3.0 新特性之 Controller