Several ways of passing values from Controller to View in MVC
Article Directory
1. ViewModel
ViewModel is a strongly typed class used to render ASP.NET MVC views, and can be used to pass data from one or more view models (that is, classes) or data tables. Think of it as a bridge connecting model, data and view. its 生命期为当前视图
. The view model is strongly typed, so there are smart hints and static detection in VS.
Use ViewModel
First create a view model class for rendering the view:
public class Student
{
public int ID {
get; set; }
public string Name {
get; set; }
public DateTime Birth {
get; set; }
}
Define this class in your controller:
public IActionResult Index()
{
Student student=new Student()
{
ID = 1,
Birth = new DateTime(2000,1,1),
Name = "test"
};
return View(student);
}
used in the view
Use at Razor视图
the beginning to @model
specify a strong type, and a view that uses @model
is called a strongly typed view, and a strongly typed view can get intellisense and static checking. If you don't use @mdoel
, the following @Model
is a dynamic type, and you won't get smart hints and static checks.
At the same time, a strongly typed Model can use helper methods, while a weakly typed Model cannot use helper methods, because c# expression trees cannot contain dynamic operations.
Index view:
@model Student
<div>
@Html.DisplayNameFor(m=>m.ID)
@Html.DisplayFor(m=>m.ID)
</div>
<div>
Birth @Model.Birth
</div>
<div>
Name @Model.Name
</div>
Strongly typed view:
Weakly typed views lack intellisense:
Two, ViewData
ViewData
is a Dictionary<string,object>
dictionary of which data is stored in the form of key-value pairs ViewData
. ViewData
Used to pass data between controllers and views, and between views and partial views. Its lifetime is the end of the current view rendering. Since ViewData
an object is returned when using object
, a cast is required to apply the actual type of property or value. No casting is required when the passed data is used in the view as a string, because c#
each object has a method that is automatically called ToString
in the view.c#
In addition to direct definitions ViewData[""]
, attribute definitions ASP.NET Core
are supported for properties in controllers .
[TempData]
ViewData
However, ViewData
it cannot be used in cross-request situations, that is, the page after the jump cannot use the definition of the page before the jump ViewData
, and the subsequent mentioned TempData
can be used for cross-request data transfer.
Use ViewData to pass data between controller and view
public IActionResult ViewDataTest()
{
ViewData["student"]=new Student()
{
ID = 1,
Birth = DateTime.Now,
Name = "test"
};
ViewData["Greeting"] = "Hello";
return View();
}
Use ViewData's data in the ViewDataTest view
@{
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 method and view for testing across requests:
public IActionResult Test()
{
return View();
}
@{
ViewData["Title"] = "Test";
}
<h2>Test</h2>
@ViewData["test"]
Directly use the properties of the data in ViewData:
When using between a view and a partial view ViewData
, the definition in the partial view ViewData
will not overwrite the original view ViewData
. When passing between views and partial views , the main helper methods and markup helper methods ViewData
are used .PartialAsync
<partial>
Using ViewData between views and partial views
public static Task<IHtmlContent> PartialAsync(this IHtmlHelper htmlHelper, string partialViewName, ViewDataDictionary viewData)
The first parameter is passed in 部分视图名称
, and the second parameter is passed in one ViewDataDictionary 对象
. If the second parameter is not specified, the current view's will be ViewData
passed to the partial view.
ViewDataTest2 view:
<h2>ViewDataTest2</h2>
@{
ViewData["Student"] = new Student()
{
ID = 1,
Birth = DateTime.Now,
Name = "test"
};
ViewData["Greeting"] = "Good morning";
}
View: @ViewData["Greeting"]
<br/>
@await Html.PartialAsync("PartialView",new ViewDataDictionary(ViewData))
View: @ViewData["Greeting"]
PartialView view:
@{
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>
Use the partial tag helper method:
About the partial markup helper method: https://docs.microsoft.com/en-us/aspnet/core/mvc/views/partial?view=aspnetcore-2.1
When used, pass the name of the partial view for the name attribute and the name of the object view-data
for the attribute ViewDataDictionary
:
<h2>ViewDataTest2</h2>
@{
ViewData["Student"] = new Student()
{
ID = 1,
Birth = DateTime.Now,
Name = "test"
};
ViewData["Greeting"] = "Good morning";
}
View: @ViewData["Greeting"]
<br/>
@*@await Html.PartialAsync("PartialView",new ViewDataDictionary(ViewData))*@
<partial name="PartialView" view-data="ViewData" />
View: @ViewData["Greeting"]
The result is consistent with using PartialAsync
the helper method.
3. ViewBag
ViewBag
ViewData
is a dynamic type that wraps ControllerBase
and inherits from , so it cannot be used in view pages ViewBag
. Since ViewBag
is a dynamic object, you can add arbitrary properties to it. Also because ViewBag
is a dynamic type, you can directly call its properties to operate.
ViewBag
The difference between and ViewData
is:
- It is not possible to pass a specific ViewBag in the view page.
- Although ViewBag can be defined in the view to be used in the current view, it cannot be defined to be passed to partial views.
ViewBag is not available in Razor pages.
ViewData
- Derived from
ViewDataDictionary
, so it has available dictionary attributes likeContainsKey、Add、Remove
andClear
. The keys in the dictionary are strings, so spaces are allowed.ViewData["Some Key With Whitespace"]
- Any non-
string
type must be cast in the view before it can be usedViewData
.
ViewBag
- Derived from
DynamicViewData
, so it can use dot notation(@ViewBag.SomeKey = <value or object>)
to create dynamic properties without casting. The ViewBag syntax makes adding to controllers and views much faster. (actually almost) - Easier to check for NULL values.
@ViewBag.Person?.Name
public IActionResult ViewBagTest()
{
ViewBag.Student = new Student()
{
ID = 1,
Birth = new DateTime(1997,1,1),
Name = "test"
};
return View();
}
ViewBagTest view:
<h2>ViewBagTest</h2>
<div>View: @(ViewBag.Student.ID+1)</div>
@await Html.PartialAsync("_ViewBagPartial")
_ViewBagPartial view:
<div>ID: @ViewBag.Student.ID</div>
<div>Name: @ViewBag.Student.Name</div>
<div>Birth: @ViewBag.Student.Birth</div>
4、TempData
TempData
is a System.Web.Mvc.TempDataDictionary
type inherited from and is a Dictionary<string,object>
dictionary of . The lifetime is from the beginning of life in the controller TempData
to the end when the is read, even if redirected to another controller method, as long as a TempData
is not read, it still exists. TempData
Refreshing a page that has been visited will visit the page again TempData
, and the unextended lifetime TempData
will be deleted. TempData
Typically used to pass data (such as error messages) between action methods.
If you want to persist the object after one access TempData
, you need to call the method in the controller's method TempData.Keep
, or use the method in the view TempData.Peek
to access TempData
the object. However, it should be noted that the method will not extend the lifetime of the object TempData.Keep
accessed in the redirected view . TempData
A redirected view is RedirectXXX
a view reached using .
Since TempData
the saves itself in ASP.NET
the , it needs to be used with caution and can be problematic Session
when hosting the application on multiple servers . TempData
To solve this problem, you can choose to session
assign all user requests to the same server within the lifetime of the server, or forward session
information between servers.
In addition to using TempData[""]
to TempData
define , you can also use to [TempData]
modify attributes to TempData
define .
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 view:
@{
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")
The ReceiveTempData view used to test across requests:
@{
ViewData["Title"] = "ReceiveTempData";
}
<h2>ReceiveTempData</h2>
<div>@TempData["error"]</div>
@*将 TempData["greetng"] 生命期延长一次*@
<div>@TempData.Peek("greeting")</div>
<br/>@Html.ActionLink("ReceiveTempData2", "ReceiveTempData2")
ReceiveTempData2 view:
@{
ViewData["Title"] = "ReceiveTempData2";
}
<h2>ReceiveTempData2</h2>
<div>@TempData["error"]</div>
<div>@TempData["greeting"]</div>
Another controller TempDataController:
public class TempDataController : Controller
{
public IActionResult Index()
{
return View();
}
}
The Index view for this controller:
@{
ViewData["Title"] = "Index";
}
<h2>Index</h2>
<div>@TempData["error"]</div>
result:
Use redirection:
public IActionResult TempDataTest()
{
TempData["error"] = "An error";
TempData["greeting"] = "Hello";
TempData.Keep("error");
//return View();
return RedirectToAction("ReceiveTempData");
}
Result:
TempData["error"] that should have been extended was not.
5. Session
session
is Web.SessionState
a key-value object inherited from . Pass data between controllers, which can be used to pass data between controllers and views across request states. It is generally Session
used to keep data for a specific user, but it is best not to place sensitive data in it. The lifetime lasts until it is explicitly destroyed by timeout
an event bound by the parameter, by calling the method, or by closing the browser. Clear、RemoveAll、Abandon
It is best to reduce Session
the use of because it is not reliable in server cluster environments and will always occupy server resources while in use.
Session
It needs Startup.cs
to be configured in when using (configuration details).
Instructions:
Here we set the session expiration time to 5 seconds, which is calculated after each operation.
In the ConfigureServices method:
services.AddDistributedMemoryCache();
services.AddSession(options =>
{
options.IdleTimeout = TimeSpan.FromSeconds(5);
options.Cookie.HttpOnly = true;
});
In the Configure method:
app.UseSession();
app.UseMvc();
The order of middleware is important.
An exception occurs when is UseMvc
called after .UseSession
InvalidOperationException
In the default ASP.NET Core implementation, the methods for obtaining and setting byte stream, int and string data are provided in Session, respectively:
Get(ISession, String)
GetInt32(ISession, String)
GetString(ISession, String)
SetInt32(ISession, String, Int32)
SetString(ISession, String, String)
For convenience, implement a generic extension method of Set
and respectively: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);
}
In the controller:
//用来获取和设置值的键
public const string SessionKeyStudent = "_Student";
public string AddSession()
{
if (HttpContext.Session.Get<Student>(SessionKeyStudent)==default(Student))
{
Student student=new Student()
{
Birth = new DateTime(1996,1,1),
ID = 2,
Name = "test"
};
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 view:
@model Student
@{
ViewData["Title"] = "SessionTest";
}
<h2>SessionTest2</h2>
<div>ID: @Model.ID</div>
<div>Name: @Model.Name</div>
<div>Birth: @Model.Birth</div>