我在asp.net mvc (三) 中有類似如下的問題:有一個Partial View控制項,在home這個view中使用該控制項,怎麼取key和value??就是在Partial View控制項如何向View傳值。
我當時說到ViewData的應用,但ViewData 局限於當前Action。現在有了TempData後,一切都解決了。
解決方案:修改產生留言的Action:這裡給一個TempData賦值。
[AcceptVerbs(HttpVerbs.Post)]
public ActionResult Create(GuestBookInfo model)
{
try
{
inter.Add(model);
var models = inter.FindAllInfo();
TempData["TempData"] = "已經成功建立";
return RedirectToAction("Index");
}
catch(Exception ex)
{
ModelState.AddModelError("ex",ex);
return View(model);
}
}
然後在index View 就可以方便的訪問下面的值:<%=TempData["TempData"]%>,有趣的是當TempData["TempData"]沒有賦值時,這條語句並不會出錯。
我們來看下Controller之間為什麼可以通過TempData來實現傳值,在傳統的asp.net 中我們經常會利用Session或者是Cookie來傳值,TempData因為並不是通過網頁參數傳值,所以肯定是把資料存放區在某個地方的原因。
第一:查看Controller類的源碼,其中包含一個重要的方法:在這個方面開始前就調用了基類的TempData.Load方法。
protected override void ExecuteCore()
{
base.TempData.Load(base.ControllerContext, this.TempDataProvider);
try
{
string requiredString = this.RouteData.GetRequiredString("action");
if (!this.ActionInvoker.InvokeAction(base.ControllerContext, requiredString))
{
this.HandleUnknownAction(requiredString);
}
}
finally
{
base.TempData.Save(base.ControllerContext, this.TempDataProvider);
}
}
第二:TempData.Load方法:可以看到最終是由ITempDataProvider這個介面來完成。
public void Load(ControllerContext controllerContext, ITempDataProvider tempDataProvider)
{
IDictionary<string, object> dictionary = tempDataProvider.LoadTempData(controllerContext);
this._data = (dictionary != null) ? new Dictionary<string, object>(dictionary,
StringComparer.OrdinalIgnoreCase) : new Dictionary<string, object>(StringComparer.OrdinalIgnoreCase);
this._initialKeys = new HashSet<string>(this._data.Keys);
this._modifiedKeys.Clear();
}
第三:ITempDataProvider:我們可以在第一條中的代碼中發現,介面是這樣取的:
public ITempDataProvider TempDataProvider
{
get
{
if (this._tempDataProvider == null)
{
this._tempDataProvider = new SessionStateTempDataProvider();
}
return this._tempDataProvider;
}
set
{
this._tempDataProvider = value;
}
}
第四:SessionStateTempDataProvider,從這個名字我們就可以猜測,資料應該是用Session方式儲存。主要包含了兩個方法,分別用於載入資料和儲存資料。
public virtual IDictionary<string, object> LoadTempData(ControllerContext controllerContext)
{
HttpContextBase httpContext = controllerContext.HttpContext;
if (httpContext.Session == null)
{
throw new InvalidOperationException(MvcResources.SessionStateTempDataProvider_SessionStateDisabled);
}
Dictionary<string, object> dictionary = httpContext.Session["__ControllerTempData"] as Dictionary<string,
object>;
if (dictionary != null)
{
httpContext.Session.Remove("__ControllerTempData");
return dictionary;
}
return new Dictionary<string, object>(StringComparer.OrdinalIgnoreCase);
}
public virtual void SaveTempData(ControllerContext controllerContext, IDictionary<string, object> values)
{
HttpContextBase httpContext = controllerContext.HttpContext;
if (httpContext.Session == null)
{
throw new InvalidOperationException(MvcResources.SessionStateTempDataProvider_SessionStateDisabled);
}
httpContext.Session["__ControllerTempData"] = values;
}
小結:TempData雖然用Session來實現資料的儲存,但對伺服器來講,代價雖然有,但並不高,因為從代碼上看TempData用完一次就會被消除掉。看到這,我們可以想,是否可以看定義一個TempDataProvider,當然可以。這裡我建立一個樣本,並沒有做功能上的改變,可以根據實際情況修改:
1:建立MyTempDataProvider,讓它繼承ITempDataProvider ,並且實現LoadTempData和SaveTempData。
2:將MyTempDataProvider與Controller聯絡上,我們可以選擇擴充預設控制器工廠(DefaultControllerFactory) ,重寫IController CreateController方法:
public override IController CreateController(RequestContext requestContext, string controllerName)
{
Controller controller = base.CreateController(requestContext, controllerName) as Controller ;
if (null != controller)
{
controller.TempDataProvider = new MyTempDataProvider();
}
return controller;
}
3:註冊我們自訂的MyControllerFactory,這也是最後一步。
protected void Application_Start()
{
ControllerBuilder.Current.DefaultNamespaces.Add("GuestBook.MVC.Controller");
ModelBinders.Binders.Add(typeof(GuestBookInfo ), new GuestBookBinder ());
ControllerBuilder.Current.SetControllerFactory(typeof(MyControllerFactory ));
RegisterRoutes(RouteTable.Routes);
}
總結:通過瞭解TempData的實現機制以及生命週期,我們就不難實現我之前的難題了。
註:本文參考:http://www.cnblogs.com/tristanguo/archive/2009/04/12/1433462.html