超碰91资源站-超碰97豆花-超碰97人妻-超碰97人人干-超碰97人人香蕉-超碰97天天操-超碰97在线资源站-超碰97资源站共享-超碰97资源站总站-超碰aa在线91-超碰av操-超碰爱爱

半岛外围网上直营

ASP.NET MVC Preview生命周期分析

轉帖|其它|編輯:郝浩|2008-07-17 10:13:50.000|閱讀 1306 次

概述:ASP.NET MVC Preview生命周期分析

# 界面/圖表報表/文檔/IDE等千款熱門軟控件火熱銷售中 >>

  做ASP.NET WebForm開發都知道,ASP.NET有復雜的生命周期,學習ASP.NET MVC就要深入理解它的生命周期。今天從CodePlex上下載了ASP.NET Preview 2 的源代碼,還有兩個程序集Routing與Abstractions并未發布,不過這兩個程序集的類并不多,可以用NET反編譯工具 Reflector解開來看看,可惜這兩個程序集用的是VS2008使用.net 3.5開發的,用了c# 3.0的很多特性,Reflector反編譯不完全。

  ASP.NET MVC通過HttpModule(UrlRoutingModule)開始他的執行流程

<httpModules>
     <add name="UrlRoutingModule" type="System.Web.Routing.UrlRoutingModule, System.Web.Routing" />
</httpModules>
代碼如下:

namespace System.Web.Routing
{
    using System;
    using System.Globalization;
    using System.Runtime.CompilerServices;
    using System.Security.Permissions;
    using System.Web;
    using System.Web.Resources;

    [AspNetHostingPermission(SecurityAction.InheritanceDemand, Level=AspNetHostingPermissionLevel.Minimal), AspNetHostingPermission(SecurityAction.LinkDemand, Level=AspNetHostingPermissionLevel.Minimal)]
    public class UrlRoutingModule : IHttpModule
    {
        private static readonly object _requestDataKey = new object();
         private System.Web.Routing.RouteCollection _routeCollection;

        protected virtual void Dispose()
        {
        }

        protected virtual void Init(HttpApplication application)
        {
            application.PostResolveRequestCache += new EventHandler(this.OnApplicationPostResolveRequestCache);
            application.PostMapRequestHandler += new EventHandler(this.OnApplicationPostMapRequestHandler);
        }

        private void OnApplicationPostMapRequestHandler(object sender, EventArgs e)
        {
            HttpContextBase context = new HttpContextWrapper2(((HttpApplication) sender).Context);
            this.PostMapRequestHandler(context);
        }

        private void OnApplicationPostResolveRequestCache(object sender, EventArgs e)
        {
            HttpContextBase context = new HttpContextWrapper2(((HttpApplication) sender).Context);
            this.PostResolveRequestCache(context);
        }

        public virtual void PostMapRequestHandler(HttpContextBase context)
        {
            RequestData data = (RequestData) context.Items[_requestDataKey];
            if (data != null)
            {
                context.RewritePath(data.OriginalPath);
                context.Handler = data.HttpHandler;
            }
        }

        public virtual void PostResolveRequestCache(HttpContextBase context)
        {
            RouteData routeData = this.RouteCollection.GetRouteData(context);
            if (routeData != null)
            {
                IRouteHandler routeHandler = routeData.RouteHandler;
                if (routeHandler == null)
                {
                    throw new InvalidOperationException(string.Format(CultureInfo.CurrentUICulture, RoutingResources.UrlRoutingModule_NoRouteHandler, new object[0]));
                }
                RequestContext requestContext = new RequestContext(context, routeData);
                IHttpHandler httpHandler = routeHandler.GetHttpHandler(requestContext);
                if (httpHandler == null)
                {
                    throw new InvalidOperationException(string.Format(CultureInfo.CurrentUICulture, RoutingResources.UrlRoutingModule_NoHttpHandler, new object[] { routeHandler.GetType() }));
                }
                RequestData data2 = new RequestData();
                data2.OriginalPath = context.Request.Path;
                data2.HttpHandler = httpHandler;
                context.Items[_requestDataKey] = data2;
                context.RewritePath("~/UrlRouting.axd");
            }
        }

        void IHttpModule.Dispose()
        {
            this.Dispose();
        }

        void IHttpModule.Init(HttpApplication application)
        {
            this.Init(application);
        }

        public System.Web.Routing.RouteCollection RouteCollection
        {
            get
            {
                if (this._routeCollection == null)
                {
                    this._routeCollection = RouteTable.Routes;
                }
                return this._routeCollection;
            }
            set
            {
                this._routeCollection = value;
            }
        }

 }

  里面還定義了一個RequestData,主要就是當前處理的HttpHandler和URL原始路徑。來看看ASP.NET 的HttpApplication 管線會依次處理下面的請求:

  1. 對請求進行驗證,將檢查瀏覽器發送的信息,并確定其是否包含潛在惡意標記。
  2. 如果已在 Web.config 文件的 UrlMappingsSection 節中配置了任何 URL,則執行 URL 映射。
  3. 引發 BeginRequest 事件。
  4. 引發 AuthenticateRequest 事件。
  5. 引發 PostAuthenticateRequest 事件。
  6. 引發 AuthorizeRequest 事件。
  7. 引發 PostAuthorizeRequest 事件。
  8. 引發 ResolveRequestCache 事件。
  9. 引發 PostResolveRequestCache 事件。
  10. 根據所請求資源的文件擴展名(在應用程序的配置文件中映射),選擇實現 IHttpHandler 的類,對請求進行處理。如果該請求針對從 Page 類派生的對象(頁),并且需要對該頁進行編譯,則 ASP.NET 會在創建該頁的實例之前對其進行編譯。
  11. 引發 PostMapRequestHandler 事件。
  12. 引發 AcquireRequestState 事件。
  13. 引發 PostAcquireRequestState 事件。
  14. 引發 PreRequestHandlerExecute 事件。
  15. 為該請求調用合適的 IHttpHandler 類的 ProcessRequest 方法(或異步版 BeginProcessRequest)。例如,如果該請求針對某頁,則當前的頁實例將處理該請求。
  16. 引發 PostRequestHandlerExecute 事件。
  17. 引發 ReleaseRequestState 事件。
  18. 引發 PostReleaseRequestState 事件。
  19. 如果定義了 Filter 屬性,則執行響應篩選。
  20. 引發 UpdateRequestCache 事件。
  21. 引發 PostUpdateRequestCache 事件。
  22. 引發 EndRequest 事件。

  上述UrlRoutingModule訂閱了兩個 HttpApplication 事件,PostResolveRequestCache 要比 PostMapRequestHandler 更早執行,先看PostResolveRequestCache 事件,他首先從首先從 RouteCollection 中獲取一個 RouteData 對象??纯碦outeCollection 屬性:

    public System.Web.Routing.RouteCollection RouteCollection
        {
            get
            {
                if (this._routeCollection == null)
                {
                    this._routeCollection = RouteTable.Routes;
                }
                return this._routeCollection;
            }
            set
            {
                this._routeCollection = value;
            }
        }

  看到了來自RouteTable,這不正是在Global.asax.cs 中添加的 Route 集合:


  protected void Application_Start(object sender, EventArgs e)
       {
           RegisterRoutes(RouteTable.Routes);
           CreateDefaultUserIfNotExists();
       }

       public static void RegisterRoutes(RouteCollection routes)
       {
            int iisVersion = Convert.ToInt32(ConfigurationManager.AppSettings["IISVersion"], System.Globalization.CultureInfo.InvariantCulture);

           if (iisVersion >= 7)
           {
               RegisterRoutesForNewIIS(routes);
           }
           else
           {
               RegisterRoutesForOldIIS(routes);
           }
       }

      private static void RegisterRoutesForNewIIS(ICollection<RouteBase> routes)
       {
           routes.Add(new Route("User/Login", new RouteValueDictionary(new { controller = "User", action = "Login" }), new MvcRouteHandler()));
           routes.Add(new Route("User/Logout", new RouteValueDictionary(new { controller = "User", action = "Logout" }), new MvcRouteHandler()));
           routes.Add(new Route("User/Signup", new RouteValueDictionary(new { controller = "User", action = "Signup" }), new MvcRouteHandler()));
            routes.Add(new Route("User/SendPassword", new RouteValueDictionary(new { controller = "User", action = "SendPassword" }), new MvcRouteHandler()));

           routes.Add(new Route("Story/Detail/{id}", new RouteValueDictionary(new { controller = "Story", action = "Detail" }), new MvcRouteHandler()));
           routes.Add(new Route("Story/Upcoming/{page}", new RouteValueDictionary(new { controller = "Story", action = "Upcoming" }), new MvcRouteHandler()));
            routes.Add(new Route("Story/Search/{q}/{page}", new RouteValueDictionary(new { controller = "Story", action = "Search" }), new MvcRouteHandler()));

           var defaults = new RouteValueDictionary (
                                                       new
                                                       {
                                                           controller = "Story",
                                                           action = "Category",
                                                           name = (string)null,
                                                           page = (int?)null
                                                       }
                                                    );

           routes.Add(new Route("Story/Category/{page}", defaults, new MvcRouteHandler()));
           routes.Add(new Route("Story/{action}/{name}/{page}", defaults, new MvcRouteHandler()));
           routes.Add(new Route("{controller}/{action}/{id}", defaults, new MvcRouteHandler()));
           routes.Add(new Route("Default.aspx", defaults, new MvcRouteHandler()));
       }

       private static void RegisterRoutesForOldIIS(ICollection<RouteBase> routes)
       {
           routes.Add(new Route("User.mvc/Login", new RouteValueDictionary(new { controller = "User", action = "Login" }), new MvcRouteHandler()));
           routes.Add(new Route("User.mvc/Logout", new RouteValueDictionary(new { controller = "User", action = "Logout" }), new MvcRouteHandler()));
           routes.Add(new Route("User.mvc/Signup", new RouteValueDictionary(new { controller = "User", action = "Signup" }), new MvcRouteHandler()));
            routes.Add(new Route("User.mvc/SendPassword", new RouteValueDictionary(new { controller = "User", action = "SendPassword" }), new MvcRouteHandler()));

           routes.Add(new Route("Story.mvc/Detail/{id}", new RouteValueDictionary(new { controller = "Story", action = "Detail" }), new MvcRouteHandler()));
           routes.Add(new Route("Story.mvc/Upcoming/{page}", new RouteValueDictionary(new { controller = "Story", action = "Upcoming" }), new MvcRouteHandler()));
            routes.Add(new Route("Story.mvc/Search/{q}/{page}", new RouteValueDictionary(new { controller = "Story", action = "Search" }), new MvcRouteHandler()));

           var defaults = new RouteValueDictionary(
                                                       new
                                                       {
                                                           controller = "Story",
                                                           action = "Category",
                                                           name = (string)null,
                                                           page = (int?)null
                                                       }
                                                    );

           routes.Add(new Route("Story.mvc/Category/{page}", defaults, new MvcRouteHandler()));
           routes.Add(new Route("Story.mvc/{action}/{name}/{page}", defaults, new MvcRouteHandler()));
           routes.Add(new Route("{controller}.mvc/{action}/{id}", defaults, new MvcRouteHandler()));
           routes.Add(new Route("Default.aspx", defaults, new MvcRouteHandler()));
       }

