Asp.Net MVC<四>:路由器

ASP.NET的路由系統:路由映射css

ASP.NET MVC路由擴展:路由映射html

ASP.NET的路由系統:根據路由規則生成URLweb

ASP.NET MVC 請求流程:Route緩存

http://www.cnblogs.com/zeusro/p/RouteConfig.htmlmvc

路由的核心類型基本定義於System.Web.dll中,路由機制一樣可應用與Web Forms,實現請求地址和物理文件的分離。app

web form中使用路由器的示例

路由配置

protected void Application_Start(object sender, EventArgs e)
{
    var defaults = new RouteValueDictionary { { "name", "*" }, { "id", "*" } };
    //將物理文件路徑映射到一個路由模版上
    RouteTable.Routes.MapPageRoute("", "employees/{name}/{id}","~/default.aspx",true,defaults);
}

頁面

public partial class Default : System.Web.UI.Page
{
    protected string EmployeeId;
    protected string EmployeeName;
    protected void Page_Load(object sender, EventArgs e)
    {
        EmployeeId = this.RouteData.Values["id"] as string;
        EmployeeName = this.RouteData.Values["name"] as string;
    }
}
<form id="form1" runat="server">
<div>
    EmployeeId:<%=EmployeeId %>
    <br/> 
    EmployeeName:<%=EmployeeName %>
</div>
</form>

 

測試

訪問地址:http://localhost:65042/Default.aspxide

訪問地址:http://localhost:65042/employees函數

訪問地址:http://localhost:65042/employees/張飛post

訪問地址:http://localhost:65042/employees/張飛/001測試

訪問地址:http://localhost:65042/employees/張飛/001/sdfs

404報錯

ASP.NET路由註冊

RouteTable.Routes.MapPageRoute(
    routeName               : "myRoute",
    routeUrl                : "dirtest/{name}/{id}",
    physicalFile            : "~/default.aspx",
    checkPhysicalUrlAccess  : true,
    defaults                : new RouteValueDictionary { { "name", "*" }, { "id", "010" } },
    constraints             : new RouteValueDictionary { { "id", @"0\d{2,3}" }, { "httpMethod", new HttpMethodConstraint("GET") } },
    dataTokens              : new RouteValueDictionary { { "city", "hangzhou" } }
);

另外一種註冊方式

Route route = new Route(
    url:"dirtest/{name}/{id}",
    defaults: new RouteValueDictionary { { "name", "*" }, { "id", "010" } },
    constraints: new RouteValueDictionary { { "id", @"0\d{2,3}" }, { "httpMethod", new HttpMethodConstraint("GET") } },
    dataTokens: new RouteValueDictionary { { "city", "hangzhou" } },
    routeHandler:new PageRouteHandler("~/default.aspx",true)
);
RouteTable.Routes.Add("myRoute",route);

直接請求現存的物理文件

借用路由能夠採用一個與路徑無關的URL訪問某個物理文件,但若是就是但願以物理地址的方式訪問對應的物理文件時。

RouteBase定義了一個布爾類型的屬性RouteExistingFiles,表示是否對現有物理文件實施路由。

註冊路由忽略地址

若是設置爲RouteTable.Routes.RouteExistingFiles = true; 路由系統會對全部請求實施路由,但這一樣會帶來一些問題。

例如若是應用運行在集成模式下,則靜態資源的請求也會進入ASP.NET管道,因而針對靜態文件的請求也可能會被重定向。

經過Ignore方法來添加例外,Ignore方法的調用必需放在路由註冊以前。

RouteTable.Routes.RouteExistingFiles = true;
RouteTable.Routes.Ignore("content/{filename}.css/{*pathInfo}");

默認值

defaults 爲路由模版中的兩個變量指定了默認值。

約束

constraints 能夠爲變量指定基於正則的約束,也能夠指定一個RouteConstraint對象。

路由變量

在Route對象的DataTokens屬性中可添加路由變量

根據路由規則生成URL

經過RouteCollection的GetVirtualPath方法。

