ViewModel   

  ViewModel 是一个用来渲染 ASP.NET MVC 视图的强类型类,可用来传递来自一个或多个视图模型(即类)或数据表的数据。可将其看做一座连接着模型、数据和视图的桥梁。其生命期为当前视图。视图模型属于强类型,所以在VS中便有智能提示并且可以进行静态检测。

在ASP.NET Core 中使用ViewModel:

先创建一个用于呈现视图的视图模型类:

     public class Student
{
public int ID { get; set; }
public string Name { get; set; }
public DateTime Birth { get; set; }
}

在控制器中定义该类:

         public IActionResult Index()
{
Student student=new Student()
{
ID = ,
6          Birth = new DateTime(1997,1,1),
7 Name = "Nanase"
};
return View(student);
10 }

在视图中使用

在Razor视图开头使用@model 指定强类型,使用了@model 的视图称为强类型视图,强类型视图可获得智能提示和静态检查。不使用@mdoel 则后面的 @Model 为动态类型,不会获得智能提示和静态检查。

同时强类型 Model 可使用辅助器方法,而弱类型 Model 不能使用辅助器方法,因为 c# 表达式树不能包含动态操作。

Index视图:

@model Student

<div>
@Html.DisplayNameFor(m=>m.ID)
@Html.DisplayFor(m=>m.ID)
</div>
<div>
Birth @Model.Birth
</div>
<div>
Name @Model.Name
</div>

强类型视图:

弱类型视图缺少智能提示:

最终结果:

ViewData

  ViewData是一个Dictionary<string,object>的字典,数据以键值对的形式存储在 ViewData 中。ViewData 用来在控制器和视图之间传递数据,也可以在视图和分部视图之间传递数据。其生存期为当前视图渲染结束。由于在使用 ViewData 时返回的是一个object对象,所以应用实际类型的属性或值时需要使用强制类型转换。当传递的数据作为字符串在视图中使用时不需要进行强制转换,因为 c# 每个对象存在 ToString 方法,而在 c# 视图中会自动调用该方法。

除直接定义 ViewData[""] 外,ASP.NET Core 还支持对控制器中的属性使用 [ViewData] 特性定义ViewData。

但是 ViewData 不能用于跨请求的情形,即无法在跳转后的页面使用跳转前页面定义的 ViewData ,而后续提到的 TempData 可以用于跨请求的数据传递。

在控制器和视图间使用ViewData传递数据:

         public IActionResult ViewDataTest()
{
ViewData["student"]=new Student()
{
ID = ,
Birth = DateTime.Now,
Name = "Nanase"
};
ViewData["Greeting"] = "Hello";
return View();
}

在 ViewDataTest 视图中使用ViewData的数据:

@{
Student student = ViewData["student"] as Student;
ViewData["test"] = "test";
} @ViewData["greeting"]
<div>ID: @student.ID</div>
<div>Name: @student.Name</div>
<div>Birth: @student.Birth</div>
<br/>
@Html.ActionLink("Test","Test")

用来测试跨请求的 Test 方法和视图:

         public IActionResult Test()
{
return View();
}
@{
ViewData["Title"] = "Test";
} <h2>Test</h2> @ViewData["test"]

结果:

Test视图:

直接使用 ViewData 中数据的属性:

在视图和部分视图间使用 ViewData 时,部分视图中的 ViewData 的定义不会覆盖原视图的 ViewData 。在视图和部分视图之间传递 ViewData 时,主要使用的是 PartialAsync 辅助器方法以及 <partial> 标记辅助器方法。

在视图和部分视图间使用ViewData:

public static Task<IHtmlContent> PartialAsync(this IHtmlHelper htmlHelper, string partialViewName, ViewDataDictionary viewData)

第一个参数传入部分视图名称,第二个参数传入一个 ViewDataDictionary 对象。若不指定第二个参数,则会将当前视图的 ViewDate 传入部分视图。

ViewDataTest2 视图:

 <h2>ViewDataTest2</h2>
@{
ViewData["Student"] = new Student()
{
ID = ,
Birth = DateTime.Now,
Name = "Nanase"
};
ViewData["Greeting"] = "Good morning";
} View: @ViewData["Greeting"]
<br/>
@await Html.PartialAsync("PartialView",new
ViewDataDictionary(ViewData)) View: @ViewData["Greeting"]

PartialView 视图:

@{
Student student = ViewData["Student"] as Student;
} Partial: @ViewData["Greeting"]
<hr/>
<div>ID: @student.ID</div>
<div>Name: @student.Name</div>
<div>Birth: @student.Birth</div>
<hr/>
@{
ViewData["Greeting"] = "Good afternoon";
} <div>Partial: @ViewData["Greeting"]</div>

