MVC杂记<三>---Controller
ASP.NET MVC 框架可将 URL 映射到称为“controller”的类。 控制器将处理传入的请求,处理用户输入和交互,并执行相应的应用程序逻辑。
所有控制器的基类为 ControllerBase 类,该类可进行普通的 MVC 处理。 Controller 类从 ControllerBase 中继承并且是控制器的默认实现。 Controller 类负责以下处理阶段的工作:
-
查找要调用的相应操作方法,并验证是否可以调用该方法。
-
获取要用作操作方法的参数的值。
-
处理在执行操作方法期间可能发生的所有错误。
-
提供用于呈现 ASP.NET 页面类型(视图)的默认 WebFormViewEngine
当Controller被MVCHandler选中以后,紧接着就会用过ActionInvoker选择合适的Action来进行执行操作,当然在我们用习惯MVC以后,就会自然而然的不去思考参数是怎么转换和绑定了,我们不在需要使用asp.netWebForm那样的方式通过Reuqest.QueryString[]\Request.Form[]去获取,在进行处理,我们只需要习惯这种模型绑定方式,那么现在我们是怎么处理View传过来的数据的?
很多新学习web的同学可能更喜欢使用原始的Form提交的方式,那么我们来看这个例子:
<form action="Home/Accept" method="post"> 编号<input name="id" type="text" /> 姓名<input name="name" type="text" /> <input type="submit" value="提交"/> </form>
这是前台的,我们定义了两个有效地数据获取控件,指定了网址路由,然后我们在后台的Action中获取,先看看后台是怎么定义的
public ActionResult Accept(int id, string name) { return Content(string.Format("学生{0}的编号是{1}",name,id)); }
当我们运行并点击提交按钮就会发现,前台传过去的id和name自动的被获取到了,你已经发现前台传过来的数据自动的进行了转换,这就是MVC方便的绑定机制,当然,在
开发中你还会遇到强类型视图传过来的多个复杂对象的模型绑定机制。这里就不在多说了,全部放在之后的几个例子里大概说一下,自己理解这些基础更好。
Action执行完通常返回的是是一个ActionResult 中派生的类的实例。 ActionResult 类是所有操作结果的基础。他其实是一个抽象类。我们来看一下它的定义:
1 // 摘要: 2 // Encapsulates the result of an action method and is used to perform a framework-level 3 // operation on behalf of the action method. 4 public abstract class ActionResult 5 { 6 // 摘要: 7 // Initializes a new instance of the System.Web.Mvc.ActionResult class. 8 protected ActionResult(); 9 10 // 摘要: 11 // Enables processing of the result of an action method by a custom type that 12 // inherits from the System.Web.Mvc.ActionResult class. 13 // 14 // 参数: 15 // context: 16 // The context in which the result is executed. The context information includes 17 // the controller, HTTP content, request context, and route data. 18 public abstract void ExecuteResult(ControllerContext context); 19 }
现在很明了,他就是获取ActionResult子类的对象,并执行它的ExecuteReslut方法,然后将执行结果返回给客户端。
您可以创建返回任意类型(如字符串、整数或布尔值)的对象的操作方法。 这些返回类型在呈现到响应流之前包装在合适的 ActionResult 类型中。
下表显示了内置操作结果类型以及返回这些类型的操作帮助器方法。
此外,新学习的同学们也应该对常见的Action选择器进行一个了解和认识,例如HTTPPost,HTTPGet,HttpDelete,HttpPut,NonAction这些都比较简单,看下就会了。
下面我们就演示几个例子来初步了解一下其中的某些ActionResult对象的用法。
我们来做下面这个常见的效果:
也就是前后两个下拉列表框的数据来自不同的表,但是又相互关联。
我们先来看后台处理代码:(这里并不需要绑定selected选择项,在这里不是重点,之后有时间会介绍在Edit等页面中怎么绑定已选中的项和值)
我们先来看刚进入的时候,先默认绑定文章类下面的所以关联的数据
List<SelectListItem> types = new List<SelectListItem>(); var query = from type in new ArticleTypeDAL().GetList() select type; foreach (var type in query) { types.Add(new SelectListItem { Value = type.ArticleTypeId.ToString(), Text = type.ArticleTypeName }); } ViewData["ContentType"] = new SelectList(types,"Value","Text"); var query2 = from item in new ArticleItemDAL().GetList().Where(c => c.ArticleTypeId == Convert.ToInt32(types[0].Value)) select item; List<SelectListItem> items = new List<SelectListItem>(); foreach (var item in query2) { items.Add(new SelectListItem { Value = item.ArticleItemId.ToString(), Text = item.ArticleItemName }); } ViewData["ContentItem"] = new SelectList(items, "Value", "Text"); return View();
客户端:
文章类别:<%=Html.DropDownList("Seltype", ViewData["ContentType"] as SelectList)%> <%=Html.DropDownList("Selitem", ViewData["ContentItem"] as SelectList)%>
现在我们的要求是动态的根据前面的内容改变后面的下拉框的数据
我们根据前面的类型Id动态的获取后面的关联项,于是我们这么写
public JsonResult SearchArticleItem(int typeId) { List<SelectListItem> items = new List<SelectListItem>(); var query3 = from item in new ArticleItemDAL().GetList().Where(c => c.ArticleTypeId == typeId) select item; foreach (var item in query3) { items.Add(new SelectListItem { Value = item.ArticleItemId.ToString(), Text = item.ArticleItemName }); } return Json(items, JsonRequestBehavior.AllowGet); }
JsonRequestBehavior.AllowGet,这个是告知客户端可以通过HTTPGet方式获取json数据,为了安全起见,默认是不允许使用Get方式获取的。
然后我们通过ajax方式前台动态的加载关联数据:
$(function() { $("#Seltype").change(function() { $("#Selitem").find("option").remove(); var sp = $("#Seltype option:selected"); var url = '<%=Url.Action("SearchArticleItem","Article")%>'; $.post(url, { typeId: sp.val() }, function(response) { $.each(response, function(i, item) { $("<option></option>").val(item.Value).text(item.Text).appendTo($("#Selitem")); }); }); }); });
学习Controller的时候你有必要了解一下 ControllerBase 中一些虚方法,下面介绍一个很好玩的也是很有用的一个虚方法HandleUnknownAction
这个方法使用来干什么的?你熟悉这个吗?
嗯,他就是找不到相应的Action后的一个处理函数,这里注意下不是找不到View是找不到Action,如果是找不到View的话就会出现你懂得(不截图自己试试就知道了)。。。
至于内部怎么处理,完全按照你的要求啦。
此外如果一个ViewData或者ViewBag要在同一个controller下的多个Action中复用的话,建议直接写在Controller的构造函数中,这样就不用多费体力了。
很多东西既不是一两篇文章可以说完的, 也没有那么多的时间去写东西,所以开始要和大家一起自己研究。
下面对TempData进行一个解释
TempData的数据结构和ViewData一样,也属于字典类,他和ViewData不一样的地方就是它使用Session来存储数据,他的有效期仅仅限于一次网络请求,
也就是说他在一次王爷请求后就自动清空了。
我们对前面的例子稍微修改一下:
public ActionResult About()
{
return View(TempData["msg"]);
}
public ActionResult Accept(int id, string name)
{
TempData["msg"] = string.Format("学生{0}的编号是{1}", name, id);
return RedirectToAction("About");
}
这样运行以后我们输入111,阿斯达;
提交后我们会得到一样一行信息:,之后我们一刷新,没了,现在我们换成ViewData试试
我们再来修改一下代码:
public ActionResult About() { return View(TempData["msg"]); } public ActionResult Accept(int id, string name) { TempData["msg"] = string.Format("学生{0}的编号是{1}", name, id);//写入 string msg = TempData["msg"].ToString();//读取 return RedirectToAction("About"); }
我们执行发现数据没有了,这是因为在Acctpt这个Action中写入后又一次请求获取的值的过程,里面的数据自动清空,跳转到别的页面数据也就没有了。