RequestContext requestContext = new RequestContext();
requestContext.HttpContext = new HttpContextWrapper(HttpContext.Current);
requestContext.RouteData = this.RouteData;
RouteValueDictionary values = new RouteValueDictionary { { "name", "劉備" }, { "id", "013" } };
Response.Write("<br>");
Response.Write(RouteTable.Routes.GetVirtualPath(requestContext, values).VirtualPath);
Response.Write("<br>");
Response.Write(RouteTable.Routes.GetVirtualPath(requestContext, null).VirtualPath);
Response.Write("<br>");
Response.Write(RouteTable.Routes.GetVirtualPath(null, null).VirtualPath);

MVC路由

MapPageRoute方法和Ignore方法的調用能夠完成針對某個物理文件的路由。返回的RouteData中的RouteHander屬性會返回一個PageRouteHandler對象。PageRouteHandler對象最終會建立一個針對映射.aspx文件的Page對象來處理請求。

而MVC爲RouteCollection增長了一系列擴展方法,定義在System.Web.Mvc.RouteCollectionExtensions中。新增了兩組方法 MapRoute和IgnoreRoute

MapRoute方法的幾個重載中都不能直接操做DataTokens,但能夠往DataTokens中添加命名空間列表。當存在多個同名的Controller類型時,在激活Controller類型時會由於沒法肯定Controller的類型而拋出異常。DataTokens中得Namespaces成員用於設置優先級。

MapRoute方法返回的RouteData中的RouteHander屬性會返回一個MvcRouteHandler對象。

UrlParameter.Optional

將變量的默認值設置爲UrlParameter.Optional,則只有請求URL中真正包含具體變量值的狀況下生成的RouteData的Values屬性中才會包含相應的路由變量。

基於Area的路由映射

經過Area能夠從功能上將應用劃分爲幾個較小的單元。每一個Area至關於一個獨立的子系統。它們具備一套包含Models,Views,Controllers在內的目錄結構和配置文件。每一個路由結構通常也會具備各自獨立的路由規則,經過AreaRegistration類型進行註冊。

protected void Application_Start()
{
    //針對全部Area的註冊
    AreaRegistration.RegisterAllAreas();
}

 

RegisterAllAreas方法執行時,全部被當前Web應用直接或間接引用的程序集都會被加載(若是還沒有被加載),ASP.NET MVC會從中找到全部繼承自AreaRegistration的類型,並經過反射建立相應的對象。針對每一個被建立出來的AreaRegistration對象,一個做爲Area註冊上下文的AreaRegistrationContext對象會被建立出來,做爲參數調用AreaRegistration對象的RegisterArea方法對相應的Area的路由進行註冊。
AreaRegistrationContext對象的State屬性的值來自AreaRegistration.RegisterAllAreas方法指定的參數state。

public class adminAreaRegistration : AreaRegistration 
{
    public override string AreaName 
    {
        get 
        {
            return "admin";
        }
    }

    public override void RegisterArea(AreaRegistrationContext context) 
    {
        context.MapRoute(
           name: "admin_default",
           url: "admin/{controller}/{action}/{id}",
           defaults: new { controller = "Home", action = "Index", id = UrlParameter.Optional }
        );
    }
}

  

當存在相同的Controller類型名時,如域Area中也定義了一個Home控制器,則全局路由器會由於重複匹配而報錯。須要對其設置優先匹配的命名空間。

public static void RegisterRoutes(RouteCollection routes)
{
    routes.IgnoreRoute("{resource}.axd/{*pathInfo}");

    routes.MapRoute(
        name: "Default",
        url: "{controller}/{action}/{id}",
        defaults: new { controller = "Home", action = "Index", id = UrlParameter.Optional },
        namespaces: new string[] { "WebApplication1.Controllers.*" }
    );
}

 

AreaRegistration註冊的路由對象

由AreaRegistration註冊的路由對象生成的RouteData的不一樣之處主要表如今DataTokens屬性上,默認多出兩個變量:

  1. area:                           標記Area的名稱
  2. UseNamespaceFallback: 當MapRoute方法顯式地指定了命名空間或者對應的AreaRegistration定義在某個命名空間下,則UseNamespaceFallback爲False,反之則被設置爲True。若是MapRoute方法顯式地指定了命名空間,則AreaRegistration類型所在的命名空間也會被忽略。