  上述代碼來自[翻譯]使用asp.net mvc再造一個digg 第一部分的kigg。回到上文,在獲取 RoteCollection 之后,通過調用 GetRouteData(context) 返回一個 RouteData 對象,該對象內部包含了我們注冊 Route 時的相關設置,包括下面所需要的 MvcRouteHandler。接下來,該方法將 routeData 和上下文一起打包成 RequestContext,這就是為相關處理準備的上下文環境。通過調用 IRouteHandler.GetHttpHandler() 方法,終于到達流程的關鍵IHttpHandler(MvcHandler)。在WebForm中我們知道每一個頁面都是一個HttpHandler,Asp.net mvc也不例外。

先來看看MvcRouteHandler:

namespace System.Web.Mvc {
    using System.Web.Routing;

    [AspNetHostingPermission(System.Security.Permissions.SecurityAction.LinkDemand, Level = AspNetHostingPermissionLevel.Minimal)]
    [AspNetHostingPermission(System.Security.Permissions.SecurityAction.InheritanceDemand, Level = AspNetHostingPermissionLevel.Minimal)]
    public class MvcRouteHandler : IRouteHandler {
        protected virtual IHttpHandler GetHttpHandler(RequestContext requestContext) {
            return new MvcHandler(requestContext);
        }

        IRouteHandler Members#region IRouteHandler Members
        IHttpHandler IRouteHandler.GetHttpHandler(RequestContext requestContext) {
            return GetHttpHandler(requestContext);
        }
        #endregion
    }
}
這里得到了MvcHandler:

namespace System.Web.Mvc {
    using System.Globalization;
    using System.Web.Mvc.Resources;
    using System.Web.Routing;
     using System.Web.SessionState;

    [AspNetHostingPermission(System.Security.Permissions.SecurityAction.LinkDemand, Level = AspNetHostingPermissionLevel.Minimal)]
    [AspNetHostingPermission(System.Security.Permissions.SecurityAction.InheritanceDemand, Level = AspNetHostingPermissionLevel.Minimal)]
    public class MvcHandler : IHttpHandler, IRequiresSessionState {
         private ControllerBuilder _controllerBuilder;

        public MvcHandler(RequestContext requestContext) {
            if (requestContext == null) {
                throw new ArgumentNullException("requestContext");
            }
            RequestContext = requestContext;
        }

        protected virtual bool IsReusable {
            get {
                // REVIEW: What's this?
                return false;
            }
        }

        internal ControllerBuilder ControllerBuilder {
            get {
                if (_controllerBuilder == null) {
                    _controllerBuilder = ControllerBuilder.Current;
                }
                return _controllerBuilder;
            }
            set {
                _controllerBuilder = value;
            }
        }

        public RequestContext RequestContext {
            get;
            private set;
        }

        protected virtual void ProcessRequest(HttpContext httpContext) {
            HttpContextBase iHttpContext = new HttpContextWrapper2(httpContext);
            ProcessRequest(iHttpContext);
        }

        protected internal virtual void ProcessRequest(HttpContextBase httpContext) {
            // Get the controller type
             string controllerName = RequestContext.RouteData.GetRequiredString("controller");

            // Instantiate the controller and call Execute
            IControllerFactory factory = ControllerBuilder.GetControllerFactory();
            IController controller = factory.CreateController(RequestContext, controllerName);
            if (controller == null) {
                throw new InvalidOperationException(
                    String.Format(
                        CultureInfo.CurrentUICulture,
                        MvcResources.ControllerBuilder_FactoryReturnedNull,
                        factory.GetType(),
                        controllerName));
            }
            try {
                ControllerContext controllerContext = new ControllerContext(RequestContext, controller);
                controller.Execute(controllerContext);
            }
            finally {
                factory.DisposeController(controller);
            }
        }

        IHttpHandler Members#region IHttpHandler Members
        bool IHttpHandler.IsReusable {
            get {
                return IsReusable;
            }
        }

        void IHttpHandler.ProcessRequest(HttpContext httpContext) {
            ProcessRequest(httpContext);
        }
        #endregion
    }
}到了這一步,MVC 框架已經準備好了相應的執行場景,接下來就是修改默認(指WebForm)的執行流程了。              RequestData data2 = new RequestData();
                data2.OriginalPath = context.Request.Path;
                data2.HttpHandler = httpHandler;
                context.Items[_requestDataKey] = data2;
                 context.RewritePath("~/UrlRouting.axd");

  OnApplicationPostMapRequestHandler 被執行。在 PostMapRequestHandler 中,它提取了前面預先準備好的上下文,并修改了 HttpContext.Handler,使得 MvcHandler 接管默認的WebForm的HttpHandler,才是執行ASP.NET MVC的流程?,F在來繼續看MvcHandler。

  首先從 RouteData 中提取 Controller 的名字(這個名字是我們在 Global.asax.cs RegisterRoutes 中注冊 Route 時提供的),然后獲取 ControllerFactory,只不過這里面專門提供了一個 ControllerBuilder。

internal ControllerBuilder ControllerBuilder {
            get {
                if (_controllerBuilder == null) {
                    _controllerBuilder = ControllerBuilder.Current;
                }
                return _controllerBuilder;
            }
            set {
                _controllerBuilder = value;
            }
        }
   如果我們自定義MvcHandler,則需要好好的看看ControllerBuilder.Current:

namespace System.Web.Mvc {
    using System;
    using System.Diagnostics.CodeAnalysis;
    using System.Globalization;
    using System.Web;
     using System.Web.Mvc.Resources;

    [AspNetHostingPermission(System.Security.Permissions.SecurityAction.LinkDemand, Level = AspNetHostingPermissionLevel.Minimal)]
    [AspNetHostingPermission(System.Security.Permissions.SecurityAction.InheritanceDemand, Level = AspNetHostingPermissionLevel.Minimal)]
    public class ControllerBuilder {
        private static ControllerBuilder _instance = new ControllerBuilder();
         private Func<IControllerFactory> _factoryThunk;

        public ControllerBuilder() {
            SetControllerFactory(new DefaultControllerFactory());
        }

        public static ControllerBuilder Current {
            get {
                return _instance;
            }
        }

        [SuppressMessage("Microsoft.Design", "CA1024:UsePropertiesWhereAppropriate",
            Justification = "Calling method multiple times might return different objects.")]
        public IControllerFactory GetControllerFactory() {
            IControllerFactory controllerFactoryInstance = _factoryThunk();
            return controllerFactoryInstance;
        }

        public void SetControllerFactory(IControllerFactory controllerFactory) {
            if (controllerFactory == null) {
                throw new ArgumentNullException("controllerFactory");
             }

            _factoryThunk = () => controllerFactory;
        }

        public void SetControllerFactory(Type controllerFactoryType) {
            if (controllerFactoryType == null) {
                throw new ArgumentNullException("controllerFactoryType");
            }
            if (!typeof(IControllerFactory).IsAssignableFrom(controllerFactoryType)) {
                throw new ArgumentException(
                    String.Format(
                        CultureInfo.CurrentUICulture,
                        MvcResources.ControllerBuilder_MissingIControllerFactory,
                        controllerFactoryType),
                    "controllerFactoryType");
             }

            _factoryThunk = delegate() {
                try {
                    return (IControllerFactory) Activator.CreateInstance(controllerFactoryType);
                }
                catch (Exception ex) {
                    throw new InvalidOperationException(
                        String.Format(
                            CultureInfo.CurrentUICulture,
                            MvcResources.ControllerBuilder_ErrorCreatingControllerFactory,
                            controllerFactoryType),
                        ex);
                }
            };
        }
    }
}
(1) 通常情況下,返回一個默認的 DefaultControllerFactory 實例。
(2) 我們可以在 Application_Start 中通過 ControllerBuilder.Current.SetControllerFactory 方法來注冊一個我們自定義的工廠。
 (3) 核心代碼: factory = (IControllerFactory)Activator.CreateInstance(controllerFactoryType),通過反射創建IControllerFactory;

  回到MvcHandler的 ProcessRequest ,DefaultControllerFactory.CreateController(RequestContext, requiredString) 來返回 IController 實例。下面看看DefaultControllerFactory的代碼:

  通過反射來創建 Controller 實例,GetControllerType 里面做了些緩存處理,以此來避免頻繁使用反射造成的性能問題。繼續
 MvcHandler.ProcessRequest(),在得到控制器實例后,MvcHandler 開始了調用 Controller.Execute() 來進一步后續操作,同時對其上下文進一步封裝,除了前面創建的 RequestContext,還加上了當前這個 Controller 對象的引用,類名叫ControllerContext。

 namespace System.Web.Mvc {
    using System.Web.Routing;

    [AspNetHostingPermission(System.Security.Permissions.SecurityAction.LinkDemand, Level = AspNetHostingPermissionLevel.Minimal)]
    [AspNetHostingPermission(System.Security.Permissions.SecurityAction.InheritanceDemand, Level = AspNetHostingPermissionLevel.Minimal)]
    public class ControllerContext : RequestContext {
        public ControllerContext(HttpContextBase httpContext, RouteData routeData, IController controller)
            : base(httpContext, routeData) {
            if (controller == null) {
                throw new ArgumentNullException("controller");
            }
            Controller = controller;
        }

        public ControllerContext(RequestContext requestContext, IController controller)
            : this(GetRequestContext(requestContext).HttpContext, GetRequestContext(requestContext).RouteData, controller) {
        }

        public IController Controller {
            get;
            private set;
        }

        internal static RequestContext GetRequestContext(RequestContext requestContext) {
            if (requestContext == null) {
                throw new ArgumentNullException("requestContext");
            }
            return requestContext;
        }
    }
}
繼續看IController的默認實現類Controller:

 namespace System.Web.Mvc {
    using System;
    using System.Collections.Generic;
    using System.ComponentModel;
    using System.Diagnostics.CodeAnalysis;
    using System.Globalization;
    using System.Reflection;
    using System.Security.Principal;
    using System.Web;
    using System.Web.Mvc.Resources;
    using System.Web.Routing;

    [AspNetHostingPermission(System.Security.Permissions.SecurityAction.LinkDemand, Level = AspNetHostingPermissionLevel.Minimal)]
    [AspNetHostingPermission(System.Security.Permissions.SecurityAction.InheritanceDemand, Level = AspNetHostingPermissionLevel.Minimal)]
    public class Controller : IController {
        private RouteCollection _routeCollection;
        private IDictionary<string, object> _viewData;
         private IViewEngine _viewEngine;

        public ControllerContext ControllerContext {
            get;
            set;
        }

        public HttpContextBase HttpContext {
            get {
                return ControllerContext == null ? null : ControllerContext.HttpContext;
            }
        }

        public HttpRequestBase Request {
            get {
                return HttpContext == null ? null : HttpContext.Request;
            }
        }

        public HttpResponseBase Response {
            get {
                return HttpContext == null ? null : HttpContext.Response;
            }
        }

