我在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