MVC中生成URL的快捷方式

MVC則定義了兩個幫助類: HtmlHelper 和UrlHelper,經過調用它們的ActionLink/RouteLink 和Action/RouteUrl方法生成Url。從本質上講,最終依賴於RouteCollection對象的GetVirtualPathData方法。

Action、ActionLink

UrlHelper.Action(……)返回相對地址或絕對地址,HtmlHelper.ActionLink(……) 則不只僅返回一個Url,而是生成一個連接(<a>……</a>)。

調用的是GetVirtualPathData(RequestContext requestContext,RouteValueDictionary values)方法。 也就是使用路由表中第一個匹配的Route對象來生成URL或者連接。

RouteUrl、RouteLink 

UrlHelper.RouteUrl(……)方法和HtmlHelper.RouteLink (……) 方法則能夠針對註冊的某個具體的Route對象來生成URL或者連接。也便是調用GetVirtualPathData(RequestContext requestContext,string name,RouteValueDictionary values)方法。

特性路由

特性路由是對現有路由系統的擴展,提供了一種針對某個具體Controller類型或Action方法的路由註冊方式。從而能夠對路由規則進行細粒度的設計。

特性路由(Attribute Route)就是利用標註在Controller類型或Action方法上的特性來提供路由規則的路由註冊方式

註冊

默認狀況下特性路由功能是關閉的,須要調用RouteCollection的擴展方法MapMvcAttributeRoutes來開啓。

這個方法的調用要放在路由註冊以前。

public static void RegisterRoutes(RouteCollection routes)
{
    routes.IgnoreRoute("{resource}.axd/{*pathInfo}");

    RouteTable.Routes.MapMvcAttributeRoutes();

    routes.MapRoute(
    name: "Default",
    url: "{controller}/{action}/{id}",
    defaults: new { controller = "Home", action = "Index", id = UrlParameter.Optional }
    );
}

 

public class MoviesController : Controller
{
    // GET: Movies
    public ActionResult Index()
    {
        return View();
    }
    [HttpGet]
    [Route("movies/{id}")]
    public ActionResult GetMoviesById(string id)
    {
        ViewBag.id = id;
        return View();
    }
    [HttpGet]
    [Route("movies/starring/{starring}")]
    [Route("movies/starring/{starring}/{genre}")]
    [Route("movies/director/{director}/{genre}")]
    public ActionResult FindMovies(string starring, string director, string genre)
    {
        ViewBag.starring = starring;
        ViewBag.director = director;
        ViewBag.genre = genre;
        return View();
    }
}

  

默認狀況下使用特性類型RouteAttribute,它實現了接口IRouteInfoProvider。

當使用RouteAttribute時,須要提供一個路由模版來對Template這個只讀屬性進行初始化。而若是須要用這個路由特性註冊的路由對象來生成URL,還須要爲它提供一個Name,以即可以從路由表中把它提取出來。

爲特性路由的變量添加約束

路由變量基本都會直接綁定到目標Action方法相應的參數上,因爲這些變量值在請求URL中以字符串的形式體現,因此被綁定參數必需支持源自字符串的類型轉換。

爲了確保參數綁定的正常進行,須要對路由變量在數據類型上進行約束。這些約束能夠直接之內聯的形式定義在路由模版裏。

[HttpGet]
[Route("movies/{id:range(20,50)}")]
public ActionResult GetMoviesById(int id)

對於路由系統來講,約束經過RouteContraint對象來表示,全部RouteContraint類型均實現了IRouteContraint接口。

特性路由的這些之內聯形式定義在路由模版中的約束,它們的約束類型也是實現了IRouteContraint接口。

 