        internal RouteCollection RouteCollection {
            get {
                if (_routeCollection == null) {
                    _routeCollection = RouteTable.Routes;
                }
                return _routeCollection;
            }
            set {
                _routeCollection = value;
            }
        }

        public RouteData RouteData {
            get {
                return ControllerContext == null ? null : ControllerContext.RouteData;
            }
        }

        public HttpServerUtilityBase Server {
            get {
                return HttpContext == null ? null : HttpContext.Server;
            }
        }

        [System.Diagnostics.CodeAnalysis.SuppressMessage("Microsoft.Usage", "CA2227:CollectionPropertiesShouldBeReadOnly",
            Justification = "This property is settable so that unit tests can provide mock implementations.")]
        public TempDataDictionary TempData {
            get;
            set;
        }

        public IPrincipal User {
            get {
                return HttpContext == null ? null : HttpContext.User;
            }
        }

        public IDictionary<string, object> ViewData {
            get {
                if (_viewData == null) {
                    _viewData = new Dictionary<string, object>();
                }
                return _viewData;
            }
        }

        public IViewEngine ViewEngine {
            get {
                return _viewEngine ?? new WebFormViewEngine();
            }
            set {
                if (value == null) {
                    throw new ArgumentNullException("value");
                }
                _viewEngine = value;
            }
        }

        private static object ConvertParameterType(object value, Type destinationType, string parameterName, string actionName) {
            if (value == null || value.GetType() == destinationType) {
                return value;
             }

            TypeConverter converter = TypeDescriptor.GetConverter(destinationType);
            bool canConvertFrom = converter.CanConvertFrom(value.GetType());
            if (!canConvertFrom) {
                converter = TypeDescriptor.GetConverter(value.GetType());
            }
            if (!(canConvertFrom || converter.CanConvertTo(destinationType))) {
                throw new InvalidOperationException(String.Format(
                    CultureInfo.CurrentUICulture,
                    MvcResources.Controller_CannotConvertParameter,
                    parameterName, actionName, value, destinationType));
            }
            try {
                return canConvertFrom ? converter.ConvertFrom(value) : converter.ConvertTo(value, destinationType);
            }
            catch (Exception ex) {
                throw new InvalidOperationException(String.Format(
                    CultureInfo.CurrentUICulture,
                    MvcResources.Controller_CannotConvertParameter,
                    parameterName, actionName, value, destinationType),
                    ex);
            }
        }

        protected internal virtual void Execute(ControllerContext controllerContext) {
            if (controllerContext == null) {
                throw new ArgumentNullException("controllerContext");
             }

            ControllerContext = controllerContext;
             TempData = new TempDataDictionary(controllerContext.HttpContext);

            string actionName = RouteData.GetRequiredString("action");
            if (!InvokeAction(actionName)) {
                HandleUnknownAction(actionName);
            }
        }

        protected internal virtual void HandleUnknownAction(string actionName) {
            throw new InvalidOperationException(String.Format(CultureInfo.CurrentUICulture, MvcResources.Controller_UnknownAction, actionName));
        }

        protected internal bool InvokeAction(string actionName) {
            return InvokeAction(actionName, new RouteValueDictionary());
        }

        protected internal virtual bool InvokeAction(string actionName, RouteValueDictionary values) {
            if (String.IsNullOrEmpty(actionName)) {
                throw new ArgumentException(MvcResources.Common_NullOrEmpty, "actionName");
             }

            // We have to loop through all the methods to make sure there isn't
            // a conflict. If we stop the loop the first time we find a match
             // we might miss some error cases.

            MemberInfo[] membInfos = GetType().GetMember(actionName, MemberTypes.Method,
                BindingFlags.IgnoreCase | BindingFlags.InvokeMethod | BindingFlags.Instance | BindingFlags.Public);
             MethodInfo foundMatch = null;

            foreach (MemberInfo memberInfo in membInfos) {
                 MethodInfo mi = (MethodInfo)memberInfo;

                // 1) Action methods must not have the non-action attribute in their inheritance chain, and
                // 2) special methods like constructors, property accessors, and event accessors cannot be action methods, and
                // 3) methods originally defined on Object (like ToString) or Controller cannot be action methods.
                if (!mi.IsDefined(typeof(NonActionAttribute), true) &&
                    !mi.IsSpecialName &&
                    mi.DeclaringType.IsSubclassOf(typeof(Controller))) {
                    if (foundMatch != null) {
                        throw new InvalidOperationException(
                            String.Format(CultureInfo.CurrentUICulture, MvcResources.Controller_MoreThanOneAction, actionName, GetType()));
                    }
                    foundMatch = mi;
                }
             }

            if (foundMatch != null) {
                InvokeActionMethod(foundMatch, values);
                return true;
            }
            return false;
        }

        [SuppressMessage("Microsoft.Design", "CA1011:ConsiderPassingBaseTypesAsParameters",
            Justification = "We use MethodInfo since it represents only methods and not constructors." +
            "This method only makes sense for use with methods.")]
        protected internal virtual void InvokeActionMethod(MethodInfo methodInfo, RouteValueDictionary values) {
            if (methodInfo == null) {
                throw new ArgumentNullException("methodInfo");
            }
            if (values == null) {
                values = new RouteValueDictionary();
            }
            if (methodInfo.ContainsGenericParameters) {
                throw new InvalidOperationException(String.Format(CultureInfo.CurrentUICulture, MvcResources.Controller_ActionCannotBeGeneric, methodInfo.Name));
             }

            ParameterInfo[] methodParameters = methodInfo.GetParameters();
            object[] parameterValues = null;
             if (methodParameters.Length > 0) {

                parameterValues = new object[methodParameters.Length];
                for (int i = 0; i < methodParameters.Length; i++) {
                     ParameterInfo pi = methodParameters[i];

                    if (pi.IsOut || pi.ParameterType.IsByRef) {
                        throw new InvalidOperationException(String.Format(CultureInfo.CurrentUICulture, MvcResources.Controller_ReferenceParametersNotSupported, pi.Name, methodInfo.Name));
                     }

                    bool valueRequired = true;
                    if (pi.ParameterType.IsClass) {
                        // Classes (ref types) don't require values since we can pass in null
                        valueRequired = false;
                    }
                    else {
                        if ((pi.ParameterType.IsGenericType && !pi.ParameterType.IsGenericTypeDefinition) &&
                            (pi.ParameterType.GetGenericTypeDefinition() == typeof(Nullable<>))) {
                            // Nullable types don't require values since we can pass in null
                            valueRequired = false;
                        }
                     }

                    // Try to get a value for the parameter. We use this order of precedence:
                    // 1. Explicitly-provided extra parameters in the call to InvokeAction()
                    // 2. Values from the RouteData (could be from the typed-in URL or from the route's default values)
                    // 3. Request values (query string, form post data, cookie)
                    object parameterValue = null;
                    if (!values.TryGetValue(methodParameters[i].Name, out parameterValue)) {
                        if (RouteData == null || !RouteData.Values.TryGetValue(methodParameters[i].Name, out parameterValue)) {
                            if (Request != null) {
                                parameterValue = Request[methodParameters[i].Name];
                            }
                        }
                     }

                    if (parameterValue == null && valueRequired) {
                        throw new InvalidOperationException(String.Format(CultureInfo.CurrentUICulture, MvcResources.Controller_MissingParameter, pi.Name, methodInfo.Name));
                     }

                    try {
                        parameterValues[i] = ConvertParameterType(parameterValue, methodParameters[i].ParameterType, methodParameters[i].Name, methodInfo.Name);
                    }
                    catch (Exception ex) {
                        // Parameter value conversion errors are acceptable unless the value is required
                        if (valueRequired) {
                            throw new InvalidOperationException(String.Format(CultureInfo.CurrentUICulture, MvcResources.Controller_MissingParameter, pi.Name, methodInfo.Name), ex);
                        }
                    }
                }
             }

            InvokeActionMethodFilters(methodInfo, () => methodInfo.Invoke(this, parameterValues));
        }

        private void InvokeActionMethodFilters(MethodInfo methodInfo, Action continuation) {

            // filters should execute in this order:
            // controller virtual overrides -> controller base attributes -> controller type attributes ->
             //   base action method attributes -> action method attributes

            List<ActionFilterAttribute> filters = new List<ActionFilterAttribute>() {
                new ControllerActionFilter(this)
             };

            Stack<MemberInfo> memberChain = new Stack<MemberInfo>();
            Type curType = GetType();
            while (curType != null) {
                memberChain.Push(curType);
                curType = curType.BaseType;
             }

            List<ActionFilterAttribute> sortedClassFilters = SortActionFilters(memberChain);
            filters.AddRange(sortedClassFilters);
            List<ActionFilterAttribute> sortedMethodFilters = PrepareMethodActionFilters(methodInfo);
             filters.AddRange(sortedMethodFilters);

            FilterContext context = new FilterContext(ControllerContext, methodInfo);
            ActionFilterExecutor executor = new ActionFilterExecutor(filters, context, continuation);
            executor.Execute();
        }

        protected virtual void OnActionExecuted(FilterExecutedContext filterContext) {
        }

        protected virtual void OnActionExecuting(FilterExecutingContext filterContext) {
        }

        internal static List<ActionFilterAttribute> PrepareMethodActionFilters(MethodInfo methodInfo) {

            Stack<MemberInfo> memberChain = new Stack<MemberInfo>();
             memberChain.Push(methodInfo);

            MethodInfo baseMethod = methodInfo.GetBaseDefinition();
            Type curType = methodInfo.DeclaringType.BaseType;
            while (true) {
                MemberInfo[] membInfos = curType.GetMember(methodInfo.Name, MemberTypes.Method,
                    BindingFlags.IgnoreCase | BindingFlags.InvokeMethod | BindingFlags.Instance | BindingFlags.Public);
                MethodInfo foundMatch = null;
                foreach (MemberInfo memberInfo in membInfos) {
                    MethodInfo mi = (MethodInfo)memberInfo;
                    if (mi.GetBaseDefinition() == baseMethod && mi.DeclaringType == curType) {
                        foundMatch = mi;
                        break;
                    }
                }
                if (foundMatch == null) {
                    break;
                }
                memberChain.Push(foundMatch);
                curType = curType.BaseType;
             }

            return SortActionFilters(memberChain);
        }

        protected virtual void RedirectToAction(RouteValueDictionary values) {
            VirtualPathData vpd = RouteCollection.GetVirtualPath(ControllerContext, values);
            string target = null;
            if (vpd != null) {
                target = vpd.VirtualPath;
            }
            HttpContext.Response.Redirect(target);
        }

        protected void RedirectToAction(string actionName) {
            if (String.IsNullOrEmpty(actionName)) {
                throw new ArgumentException(MvcResources.Common_NullOrEmpty, "actionName");
            }
            RouteValueDictionary valuesDictionary = new RouteValueDictionary();
            valuesDictionary.Add("action", actionName);
            RedirectToAction(valuesDictionary);
        }

