第一部分:看控制器如何拿到视图数据,
主要基于上下文对象,拿到视图四种类型的数据,参数接收数据,路由数据,表单提交数据,url后面参数,
将表单数据提交给后台控制器,比较快捷,推荐的做法是如下,即利用FormData对象,它有set,get等访问属性方法,后台Request.Form[]拿到
var formData = new FormData($('#myForm')[0]);
formData.append("DocumentIDList", docIds.join(","));
//如果已存在DocumentIDList,再次这里添加会额外拼接
ajax.form('/PeopleOpinionManage/PeopleOpinion/SavePeopleOpinion', formData, function (result) {
if (result.Code == 100) {
hui.layer.success(result.Message);
setTimeout(close, 500);
} else {
hui.layer.error(result.Message);
}
});
//完全可以不用写View视图,因为控制器可以返回字符串内容
public ActionResult Login(string name, int age = 18)
{
StringBuilder sb = new StringBuilder();
sb.AppendFormat("<h1>login的action方法,</h1><p>接收参数name:{0},接收参数age{1}</p>", name, age);
sb.AppendFormat("<h2>路由数据</h2>");
sb.AppendFormat("<p>键的count数:{0}</p>", this.RouteData.Values.Count);
foreach (KeyValuePair<string, object> item in this.RouteData.Values)
{
sb.AppendFormat("<p>{0}:{1}</p>", item.Key, item.Value);
}
sb.AppendFormat("<h2>获取表单数据</h2>");
sb.AppendFormat("<p>键的count数:{0}</p>", Request.Form.AllKeys.Length);
foreach (string key in Request.Form.AllKeys)
{
sb.AppendFormat("<p>{0}:{1}</p>", key, Request.Form[key]);
}
sb.AppendFormat("<h2>获取url后面数据</h2>");
sb.AppendFormat("<p>键的count数:{0}</p>", Request.QueryString.AllKeys.Length);
foreach (string key in Request.QueryString.AllKeys)
{
sb.AppendFormat("<p>{0}:{1}</p>", key, Request.QueryString[key]);
}
return Content(sb.ToString());
}
显示结果如下:
第二部分:控制器如何如何返回数据给视图
第一种方式: ViewBag,ViewData,它们有效范围都是在本视图中,实际上两者公用一个集合完成功能,因此不能重名
跳转则需要TempData,
见下面控制台Acyion代码
//内部在执行完这个方法,将数据放在session里面,执行跳转之后,
//将相关key拿出,放在里面,如果有这个key,
public ActionResult Index()
{
//关于ViewBag,通过视图袋子,将数据展现带给视图,它生命周期比较短,就是展现给视图,
//并且ViewBag,和ViewData实际上操作同一个数据源集合,简而言之,通过ViewBag,添加一对键值,在ViewData里面其实也增加了
ViewBag.info = "viewbag.info";
ViewData["info2"] = "viewdata[info2]";
ViewData["info"] = "viewdata[info]";
ViewBag.name = "viewbag.name";
//return View();
//return View("Index2");
//不加/home/index实际上从当前的home文件下找,
//加/home/index3才是正确的
//return Redirect("/Home/index3");//~/ Views /
//redirect必须是带有action的方法,不能直接视图找到,比如index4没有视图,
//return Redirect("/home/index4");
//return Redirect("/home/index4.cshtml");
/*
*在TempData.Load()方法中,TempDataProvider中保存的数据会被读到TempData中,供Action调用过程中使用。
* Action执行完后,TempData.Save()所作的事情则是,移除TempData中任何没有被更新的键值对,然后再将TempData中的数据保存,供下一次调用使用
* (注:也就是说,只有更新过的,以及新添加的键值对才能再下次request中继续使用)。为什么TempData中的数据需要迅速被清除呢?很简单,节约内存嘛。
*
* action执行前,首先会将临时保存数据privider数据给它,假定是要使用者,有的话给tempdata,
* 执行完,没有就添加一个键值对,同时删除已有的临时保存的provider涉及session,
*/
//action之前,TempDataProvide会将数据给它tempdata,执行后保存它的值,还要删除没有被更新的键值对,
//之所有另一个action可以,
TempData["user"] = "xw";
//如果希望跳转依旧拿到这个值,进入之前临时有数据,先存到TempData给跳转之后使用,执行完就删除未被使用的
//有对应的键,直接赋值给它,
return RedirectToAction("Index3");
//进入之前有别的tempdata托付的数据就给它,没有就添加新的键值对,移除之前留下的,
//如果再次刷新这个值失效,因为一直没有被改变,第二次使用后,没有被更新,执行完就被删除掉了,
//有键值对将值给它,第一次可能没有对应键,直接添加键值对,执行完将未被改变值的其他键的删除,当然第一次应该没有未被改变
//接着重定向后发现再次进入action,发现有将键值中的值给它tempdata,这一次它未被改变,执行完即视图已调用,那么删除它
//再次刷新,就没有值
}
@{
ViewBag.Title = "index3";
}
<h4>
@ViewBag.info
</h4>
<h4>
@ViewBag.info2
</h4>
<h4>
@ViewBag.info
</h4>
<h4>
@ViewBag.name
</h4>
<h4>
@TempData["user"]
</h4>
<h4>
@TempData["user2"]
</h4>
第二种方式:
通过View()方法本身,传递视图对象,或是集合数据,
View则通过Model对象,取出都不需要再声明类型,利用@razor视图语法,代码块中嵌套html标签,像极了phpsmart模板语法,还有java的自定义标签
同时利用@Html.TextBoxt();等标记控件,自动完成值的绑定
且还能自定义绑定方式,比如额外增加默认的字段值等等
//虽然数据并未匹配,比如age实际上是非正数,和模型字段整数型,不太一致,包括密码是pswd和模型字段,属性不太一致,
//但是没有报错,奇怪的是一开始就有模型就有值,通过路由进入的
public ActionResult Register(Student stu)
{
if (Request.HttpMethod.ToLower()=="get")
{
stu=new Student(){Age = 22,Name = "张三默认值",sex = 100};
}
return View(stu);
}
//添加一个特性,也可以在模型视图中的类上面标记,但是无法引入System.Web.Mvc,奇怪
//含义是排除这个属性的绑定
//mvc框架,自动反射将收集数据,赋值到模型视图中间
//其中,前缀Prefix,就是视图中前缀,如果不是这个无效的
public ActionResult List([Bind(Exclude = "age",Prefix = "list2")]List<Student> list)
{
//如果是在模型上面添加,prefix,那么这里设置无效,仍然是list为前缀,而不是就近的list2
if (Request.HttpMethod.ToLower() == "get")
{
list = new List<Student>();
list.Add(new Student() { Age = 23, Name = "张三", password = "23", sex = 0 });
list.Add(new Student() { Age = 213, Name = "2张三", password = "2风格3", sex = 1 });
list.Add(new Student() { Age = 123, Name = "3张三", password = "2地方3", sex = 2 });
}
//List<Student> list=new List<Student>();
//设置以上重重限制,没有将数据收集过来,这里的list变为null,尽量留下一些属性,可以反射上去
return View(list);
}
//使用自定义的模型绑定规则,这里方法里面使用特性很诡异的感觉,
//List<Teacher>
public ActionResult List2([ModelBinder(typeof(EmailBind))]Teacher list2)
{
//这里传递另一个对象,通过数组形式,
if (Request.HttpMethod.ToLower() == "get")
{
//list2 = new List<Teacher>();
//list2.Add(new Teacher() { Age = 23, Name = "张三", password = "23", sex = 0 });
//list2.Add(new Teacher() { Age = 213, Name = "2张三", password = "2风格3", sex = 1 });
//list2.Add(new Teacher() { Age = 123, Name = "3张三", password = "2地方3", sex = 2 });
list2 = new Teacher() {Age = 23, Name = "张三", password = "23", sex = 0};
}
//一开始model是不为空的,因为get请求,请求之后加特性,没有获取到值赋值为null,因此前端循环遍历model出现问题,报错为空
return View(list2);
//return View(list2);
}
@*@using MVCModel*@
@{
ViewBag.Title = "List";
}
<h2>List</h2>
@*太牛逼的语法,返回list集合,直接可以像下面写法,自动识别student对象,????!!!!!!!!!!!*@
<table>
<tr><th>姓名</th><th>性别</th><th>年龄</th><th>密码</th></tr>
@{
foreach (var student in Model)
{
<tr><td>@student.Name</td><td>@student.sex</td><td>@student.Age</td><td>@student.password</td></tr>
}
}
</table>
<h1>获取数组中第一对象,</h1>
<h4>@Model[0].Name</h4>
@*这里[0]可以看出是通过反射
[0].Age,无法识别
必须是list[0],反正是统一的是list[0],要么是[],
同时的话,混合着就只有一个list[],里面能够正常传值,赋值给list
*@
<form action="list" method="post">
<p>
@Html.TextBox("list2[0].Name")
</p>
<p>@Html.TextBox("list[0].Age")</p>
<p>@Html.TextBox("list[0].password")</p>
<p>@Html.TextBox("[0].Sex")</p>
<p><input type="submit" value="提交"/></p>
</form>
增加自定义绑定,新建绑定类,必须继承默认的接口,实现其方法,它接收两个对象上下文,当前控制器上下文,和视图绑定相关上下文,
相关绑定特性,可在action方法里,利用特性参数写,也可以写在模型视图上面,注意继承接口IModelBinder有两个命名空间,是System.Web.Mvc下面的
//除了在action限定绑定规则,这里模型也可以,不过这里加绑定,那么prefix无效
[Bind(Exclude = "Age")]
public class Teacher
{
public string Name { get; set; }
//[BindNever]
public int Age { get; set; }
public int sex { get; set; }
public string Email { set; get; }
public string password { get; set; }
}
public class EmailBind : System.Web.Mvc.IModelBinder
{
//public bool BindModel(ModelBindingExecutionContext modelBindingExecutionContext, ModelBindingContext bindingContext)
//{
// var teacher = bindingContext.Model as Teacher;
// if (teacher == null)
// {
// teacher = new Teacher();
// }
// //后面属性,字段,包括ConvertTo都是基于BindindContext的方法,查看定义即知道
// teacher.Name = (string)bindingContext.ValueProvider.GetValue("Name").ConvertTo(typeof(string));
// teacher.Age = (int)bindingContext.ValueProvider.GetValue("Age").ConvertTo(typeof(int));
// teacher.Name = bindingContext.ValueProvider.GetValue("Name").ConvertTo(typeof(string)).ToString();
// teacher.Email = teacher.Name + "@qq.com";
// return true;
//}
public object BindModel(ControllerContext controllerContext, ModelBindingContext bindingContext)
{
//运行当前模型对象,即拿到当前实例
//var teacher = bindingContext as Teacher;
var teacher = bindingContext.Model as Teacher;
if (teacher == null)
{
teacher = new Teacher();
}
//后面属性,字段,包括ConvertTo都是基于BindindContext的方法,查看定义即知道
//没有获取到表单里面的值,一开始就要判断这个里面有没有值,没有就不应该执行下面的绑定
if (bindingContext.ValueProvider.GetValue("Age") == null)
{
return null;
}
//调试bindingContext.ValueProvider的这个属性,可以很清楚看到有哪些数据,详细的数据结构里面的数据,包含的key等信息,实际上是前端页面的list2[0].Name
teacher.Name = (string)bindingContext.ValueProvider.GetValue("Name").ConvertTo(typeof(string));
teacher.Age = (int)bindingContext.ValueProvider.GetValue("Age").ConvertTo(typeof(int));
teacher.sex = (int)bindingContext.ValueProvider.GetValue("Sex").ConvertTo(typeof(int));
teacher.password = (string)bindingContext.ValueProvider.GetValue("password").ConvertTo(typeof(string));
teacher.Email = teacher.Name + "@qq.com";
//返回一个list,才符合前端需要,或者说一致
List<Teacher> list2=new List<Teacher>();
list2.Add(teacher);
return teacher;
return list2;
}
}
//public class BindAttribute : Attribute
//{
//}
时间仓促,代码未经整理,先留做记录方便查看温故