系統提供的約束
約束 描述 用法 類型
bool 類型匹配 (布爾類型) {x:bool} BoolRouteContraint
datetime 類型匹配 (DateTime類型) {x:datetime} DateTimeRouteContraint
decimal 類型匹配 (Decimal類型) {x:decimal} DecimalRouteContraint
double 類型匹配 (Double類型) {x:double} DoubleRouteContraint
float 類型匹配 (Float類型) {x:float} FloatRouteContraint
guid 類型匹配 (Guid類型) {x:guid} GuidRouteContraint
int 類型匹配 (32位整數) {x:int} IntRouteContraint
long 類型匹配 (64位整數) {x:long} LongRouteContraint
alpha 字符組成(必須有拉丁字母組成) {x:alpha} AlphaRouteContraint
regex 字符組成(必須與指定的正則匹配) {x:regex(^\d{3}-\d{3}-\d{4}$)} RegexRouteContraint
max 值範圍(小於或等於指定的最大值) {x:max(20)} MaxRouteContraint
min 值範圍(大於或等於指定的最小值) {x:max(20)} MinRouteContraint
range 值範圍(在指定的最大值和最小值之間) {x:range(20,50)} RangeRouteContraint
maxlength 字符串長度(小於或等於指定的最大長度) {x:maxlength(20)} MaxLengthRouteContraint
minlength 字符串長度(大於或等於指定的最小長度) {x:minlength(20)} MinlengthRouteContraint
length 字符串長度(等於指定的長度或者在指定的範圍內) {x:length(6)} LengthRouteContraint

爲路由變量設置缺省值

1.將對應的參數定義爲可缺省參數,路由模版裏使用「?」

[HttpGet]
[Route("movies/language/{language?}")]
public ActionResult GetMoviesByLanguage(string language = "en")
{
    return View();
}

2.將默認值定義在路由模版中

[HttpGet]
[Route("movies/language/{language=en}")]
public ActionResult GetMoviesByLanguage(string language)
{
    return View();
}

設置模版前綴

使用RoutePrefixAttribute類型的特性,它只有一個只讀屬性Prefix,表示目標Controller全部Action方法共享的URL前綴。這個屬性只能應用在Controller類型上,且只能有一個。

 

[RoutePrefix("movies")]
public class MoviesController : Controller
{
    [HttpGet]
    [Route("{id:range(20,50)}")]
    public ActionResult GetMoviesById(int id)
    {
        ViewBag.id = id;
        return View();
    }
    [HttpGet]
    [Route("starring/{starring}")]
    [Route("starring/{starring}/{genre}")]
    [Route("director/{director}/{genre}")]
    public ActionResult FindMovies(string starring, string director, string genre)
    {
        ViewBag.starring = starring;
        ViewBag.director = director;
        ViewBag.genre = genre;
        return View();
    }

    [HttpGet]
    [Route("~/actors/{criteria}")] //使用「~」爲前綴,屏蔽掉Controller類型上的前綴「movies」
    public ActionResult FindActors(string criteria)
    {
        return View();
    }
}

設置Area名

使用RouteAreaAttribute類型的特性,它由兩個屬性AreaName和AreaPrefix,默認狀況下使用AreaName作模版前綴,若是但願具備一個不一樣於Area名稱的前綴,則要經過設置AreaPrefix屬性來實現。

若是沒有使用字符「~」前綴,特性路由的完整格式爲{AreaPrefix}/{RoutePrefix}/{Template} 或者{AreaName}/{RoutePrefix}/{Template} 。

 

[RouteArea("MoviesArea")]//[RouteArea()]
[RoutePrefix("movies")]
public class MoviesController : Controller
{
    [HttpGet]
    [Route("{id:range(20,50)}")]
    public ActionResult GetMoviesById(int id)
    {
        ViewBag.id = id;
        return View();
    }
    [HttpGet]
    [Route("starring/{starring}")]
    [Route("starring/{starring}/{genre}")]
    [Route("director/{director}/{genre}")]
    public ActionResult FindMovies(string starring, string director, string genre)
    {
        ViewBag.starring = starring;
        ViewBag.director = director;
        ViewBag.genre = genre;
        return View();
    }