        protected void RedirectToAction(string actionName, string controllerName) {
            if (String.IsNullOrEmpty(actionName)) {
                throw new ArgumentException(MvcResources.Common_NullOrEmpty, "actionName");
            }
            if (String.IsNullOrEmpty(controllerName)) {
                throw new ArgumentException(MvcResources.Common_NullOrEmpty, "controllerName");
            }
            RouteValueDictionary valuesDictionary = new RouteValueDictionary();
            valuesDictionary.Add("action", actionName);
            valuesDictionary.Add("controller", controllerName);
            RedirectToAction(valuesDictionary);
        }

        protected void RenderView(string viewName) {
            RenderView(viewName, String.Empty, ViewData);
        }

        protected void RenderView(string viewName, string masterName) {
            RenderView(viewName, masterName, ViewData);
        }

        protected void RenderView(string viewName, object viewData) {
            RenderView(viewName, String.Empty, viewData);
        }

        protected virtual void RenderView(string viewName, string masterName, object viewData) {
            ViewContext viewContext = new ViewContext(ControllerContext, viewName, masterName, viewData, TempData);
            ViewEngine.RenderView(viewContext);
        }

        private static List<ActionFilterAttribute> SortActionFilters(Stack<MemberInfo> memberChain) {
             List<ActionFilterAttribute> filters = new List<ActionFilterAttribute>();

            foreach (MemberInfo member in memberChain) {
                ActionFilterAttribute[] attrs = (ActionFilterAttribute[])member.GetCustomAttributes(typeof(ActionFilterAttribute), false /**//* inherit */);
                SortedList<int, ActionFilterAttribute> orderedFilters = new SortedList<int, ActionFilterAttribute>();
                foreach (ActionFilterAttribute filter in attrs) {
                    // filters are allowed to have the same order only if the order is -1.  in that case,
                    // they are processed before explicitly ordered filters but in no particular order in
                    // relation to one another.
                    if (filter.Order >= 0) {
                        if (orderedFilters.ContainsKey(filter.Order)) {
                            throw new InvalidOperationException(
                                String.Format(
                                    CultureInfo.CurrentUICulture,
                                    MvcResources.ActionFilter_DuplicateOrder,
                                    member,
                                    filter.Order));
                        }
                        orderedFilters.Add(filter.Order, filter);
                    }
                    else {
                        filters.Add(filter);
                    }
                }
                filters.AddRange(orderedFilters.Values);
             }

            return filters;
        }

        IController Members#region IController Members
        void IController.Execute(ControllerContext controllerContext) {
            Execute(controllerContext);
        }
         #endregion

        private sealed class ControllerActionFilter : ActionFilterAttribute {

            private Controller _controller;

            public ControllerActionFilter(Controller controller) {
                _controller = controller;
             }

            public override void OnActionExecuted(FilterExecutedContext filterContext) {
                _controller.OnActionExecuted(filterContext);
             }

            public override void OnActionExecuting(FilterExecutingContext filterContext) {
                _controller.OnActionExecuting(filterContext);
             }

        }

    }
}
 獲取 Action 的名字,然后開始執行 InvokeAction,如果找不到Action,則調用HandleUnknownAction,這是一個虛擬方法,可以在子類中重寫,默認是拋出一個異常InvalidOperationException。

 

          protected internal virtual void Execute(ControllerContext controllerContext) {
            if (controllerContext == null) {
                throw new ArgumentNullException("controllerContext");
             }

            ControllerContext = controllerContext;
             TempData = new TempDataDictionary(controllerContext.HttpContext);

            string actionName = RouteData.GetRequiredString("action");
            if (!InvokeAction(actionName)) {
                HandleUnknownAction(actionName);
            }
        }

詳細看看InvokeAction方式的執行:

 protected internal bool InvokeAction(string actionName) {
            return InvokeAction(actionName, new RouteValueDictionary());
        }

        protected internal virtual bool InvokeAction(string actionName, RouteValueDictionary values) {
            if (String.IsNullOrEmpty(actionName)) {
                throw new ArgumentException(MvcResources.Common_NullOrEmpty, "actionName");
             }

            // We have to loop through all the methods to make sure there isn't
            // a conflict. If we stop the loop the first time we find a match
             // we might miss some error cases.

            MemberInfo[] membInfos = GetType().GetMember(actionName, MemberTypes.Method,
                BindingFlags.IgnoreCase | BindingFlags.InvokeMethod | BindingFlags.Instance | BindingFlags.Public);
             MethodInfo foundMatch = null;

            foreach (MemberInfo memberInfo in membInfos) {
                 MethodInfo mi = (MethodInfo)memberInfo;

                // 1) Action methods must not have the non-action attribute in their inheritance chain, and
                // 2) special methods like constructors, property accessors, and event accessors cannot be action methods, and
                // 3) methods originally defined on Object (like ToString) or Controller cannot be action methods.
                if (!mi.IsDefined(typeof(NonActionAttribute), true) &&
                    !mi.IsSpecialName &&
                    mi.DeclaringType.IsSubclassOf(typeof(Controller))) {
                    if (foundMatch != null) {
                        throw new InvalidOperationException(
                            String.Format(CultureInfo.CurrentUICulture, MvcResources.Controller_MoreThanOneAction, actionName, GetType()));
                    }
                    foundMatch = mi;
                }
             }

            if (foundMatch != null) {
                InvokeActionMethod(foundMatch, values);
                return true;
            }
            return false;
        }
   它通過反射獲取所有同名 Action 方法信息;其次,它過濾掉所有有 NonActionAttribute 和 IsSpecialName 標記的方法;第三,當同名有效 Action 被重載時它會拋出異常(提示Controller_MoreThanOneAction),繼續調用InvokeActionMethod:

[SuppressMessage("Microsoft.Design", "CA1011:ConsiderPassingBaseTypesAsParameters",
     Justification = "We use MethodInfo since it represents only methods and not constructors." +
     "This method only makes sense for use with methods.")]
protected internal virtual void InvokeActionMethod(MethodInfo methodInfo, RouteValueDictionary values) {
     if (methodInfo == null) {
         throw new ArgumentNullException("methodInfo");
     }
     if (values == null) {
         values = new RouteValueDictionary();
     }
     if (methodInfo.ContainsGenericParameters) {
         throw new InvalidOperationException(String.Format(CultureInfo.CurrentUICulture, MvcResources.Controller_ActionCannotBeGeneric, methodInfo.Name));
     }

     ParameterInfo[] methodParameters = methodInfo.GetParameters();
     object[] parameterValues = null;
      if (methodParameters.Length > 0) {

         parameterValues = new object[methodParameters.Length];
         for (int i = 0; i < methodParameters.Length; i++) {
              ParameterInfo pi = methodParameters[i];

             if (pi.IsOut || pi.ParameterType.IsByRef) {
                 throw new InvalidOperationException(String.Format(CultureInfo.CurrentUICulture, MvcResources.Controller_ReferenceParametersNotSupported, pi.Name, methodInfo.Name));
              }

             bool valueRequired = true;
             if (pi.ParameterType.IsClass) {
                 // Classes (ref types) don't require values since we can pass in null
                 valueRequired = false;
             }
             else {
                 if ((pi.ParameterType.IsGenericType && !pi.ParameterType.IsGenericTypeDefinition) &&
                     (pi.ParameterType.GetGenericTypeDefinition() == typeof(Nullable<>))) {
                     // Nullable types don't require values since we can pass in null
                     valueRequired = false;
                 }
              }

             // Try to get a value for the parameter. We use this order of precedence:
             // 1. Explicitly-provided extra parameters in the call to InvokeAction()
             // 2. Values from the RouteData (could be from the typed-in URL or from the route's default values)
             // 3. Request values (query string, form post data, cookie)
             object parameterValue = null;
             if (!values.TryGetValue(methodParameters[i].Name, out parameterValue)) {
                 if (RouteData == null || !RouteData.Values.TryGetValue(methodParameters[i].Name, out parameterValue)) {
                     if (Request != null) {
                         parameterValue = Request[methodParameters[i].Name];
                     }
                 }
              }

             if (parameterValue == null && valueRequired) {
                 throw new InvalidOperationException(String.Format(CultureInfo.CurrentUICulture, MvcResources.Controller_MissingParameter, pi.Name, methodInfo.Name));
              }

             try {
                 parameterValues[i] = ConvertParameterType(parameterValue, methodParameters[i].ParameterType, methodParameters[i].Name, methodInfo.Name);
             }
             catch (Exception ex) {
                 // Parameter value conversion errors are acceptable unless the value is required
                 if (valueRequired) {
                     throw new InvalidOperationException(String.Format(CultureInfo.CurrentUICulture, MvcResources.Controller_MissingParameter, pi.Name, methodInfo.Name), ex);
                 }
             }
         }
     }

     InvokeActionMethodFilters(methodInfo, () => methodInfo.Invoke(this, parameterValues));
}這個方法很復雜,有大量的代碼是參數的分解 ,只有最后一行是關鍵的。
 InvokeActionMethodFilters(methodInfo, () => methodInfo.Invoke(this, parameterValues));

這行代碼將 Action 的調用作為一個委托,連同反射信息傳遞給 InvokeActionMethodFilters。

 private void InvokeActionMethodFilters(MethodInfo methodInfo, Action continuation) {

           // filters should execute in this order:
           // controller virtual overrides -> controller base attributes -> controller type attributes ->
            //   base action method attributes -> action method attributes

           List<ActionFilterAttribute> filters = new List<ActionFilterAttribute>() {
               new ControllerActionFilter(this)
            };

           Stack<MemberInfo> memberChain = new Stack<MemberInfo>();
           Type curType = GetType();
           while (curType != null) {
               memberChain.Push(curType);
               curType = curType.BaseType;
            }

           List<ActionFilterAttribute> sortedClassFilters = SortActionFilters(memberChain);
           filters.AddRange(sortedClassFilters);
           List<ActionFilterAttribute> sortedMethodFilters = PrepareMethodActionFilters(methodInfo);
            filters.AddRange(sortedMethodFilters);

           FilterContext context = new FilterContext(ControllerContext, methodInfo);
           ActionFilterExecutor executor = new ActionFilterExecutor(filters, context, continuation);
           executor.Execute();
       }
   這個方法首先將默認的過濾器 ControllerActionFilter 加到列表,然后提取所有繼承層次上基類的過濾器特性。最后將這些過濾器集合、過濾上下文,連同前一個方法傳遞進來的 Action 執行委托(continuation) 再次轉交給了一個 ActionFilterExecutor 對象實例,并調用其 Execute 方法。

  ExecuteRecursive使用了遞歸算法,通過迭代器 MoveNext() 方法提取一個過濾器對象,執行其 OnActionExecuting 方法。 如果該方法設置了 filterContext.Cancel = true,則放棄后續執行代碼。這種機制為我們提供了更好的控制,例如用它來實現偽靜態頁。一層一層調用所有的 ActionFilterAttribute.OnActionExecuting 方法,直到 MoveNext() == false。 在最后一次遞歸調用時,由于 enumerator.MoveNext() == false, _continuation() 方法被執行。這個就是前面給傳遞過來的 Action 方法委托,Action 方法總算是執行了。 在 Action 委托執行完成后,遞歸調逐級往上回溯,直到最初那個方法堆棧。這樣所有ActionFilterAttribute.OnActionExecuted 也被執行完成。

