Controller的职责是把模型数据交给视图呈现。每个Controller中含有多个Action(动作), Url通过路由功能找到相应控制器下的相应的动作。动作返回一个ActionResult 类型的结果。
看一下ActionResult 的结构:
public
abstract
class
ActionResult
{
protected
ActionResult();
public
abstract
void
ExecuteResult(ControllerContext context);
}
最主要的是这个结果带有一个ExecuteResult方法,这个方法用于把ControllerContext和TempData,ViewData 传递到视图上下文中(ViewContext)。
动作返回的结果View()方法返回类型是:ViewResult。它的父类是:ViewResultBase。
它重写了:protected override ViewEngineResult FindView(ControllerContext context);用于寻找aspx文件
ViewResult父类的基类是ActionResult,它有很多个重载。
System.Web.Mvc.ContentResult;
System.Web.Mvc.EmptyResult
System.Web.Mvc.FileResult
System.Web.Mvc.HttpUnauthorizedResult
System.Web.Mvc.JavaScriptResult
System.Web.Mvc.JsonResult
System.Web.Mvc.RedirectResult
System.Web.Mvc.RedirectToRouteResult
System.Web.Mvc.ViewResultBase
下边列出controller中用于得到ActionResult派生类实例的一些方法:
protected
internal
ContentResult Content(
string
content);
protected
internal
FileStreamResult File(Stream fileStream,
string
contentType);
protected
internal
FileContentResult File(
byte
[] fileContents,
string
contentType);
protected
internal
FilePathResult File(
string
fileName,
string
contentType);
protected
internal
JsonResult Json(
object
data);
protected
internal
RedirectToRouteResult RedirectToAction(
string
actionName);
protected
internal
RedirectToRouteResult RedirectToRoute(
string
routeName);
(一)ContentResult
以ContentResult为例来测试一下:
public
ActionResult TextTest()
{
return
Content(
"
文本
"
);
}
在源码中查看,它就是一行文本。现在分析一下这个过程,它是怎样显示在页面上的。
调用Controller的Content(string s)方法,就是调用Content(string,null,null)
protected
internal
virtual
ContentResult Content(
string
content,
string
contentType, Encoding contentEncoding)
{
ContentResult result
=
new
ContentResult();
result.Content
=
content;
result.ContentType
=
contentType;
result.ContentEncoding
=
contentEncoding;
return
result;
}
这里它返回一个ContentResult类型对象,这个对象的Content属性设置为Content("文本")中的“文本”。在动作中的
return
之后,执行ExecuteResult方法:
public
override
void
ExecuteResult(ControllerContext context)
{
if
(context
==
null
)
{
throw
new
ArgumentNullException(
"
context
"
);
}
HttpResponseBase response
=
context.HttpContext.Response;
if
(
!
string
.IsNullOrEmpty(
this
.ContentType))
{
response.ContentType
=
this
.ContentType;
}
if
(
this
.ContentEncoding
!=
null
)
{
response.ContentEncoding
=
this
.ContentEncoding;
}
if
(
this
.Content
!=
null
)
{
response.Write(
this
.Content);
}
}
这个方法与View()方法中的ExecuteResult有区别:
public
override
void
ExecuteResult(ControllerContext context)
{
if
(context
==
null
)
{
throw
new
ArgumentNullException(
"
context
"
);
}
if
(
string
.IsNullOrEmpty(
this
.ViewName))
{
this
.ViewName
=
context.RouteData.GetRequiredString(
"
action
"
);
}
ViewEngineResult result
=
null
;
if
(
this
.View
==
null
)
{
result
=
this
.FindView(context);
this
.View
=
result.View;
}
ViewContext viewContext
=
new
ViewContext(context,
this
.View,
this
.ViewData,
this
.TempData);
this
.View.Render(viewContext, context.HttpContext.Response.Output);
if
(result
!=
null
)
{
Result.ViewEngine.ReleaseView(context,
this
.View);
}
}
从这里来看,ContentResult是直接响应文本,而不生成ViewContext。
(二)JsonResult
再来看一下JsonResult,因为这个会经常用到,所以也说明一下这个。
Controller的protected internal JsonResult Json(object data)方法,最终调用的是:
protected
internal
virtual
JsonResult Json(
object
data,
string
contentType,
Encoding contentEncoding)
{
JsonResult result
=
new
JsonResult();
result.Data
=
data;
result.ContentType
=
contentType;
result.ContentEncoding
=
contentEncoding;
return
result;
}
其中的要json序列化的对象data,被写给了JsonResult的Data属性。
然后,在JsonResult 中的Data属性是这样的:
public
object
Data
{
[CompilerGenerated]
get
{
return
this
.
<
Data
>
k__BackingField;
}
[CompilerGenerated]
set
{
this
.
<
Data
>
k__BackingField
=
value;
}
}
然后执行ExecuteResult方法:
public
override
void
ExecuteResult(ControllerContext context)
{
if
(context
==
null
)
{
throw
new
ArgumentNullException(
"
context
"
);
}
HttpResponseBase response
=
context.HttpContext.Response;
if
(
!
string
.IsNullOrEmpty(
this
.ContentType))
{
response.ContentType
=
this
.ContentType;
}
else
{
response.ContentType
=
"
application/json
"
;
}
if
(
this
.ContentEncoding
!=
null
)
{
response.ContentEncoding
=
this
.ContentEncoding;
}
if
(
this
.Data
!=
null
)
{
JavaScriptSerializer serializer
=
new
JavaScriptSerializer();
response.Write(serializer.Serialize(
this
.Data));
}
}
可以看到当JsonResult的Data属性不为无的时候,被序列化了。用的方法是JavaScriptSerializer 对象的Serialize()方法。这个对象位于:System.Web.Script.Serialization
到这里,也没有生成视图上下文,直接响应为一个Json对象(在浏览器上可以看到是一个Json串,有关Json串与Json对象可以参见我的博客:http://www.cnblogs.com/jams742003/archive/2009/12/29/1634764.html)。
现在测试一下JsonResult。
{"UserName":"宋江","Age":30,"Company":"好汉公司"}
(三)RedirectResult
RedirectResult用于重定向页面。这里也说明一下。
在controller中,用于返回RedirectResult类型的方法是Redirect(string url):
protected
internal
virtual
RedirectResult Redirect(
string
url)
{
if
(
string
.IsNullOrEmpty(url))
{
throw
new
ArgumentException(MvcResources.Common_NullOrEmpty,
"
url
"
);
}
return
new
RedirectResult(url);
}
然后看RedirectResult 类:
通过传递重定向地址的参数的构造器来给Url属性写值,然后执行ExecuteResult方法:
public
override
void
ExecuteResult(ControllerContext context)
{
if
(context
==
null
)
{
throw
new
ArgumentNullException(
"
context
"
);
}
string
url
=
UrlHelper.Content(
this
.Url, context.HttpContext);
context.HttpContext.Response.Redirect(url,
false
);
}
来重定向到目标Url
以示例说明。
public
ActionResult TextTest()
{
return
Redirect(
"
http://www.126.com
"
);
}
(四)RedirectToRouteResult
RedirectToRouteResult是一个很有用的,它用于路由重定向
(1)RedirectToAction方法
protected
internal
RedirectToRouteResult RedirectToAction(
string
actionName,
string
controllerName)
{
return
this
.RedirectToAction(actionName, controllerName, (RouteValueDictionary)
null
);
}
它用于重订向到特定控制器中的动作(动作,应该说是控制器通过动作返回模型到视图)。
它最终要执行的方法是:
protected
internal
virtual
RedirectToRouteResult
RedirectToAction(
string
actionName,
string
controllerName, RouteValueDictionary routeValues)
{
RouteValueDictionary dictionary;
if
(
this
.RouteData
==
null
)
{
dictionary
=
RouteValuesHelpers.MergeRouteValues(actionName,
controllerName,
null
, routeValues,
true
);
}
else
{
dictionary
=
RouteValuesHelpers.MergeRouteValues(actionName,
controllerName,
this
.RouteData.Values, routeValues,
true
);
}
return
new
RedirectToRouteResult(dictionary);
}
如果routeValues为无的话,
if
(
this
.RouteData
==
null
)
{
dictionary
=
RouteValuesHelpers.MergeRouteValues(actionName,
controllerName,
null
, routeValues,
true
);
}
mergeRouteValues方法会根据提供的控制器名和动作名,创建RouteValueDictionary dictionary
然后通过RedirectToRouteResult的构造器来创建一个RedirectToRouteResult对象。然后执行ExecuteResult方法:
public
override
void
ExecuteResult(ControllerContext context)
{
if
(context
==
null
)
{
throw
new
ArgumentNullException(
"
context
"
);
}
string
str
=
UrlHelper.GenerateUrl(
this
.RouteName,
null
,
null
,
this
.RouteValues,
this
.Routes, context.RequestContext,
false
);
if
(
string
.IsNullOrEmpty(str))
{
throw
new
InvalidOperationException(MvcResources.ActionRedirectResult_NoRouteMatched);
}
context.HttpContext.Response.Redirect(str,
false
);
}
重定向到新地址。示例:
public
ActionResult TextTest()
{
return
RedirectToAction(
"
ModelTest
"
,
"
News
"
);
}
(2)RedirectToRoute
这个方法也是要创建RedirectToRouteResult对象,这里不再赘述。
protected
internal
virtual
RedirectToRouteResult RedirectToRoute(
string
routeName,
RouteValueDictionary routeValues)
{
return
new
RedirectToRouteResult(routeName,
RouteValuesHelpers.GetRouteValues(routeValues));
}