    [HttpGet]
    [Route("~/admin/actors/{criteria}")] //使用「~」爲前綴,屏蔽掉Controller類型上的前綴「movies」
    public ActionResult FindActors(string criteria)
    {
        return View();
    }
}

直接應用到Controller上的RouteAttribute

[RouteArea("vedio")]
[RoutePrefix("movies")]
[Route("{action}/{id}", Name = "FindMovies")]
public class MoviesController : Controller
{
    public ActionResult Index(string id)
    {
        throw new NotImplementedException();
    }
}

 

自定義約束

內聯表達式約束的解析

 約束是之內聯表達式的形式定義在路由模版裏的,ASP.NET MVC經過一個實現IInlineConstraintResolver接口的對象來完成約束從字符串表達式到RouteConstraint對象之間的轉換。

 系統提供的這個解析類型是DefaultInlineConstraintResolver。

public class MyInlineConstraintResolver : IInlineConstraintResolver
{
    public IDictionary<string, Type> ConstraintMap { get; private set; }
    public MyInlineConstraintResolver()
    {
        this.ConstraintMap = new Dictionary<string, Type>(StringComparer.OrdinalIgnoreCase);
        this.ConstraintMap.Add("bool", typeof(BoolRouteConstraint));
        this.ConstraintMap.Add("datetime", typeof(DateTimeRouteConstraint));
        this.ConstraintMap.Add("decimal", typeof(DecimalRouteConstraint));
        this.ConstraintMap.Add("double", typeof(DoubleRouteConstraint));
        this.ConstraintMap.Add("float", typeof(FloatRouteConstraint));
        this.ConstraintMap.Add("guid", typeof(GuidRouteConstraint));
        this.ConstraintMap.Add("int", typeof(IntRouteConstraint));
        this.ConstraintMap.Add("long", typeof(LongRouteConstraint));
        this.ConstraintMap.Add("minlength",typeof(MinLengthRouteConstraint));
        this.ConstraintMap.Add("maxlength",typeof(MaxLengthRouteConstraint));
        this.ConstraintMap.Add("length", typeof(LengthRouteConstraint));
        this.ConstraintMap.Add("min", typeof(MinRouteConstraint));
        this.ConstraintMap.Add("max", typeof(MaxRouteConstraint));
        this.ConstraintMap.Add("range", typeof(RangeRouteConstraint));
        this.ConstraintMap.Add("alpha", typeof(AlphaRouteConstraint));
        this.ConstraintMap.Add("regex", typeof(RegexRouteConstraint));
    }

    public IRouteConstraint ResolveConstraint(string inlineConstraint)
    {
        string[] split = inlineConstraint.Split('(');
        string type = split[0];
        string argumentList = split.Length > 1 ? split[1].Trim().TrimEnd(')') : "";
        Type constraintType;
        if (this.ConstraintMap.TryGetValue(type, out constraintType))
        {
            split = string.IsNullOrEmpty(argumentList)? new string[0] : argumentList.Split(',');
            ConstructorInfo[] constructors =(from c in constraintType.GetConstructors()
                 where c.GetParameters().Count() == split.Length
                 select c).ToArray();
            if (constructors.Length != 1)
            {
                throw new InvalidOperationException("找不到與指定參數匹配的構造函數");
            }
            ConstructorInfo constructor = constructors[0];
            ParameterInfo[] parameters = constructor.GetParameters();
            object[] arguments = new object[parameters.Length];
            for (int i = 0; i < parameters.Length; i++)
            {
                arguments[i] = Convert.ChangeType(split[i],parameters[i].ParameterType);
            }
            return (IRouteConstraint)constructor.Invoke(arguments);
        }
        return null;
    }
}
static void Main(string[] args)
{
    string[] inlineConstraints = new string[]{
    "bool","datetime", "decimal","double","float","guid","int",
    "long","alpha", @"regex(^\d{3}-\d{7}$)","max(50)","min(10)","range(10,50)","maxlength(50)","minlength(10)","length(10,50)"};
    MyInlineConstraintResolver constraintResolver = new MyInlineConstraintResolver();
    IDictionary<string, IRouteConstraint> constraints = inlineConstraints.ToDictionary(inlineConstraint => inlineConstraint, inlineConstraint => constraintResolver.ResolveConstraint(inlineConstraint));
    Console.WriteLine("{0,-24}{1}", "Expression", "RouteConstraint");
    foreach (var item in constraints)
    {
        Console.WriteLine("{0,-24}{1}", item.Key,
        item.Value.GetType().Name);
    }

    Console.ReadKey();
}