  到此開始進入最后的視圖呈現階段,可以把數據呈現到視圖上,Controller 提供了幾個重載的 RenderView() 來完成這個工作。

        protected void RenderView(string viewName) {
           RenderView(viewName, String.Empty, ViewData);
       }

       protected void RenderView(string viewName, string masterName) {
           RenderView(viewName, masterName, ViewData);
       }

       protected void RenderView(string viewName, object viewData) {
           RenderView(viewName, String.Empty, viewData);
       }

       protected virtual void RenderView(string viewName, string masterName, object viewData) {
           ViewContext viewContext = new ViewContext(ControllerContext, viewName, masterName, viewData, TempData);
           ViewEngine.RenderView(viewContext);
       }

  將一路傳遞過來的相關 "數據" (上下文)ControllerContext 再次包裝成ViewContext 。當然,這次依然會多出些東西,里面就有我們向視圖傳遞的數據 —— viewData 和tempData。作為默認選擇,MVC 創建 WebForm 視圖引擎來展示結果。其他的視圖引擎可以去看mvccontrib,這個項目就是整合:Castle Windsor 、StructureMap 、Spring.NET 等IoC框架以及視圖引擎,包括Castle MonoRail所用的NVelocityView視圖引擎、NHamlView視圖引擎、XsltViewEngine視圖引擎等等。

繼續看這個 WebFormViewEngine:

namespace System.Web.Mvc {
    using System;
    using System.Globalization;
    using System.Web.Compilation;
    using System.Web.Resources;
    using System.Web.Routing;
     using System.Web.Mvc.Resources;

    [AspNetHostingPermission(System.Security.Permissions.SecurityAction.LinkDemand, Level = AspNetHostingPermissionLevel.Minimal)]
    [AspNetHostingPermission(System.Security.Permissions.SecurityAction.InheritanceDemand, Level = AspNetHostingPermissionLevel.Minimal)]
    public class WebFormViewEngine : IViewEngine {
        private IBuildManager _buildManager;
         private IViewLocator _viewLocator;

        internal IBuildManager BuildManager {
            get {
                if (_buildManager == null) {
                    _buildManager = new BuildManagerWrapper();
                }
                return _buildManager;
            }
            set {
                _buildManager = value;
            }
        }

        public IViewLocator ViewLocator {
            get {
                if (_viewLocator == null) {
                    _viewLocator = new WebFormViewLocator();
                }
                return _viewLocator;
            }
            set {
                _viewLocator = value;
            }
        }

        protected virtual void RenderView(ViewContext viewContext) {
            if (viewContext == null) {
                throw new ArgumentNullException("viewContext");
             }

            string viewPath = ViewLocator.GetViewLocation(viewContext, viewContext.ViewName);
            if (String.IsNullOrEmpty(viewPath)) {
                throw new InvalidOperationException(
                    String.Format(
                        CultureInfo.CurrentUICulture,
                        MvcResources.WebFormViewEngine_ViewNotFound,
                        viewContext.ViewName));
            }
            object viewInstance = BuildManager.CreateInstanceFromVirtualPath(viewPath, typeof(object));
            if (viewInstance == null) {
                throw new InvalidOperationException(
                    String.Format(
                        CultureInfo.CurrentUICulture,
                        MvcResources.WebFormViewEngine_ViewCouldNotBeCreated,
                        viewPath));
             }

            ViewPage viewPage = viewInstance as ViewPage;

            if (viewPage != null) {

                if (!String.IsNullOrEmpty(viewContext.MasterName)) {
                    string masterLocation = ViewLocator.GetMasterLocation(viewContext, viewContext.MasterName);
                    if (String.IsNullOrEmpty(masterLocation)) {
                        throw new InvalidOperationException(
                            String.Format(
                                CultureInfo.CurrentUICulture,
                                MvcResources.WebFormViewEngine_MasterNotFound,
                                viewContext.MasterName));
                     }

                    // We don't set the page's MasterPageFile directly since it will get
                    // overwritten by a statically-defined value. In ViewPage we wait until
                    // the PreInit phase until we set the new value.
                    viewPage.MasterLocation = masterLocation;
                }
                viewPage.SetViewData(viewContext.ViewData);
                viewPage.RenderView(viewContext);
            }
            else {
                ViewUserControl viewUserControl = viewInstance as ViewUserControl;
                if (viewUserControl != null) {
                    if (!String.IsNullOrEmpty(viewContext.MasterName)) {
                        throw new InvalidOperationException(MvcResources.WebFormViewEngine_UserControlCannotHaveMaster);
                     }

                    viewUserControl.SetViewData(viewContext.ViewData);
                    viewUserControl.RenderView(viewContext);
                }
                else {
                    throw new InvalidOperationException(
                        String.Format(
                            CultureInfo.CurrentUICulture,
                            MvcResources.WebFormViewEngine_WrongViewBase,
                            viewPath));
                }
            }
        }

        IViewEngine Members#region IViewEngine Members
        void IViewEngine.RenderView(ViewContext viewContext) {
            RenderView(viewContext);
        }
        #endregion
    }
}
首先會創建一個 WebFormViewLocator 對象來獲取視圖存放路徑。

namespace System.Web.Mvc {
    public class WebFormViewLocator : ViewLocator {
        public WebFormViewLocator() {
            ViewLocationFormats = new[] {
                "~/Views/{1}/{0}.aspx",
                "~/Views/{1}/{0}.ascx",
                "~/Views/Shared/{0}.aspx",
                "~/Views/Shared/{0}.ascx"
            };
            MasterLocationFormats = new[] {
                "~/Views/{1}/{0}.master",
                "~/Views/Shared/{0}.master"
            };
        }
    }
}

  在獲取路徑后,WebFormViewEngine 通過一個包裝類 BuildManagerWrapper 間接調用 System.Web.Compilation.BuildManager 的靜態方法 CreateInstanceFromVirtualPath() 將視圖進行編譯,并返回一個對象實例。(System.Web.Compilation.BuildManager BuildManager 類管理應用程序的程序集和頁的編譯過程),后面通過 as 轉換結果來判斷視圖是 ViewPage 還是 ViewUserControl。ViewPage 繼承自我們所熟悉的 System.Web.UI.Page,它的 RenderView() 方法也就是完成WebForm的 Page.ProcessRequest() 的處理而已,也就完成了對WebForm模型的置換。

下面看看ViewPage和ViewUserControl的代碼:

namespace System.Web.Mvc {
    using System.Web.UI;

    [AspNetHostingPermission(System.Security.Permissions.SecurityAction.LinkDemand, Level = AspNetHostingPermissionLevel.Minimal)]
    [AspNetHostingPermission(System.Security.Permissions.SecurityAction.InheritanceDemand, Level = AspNetHostingPermissionLevel.Minimal)]
    public class ViewPage : Page, IViewDataContainer {
        private string _masterLocation;
         private object _viewData;

        public string MasterLocation {
            get {
                return _masterLocation ?? String.Empty;
            }
            set {
                _masterLocation = value;
            }
        }

        public AjaxHelper Ajax {
            get;
            set;
        }

        public HtmlHelper Html {
            get;
            set;
        }

        public TempDataDictionary TempData {
            get {
                return ViewContext.TempData;
            }
        }

        public UrlHelper Url {
            get;
            set;
        }

        public ViewContext ViewContext {
            get;
            private set;
        }

        public ViewData ViewData {
            get {
                return new ViewData(_viewData);
            }
        }

        public HtmlTextWriter Writer {
            get;
            private set;
        }

        [System.Diagnostics.CodeAnalysis.SuppressMessage("Microsoft.Security", "CA2109:ReviewVisibleEventHandlers")]
        protected override void OnPreInit(EventArgs e) {
             base.OnPreInit(e);

            if (!String.IsNullOrEmpty(MasterLocation)) {
                MasterPageFile = MasterLocation;
            }
        }

        public virtual void RenderView(ViewContext viewContext) {
            ViewContext = viewContext;
            Ajax = new AjaxHelper(viewContext);
            Html = new HtmlHelper(viewContext);
             Url = new UrlHelper(viewContext);

            ProcessRequest(HttpContext.Current);
        }

        protected override void Render(HtmlTextWriter writer) {
            Writer = writer;
            try {
                base.Render(writer);
            }
            finally {
                Writer = null;
            }
        }

        [System.Diagnostics.CodeAnalysis.SuppressMessage("Microsoft.Design", "CA1024:UsePropertiesWhereAppropriate",
            Justification = "There is already a ViewData property and it has a slightly different meaning.")]
        protected internal virtual void SetViewData(object viewData) {
            _viewData = viewData;
        }

        #region IViewDataContainer Members
        object IViewDataContainer.ViewData {
            get {
                return _viewData;
            }
        }
        #endregion
    }
}

 namespace System.Web.Mvc {
    using System.ComponentModel;
    using System.Globalization;
    using System.Web.Resources;
    using System.Web.UI;
     using System.Web.Mvc.Resources;

    [AspNetHostingPermission(System.Security.Permissions.SecurityAction.LinkDemand, Level = AspNetHostingPermissionLevel.Minimal)]
    [AspNetHostingPermission(System.Security.Permissions.SecurityAction.InheritanceDemand, Level = AspNetHostingPermissionLevel.Minimal)]
    public class ViewUserControl : UserControl, IViewDataContainer {
        private string _viewDataKey;
         private object _viewData;

        public AjaxHelper Ajax {
            get {
                return ViewPage.Ajax;
            }
        }

        public HtmlHelper Html {
            get {
                return ViewPage.Html;
            }
        }

        public TempDataDictionary TempData {
            get {
                return ViewPage.TempData;
            }
        }

        public UrlHelper Url {
            get {
                return ViewPage.Url;
            }
        }

        public ViewData ViewData {
            get {
                EnsureViewData();
                return new ViewData(_viewData);
            }
        }

        public ViewContext ViewContext {
            get {
                return ViewPage.ViewContext;
            }
        }

        [DefaultValue("")]
        public string ViewDataKey {
            get {
                return _viewDataKey ?? String.Empty;
            }
            set {
                _viewDataKey = value;
            }
        }

        private ViewPage ViewPage {
            get {
                ViewPage viewPage = Page as ViewPage;
                if (viewPage == null) {
                    throw new InvalidOperationException(String.Format(CultureInfo.CurrentUICulture, MvcResources.ViewUserControl_RequiresViewPage));
                }
                return viewPage;
            }
        }

        public HtmlTextWriter Writer {
            get {
                return ViewPage.Writer;
            }
        }

        private void EnsureViewData() {
            // Get the ViewData for this ViewUserControl, optionally using the specified ViewDataKey
            if (_viewData != null) {
                return;
            }
            IViewDataContainer vdc = GetViewDataContainer(this);
            if (vdc == null) {
                throw new InvalidOperationException(
                    String.Format(
                        CultureInfo.CurrentUICulture,
                        MvcResources.ViewUserControl_RequiresViewDataProvider,
                        AppRelativeVirtualPath));
            }
            if (String.IsNullOrEmpty(ViewDataKey)) {
                _viewData = vdc.ViewData;
            }
            else {
                _viewData = DataBinder.Eval(vdc.ViewData, ViewDataKey);
            }
        }