结果:

使用 partial 标记辅助器方法:

关于 partial 标记辅助器方法:https://docs.microsoft.com/zh-cn/aspnet/core/mvc/views/partial?view=aspnetcore-2.1

使用时,为 name 属性传递部分视图的名称,为 view-data 属性传递 ViewDataDictionary 对象的名称:

<h2>ViewDataTest2</h2>
@{
ViewData["Student"] = new Student()
{
ID = ,
Birth = DateTime.Now,
Name = "Nanase"
};
ViewData["Greeting"] = "Good morning";
} View: @ViewData["Greeting"]
<br/>
@*@await Html.PartialAsync("PartialView",new ViewDataDictionary(ViewData))*@
<partial name="PartialView" view-data="ViewData" />
View: @ViewData["Greeting"]

结果和使用 PartialAsync 辅助器方法一致。

ViewBag

ViewBag 是一个包装了 ViewData 的动态类型,从 ControllerBase 继承而来,因此在视图页中也无法使用 ViewBag。由于 ViewBag 是一个动态对象,所以可以为其添加任意属性。也由于 ViewBag 属于动态类型,所以可以直接调用其中的属性进行操作。ViewBag 和 ViewData 的区别在于:不能在视图页中传递特定的 ViewBag。

在视图页中使用 ViewBag 失败。

         public IActionResult ViewBagTest()
{
ViewBag.Student = new Student()
{
ID = ,
6          Birth = new DateTime(1997,1,1),
7 Name = "Nanase"
8 };
9 return View();
10 }

ViewBagTest 视图:

 <h2>ViewBagTest</h2>

 <div>View: @(ViewBag.Student.ID+)</div>

 @await Html.PartialAsync("_ViewBagPartial")

_ViewBagPartial 视图:

 <div>ID: @ViewBag.Student.ID</div>
<div>Name: @ViewBag.Student.Name</div>
<div>Birth: @ViewBag.Student.Birth</div>

结果:

TempData

TempData 是一个继承自 System.Web.Mvc.TempDataDictionary 的类型,是一个 Dictionary<string,object> 的字典。生命期为控制器中生命开始到该 TempData 被读取结束,即使重定向到另一个控制器的方法,只要一个 TempData 未被读取,它就仍然存在。在一个访问过 TempData 的页面进行刷新会再次访问该 TempData ,未被延长生命期的 TempData 将被删除。TempData 通常用于在动作方法之间传递数据(如错误信息)。

如果希望在一次访问后保留 TempData 对象,则需要在控制器的方法中调用 TempData.Keep 方法,或者在视图中使用 TempData.Peek 方法访问 TempData 对象。但是需要注意的是 TempData.Keep 方法不会延长重定向的视图中被访问的 TempData 对象的生命期。重定向的视图即指使用 RedirectXXX 抵达的视图。

由于 TempData 将它本身保存在 ASP.NET 的 Session 中,因此需要谨慎使用,当将应用程序托管到多个服务器时 TempData 会出现问题。为解决该问题此时可选择在 session 的生命期内将用户的请求全部分配给同一个服务器,或者在服务器之间转发 session 信息。

除了使用 TempData[""] 对 TempData 进行定义外,还可以使用对属性使用 [TempData] 修饰对 TempData 进行定义。

         public IActionResult TempDataTest()
{
TempData["error"] = "An error";
TempData["greeting"] = "Hello"; //将 TempData["error"] 生存期延长一次
TempData.Keep("error"); return View();
} public IActionResult ReceiveTempData()
{
return View();
} public IActionResult ReceiveTempData2()
{
return View();
}

TempDataTest 视图:

 @{
ViewData["Title"] = "TempDataTest";
} <h2>TempDataTest</h2> <div>@TempData["error"]</div> @*访问 TempData["greeting"] 并将 TempData["greetng"] 延长一次*@
<div>@TempData.Peek("greeting")</div>
<br/>
<div>@Html.ActionLink("Another", "Index", "TempData")</div>
@Html.ActionLink("ReceiveTempData","ReceiveTempData")

用来测试跨请求的 ReceiveTempData 视图:

 @{
ViewData["Title"] = "ReceiveTempData";
} <h2>ReceiveTempData</h2> <div>@TempData["error"]</div> @*将 TempData["greetng"] 生命期延长一次*@
<div>@TempData.Peek("greeting")</div>
<br/>@Html.ActionLink("ReceiveTempData2", "ReceiveTempData2")

ReceiveTempData2 视图:

 @{
ViewData["Title"] = "ReceiveTempData2";
} <h2>ReceiveTempData2</h2> <div>@TempData["error"]</div>
<div>@TempData["greeting"]</div>

另一个控制器 TempDataController:

     public class TempDataController : Controller
{
public IActionResult Index()
{
return View();
}
}

