ASP.NET?MVC使用Session會(huì)話保持表單狀態(tài)
本篇實(shí)踐在ASP.NET MVC 4下使用Session來保持表單的狀態(tài)。

如上,輸入俱樂部名稱,點(diǎn)擊"添加球員",輸入球員名稱。我們希望,點(diǎn)擊"到別的地方轉(zhuǎn)轉(zhuǎn)"跳轉(zhuǎn)到另外一個(gè)視圖頁,當(dāng)再次返回的時(shí)候能保持表單的狀態(tài)。
點(diǎn)擊"到別的地方轉(zhuǎn)轉(zhuǎn)"跳轉(zhuǎn)到另外一個(gè)視圖頁如下:

再次返回,表單的狀態(tài)被保持了:

點(diǎn)擊"提交"按鈕,顯示表單的內(nèi)容:

關(guān)于球員,對(duì)應(yīng)的Model為:
using System.ComponentModel.DataAnnotations;
namespace MvcApplication1.Models
{
public class Player
{
public int Id { get; set; }
[Required(ErrorMessage = "必填")]
[Display(Name = "球員名稱")]
public string Name { get; set; }
}
}關(guān)于俱樂部,對(duì)應(yīng)的Model為:
using System.Collections.Generic;
using System.ComponentModel.DataAnnotations;
namespace MvcApplication1.Models
{
public class Club
{
public Club()
{
this.Players = new List<Player>();
}
public int Id { get; set; }
[Required(ErrorMessage = "必填")]
[Display(Name = "俱樂部名稱")]
public string Name { get; set; }
public List<Player> Players { get; set; }
}
}在Home/Index.cshtml強(qiáng)類型視圖中,
@model MvcApplication1.Models.Club
@{
ViewBag.Title = "Index";
Layout = "~/Views/Shared/_Layout.cshtml";
}
<h2>Index</h2>
@using (Html.BeginForm("Index", "Home", FormMethod.Post, new {id = "myForm"}))
{
@Html.LabelFor(m => m.Name)
@Html.TextBoxFor(m => m.Name)
@Html.ValidationMessageFor(m => m.Name)
<br/><br/>
<ul id="players" style="list-style-type: none">
@if (Model.Players != null)
{
foreach (var item in Model.Players)
{
Html.RenderAction("NewPlayerRow", "Home", new { player = @item });
}
}
</ul>
<a id="addPlayer" href="javascript:void(0)" rel="external nofollow" rel="external nofollow" >添加球員</a>
<br/><br/>
<div>
<a href="javascript:void(0)" rel="external nofollow" rel="external nofollow" id="gotoOther">到別的地方轉(zhuǎn)轉(zhuǎn)</a>
<input type="submit" id="up" value="提交" />
</div>
}
@section scripts
{
<script src="~/Scripts/dynamicvalidation.js"></script>
<script type="text/javascript">
$(function () {
//添加關(guān)于Player的新行
$('#addPlayer').on("click", function() {
createPlayerRow();
});
//到別的頁
$('#gotoOther').on("click", function() {
if ($('#myForm').valid()) {
$.ajax({
cache: false,
url: '@Url.Action("BeforeGoToMustSave", "Home")',
type: 'POST',
dataType: 'json',
data: $('#myForm').serialize(),
success: function (data) {
if (data.msg) {
window.location.href = '@Url.Action("RealGoTo", "Home")';
}
},
error: function (xhr, status) {
alert("添加失敗,狀態(tài)碼:" + status);
}
});
}
});
});
//添加品牌行
function createPlayerRow() {
$.ajax({
cache: false,
url: '@Url.Action("NewPlayerRow", "Home")',
type: "GET",
data: {},
success: function (data) {
$('#players').append(data);
$.validator.unobtrusive.parseDynamicContent('#players li:last', "#myForm");
},
error: function (xhr, status) {
alert("添加行失敗,狀態(tài)碼:" + status);
}
});
}
</script>
}以上,
- 點(diǎn)擊"添加球員",向控制器發(fā)出異步請(qǐng)求,把部分視圖li動(dòng)態(tài)加載到ul中
- 點(diǎn)擊"到別的地方轉(zhuǎn)轉(zhuǎn)",向控制器發(fā)出異步請(qǐng)求,正是在這時(shí)候,在控制器的Action中,實(shí)施把表單的狀態(tài)保存到Session中
- 點(diǎn)擊"提交"按鈕,把表單信息顯示出來
另外,當(dāng)在頁面上點(diǎn)擊"添加球員",為了讓動(dòng)態(tài)的部分視圖能被驗(yàn)證,需要引入dynamicvalidation.js,調(diào)用其$.validator.unobtrusive.parseDynamicContent('#players li:last', "#myForm")方法,dynamicvalidation.js具體如下:
//對(duì)動(dòng)態(tài)生成內(nèi)容客戶端驗(yàn)證
(function ($) {
$.validator.unobtrusive.parseDynamicContent = function (selector, formSelector) {
$.validator.unobtrusive.parse(selector);
var form = $(formSelector);
var unobtrusiveValidation = form.data('unobtrusiveValidation');
var validator = form.validate();
$.each(unobtrusiveValidation.options.rules, function (elname, elrules) {
if (validator.settings.rules[elname] == undefined) {
var args = {};
$.extend(args, elrules);
args.messages = unobtrusiveValidation.options.messages[elname];
//edit:use quoted strings for the name selector
$("[name='" + elname + "']").rules("add", args);
} else {
$.each(elrules, function (rulename, data) {
if (validator.settings.rules[elname][rulename] == undefined) {
var args = {};
args[rulename] = data;
args.messages = unobtrusiveValidation.options.messages[elname][rulename];
//edit:use quoted strings for the name selector
$("[name='" + elname + "']").rules("add", args);
}
});
}
});
};
})(jQuery);在HomeController中,
public class HomeController : Controller
{
private const string sessionKey = "myFormKey";
public ActionResult Index()
{
Club club = null;
if (Session[sessionKey] != null)
{
club = (Club) Session[sessionKey];
}
else
{
club = new Club();
}
return View(club);
}
//提交表單
[HttpPost]
public ActionResult Index(Club club)
{
if (ModelState.IsValid)
{
StringBuilder sb = new StringBuilder();
sb.Append(club.Name);
if (club.Players != null && club.Players.Count > 0)
{
foreach (var item in club.Players)
{
sb.AppendFormat("--{0}", item.Name);
}
}
//刪除Session
//Session.Abandon();
//Session.Clear();
Session.Remove(sessionKey);
return Content(sb.ToString());
}
else
{
return View(club);
}
}
//添加新行
public ActionResult NewPlayerRow(Player player)
{
return PartialView("_NewPlayer", player ?? new Player());
}
//跳轉(zhuǎn)之前把表單保存到Session中
[HttpPost]
public ActionResult BeforeGoToMustSave(Club club)
{
Session[sessionKey] = club;
return Json(new { msg = true });
}
//保存完Club的Session后真正跳轉(zhuǎn)到的頁面
public ActionResult RealGoTo()
{
return View();
}
}以上,
- 對(duì)于接收[HttpGet]請(qǐng)求的Index方法對(duì)應(yīng)的視圖,Session存在就從Session中取出Club實(shí)例,否則就創(chuàng)建一個(gè)空的club實(shí)例
- 對(duì)于接收[HttpPost]請(qǐng)求的Index方法對(duì)應(yīng)的視圖,顯示表單內(nèi)容之前把對(duì)應(yīng)的Session刪除
- 添加新行NewPlayerRow方法供顯示或添加用,當(dāng)Player類型參數(shù)為null的時(shí)候,實(shí)際就是點(diǎn)擊"添加球員"顯示新行
- BeforeGoToMustSave方法實(shí)際是為了在跳轉(zhuǎn)之前保存Session
- RealGoTo是點(diǎn)擊"到別的地方轉(zhuǎn)轉(zhuǎn)"后真正跳轉(zhuǎn)的視圖頁
另外,所有視圖頁的公共頁Layout.cshtml,必須引用異步驗(yàn)證的js。
<head>
<meta charset="utf-8" />
<meta name="viewport" content="width=device-width" />
<title>@ViewBag.Title</title>
@Styles.Render("~/Content/css")
@Scripts.Render("~/bundles/jquery")
@Scripts.Render("~/bundles/jqueryval")
</head>
<body>
@RenderBody()
@RenderSection("scripts", required: false)
</body>Home/_NewPlayer.cshtml部分視圖,是在點(diǎn)擊"添加球員"之后動(dòng)態(tài)加載的部分視圖。
@using MvcApplication1.Extension
@model MvcApplication1.Models.Player
<li class="newcarcolorli">
@using (Html.BeginCollectionItem("Players"))
{
@Html.HiddenFor(model => model.Id)
<div>
@Html.LabelFor(m => m.Name)
@Html.TextBoxFor(m => m.Name)
@Html.ValidationMessageFor(m => m.Name)
</div>
}
</li>其中,用到了擴(kuò)展Extension文件夾下CollectionEditingHtmlExtensions類的擴(kuò)展方法,如下:
using System;
using System.Collections.Generic;
using System.Web;
using System.Web.Mvc;
namespace MvcApplication1.Extension
{
public static class CollectionEditingHtmlExtensions
{
//目標(biāo)生成如下格式
//<input autocomplete="off" name="FavouriteMovies.Index" type="hidden" value="6d85a95b-1dee-4175-bfae-73fad6a3763b" />
//<label>Title</label>
//<input class="text-box single-line" name="FavouriteMovies[6d85a95b-1dee-4175-bfae-73fad6a3763b].Title" type="text" value="Movie 1" />
//<span class="field-validation-valid"></span>
public static IDisposable BeginCollectionItem<TModel>(this HtmlHelper<TModel> html, string collectionName)
{
//構(gòu)建name="FavouriteMovies.Index"
string collectionIndexFieldName = string.Format("{0}.Index", collectionName);
//構(gòu)建Guid字符串
string itemIndex = GetCollectionItemIndex(collectionIndexFieldName);
//構(gòu)建帶上集合屬性+Guid字符串的前綴
string collectionItemName = string.Format("{0}[{1}]", collectionName, itemIndex);
TagBuilder indexField = new TagBuilder("input");
indexField.MergeAttributes(new Dictionary<string, string>()
{
{"name", string.Format("{0}.Index", collectionName)},
{"value", itemIndex},
{"type", "hidden"},
{"autocomplete", "off"}
});
html.ViewContext.Writer.WriteLine(indexField.ToString(TagRenderMode.SelfClosing));
return new CollectionItemNamePrefixScope(html.ViewData.TemplateInfo, collectionItemName);
}
private class CollectionItemNamePrefixScope : IDisposable
{
private readonly TemplateInfo _templateInfo;
private readonly string _previousPrfix;
//通過構(gòu)造函數(shù),先把TemplateInfo以及TemplateInfo.HtmlFieldPrefix賦值給私有字段變量,并把集合屬性名稱賦值給TemplateInfo.HtmlFieldPrefix
public CollectionItemNamePrefixScope(TemplateInfo templateInfo, string collectionItemName)
{
this._templateInfo = templateInfo;
this._previousPrfix = templateInfo.HtmlFieldPrefix;
templateInfo.HtmlFieldPrefix = collectionItemName;
}
public void Dispose()
{
_templateInfo.HtmlFieldPrefix = _previousPrfix;
}
}
/// <summary>
///
/// </summary>
/// <param name="collectionIndexFieldName">比如,F(xiàn)avouriteMovies.Index</param>
/// <returns>Guid字符串</returns>
private static string GetCollectionItemIndex(string collectionIndexFieldName)
{
Queue<string> previousIndices = (Queue<string>)HttpContext.Current.Items[collectionIndexFieldName];
if (previousIndices == null)
{
HttpContext.Current.Items[collectionIndexFieldName] = previousIndices = new Queue<string>();
string previousIndicesValues = HttpContext.Current.Request[collectionIndexFieldName];
if (!string.IsNullOrWhiteSpace(previousIndicesValues))
{
foreach (string index in previousIndicesValues.Split(','))
{
previousIndices.Enqueue(index);
}
}
}
return previousIndices.Count > 0 ? previousIndices.Dequeue() : Guid.NewGuid().ToString();
}
}
}Home/RealGoTo.cshtml視圖,是點(diǎn)擊"到別的地方轉(zhuǎn)轉(zhuǎn)"后跳轉(zhuǎn)到的頁面,僅僅提供了一個(gè)跳轉(zhuǎn)到Home/Index視圖頁的鏈接。
@{
ViewBag.Title = "RealGoTo";
Layout = "~/Views/Shared/_Layout.cshtml";
}
<h2>RealGoTo</h2>
@Html.ActionLink("回到表單頁","Index","Home")本篇的源碼在這里: https://github.com/darrenji/KeepFormStateUsingSession
以上就是這篇文章的全部?jī)?nèi)容了,希望本文的內(nèi)容對(duì)大家的學(xué)習(xí)或者工作具有一定的參考學(xué)習(xí)價(jià)值,謝謝大家對(duì)腳本之家的支持。如果你想了解更多相關(guān)內(nèi)容請(qǐng)查看下面相關(guān)鏈接
- ASP.NET?MVC實(shí)現(xiàn)下拉框多選
- ASP.NET?MVC使用Quartz.NET執(zhí)行定時(shí)任務(wù)
- ASP.NET MVC視圖頁使用jQuery傳遞異步數(shù)據(jù)的幾種方式詳解
- ASP.NET?MVC通過勾選checkbox更改select的內(nèi)容
- ASP.NET?MVC使用Log4Net記錄異常日志并跳轉(zhuǎn)到靜態(tài)頁
- ASP.NET?MVC實(shí)現(xiàn)樹形導(dǎo)航菜單
- ASP.NET?MVC擴(kuò)展帶驗(yàn)證的單選按鈕
- 使用EF Code First搭建簡(jiǎn)易ASP.NET MVC網(wǎng)站并允許數(shù)據(jù)庫遷移
相關(guān)文章
.NET使用System.Timers.Timer類實(shí)現(xiàn)程序定時(shí)執(zhí)行
這篇文章介紹了.NET使用System.Timers.Timer類實(shí)現(xiàn)程序定時(shí)執(zhí)行的方法,文中通過示例代碼介紹的非常詳細(xì)。對(duì)大家的學(xué)習(xí)或工作具有一定的參考借鑒價(jià)值,需要的朋友可以參考下2022-07-07
ASP.NET Mvc開發(fā)之刪除修改數(shù)據(jù)
這篇文章主要介紹了ASP.NET Mvc開發(fā)中的刪除修改數(shù)據(jù)功能,感興趣的小伙伴們可以參考一下2016-03-03
在GridView中LinkButton的屬性的應(yīng)用(如何不用選中就刪除這一行)
GridView中LinkButton的屬性的應(yīng)用,實(shí)現(xiàn)不用選中就刪除這一行2009-04-04
Sqlite 常用函數(shù)封裝提高Codeeer的效率
以下是頻繁用到的Sqlite函數(shù),內(nèi)容格式相對(duì)固定,封裝一下有助于提高開發(fā)效率^_^至少提高Codeeer的效率了2012-12-12
如何使用.NET8 創(chuàng)建使用MySQL數(shù)據(jù)庫的webapi項(xiàng)目
這篇文章主要介紹了如何使用.NET8 創(chuàng)建使用MySQL數(shù)據(jù)庫的webapi項(xiàng)目,本文給大家介紹的非常詳細(xì),需要的朋友可以參考下2024-04-04
ASP.NET小結(jié)之MVC, MVP, MVVM比較以及區(qū)別(二)
上一篇得到大家的關(guān)注,非常感謝。由于自己對(duì)于這些模式的理解也是有限,對(duì)于MVC,MVP,MVVM這些模式的比較,是結(jié)合自己的理解,一些地方不一定準(zhǔn)確,需要的朋友可以參考下2014-05-05
ASP.NET中操作SQL數(shù)據(jù)庫(連接字符串的配置及獲取)
要想在ASP.NET中操作SQL數(shù)據(jù)庫首先需要在WebConfig中配置數(shù)據(jù)庫連接字符串,之后在.cs文件中獲取連接字符串,具體的配置及獲取方法如下,感興趣的朋友可以參考下哈2013-06-06
ASP.NET Core部署前期準(zhǔn)備 使用Hyper-V安裝Ubuntu Server 16.10
這篇文章主要為大家詳細(xì)介紹了ASP.NET Core部署的前期準(zhǔn)備,使用Hyper-V安裝Ubuntu Server 16.10,具有一定的參考價(jià)值,感興趣的小伙伴們可以參考一下2017-04-04
MVC4 基礎(chǔ) 枚舉生成 DropDownList 實(shí)用技巧
本篇文章小編為大家介紹,MVC4 基礎(chǔ) 枚舉生成 DropDownList 實(shí)用技巧。需要的朋友參考下2013-04-04