        private static IViewDataContainer GetViewDataContainer(Control control) {
            // Walk up the control hierarchy until we find someone that implements IViewDataContainer
            while (control != null) {
                control = control.Parent;
                IViewDataContainer vdc = control as IViewDataContainer;
                if (vdc != null) {
                    return vdc;
                }
            }
            return null;
        }

        public virtual void RenderView(ViewContext viewContext) {
            // TODO: Remove this hack. Without it, the browser appears to always load cached output
            viewContext.HttpContext.Response.Cache.SetExpires(DateTime.Now);
            ViewUserControlContainerPage containerPage = new ViewUserControlContainerPage(this);
            containerPage.RenderView(viewContext);
        }

        [System.Diagnostics.CodeAnalysis.SuppressMessage("Microsoft.Design", "CA1024:UsePropertiesWhereAppropriate",
           Justification = "There is already a ViewData property and it has a slightly different meaning.")]
        protected internal virtual void SetViewData(object viewData) {
            _viewData = viewData;
        }

        #region IViewDataContainer Members
        object IViewDataContainer.ViewData {
            get {
                EnsureViewData();
                return _viewData;
            }
        }
         #endregion

        private sealed class ViewUserControlContainerPage : ViewPage {
            public ViewUserControlContainerPage(ViewUserControl userControl) {
                Controls.Add(userControl);
            }
        }
    }
}

  以直接在 Controller 中 RenderView 一個用戶控件(ViewUserControl),asp.net mvc 會替我們創建了一個 "空白頁" (ViewUserControlContainerPage )來裝載這個控件RenderView(ViewUserControl) 有個限制,就是不能有 MasterPage。

    private sealed class ViewUserControlContainerPage : ViewPage {
           public ViewUserControlContainerPage(ViewUserControl userControl) {
               Controls.Add(userControl);
           }
       }

  我們從 UrlRoutingModule 開始,歷經 MvcRouteHandler、MvcHandler、Controller、ActionFilterAttribute,直到最后的 ViewEngine、ViewPage.完成了整個ASP.NET MVC的生命周期探索。


標簽:

本站文章除注明轉載外,均為本站原創或翻譯。歡迎任何形式的轉載,但請務必注明出處、不得修改原文相關鏈接,如果存在內容上的異議請郵件反饋至chenjj@ke049m.cn

文章轉載自:博客園

為你推薦