该控制器的 Index 视图:

@{
ViewData["Title"] = "Index";
} <h2>Index</h2> <div>@TempData["error"]</div>

结果:

使用重定向:

         public IActionResult TempDataTest()
{
TempData["error"] = "An error";
TempData["greeting"] = "Hello";
TempData.Keep("error");
//return View();
return RedirectToAction("ReceiveTempData");
}

结果:

本应被延长的 TempData["error"] 没有被延长。

Session

session 是从Web.SessionState 继承的键值对对象。在控制器之间传递数据,可用于跨请求状态下控制器和视图之间的数据传递。一般Session用于保留对特定用户的数据,但最好不要在其中放置敏感数据。生存期一直持续到 timeout 参数所限制的事件、调用Clear、RemoveAll、Abandon 方法或者关闭浏览器来明确地销毁它。最好减少 Session 的使用因为它在服务器集群环境下不可靠,并且在使用时将一直占用服务器资源。

在使用 Session 时需要在 Startup.cs 中对其进行配置(配置详情)。

使用方法:

在此我们将 Session 的过期时间设置为 5 秒,该过期时间在每次操作之后进行计算。

在 ConfigureServices 方法中:

         services.AddDistributedMemoryCache();

         services.AddSession(options =>
{
5        options.IdleTimeout = TimeSpan.FromSeconds(5);
        options.Cookie.HttpOnly = true;
7     });

在 Configure 方法中:

         app.UseSession();
app.UseMvc();

中间件的顺序很重要。 在 UseMvc 之后调用 UseSession 时会发生 InvalidOperationException 异常。

在默认的 ASP.NET Core 实现中,在 Session 中提供了字节流、int 以及 string 数据的获取和设置方法,分别为:

  • Get(ISession, String)
  • GetInt32(ISession, String)
  • GetString(ISession, String)
  • SetInt32(ISession, String, Int32)
  • SetString(ISession, String, String)

为了方便,分别实现一个 Set 和 Get 的 ISession 泛型扩展方法:

         public static void Set<T>(this ISession session, string key, T value)
{
session.SetString(key, JsonConvert.SerializeObject(value));
} public static T Get<T>(this ISession session, string key)
{
var value = session.GetString(key); return value == null ? default(T) :
JsonConvert.DeserializeObject<T>(value);
}

控制器中:

         //用来获取和设置值的键
public const string SessionKeyStudent = "_Student"; public string AddSession()
{
if (HttpContext.Session.Get<Student>(SessionKeyStudent)==default(Student))
{
Student student=new Student()
{
Birth = new DateTime(,,),
ID = ,
Name = "Ruri"
};
HttpContext.Session.Set<Student>(SessionKeyStudent,student);
}
return "Session has been set";
} public IActionResult SessionTest()
{
Student student = HttpContext.Session.Get<Student>(SessionKeyStudent) ?? new Student();
return View(student);
}

SessionTest 视图:

 @model Student
@{
ViewData["Title"] = "SessionTest";
} <h2>SessionTest2</h2> <div>ID: @Model.ID</div>
<div>Name: @Model.Name</div>
<div>Birth: @Model.Birth</div>

结果:

直接访问 sessiontest :

设置 Session 然后再访问 SessionTest2 :

未操作 5s 之后刷新页面,Session 被移除:

总结表格:

示例代码:https://github.com/NanaseRuri/Differences

参考网页: https://www.mytecbits.com/microsoft/dot-net/viewmodel-viewdata-viewbag-tempdata-mvc

      https://docs.microsoft.com/zh-cn/aspnet/core/fundamentals/app-state?view=aspnetcore-2.1