自定義針對Culture的約束

約束類型的定義

public class CultureRouteConstraint : IRouteConstraint
{
    private static IList<string> allCultures;
    static CultureRouteConstraint()
    {
        allCultures = CultureInfo.GetCultures(CultureTypes.AllCultures).Select(culture => culture.Name).ToList();
    }

    public bool Match(HttpContextBase httpContext, Route route, string parameterName, RouteValueDictionary values, RouteDirection routeDirection)
    {
        object culture;
        if (values.TryGetValue(parameterName, out culture))
        {
            return allCultures.Any(c => string.Compare(c, culture.ToString(),true) == 0);
        }
        return false;
    }
}

應用自定義的約束

public static void RegisterRoutes(RouteCollection routes)
{
    routes.IgnoreRoute("{resource}.axd/{*pathInfo}");

    DefaultInlineConstraintResolver constraintResolver = new DefaultInlineConstraintResolver();
    constraintResolver.ConstraintMap.Add("culture", typeof(CultureRouteConstraint));
    routes.MapMvcAttributeRoutes(constraintResolver);

    //其餘操做
}

使用  

public class ResourcesController : Controller
{
    [Route("resources/{name}/{culture:culture=zh-cn}")]
    public string GetString(string name, string culture)
    {
        CultureInfo currentUICulture = CultureInfo.CurrentUICulture;
        CultureInfo currentCulture = CultureInfo.CurrentCulture;
        try
        {
            Thread.CurrentThread.CurrentCulture = Thread.CurrentThread.CurrentUICulture = new CultureInfo(culture);
            return Resources.ResourceManager.GetString(name.ToLower());
        }
        finally
        {
            Thread.CurrentThread.CurrentUICulture = currentUICulture;
            Thread.CurrentThread.CurrentCulture = currentCulture;
        }
    }
}

特性路由註冊的路由對象

路由對象的建立

特性路由主要涉及3種類型的特性:

  1. 以RouteAttribute爲表明的RouteInfoProvider特性
  2. 設置路由模版前綴的RoutePrefixAttribute特性
  3. 設置所在Area名稱的RouteAreaAttribute特性

針對應用到Controller和Action上的這些特性,ASP.NET MVC的路由系統最終會爲之建立相應的路由對象(VS調試中發現RouteTable細節上有了一些變化,下面的部分描述不對了)。

  1. 特性路由的路由模版通過格式化(拼接前綴、去除約束、默認值、「?」等)後轉換爲路由對象的模版。
  2. 路由模版中的變量約束及[HttpGet] 被解析後添加到路由對象的Contraint屬性表示的約束集合中。
  3. 路由模版中的變量默認值及目標Controller和Action名稱保存到Defaults屬性中。
  4. 若是RouteAttribute是加在Action上的,則DataTokens屬性中具備一個名爲「TargetActionMethod」的成員,它的值表明目標Action方法的MethodInfo對象。
  5. 若是RouteAttribute是加在Controller上的,則DataTokens屬性中具備一個名爲「MS_DirectControllerRoute」的成員,它的值爲描述目標Controller類型的ControllerDescriptor對象。
  6. RouteAreaAttribute特性除了改變最終的路由模版外,還會在DataTokens屬性中額外添加兩個成員:「Namespaces」、「UseNamespaceFallback」。