  • 推薦視頻
  • 推薦活動
  • 推薦產品
  • 推薦文章
  • 慧都慧問
掃碼咨詢


添加微信 立即咨詢

電話咨詢

客服熱線
023-68661681

TOP
利記足球官網(官方)網站/網頁版登錄入口/手機版登錄入口-最新版(已更新) 真人boyu·博魚滾球網(官方)網站/網頁版登錄入口/手機版登錄入口-最新版(已更新) 最大網上PM娛樂城盤口(官方)網站/網頁版登錄入口/手機版登錄入口-最新版(已更新) 正規雷火競技官方買球(官方)網站/網頁版登錄入口/手機版登錄入口-最新版(已更新) 雷火競技權威十大網(官方)網站/網頁版登錄入口/手機版登錄入口-最新版(已更新) boyu·博魚信譽足球官網(官方)網站/網頁版登錄入口/手機版登錄入口-最新版(已更新) 權威188BET足球網(官方)網站/網頁版登錄入口/手機版登錄入口-最新版(已更新) 正規188BET足球大全(官方)網站/網頁版登錄入口/手機版登錄入口-最新版(已更新) av无码一区二区在线观看 | 不卡的国产高清av一区二区三 | 国产精品无码片 | 国产麻豆91传媒入口 | 国产亚洲欧美精品手机在线 | 国产麻豆精品久久久 | 国产午夜激无码v毛片久久 国产午夜激无码αv毛片久久 | 91麻豆午夜福 | 99自偷国偷产品一区 | 国产成a人亚洲精ⅴ品无码性色 | 国产亚洲一区二区三区啪 | 国产午夜无码片 | 国产高清国产精品国产专区 | 国产黑色丝袜视频在线观看网红 | 精品视频在线视频观看 | 国产极品网站在线播放 | 国产欧美日韩亚洲一区二区三区 | 精品精品国产自在香蕉网 | 成人免费无码视频在线网站 | 精品国产仑片一区二区三区 | 福利一区二区三区不卡视频 | 国产高清一区二区三区免费视频 | 国产一区二区三区在线看片 | 成人午夜国产福到在线 | 国产精品一区二区三区久久久久 | 国产你懂的在线看网址 | 国产一级aa大片毛片 | 精品国产在线亚洲欧美 | 激情内射亚洲一区二区三区爱妻 | 国产精品白丝av在线观看播放 | 精品久久久久久中文人妻 | av无码在线观看不卡 | 国产精品麻豆三级一区视频 | 国产精品一区二区无久久久 | 国a片一级毛片免费看 | 国产原创一区二区 | av中文字幕在线播放 | 动精品动漫专区3d在线看 | 高潮喷水波多野结衣在线观看 | 2025无码专区人妻系列日韩 | 91精品一区二区三区在线播放 | 国产午夜福利精品偷伦91 | 后入内射视频 | 国产精品丝袜在线 | 国产成人自在自线视频 | 国产va免费高清在线观看 | 国产欧美日韩在线视频 | 18禁成年无码免费网 | 东京热久久无码影院 | 国产精品v欧美精品v日本精品动漫 | 精品久久国产av一区 | 国产边按摩边被躁在线播放 | 国产精品毛片一区 | 国产97无码 | 国产成人亚洲欧美日韩精品 | 国产一级一级毛片真人视频 | 国产日韩一区二区三区在线播放 | 国产交换配乱婬视频偷大叼 | 国内国外日产一区二区 | 国产成人猛男69精品视频 | 国产av免费观看 | 东京热无码人妻一区二区av | 国产欧洲一区二区在线观看 | 国产美女高潮抽搐在线播放 | 精品久久久久精品亚洲av | 国产麻豆精品免费密入口 | 成人啪精品视频免费网站 | 69国产精品成人无码免费视 | 国产在线播放线91免费 | 国产成人无码午夜大片 | 绯色国产av无码一区二区 | 99久久精品久久久久久清纯 | 国产精品福利网址在线观看 | 国产熟女性爱 | 精品一区二区三区高潮迭起 | 精品亚洲av无码专区毛片 | 精品日韩欧美一区二区在线播放 | 韩国精品久久一区二区三区 | av无码专区国产乱码电影 | 国产精品一线二线三线四线毛片 | 国产真实乱对白精彩久久老熟妇女 | 高潮国产精品一区二区喷水 | 国产成人片 | 国产精品白浆在线播放 | 91大神精品全国在线观看 | 国产精品一区二区久久久久久 | 国产办公室紧身裙丝袜av在线 | 国产精彩对白一区二区 | 2025国产精品自在自线 | 国产精品一二三四级电影 | 91露脸熟女四川熟女在线观看 | 国产1卡2卡三卡四卡久久网站 | 国产精品一级毛片在线观看 | 国产不收费b站软件 | 精品国产免费第一区二区三区 | 精品一区二区免费视频a | 国产a级毛片久久久毛片精片 | 国产精品久草在线观看 | 动漫美女爆羞羞动漫 | 国产在线观看超清无码视频一区二区 | 成人片国产在线观看无码 | 国产成人无码视频一区二区三 | 国产爆乳无码视频在线观看3 | 国产精品午夜未成人免费观看 | 国产综合精品一区二区三区 | 精品熟女一区 | 国产一区精品久久综合 | 国产精品毛片大码女人 | 国产成人无码区免费内射一片色 | 国产成人午夜精 | 精品人妻中文 | 国产午夜人做人 | 成熟女人毛片www免费版在线 | 国产精品青青在线麻豆 | 国产肉丝袜美腿 | 国产a一级黄片视频 | 国产av无码专区亚洲aⅴ | 国产精品成人国产乱一区 | 国产亚洲欧美日韩综合一区 | 国产福利麻豆精品一区 | 国产人妖 | 国产私人尤物无码不卡 | 国产免费乱理伦片在线观看 | 国产高清午夜成人在线观看 | 精品国产你懂的在线观看 | 国产成人aa午夜视频 | 国产综合精品中文第一 | 成人国产一区二区 | 东京热一本到里综合不卡 | 国产欧美日产一区二区三区大全 | 国产精品三级国产专用不卡 | 国产成人无码aⅴ片在线观 国产成人无码aⅴ片在线观看 | 国产在线视频不卡一视频大全 | 国产午夜精品视频 | 国产成人亚洲日韩欧美 | 海角社区视频百度云资源 | 国产色视频一区二区三区不卡 | 国产精品一区二区亚瑟不卡 | 国产一区精品在线 | 国产白嫩护士被 | 国产av无码一区二区二三区j | 99久久精品精品6精品精品 | 2025高清国产一区二区三区 | 91麻豆剧果 | 国产高清晰在线播放 | 国产精品亚洲天堂 | 国产精品午夜福利在线观看 | 丰满的少妇一区二区三区 | av之家免费黄片 | 国产精品无码理论片 | 精品日本三级在线观看 | 国产成人精品一区二区三区视频 | 精品视频一区二区三区免费 | 国产精品午夜福利免费 | 国产麻豆剧传媒精品国产v精品 | 国产日韩亚洲不卡高清在线观看 | 国产一在线精 | 精品无码午夜福利免费看 | 国产av无码专区亚洲av琪琪 | 91麻豆精品国产片在线观看 | 国产精品一卡二卡三卡 | 国产精品高潮丝袜无码 | 精品午夜福利免费在线观看 | 成人嫩草研究院久久久精品 | 丰满人妻系列无码专区 | 国产精品无码一区二区在线观看 | 国产午夜无码精品免费看浪潮 | 国产精品人人妻人人狠 | 成人色视频在线观看 | 国产裸体裸拍在线观看 | 变态调教一区二区三区男同 | 国产精品成人小电影在线观 | 国产无套视频免费看 | 91免费无码国产在线观看 | 国产人妻一区二区无码 | 国产高潮视频在 | 国产一人人看在线视频 | 精品久久久久久无码人妻vr | 国产成人午夜在线观看91 | 精品人妻无码专区在线视频 | 国产美女精品av免费专区 | 国产91麻豆免费观看 | 91成人在线播放 | 国产麻豆精品一区二区三区 | av无码官方网站 | 国产内射又粗又大又猛 | 精品国产你懂 | 国内偷窥一区二区三区视频 | 国产成人咱精品视频免费网站 | 成人动漫视频在线观看 | 91久久精品亚洲中文字幕无码 | 苍井空一区二区三区在线观看 | 高潮娇喘抽搐喷水潮喷视频网站 | 国产精品va在线观看丝瓜影院 | 18禁黄污吃奶免费看网站 | 国产精品大片大片看大 | 99国产欧美久久久精品蜜芽 | 国产一区二区三区欧美精品 | 国产一级精品无码 | 精品国产一区二区三区久久 | 国产精品成人无码一区二区 | 99精品免费久久久久久久 | 爆乳美女脱内衣18禁裸露网站 | 国产熟女内射oooo | 国产精品视频白浆 | 国产日韩一区在线观看视频 | 2025国产视频不卡在线 | 国产精品亚洲精品日韩动图 | 成人午夜无码影院视频在线观看 | 成人无码中文字幕在线不卡 | 国产成人高清激情视频在线观看 | 国产精品区一区二区三在放 | 国产一区二区三区免 | 国产不卡一区二区三区免费视 | 国产精品男人影院在线播放 | 国产白丝 | 91精品婷婷国产综合久久 | 国产在线一区二区三区蜜桃 | 国产成人无码精品午夜福利a | 国产精品国产日韩精 | 国产自偷在线拍精品热 | 国产精品毛片无遮挡 | 国产成人高清成人av片在线看 | 国产午夜无码片在线观看网站 | av一区二区三区蜜桃 | 91精品欧美一区二区三区 | 国产高清精品亚洲一区二区三 | 国产一区二区免费 | 国产福利电影一区 | 精品深夜av无码一区二区 | 东京热人妻无码一区二区av | 成人国产中文字幕 | 91天天综合丝袜内裤高跟鞋 | 丰满大乳奶水在线播放 | 国产精品三级在线观看 | av喷水高潮喷水在线观看 | 成人影视免费高清在线观看网站a | 国产精品成人综合网 | 国产一区二区三区免费大片天美 | 国产精品吹潮在线观看中文 | 精品人妻自在现线综合视频 | 成人国内精品视频在线观看 | 国产嫖妓在线播 | 国产精品一区二区在线网站 | 国产一区二区精品福利地址 | 精品国产专区91在线尤物 | 国产一级a级毛片久久久久精品卡 | 国产成人精品久久久久 | 国产偷抇久久精品水蜜桃 | 国产高清精品亚洲一区二区三 | 2025一本久道久久综合狂躁 | av天堂午夜精品一区二区三 | 精品视频在线观自拍自拍 | 国产成人精品久久一区二区 | 国产私拍福利视频 | 国产中文字幕免费不卡 | 成人无码区免费视频网站蜜臀 | 91精品国产熟女 | 福利姬国产精品一区在线 | 99久久久精品免 | 成人国产日本亚洲精品 | 国产成人亚洲精品无码青app | 国产一区亚洲欧美成人 | 国产成人女人在线视频观看 | 国产凹凸在线观看一区二区 | 精品日韩人伦一区二区三区蜜桃 | av嗯啊 | 国产女同一区二区在线 | 国产午夜福利精品一 | 精品视频免费在线 | 国产精品福利一区 | 国产成人毛片精品不卡在线 | 国产成人秘在线观看免费网站 | 国产丝袜视频 | 国产一区二区久久精品 | 国产美女福利片 | 精品国产一区二区三区不 | 国产无码av | 高潮激情肉欲视频 | 国产三级在线影音先锋国产精品 | 国产精品无码好吊视频一区 | 国产成人牲交在线观看视频 | 加勒比色老久久综合网 | 99久久国产综合导航电影 | 国产麻豆精品久久久 | 国产丝袜在线精品丝袜 | 果冻传媒av毛片无码蜜桃 | 国产高清专区免费资源网站 | 国产成人免费高清在线观看 | 精品麻豆国产一区 | 国产福利电影一区二区三区 | 国产一区在线观 | 国产免费无码一区二区 | 国产高清亚洲一区二区三区 | 国产精品午夜无码 | 国产av永久无码精品 | 国产美女一区二区三区 | 国产91高潮操逼视频流白浆 | 国产不卡视频一区二区三区四区 | 精品国产男人的天堂久久 | 国产在线观看免费av站 | 国产无套露脸视频在线观看 | 国产成人午夜福利小久久久 | 国产精品午夜性色视频 | 国产中文制服丝袜另类 | 国产精品嫩草影院一二三区入口 | 国产专辑免费在线不卡 | 国产一区二区三区精品网站 | 国产不卡高清在线观看视频 | 极品萝在线永久视频欧美 | 国产精品欧美一区二区三区不 | 国产精品边做奶水狂喷有码 | 国产成人啪精品午 | 国产真人免费 | 成人国产在线播放9696 | 精品无码欧美黑人又粗又 | 99精品国产高清一区二区麻豆 | 成人综合网站一区二区三区四区 | 97人妻熟女成人免费视频色戒 | 国产成人a在线观看网站站 国产成人a在一区线观看高清 | 国产在线拍揄自揄视精品 | 91久久电 | 2025国精品夜夜天天拍 | 国产对白一区视频 | 91偷拍一区 | 高潮一区二区三区在线 | 国产免费无码v片在线观看不卡 | 国产三级片在线观看 | 丰满少妇女人a | 国产精品大片免费看 | 18禁成年无码免费网站深添 | 成人av鲁丝片一区二区免费 | 国产av巨作丝袜秘书 | 国产成人精品免费无码 | 国产精品免费久久久久久久久久 | 91一区二区视频 | 国产成人无码精品久久久免费 | 精品亚洲欧美中文字幕在 | 国产毛片片精品天天看视频 | 懂色一区二区二区av免费观 | 国产美女自慰喷水 | 国内精品久久人妻 | 国产麻豆精品一区二区三区 | 丰满的少妇中出 | 2025亚洲天堂无码视屏手机版 | 国产日韩精品无码去免费专区国产 | 国产精品女人高潮毛片 | 精品国产一区二区三区 | 国产偷录视频叫床高潮 | 国产真实乱对白精彩久久91 | 国产欧美久久久久久精品四区 | 韩国无码中文字幕在线视频 | 国产日韩欧美精品区性色 | 国産精品久久久久久久 | 国产美女精品一区二区三 | 韩国三级理论无码电影在线观看 | 国产精品成人免费视频一区 | 国产自无码视频在线观看手机 | 69久久国产| 国产黄色视频 | 国产精品女同一区二区在线 | 大尺度无遮挡激 | 福利姬在线观看 | 丰满五十 | 国产综合日韩另类一区二区 | 国色天香第01集在线播放 | av视频一本无码视频 | 高清久久久久久久久 | 国产aⅴ天堂亚洲国产a | 91网红福利精品区一区二 | 国产无套露脸在线观看 | 丰满少妇大乳高潮在线 | 91精品无码人妻系列九色 | 国产黄色片在线观看 | 国产成人无码午夜福利软件 | 国产精品无码一区二区三区免费 | 激情都市综亚洲精品综合 | 国产精品无码一区二蜜臀影院 | 国产熟睡乱子伦视频观看软件 | 911国产在线观看无码专区 | 国产a级作爱片无码高级 | 国产成年人免费在 | 国产互换人妻好紧hd无码 | 国产精品一区二区国产 | 国产午夜精品无码免费不卡影院 | 韩国卡通动漫一区二区精品 | 精品三区二区一区 | 黑巨人精品一区二区三区 | 国产精品午夜自在在线精品 | 国产区香蕉精品系列在线观看不 | 精品久久久久久中文字幕无码vr | 国产高清三级免费韩剧在线 | 国产精品一区亚洲一区天堂 | 黑人巨茎精品欧美一区二区 | 国产福利萌白酱 | 国产女人高潮视频在线观看 | 国产肥熟女视频一区二区三区 | 高清无码在线观看视频 | 国产成人久久精品一区二区三 | 国产av国片精品一区二区 | 国产精品成人嫩草影院 | 激情爆乳一区二区三区 | 91久久国产成人网站 | 99国产热久久 | 成人欧美一区二区三区视频不卡 | 国产一区二区三区精品视频 | 国产精品香港三级国产av | 国产日韩精品视频一区 | 99国产欧美久久久精品蜜芽 | 国产精品一区在线观看第一页 | 国产成人精品一区二区视频免费 | 国产成人在线手机在线 | 国产欧美日韩在线综合网 | 国内外一级毛片 | 99久久久无码国产精精品免费 | 国产无码理论视频网 | 国产高清无码毛片 | 国产精品一卡二卡三卡乱码 | 波多野结衣精品一区二区三区 | 国产三级级在线观看播放 | 国产成人精品无码片网站 | 91亚洲自偷手机在线观看 | 国产免费午夜福利片在线观看 | 国产一区鲁鲁在线视频免费播放 | 精品国产专区91在线不卡 | 99久久国产精品欧美蜜芽 | 国产精品午夜福利电影 | 国产无码精品在线 | 国产精品久久久影视 | 国产麻豆剧传媒精品好看的片 | 国产午夜福利影院 | 国产精品社区在线观看 | 国产动漫一区 | 99自偷国偷产品一区电影 | 成人日韩欧美在线视频播放 | 国产成人高清激情视频在线观看 | 国产在线自在拍91 | 精品一区二区精品 | 国产午夜福利短视频在线观看 | 国产激情无码一区二区三区 | av色蜜桃一区二区三区 | 精品人妻少妇系列人妻系列 | 91女神精品系列在线观看66 | 国产黄网站手机在线观看 | 国产a视频在线亚洲 | 国产69精品久久久久9999不卡 | 国产精品+日韩精 | 国产+人+综合+亚洲 国产+人人+视频 | 91在线视频观看 | 国产精品一区二区日韩91 | 成人亚洲欧美在线观看 | 国产精品国产三级国产an | 国产精品一区二区免费在线观 | 精品97人妻无码中文永久在线 | 国产人妻精品午夜福 | 国产美女激情作爱网站 | 成人综合网站一区二区三区四区 | 国产精品成人观看视频免费 | 国产成人无码aa精品一区91 | 91久久精一区二区三区大全 | 国产91视频在线观看 | 成人黄色av播放 | 1024中文| 国产情趣一区二区三区 | 国产三级精品在线观 | 国产成人综合社区 | 国产白浆精品 | 成人欧美日本 | 国产三级aⅴ在线 | 国产无码免费的中文字幕 | 国产精品午夜理论片在线播放 | 国产精品中文久 | 国产欧美另类久久久精品图片 | 2025国产精品视频网站 | 99精品久久久久中 | 国产精品一区最新久久 | ts人妖另类国产 | 国产成人无码aⅴ片在线观 国产成人无码aⅴ片在线观看 | 精品国产一区二区三区 | 91精品国产福利在线观看麻 | 国产黄色靠逼视频网站 | 国产91精品丝袜一区二区 | 国产经典自拍视频在 | 丰满少妇又爽又紧又丰满在线 | 成在线人av无码高潮喷水 | 国产成人黄色网站 | 国产av激情久久 | 91在线国产综合 | 精品无码在线91天堂视频 | 国产精品高清一区二区三区不卡 | 国产高潮抽搐翻白眼在线播放 | 国产三级电影在线播放 | 国产麻豆精品一区二区 | 国产91在线欧美 | 91av在线国 | 国产无码大姐操逼刺激视频 | 91精品啪在线 | 精品无码国模私拍视频 | 丰满老熟好大bbb | a性色生活片久久毛片牛牛 a亚洲va老司机 | 国产欧美日韩在线视综合网频 | 国产日韩精品无码 | 国产在线视频无码台湾 | 1024看片福利永久国产 | 国产成人精品免费播放视频 | 国产精品免费久久久久软件 | 国产福利在线观看日本二区三区 | 国产成人午夜精品 | 91精品成人影院 | 国产午夜男女爽爽爽爽爽视频 | 国产精品欧美综合在线 | 国产在线精品二期不卡 | 国产精品午夜福利不卡120 | 国产劲爆∧v内射 | 按摩中出的人妻中文字幕 | 国产成人午夜福利在线观看视频 | 国产成人最新三级 | 国产无套精品一区二区 | 91麻豆精品国产高清在线 | 精品国产v无码大片在线观看 | 国产成人激烈叫床声视频对白 | 国产一区在线观看无码av | 国产区图片区小说区亚洲区 | 91精品一区二区三区在线播放 | 国产偷窥一区二区三区 | 国产不卡在线观看视频 | 国产综合亚洲欧美日韩一区 | 国产一区二区视频在线播放 | 国产精品视频全国免费 | 国产麻豆激情视频在线观看 | 精品亚洲av无码啪啪激情 | 国产成人精品999 | 国产成人综合久久 | 91无码 | 国产真实刮伦在线观看 | 国产放荡对白视频在线观看 | 国产在线精品成人欧美 | 2025在线精品自 | 18禁裸乳无遮挡高清免费观看 | 国产毛片一区二区三区精品 | 国产日韩欧美一区二区视频在线观看 | 国产一区二区三区精品视频 | 国产日韩无码精品一区二区三区 | 国内欧美一区一区三区视频 | 国产精品对白刺激音频在线观看 | 国产精品无码aⅴ一区二区三区 | 国产成人精品a∨一区二区 国产成人精品aaa | 国产午夜亚洲精品国产成人小说 | 国产一区高清视频在线观看 | 成人三级在线播放线观看 | 国产成人免费永 | av在线播放 | 国产原创在线视频 | 国产女人高潮叫床视频大片 | 国产精品亚洲综合色拍 | 国产精品欧美一区二区三区 | 国产午夜精品一区二区三区极品 | 成人无码网www在线观看精东 | 国产一区二区在线日韩 | 国产精品一区二区三区 | 国产成人av无码精品天堂 | av在线观看网址 | 国产在线观看午夜成人 | 成人免费xxx在线观看 | 国产日韩精品中文字无码樱花 | 精品日韩产品在线 | 国产精品一区二区三级 | 国产无套高潮在线观看 | 91大神 | av无码国产精品性色aⅴ | 国产午夜片无 | 国产精品一区二区av交换 | 国产精品va在线观看无码不卡 | 91麻豆精品国产综合久久久 | 国产日韩av在 | 国产毛片毛片精品天天看 | 国产精品国产av片国产 | 国产综合内射日韩久 | 国产超碰av人人做人人爽 | 国产精品亚洲片精品av | 2025国产视频2区 | 91麻豆精品国产自产 | 高清自拍影视亚洲 | 国产精品熟女 | 91日韩天堂一区二区二区 | 国偷自产av一区二区三区吞精 | 国产内射合集颜射 | 精品一区二区女厕 | 91麻豆国产自产激情在线看 | 国产真实交换配乱婬视 | 国产精品一二三四级电影 | 国产不卡在线观看视频 | 国产精品成人亚洲一区二区 | 2025国产成人综合亚洲精品 | 国产成人啪精品短视频 | 国产精品原创巨作av免费 | 国产精品白浆在线观 | av无码观 | 国产女主播精品大秀系列 | 精品日本无码综合 | 国产毛片一级 | 国产成a人亚洲精v品无码不卡 | 国产剧高清免费看 | 国产国拍亚洲精品午夜不卡嘿嘿 | 高清无码国产精品区 | 国产精品成人免费精品自在线 | 韩国无码无遮挡在线观看不 | 国产成人18黄网站免费观看 | 高清无码中文字幕影片 | 国产精品天干天干在线下载 | 精品国产免费午夜剧场 | 99久久精品国产国产毛片小说 | 1024国产精品视频一区 | 国产尤物aⅴ在线观看不卡 国产尤物av | 国产精品六区久久综合亚洲a | 高潮尖叫免费视频 | 国产做爰xxxⅹ高潮野外 | 国产一级无码视频在线观看 | 国产午夜精品一区二区三区漫 | 国产精品成人网址在线观看 | 3d动漫精品啪啪一区二区 | 18禁黄网站禁片免费观看天堂 | 91亚洲中 | 国产一三区a片在线播放 | 国产高清美女一级a毛片久久w | 91成人网站在线观看 | 国产麻豆一区二区三区在线蜜桃 | 精品国产丝袜在线拍91 | 国产午夜精品一区二区三区漫画 | 国产视频一区欧美二区日本三区动 | 国产成人亚洲精品无码v大片 | 国产精品无码专区在线播放 | 国产一区二区三区视频在线观看 | 国产成人αv无码专区亚洲αv | 国产极品精品免费视频能看的 | 国产福利短片视频在线观看 | 国产av小电影 | 国产一区二区三区免费观看在线 | 国产成人a区在线观看 | 国产精品午夜未成人免费观看 | 国产高清视频一区二区在 | 91在线免费看| 91无码久久国产线看观看 | 91精品一区国产高清在线gif | 91高清免费国产自产 | 国产一级毛片久久久久久 | 国产自愉自愉免费24区 | 国产一区私人高清影院 | 国产一区二区无码视频 | 国产成人精品久久免费 | 国产午夜精品一区理论片飘花 | 国产酒店制服丝袜在线 | 成人精品日本亚洲电影院电影 | 国产精品乱码一 | 国产在线观看自拍日本 | 国产精品免费看久久久无码 | 国产精品鲁一鲁 | 国产成人欧美日韩在线电影 | av无码免费在线一区二区三区 | 91成人网站在线观看 | 精品久久a人妻 | 国产成人精品亚洲v无人区一区 | 国产黄片软件在线观看 | 岛国在线无码免费观看 | 国产午夜精品片一区二区三区 | 国产av丝袜美腿丝袜网站 | 91人妻人人做人碰人人爽九色 | 高潮流白浆潮喷 | 东京热加勒比无码少妇 | 国产成人一区二区在线不卡 | 91美女视频| 2025无码专区人妻系列日韩 | 国产毛a片 | 国产精品先锋在线直播 | 国产成人精品202 | 91精品国产福利尤物 | 99久久精品国产波多野结衣 | 91精品国产高清久久久电影 | 国产精品亚洲综合久久 | 91在线无码精品秘在线观看 | 国产97视频| 国产自产视频在线观看香蕉 | 国产精品亚洲专区无码破解版 | 91人妻人人做人碰人人爽 | 成人午夜影院 | 精品人妻无码专区在线视频 | 国产精品无码无卡在线观看 | 国产精品国产三级国产av | 国产精品国产三级农村妇女 | 国产精品成久久久久三级四虎 | 国自产精品手机在线视频 | 99国产在线看片 | 97人人添人人澡人人澡人人澡 | 国产成在线观看免费视 | 国产不卡一区二区免费视 | 精品精品国产高清a毛片 | 精品蜜臀国产aⅴ一区二区三区 | 国产成a人亚洲精v品久久网 | 国产a级作爱 | 国产精品午夜福利电影 | 国产精品欧美在线观看 | 97人妻天天摸天天爽天天 | 爆乳熟妇一区二区三区霸乳 | 国产一区二区三区日韩精品 | av国内精品久久久久影院 | 国产无吗一区二区三区在线欢 | 成人国产精品一区二区免费 | av无码人妻一区二区三区牛牛 | 国产成人av在线亚洲天堂在线观看 | 海角视频(免费)在线观看 | 国产激情91久久精品导航 | 高清精品一区二区三区 | 国产亚洲日韩精品超碰 | 精品国产免费人成电影在线看 | 国产成人在线播放免费视频 | 国产剧情av片醉酒女邻居 | 国产91熟女一区二区三区 | 国产91精品高跟丝袜在线 | 国产涩涩视频在线观看 | 国产尤物在线无码福利网 | 成年无码av片大全在线播 | 国产免费内射又粗又爽密桃视频 | 国产成人秘在线观看免费网站 | 白丝jk女仆爆乳慰喷水流白浆 | 国产亚洲日韩欧美一区二区三区 | av日韩国产一区二 | 国产巨作原创 | 99国产成人免费视频 | 国产欧美熟妇另类久久久 | 国产av剧情md精品麻豆 | 国产黄色av天 | 国产亚洲视频在线播放大全 | 国产一级a毛看免费视频区二三 | 国产在线视频二区 | 91日亚欧国产内射成人网 | av无码精品久久 | 国产人与禽zoz0性伦 | 国产成人无码a区在线观看软件 | 国产a级精品一级毛片 | 国产午夜亚洲一区二区在线观看 | 成人综合国内精品久久久久久影院 | 国产精品亚洲精品日韩电影 | 99久久人妻精品免费二区 | 国产自产一区二区三区视频在线 | 国产一区二区福利久久 | 国产aⅴ无码精品一品二区 国产aⅴ无码精品一区二区 | 国产精品天干天干 | 国产av永久福利资源网站 | 国产成人无码av片在线观看不卡 | 国产午夜手机精彩视频 | 国产精品不卡无码av在线播 | 成人亚洲色欲色一欲 | 国产无套白浆视频在线观看 | 99精品国产一区 | 成人免费无码精品国产电影同人 | 国产精品亚洲片精品av | 国产av无码专区国产乱码 | 国产成人亚洲精品久久 | 国产福利无码一区色费 | 丰满人妻一区二区三区四季av | 91麻豆国产 | 囯产精品一品二区三区 | 国产码欧美日韩高清综合一区 | 国产精品毛多多水多 | 国产精品盗摄在线观看 | 91欧美秘密入口 | 成年人深夜福利 | 国产精品多p对白交换绿帽 国产精品多人p | 国产剧情av网 | 精品一区二区高潮 | 国产精品民宅偷窥盗摄 | 国产女人喷潮视频在线观看 | 2025v视频无码高清网站 | 国产精品秘麻豆免费版热议不断 | 国产一区二区三区影院 | 国产精品亚洲日韩欧美色窝 | 国产精品视频一区 | 国产成人精品福利网 | 国产精品亚洲香蕉第五区 | 韩国黄色片免费在线观看 | 国产成人亚洲综合无码dvd | 岛国av无码免费 | 国产成人午夜福在线观看 | 精品九九99久久在免费线 | 国产丝袜在线一区二区三区播放 | 国产aⅴ无码精品一品二区 国产aⅴ无码精品一区二区 | 国产一区二区三区夜色 | 18禁日本黄无遮挡禁免费网站 | 91黄色视频免费在线观看 | 国产成a人亚洲精v品在线观看 | 国产91丝袜在线精品 | 2025国产主播精品 | 国产精品亚洲专区在线 | 精品久久久久久久无码人妻热 | 91亚洲自偷手机 | 东京热中文字幕a∨无码 | 国产熟女高潮精品视频av | 精品久久久久久无码不卡 | 国产成人精品高清在线观看96 |