ViewModel、ViewData、ViewBag、TempData、Session之间的区别和各自的使用方法的更多相关文章

  1. ASP.NET MVC4中ViewBag、ViewData和TempData的使用和区别

    一.说明 本文章主要是讲解asp.net mvc中ViewBag.ViewData和TempData的使用和区别,ViewBag.ViewData和TempData常常用于将action方法中的数据传 ...

  2. MVC3中 ViewBag、ViewData和TempData的使用和区别(转发:汴蓝)

    MVC3中 ViewBag.ViewData和TempData的使用和区别   在MVC3开始,视图数据可以通过ViewBag属性访问,在MVC2中则是使用ViewData.MVC3中保留了ViewD ...

  3. MVC3中 ViewBag、ViewData和TempData的使用和区别(转载)

    在MVC3开始,视图数据可以通过ViewBag属性访问,在MVC2中则是使用ViewData.MVC3中保留了ViewData的使用.ViewBag 是动态类型(dynamic),ViewData 是 ...

  4. MVC3中 ViewBag、ViewData和TempData的使用和区别

    在MVC3开始,视图数据可以通过ViewBag属性访问,在MVC2中则是使用ViewData.MVC3中保留了ViewData的使用.ViewBag 是动态类型(dynamic),ViewData 是 ...

  5. ViewBag、ViewData和TempData的使用和区别

    在MVC3开始,视图数据可以通过ViewBag属性访问,在MVC2中则是使用ViewData. MVC3中保留了ViewData的使用. ViewBag 是动态类型(dynamic),ViewData ...

  6. MVC3+中 ViewBag、ViewData和TempData的使用和区别

    在MVC3开始,视图数据可以通过ViewBag属性访问,在MVC2中则是使用ViewData.MVC3中保留了ViewData的使用.ViewBag 是动态类型(dynamic),ViewData 是 ...

  7. MVC3中 ViewBag、ViewData和TempData的使用和区别(不是自己写的)

    (网上抄的,并未消化)在MVC3开始,视图数据可以通过ViewBag属性访问,在MVC2中则是使用ViewData.MVC3中保留了ViewData的使用.ViewBag 是动态类型(dynamic) ...

  8. MVC MVC3中 ViewBag、ViewData和TempData的使用和区别 【转】

    在MVC3开始,视图数据可以通过ViewBag属性访问,在MVC2中则是使用ViewData.MVC3中保留了ViewData的使用.ViewBag 是动态类型(dynamic),ViewData 是 ...

  9. 【MVC4 之 ViewData ViewBag TempData】

    ViewData (一个字典集合类型):传入的key必须是string类型,可以保存任意对象信息,特点:它只会存在这次的HTTP的要求中而已,并不像session可以将数据带到下一个Http要求. V ...

随机推荐

  1. 笔记——python风格规范

    分号 不要在行尾加分号, 也不要用分号将两条命令放在同一行. 行长度 每行不超过80个字符 例外: 长的导入模块语句 注释里的URL 不要使用反斜杠连接行. Python会将 圆括号, 中括号和花括号 ...

  2. 贪心算法求解活动安排<算法分析>

    一.实验内容及要求 1.要求按贪心算法原理求解问题: 2.要求手工输入s[10]及f[10],其中注意自己判断s[i]<f[i]: 3.要求显示所有活动及最优活动安排的i事件列表.二.实验步骤  ...

  3. 九度oj 题目1068:球的半径和体积

    题目1068:球的半径和体积 时间限制:1 秒 内存限制:32 兆 特殊判题:否 提交:6148 解决:2269 题目描述: 输入球的中心点和球上某一点的坐标,计算球的半径和体积 输入: 球的中心点和 ...

  4. codevs4439 YJQ Requires Food

    题目描述 Description 神犇YJQ有n个不同的妹子和m种食物,每一天每一种食物只供应一个妹子吃的份量.在接下来的t天内,YJQ准备包养所有的妹子. 对于每个妹子,她在t天内都只会吃某些特定的 ...

  5. Linux下汇编语言学习笔记60 ---

    这是17年暑假学习Linux汇编语言的笔记记录,参考书目为清华大学出版社 Jeff Duntemann著 梁晓辉译<汇编语言基于Linux环境>的书,喜欢看原版书的同学可以看<Ass ...

  6. Nginx 的 server_names_hash_bucket_size 问题

    在 Nginx 0.6.35 的版本中,配置多个 server 虚拟主机,必须要在配置文档中 http { 里头加上 server_names_hash_bucket_size 64; 这么一句 ht ...

  7. [bzoj2463][中山市选2009]谁能赢呢?_博弈论

    博弈论 bzoj-2463 中山市选-2009 题目大意:题目链接. 注释:略. 想法: 如果$n$是偶数的话就可以被多米诺骨牌恰好覆盖,这样的话只需要先手先走向(1,1)对应的第二段,后者必定会将棋 ...

  8. Network-POJ3694(最小公共祖先LCA+Tarjin)

    http://poj.org/problem?id=3694 这一题  为什么要找最小祖先呢 当两个节点连到一块的时候  找最小公共节点就相当于找强连通分支 再找最小公共节点的过程中直到找到  这个过 ...

  9. Oracle数据库导入导出简单备份

    oracle数据库简单备份 方法一: 1.导出 exp c##xmq/pwda@orcl owner=c##xmq file=C:/expdb.dmp buffer=8000 2.导入 2.1.删除原 ...

  10. Guass列主元、平方根法、追赶法求解方程组的C++实现

    一,要解决的问题 选用合适的算法,求解三种线性方程组:一般线性方程组,对称正定方程组,三对角线性方程组. 方程略. 二,数值方法 1,使用Guass列主元消去法求解一般线性方程组. Guass列主元是 ...