當咱們調用MapMvcAttributeRoutes方法時,ASP.NET MVC 會提取註冊到當前DependencyResolver上的用於激活目標Controllerde的ControllerFactory,若是沒有沒有對ControllerFactory進行顯式註冊或者顯式註冊的並非一個DefaultControllerFactory對象,它會建立一個DefaultControllerFactory對象。這個DefaultControllerFactory對象會解析出全部合法有效的Controller類型,並對它們實施緩存。ASP.NET MVC 利用它獲得全部合法有效的Controller類型後,針對每一個類型獲得對應的ControllerDescriptor對象(默認經過AsyncControllerActionInvoker對象得到,後者會緩存Controller類型與對應的ControllerDescriptor之間的映射關係以免ControllerDescriptor的頻繁建立)。

在獲得全部Controller類型的ControllerDescriptor對象後,會遍歷描述Action方法的每一個ActionDescriptor對象,並利用它提取應用在對應Action方法上的RouteInfoProvider特性。利用這個RouteInfoProvider特性及所在Controller類型上應用的RoutePrefixAttribute和RouteAreaAttribute特性提供的路由規則建立最終的Route對象。這個對象最終被添加到全局路由表中。

被特性路由標記的Controller、Action在特性路由功能開啓後, 將不能再經過普通路由對象的Url模版來訪問

public class HomeController : Controller
{
    [Route("movies")] //不能再經過home/about訪問
    public ActionResult About()
    {
        return View();
    }
}

Controller的激活和Action方法的選擇

由於路由對象的屬性DataTokens中的成員在路由解析匹配成功時,會直接拷貝到解析生成的RouteData的DataTokens屬性中。

DefaultControllerFactory在激活目標Controller實例前必須先解析出目標Controller的類型。在正常狀況下,它會根據路由解析獲得的Controller名稱來匹配。可是若是它可以從RouteData中提取到描述目標Controller的ControllerDescriptor或者描述目標Action方法的MethodInfo對象,就能夠根據它們直接獲得Controller類型。

ControllerDescriptor內的FindAction方法能夠根據提供的ControllerContext從候選的Action方法中選擇與當前請求匹配度最高的那一個。對於默認使用的ReflectedControllerDescriptor來講,當FindAction方法被執行時,它會先從提供的ControllerContext中提取RouteData對象,若是可以從中獲取描述目標Action方法的MethodInfo對象,返回得ActionDescriptor對象會直接依據此MethodInfo對象來建立。

public interface IControllerFactory
{
    IController CreateController(RequestContext requestContext, string controllerName);

    SessionStateBehavior GetControllerSessionBehavior(RequestContext requestContext, string controllerName);

    void ReleaseController(IController controller);
}


public abstract class ControllerDescriptor : ICustomAttributeProvider, IUniquelyIdentifiable
{
    protected ControllerDescriptor();

    public virtual string ControllerName { get; }

    public abstract Type ControllerType { get; }

    public virtual string UniqueId { get; }

    public abstract ActionDescriptor FindAction(ControllerContext controllerContext, string actionName);

    public abstract ActionDescriptor[] GetCanonicalActions();

    public virtual object[] GetCustomAttributes(bool inherit);

    public virtual object[] GetCustomAttributes(Type attributeType, bool inherit);

    public virtual IEnumerable<FilterAttribute> GetFilterAttributes(bool useCache);

    public virtual bool IsDefined(Type attributeType, bool inherit);
}
public abstract class ActionDescriptor : ICustomAttributeProvider, IUniquelyIdentifiable
{
    protected ActionDescriptor();

    public abstract string ActionName { get; }

    public abstract ControllerDescriptor ControllerDescriptor { get; }

    public virtual string UniqueId { get; }

    public abstract object Execute(ControllerContext controllerContext, IDictionary<string, object> parameters);

    public virtual object[] GetCustomAttributes(bool inherit);

    public virtual object[] GetCustomAttributes(Type attributeType, bool inherit);

    [EditorBrowsable(EditorBrowsableState.Never)]
    [Obsolete("Please call System.Web.Mvc.FilterProviders.Providers.GetFilters() now.", true)]
    public virtual FilterInfo GetFilters();

    public abstract ParameterDescriptor[] GetParameters();

    public virtual ICollection<ActionSelector> GetSelectors();

    public virtual bool IsDefined(Type attributeType, bool inherit);
}
相關文章
相關標籤/搜索