乡下人产国偷v产偷v自拍,国产午夜片在线观看,婷婷成人亚洲综合国产麻豆,久久综合给合久久狠狠狠9

  • <output id="e9wm2"></output>
    <s id="e9wm2"><nobr id="e9wm2"><ins id="e9wm2"></ins></nobr></s>

    • 分享

      ASP.NET MVC 4 視圖頁去哪里兒

       昵稱10504424 2014-03-14

      這里特別感謝 swagon 提到了Displaymodeprovider,所以才有了本篇博客,也使我對【View的呈現(xiàn)】中尋找視圖頁的過程有了清晰的認識!

      前戲

      在MVC中,執(zhí)行完Action之后,會返回一個ActionResult對象,之后再執(zhí)行該對象的ExecuteResult方法,這也就是【View的呈現(xiàn)】的入口!

      【View的呈現(xiàn)】包括了:根據(jù)模版去尋找請求的視圖頁、編譯視圖頁、再執(zhí)行視圖頁的內容。本篇就來介紹尋找視圖頁的詳細過程,其中涉及到了MVC 4的一個新特性--“手機視圖頁”

      1
      2
      3
      4
      5
      6
      7
      8
      9
      10
      11
      12
      13
      14
      15
      16
      17
      18
      19
      20
      21
      22
      23
      24
      25
      26
      27
      28
      29
      30
      31
      32
      33
      34
      35
      36
      37
      38
      39
      40
      41
      42
      43
      44
      45
      46
      47
      48
      49
      50
      51
      52
      53
      54
      public abstract class ViewResultBase : ActionResult
      {
      public override void ExecuteResult(ControllerContext context)
      {
      if (context == null)
      {
      throw new ArgumentNullException("context");
      }
      if (String.IsNullOrEmpty(ViewName))
      {
      ViewName = context.RouteData.GetRequiredString("action");
      }
        ViewEngineResult result = null;
      if (View == null)
      {
      //通過視圖引擎去創(chuàng)建視圖對象,并將視圖對象和該視圖相關的信息封裝在ViewEngineResult對象中。
      result = FindView(context);
      View = result.View;
      }
      TextWriter writer = context.HttpContext.Response.Output;
      ViewContext viewContext = new ViewContext(context, View, ViewData, TempData, writer);
      View.Render(viewContext, writer);
      if (result != null)
      {
      result.ViewEngine.ReleaseView(context, View);
      }
      }
      }
      public class ViewResult : ViewResultBase
      {
      protected override ViewEngineResult FindView(ControllerContext context)
      {
      //尋找當前請求的視圖頁,如果能找到則創(chuàng)建視圖對象。
      //遍歷每個視圖引擎(默認有兩個WebFormEngine、RazorViewEngine),并執(zhí)行每一個視圖引擎的FindView方法。
      ViewEngineResult result = ViewEngineCollection.FindView(context, ViewName, MasterName);
      //如果創(chuàng)建了視圖對象,即:指定路徑中存在相匹配的視圖頁(.cshtml文件)。
      if (result.View != null)
      {
      return result;
      }
      //沒有創(chuàng)建視圖對象,即:指定路徑中不存在相匹配的視圖頁(.cshtml文件)。
      StringBuilder locationsText = new StringBuilder();
      foreach (string location in result.SearchedLocations)
      {
      locationsText.AppendLine();
      locationsText.Append(location);
      }
      throw new InvalidOperationException(String.Format(CultureInfo.CurrentCulture,
      MvcResources.Common_ViewNotFound, ViewName, locationsText));
      }
      }

        ViewEngineResult result = ViewEngineCollection.FindView(context, ViewName, MasterName);則是遍歷每個視圖引擎(默認有兩個WebFormEngine、RazorViewEngine),并執(zhí)行每一個視圖引擎的FindView方法。
      注:在執(zhí)行視圖引擎的FindView方法時,先按照從緩存表中找是否存在請求的視圖頁,如果沒有的話,再進行一次尋找!

      下面以RazorViewEngine為例:

      1
      2
      3
      4
      5
      6
      7
      8
      9
      10
      11
      12
      13
      14
      15
      16
      17
      18
      19
      20
      21
      22
      23
      24
      25
      26
      27
      28
      29
      30
      31
      32
      33
      34
      35
      public abstract class VirtualPathProviderViewEngine : IViewEngine
      {
      //useCache先是true,該方法返回的是null。則讓useCache=false,再執(zhí)行一遍。即:先通過緩存去找,如果沒有找到的話,就正經(jīng)的去找。
      public virtual ViewEngineResult FindView(ControllerContext controllerContext, string viewName, string masterName, bool useCache)
      {
      if (controllerContext == null)
      {
      throw new ArgumentNullException("controllerContext");
      }
      if (String.IsNullOrEmpty(viewName))
      {
      throw new ArgumentException(MvcResources.Common_NullOrEmpty, "viewName");
      }
      string[] viewLocationsSearched;
      string[] masterLocationsSearched;
      string controllerName = controllerContext.RouteData.GetRequiredString("controller");
      //獲取視圖的路徑,這里就是咱們本篇博文的內容的入口點?。。。。。。。。。。。。。。。。。?!
      //ViewLocationFormats、AreaViewLocationFormats定義在派生類RazorViewEngine類中。
      //ViewLocationFormats:"~/Views/{1}/{0}.cshtml","~/Views/{1}/{0}.vbhtml", "~/Views/Shared/{0}.cshtml","~/Views/Shared/{0}.vbhtml"
      //AreaViewLocationFormats:"~/Areas/{2}/Views/{1}/{0}.cshtml", "~/Areas/{2}/Views/{1}/{0}.vbhtml", "~/Areas/{2}/Views/Shared/{0}.cshtml","~/Areas/{2}/Views/Shared/{0}.vbhtml"
      string viewPath = GetPath(controllerContext, ViewLocationFormats, AreaViewLocationFormats, "ViewLocationFormats", viewName, controllerName, CacheKeyPrefixView, useCache, out viewLocationsSearched);
      string masterPath = GetPath(controllerContext, MasterLocationFormats, AreaMasterLocationFormats, "MasterLocationFormats", masterName, controllerName, CacheKeyPrefixMaster, useCache, out masterLocationsSearched);
      if (String.IsNullOrEmpty(viewPath) || (String.IsNullOrEmpty(masterPath) && !String.IsNullOrEmpty(masterName)))
      {
      return new ViewEngineResult(viewLocationsSearched.Union(masterLocationsSearched));
      }
      return new ViewEngineResult(CreateView(controllerContext, viewPath, masterPath), this);
      }
      }

      啪啪啪

        GetPath方法在尋找【視圖頁】時,首先將當前請求的Controller和Action的名稱添加到地址格式化器中,這樣就有了要尋找的地址(們),之后就來檢查格式化后的地址是否真的存在指定的【視圖頁】。如果是通過手機端來請求,則會對格式化之后的地址進行再進行處理(如:Index.cshtml修改為Index.Mobile.cshtml),之后再檢查新地址下是否存在【視圖頁】。

      注:默認情況下會先檢查是否為手機端訪問!

      口說無憑,上源碼吧:

      復制代碼
      // Copyright (c) Microsoft Open Technologies, Inc. All rights reserved. See License.txt in the project root for license information.
      using System.Collections.Generic;
      using System.Diagnostics.CodeAnalysis;
      using System.Globalization;
      using System.Linq;
      using System.Web.Hosting;
      using System.Web.Mvc.Properties;
      using System.Web.WebPages;
      namespace System.Web.Mvc
      {
      public abstract class VirtualPathProviderViewEngine : IViewEngine
      {
      // format is ":ViewCacheEntry:{cacheType}:{prefix}:{name}:{controllerName}:{areaName}:"
      private const string CacheKeyFormat = ":ViewCacheEntry:{0}:{1}:{2}:{3}:{4}:";
      private const string CacheKeyPrefixMaster = "Master";
      private const string CacheKeyPrefixPartial = "Partial";
      private const string CacheKeyPrefixView = "View";
      private static readonly string[] _emptyLocations = new string[0];
      private DisplayModeProvider _displayModeProvider;
      private Func<VirtualPathProvider> _vppFunc = () => HostingEnvironment.VirtualPathProvider;
      internal Func<string, string> GetExtensionThunk = VirtualPathUtility.GetExtension;
      private IViewLocationCache _viewLocationCache;
      [SuppressMessage("Microsoft.Performance", "CA1819:PropertiesShouldNotReturnArrays", Justification = "This is a shipped API")]
      public string[] AreaMasterLocationFormats { get; set; }
      [SuppressMessage("Microsoft.Performance", "CA1819:PropertiesShouldNotReturnArrays", Justification = "This is a shipped API")]
      public string[] AreaPartialViewLocationFormats { get; set; }
      [SuppressMessage("Microsoft.Performance", "CA1819:PropertiesShouldNotReturnArrays", Justification = "This is a shipped API")]
      public string[] AreaViewLocationFormats { get; set; }
      [SuppressMessage("Microsoft.Performance", "CA1819:PropertiesShouldNotReturnArrays", Justification = "This is a shipped API")]
      public string[] FileExtensions { get; set; }
      [SuppressMessage("Microsoft.Performance", "CA1819:PropertiesShouldNotReturnArrays", Justification = "This is a shipped API")]
      public string[] MasterLocationFormats { get; set; }
      [SuppressMessage("Microsoft.Performance", "CA1819:PropertiesShouldNotReturnArrays", Justification = "This is a shipped API")]
      public string[] PartialViewLocationFormats { get; set; }
      // Neither DefaultViewLocationCache.Null nor a DefaultViewLocationCache instance maintain internal state. Fine
      // if multiple threads race to initialize _viewLocationCache.
      public IViewLocationCache ViewLocationCache
      {
      get
      {
      if (_viewLocationCache == null)
      {
      if (HttpContext.Current == null || HttpContext.Current.IsDebuggingEnabled)
      {
      _viewLocationCache = DefaultViewLocationCache.Null;
      }
      else
      {
      _viewLocationCache = new DefaultViewLocationCache();
      }
      }
      return _viewLocationCache;
      }
      set
      {
      if (value == null)
      {
      throw Error.ArgumentNull("value");
      }
      _viewLocationCache = value;
      }
      }
      [SuppressMessage("Microsoft.Performance", "CA1819:PropertiesShouldNotReturnArrays", Justification = "This is a shipped API")]
      public string[] ViewLocationFormats { get; set; }
      // Likely exists for testing only
      protected VirtualPathProvider VirtualPathProvider
      {
      get { return _vppFunc(); }
      set
      {
      if (value == null)
      {
      throw Error.ArgumentNull("value");
      }
      _vppFunc = () => value;
      }
      }
      // Provided for testing only; setter used in BuildManagerViewEngine but only for test scenarios
      internal Func<VirtualPathProvider> VirtualPathProviderFunc
      {
      get { return _vppFunc; }
      set
      {
      if (value == null)
      {
      throw Error.ArgumentNull("value");
      }
      _vppFunc = value;
      }
      }
      protected internal DisplayModeProvider DisplayModeProvider
      {
      get { return _displayModeProvider ?? DisplayModeProvider.Instance; }
      set { _displayModeProvider = value; }
      }
      internal virtual string CreateCacheKey(string prefix, string name, string controllerName, string areaName)
      {
      return String.Format(CultureInfo.InvariantCulture, CacheKeyFormat,
      GetType().AssemblyQualifiedName, prefix, name, controllerName, areaName);
      }
      internal static string AppendDisplayModeToCacheKey(string cacheKey, string displayMode)
      {
      // key format is ":ViewCacheEntry:{cacheType}:{prefix}:{name}:{controllerName}:{areaName}:"
      // so append "{displayMode}:" to the key
      return cacheKey + displayMode + ":";
      }
      protected abstract IView CreatePartialView(ControllerContext controllerContext, string partialPath);
      protected abstract IView CreateView(ControllerContext controllerContext, string viewPath, string masterPath);
      protected virtual bool FileExists(ControllerContext controllerContext, string virtualPath)
      {
      return VirtualPathProvider.FileExists(virtualPath);
      }
      public virtual ViewEngineResult FindPartialView(ControllerContext controllerContext, string partialViewName, bool useCache)
      {
      if (controllerContext == null)
      {
      throw new ArgumentNullException("controllerContext");
      }
      if (String.IsNullOrEmpty(partialViewName))
      {
      throw new ArgumentException(MvcResources.Common_NullOrEmpty, "partialViewName");
      }
      string[] searched;
      string controllerName = controllerContext.RouteData.GetRequiredString("controller");
      string partialPath = GetPath(controllerContext, PartialViewLocationFormats, AreaPartialViewLocationFormats, "PartialViewLocationFormats", partialViewName, controllerName, CacheKeyPrefixPartial, useCache, out searched);
      if (String.IsNullOrEmpty(partialPath))
      {
      return new ViewEngineResult(searched);
      }
      return new ViewEngineResult(CreatePartialView(controllerContext, partialPath), this);
      }
      //開始開始開始開始開始開始開始開始開始開始開始開始開始開始開始開始開始開始開始開始
      //useCache先是true,該方法返回的是null。則讓useCache=false,再執(zhí)行一遍。即:先通過緩存去找,如果沒有找到的話,就正經(jīng)的去找。
      public virtual ViewEngineResult FindView(ControllerContext controllerContext, string viewName, string masterName, bool useCache)
      {
      if (controllerContext == null)
      {
      throw new ArgumentNullException("controllerContext");
      }
      if (String.IsNullOrEmpty(viewName))
      {
      throw new ArgumentException(MvcResources.Common_NullOrEmpty, "viewName");
      }
      string[] viewLocationsSearched;
      string[] masterLocationsSearched;
      string controllerName = controllerContext.RouteData.GetRequiredString("controller");
      //獲取視圖的路徑
      //ViewLocationFormats、AreaViewLocationFormats定義在派生類RazorViewEngine類中。
      //ViewLocationFormats:"~/Views/{1}/{0}.cshtml","~/Views/{1}/{0}.vbhtml", "~/Views/Shared/{0}.cshtml","~/Views/Shared/{0}.vbhtml"
      //AreaViewLocationFormats:"~/Areas/{2}/Views/{1}/{0}.cshtml", "~/Areas/{2}/Views/{1}/{0}.vbhtml", "~/Areas/{2}/Views/Shared/{0}.cshtml","~/Areas/{2}/Views/Shared/{0}.vbhtml"
      string viewPath = GetPath(controllerContext, ViewLocationFormats, AreaViewLocationFormats, "ViewLocationFormats", viewName, controllerName, CacheKeyPrefixView, useCache, out viewLocationsSearched);
      string masterPath = GetPath(controllerContext, MasterLocationFormats, AreaMasterLocationFormats, "MasterLocationFormats", masterName, controllerName, CacheKeyPrefixMaster, useCache, out masterLocationsSearched);
      if (String.IsNullOrEmpty(viewPath) || (String.IsNullOrEmpty(masterPath) && !String.IsNullOrEmpty(masterName)))
      {
      return new ViewEngineResult(viewLocationsSearched.Union(masterLocationsSearched));
      }
      return new ViewEngineResult(CreateView(controllerContext, viewPath, masterPath), this);
      }
      //獲取視圖路徑方法
      private string GetPath(ControllerContext controllerContext, string[] locations, string[] areaLocations, string locationsPropertyName, string name, string controllerName, string cacheKeyPrefix, bool useCache, out string[] searchedLocations)
      {
      searchedLocations = _emptyLocations;
      if (String.IsNullOrEmpty(name))
      {
      return String.Empty;
      }
      //從RouteData的DataTokens中獲取key為'area’的值
      string areaName = AreaHelpers.GetAreaName(controllerContext.RouteData);
      bool usingAreas = !String.IsNullOrEmpty(areaName);
      //
                  List<ViewLocation> viewLocations = GetViewLocations(locations, (usingAreas) ? areaLocations : null);
      if (viewLocations.Count == 0)
      {
      throw new InvalidOperationException(String.Format(CultureInfo.CurrentCulture,
      MvcResources.Common_PropertyCannotBeNullOrEmpty, locationsPropertyName));
      }
      bool nameRepresentsPath = IsSpecificPath(name);
      string cacheKey = CreateCacheKey(cacheKeyPrefix, name, (nameRepresentsPath) ? String.Empty : controllerName, areaName);
      //是否使用緩存,其實就將一個已知的路徑保存在緩存表中,如果是第一次請求,緩存表中什么也么有啊,所以暫且不看它。
      if (useCache)
      {
      //根據(jù)請求上下文獲取可用的DisplayModelProvider
      IEnumerable<IDisplayMode> possibleDisplayModes = DisplayModeProvider.GetAvailableDisplayModesForContext(controllerContext.HttpContext, controllerContext.DisplayMode);
      foreach (IDisplayMode displayMode in possibleDisplayModes)
      {
      //displayMode.DisplayModeId就是“Mobile”,即:執(zhí)行DefaultDisplayMode有參數(shù)的構造函數(shù)
      string cachedLocation = ViewLocationCache.GetViewLocation(controllerContext.HttpContext, AppendDisplayModeToCacheKey(cacheKey, displayMode.DisplayModeId));
      if (cachedLocation == null)
      {
      // If any matching display mode location is not in the cache, fall back to the uncached behavior, which will repopulate all of our caches.
      return null;
      }
      // A non-empty cachedLocation indicates that we have a matching file on disk. Return that result.
      if (cachedLocation.Length > 0)
      {
      if (controllerContext.DisplayMode == null)
      {
      controllerContext.DisplayMode = displayMode;
      }
      return cachedLocation;
      }
      // An empty cachedLocation value indicates that we don't have a matching file on disk. Keep going down the list of possible display modes.
                      }
      // GetPath is called again without using the cache.
      return null;
      }
      else
      {
      //如果ViewResult的參數(shù)的第一個字符是:~ 或 /,則執(zhí)行第一個方法,否則執(zhí)行第二個方法!
      //第一個方法:直接指定了路徑去尋找
      //第二個方法:只通過試圖名稱再拼接路徑去尋找(用到了DisplayModeProvider)
      //第二個方法的viewLocations參數(shù)是含有8條數(shù)據(jù)的集合。
      return nameRepresentsPath
       GetPathFromSpecificName(controllerContext, name, cacheKey, ref searchedLocations)
      : GetPathFromGeneralName(controllerContext, viewLocations, name, controllerName, areaName, cacheKey, ref searchedLocations);
      }
      }
      private string GetPathFromGeneralName(ControllerContext controllerContext, List<ViewLocation> locations, string name, string controllerName, string areaName, string cacheKey, ref string[] searchedLocations)
      {
      string result = String.Empty;
      searchedLocations = new string[locations.Count];
      for (int i = 0; i < locations.Count; i++)
      {
      ViewLocation location = locations[i];
      //根據(jù)8種格式器創(chuàng)建路徑
      string virtualPath = location.Format(name, controllerName, areaName);
      //這里的controllerContext.DisplayMode屬性執(zhí)行DisplayModeProvider的GetDisplayMode、SetDisplayMode方法!
      DisplayInfo virtualPathDisplayInfo = DisplayModeProvider.GetDisplayInfoForVirtualPath(virtualPath, controllerContext.HttpContext, path => FileExists(controllerContext, path), controllerContext.DisplayMode);
      if (virtualPathDisplayInfo != null)
      {
      string resolvedVirtualPath = virtualPathDisplayInfo.FilePath;
      searchedLocations = _emptyLocations;
      result = resolvedVirtualPath;
      ViewLocationCache.InsertViewLocation(controllerContext.HttpContext, AppendDisplayModeToCacheKey(cacheKey, virtualPathDisplayInfo.DisplayMode.DisplayModeId), result);
      if (controllerContext.DisplayMode == null)
      {
      controllerContext.DisplayMode = virtualPathDisplayInfo.DisplayMode;
      }
      // Populate the cache for all other display modes. We want to cache both file system hits and misses so that we can distinguish
      // in future requests whether a file's status was evicted from the cache (null value) or if the file doesn't exist (empty string).
      //再執(zhí)行循環(huán)執(zhí)行除了適合的那個DefaultDisplayMode之外的所有DefaultDisplayMode對象,將所有存在的路徑封裝到DisplayInfo對象中,并添加到緩存表中,以便之后請求時直接去緩存中獲取。
      //例如:當前是手機的請求,則會通過執(zhí)行DisplayModeId='Mobile’的那個DefaultDisplayMode來獲取【視圖頁】的路徑(Index.Mobile.cshtml),
      //        但是在執(zhí)行完成之后,還會執(zhí)行DisplayModeId!='Mobile’所有其他的DefaultDisplayMode對象,也就是pc端請求時的路徑(Index.cshtml),將其加入緩存表中,以便下次請求時直接去緩存表中獲取。
      IEnumerable<IDisplayMode> allDisplayModes = DisplayModeProvider.Modes;
      foreach (IDisplayMode displayMode in allDisplayModes)
      {
      if (displayMode.DisplayModeId != virtualPathDisplayInfo.DisplayMode.DisplayModeId)
      {
      DisplayInfo displayInfoToCache = displayMode.GetDisplayInfo(controllerContext.HttpContext, virtualPath, virtualPathExists: path => FileExists(controllerContext, path));
      string cacheValue = String.Empty;
      if (displayInfoToCache != null && displayInfoToCache.FilePath != null)
      {
      cacheValue = displayInfoToCache.FilePath;
      }
      ViewLocationCache.InsertViewLocation(controllerContext.HttpContext, AppendDisplayModeToCacheKey(cacheKey, displayMode.DisplayModeId), cacheValue);
      }
      }
      break;
      }
      searchedLocations[i] = virtualPath;
      }
      return result;
      }
      private string GetPathFromSpecificName(ControllerContext controllerContext, string name, string cacheKey, ref string[] searchedLocations)
      {
      string result = name;
      if (!(FilePathIsSupported(name) && FileExists(controllerContext, name)))
      {
      result = String.Empty;
      searchedLocations = new[] { name };
      }
      ViewLocationCache.InsertViewLocation(controllerContext.HttpContext, cacheKey, result);
      return result;
      }
      private bool FilePathIsSupported(string virtualPath)
      {
      if (FileExtensions == null)
      {
      // legacy behavior for custom ViewEngine that might not set the FileExtensions property
      return true;
      }
      else
      {
      // get rid of the '.' because the FileExtensions property expects extensions withouth a dot.
      string extension = GetExtensionThunk(virtualPath).TrimStart('.');
      return FileExtensions.Contains(extension, StringComparer.OrdinalIgnoreCase);
      }
      }
      private static List<ViewLocation> GetViewLocations(string[] viewLocationFormats, string[] areaViewLocationFormats)
      {
      //將四個AreaAwareViewLocation和四個ViewLocation添加到 allLocations集合中!并返回
      //AreaAwareViewLocation繼承自ViewLocation
      List<ViewLocation> allLocations = new List<ViewLocation>();
      if (areaViewLocationFormats != null)
      {
      foreach (string areaViewLocationFormat in areaViewLocationFormats)
      {
      allLocations.Add(new AreaAwareViewLocation(areaViewLocationFormat));
      }
      }
      if (viewLocationFormats != null)
      {
      foreach (string viewLocationFormat in viewLocationFormats)
      {
      allLocations.Add(new ViewLocation(viewLocationFormat));
      }
      }
      return allLocations;
      }
      private static bool IsSpecificPath(string name)
      {
      char c = name[0];
      return (c == '~' || c == '/');
      }
      public virtual void ReleaseView(ControllerContext controllerContext, IView view)
      {
      IDisposable disposable = view as IDisposable;
      if (disposable != null)
      {
      disposable.Dispose();
      }
      }
      private class AreaAwareViewLocation : ViewLocation
      {
      public AreaAwareViewLocation(string virtualPathFormatString)
      : base(virtualPathFormatString)
      {
      }
      public override string Format(string viewName, string controllerName, string areaName)
      {
      return String.Format(CultureInfo.InvariantCulture, _virtualPathFormatString, viewName, controllerName, areaName);
      }
      }
      private class ViewLocation
      {
      protected string _virtualPathFormatString;
      public ViewLocation(string virtualPathFormatString)
      {
      _virtualPathFormatString = virtualPathFormatString;
      }
      public virtual string Format(string viewName, string controllerName, string areaName)
      {
      return String.Format(CultureInfo.InvariantCulture, _virtualPathFormatString, viewName, controllerName);
      }
      }
      }
      }
      復制代碼
      復制代碼
      // Copyright (c) Microsoft Open Technologies, Inc. All rights reserved. See License.txt in the project root for license information.
      using System.Collections.Generic;
      using System.Linq;
      namespace System.Web.WebPages
      {
      public sealed class DisplayModeProvider
      {
      public static readonly string MobileDisplayModeId = "Mobile";
      public static readonly string DefaultDisplayModeId = String.Empty;
      private static readonly object _displayModeKey = new object();
      private static readonly DisplayModeProvider _instance = new DisplayModeProvider();
      //默認情況下只有兩個DefaultDisplayMode,可以自定義并添加到該集合中!
      private readonly List<IDisplayMode> _displayModes = new List<IDisplayMode>
      {
      new DefaultDisplayMode(MobileDisplayModeId)
      {
      ContextCondition = context => context.GetOverriddenBrowser().IsMobileDevice
      },
      new DefaultDisplayMode()
      };
      internal DisplayModeProvider()
      {
      // The type is a psuedo-singleton. A user would gain nothing from constructing it since we won't use anything but DisplayModeProvider.Instance internally.
              }
      /// <summary>
      /// Restricts the search for Display Info to Display Modes either equal to or following the current
      /// Display Mode in Modes. For example, a page being rendered in the Default Display Mode will not
      /// display Mobile partial views in order to achieve a consistent look and feel.
      /// </summary>
      public bool RequireConsistentDisplayMode { get; set; }
      public static DisplayModeProvider Instance
      {
      get { return _instance; }
      }
      /// <summary>
      /// All Display Modes that are available to handle a request.
      /// </summary>
      public IList<IDisplayMode> Modes
      {
      get { return _displayModes; }
      }
      //這個方法的功能:如果指定集合中的某個DefaultDisplayMode來處理請求的話,則直接從它開始。可以在HomeController中通過this.ControllerContext.DisplayMode來設置。
      private int FindFirstAvailableDisplayMode(IDisplayMode currentDisplayMode, bool requireConsistentDisplayMode)
      {
      if (requireConsistentDisplayMode && currentDisplayMode != null)
      {
      //如果集合中么有和當前currentDisplayMode匹配的話,first值為 -1
      int first = _displayModes.IndexOf(currentDisplayMode);
      return (first >= 0) ? first : _displayModes.Count;
      }
      return 0;
      }
      /// <summary>
      /// Returns any IDisplayMode that can handle the given request.
      /// </summary>
      public IEnumerable<IDisplayMode> GetAvailableDisplayModesForContext(HttpContextBase httpContext, IDisplayMode currentDisplayMode)
      {
      return GetAvailableDisplayModesForContext(httpContext, currentDisplayMode, RequireConsistentDisplayMode);
      }
      internal IEnumerable<IDisplayMode> GetAvailableDisplayModesForContext(HttpContextBase httpContext, IDisplayMode currentDisplayMode, bool requireConsistentDisplayMode)
      {
      int first = FindFirstAvailableDisplayMode(currentDisplayMode, requireConsistentDisplayMode);
      for (int i = first; i < _displayModes.Count; i++)
      {
      IDisplayMode mode = _displayModes[i];
      if (mode.CanHandleContext(httpContext))
      {
      yield return mode;
      }
      }
      }
      /// <summary>
      /// Returns DisplayInfo from the first IDisplayMode in Modes that can handle the given request and locate the virtual path.
      /// If currentDisplayMode is not null and RequireConsistentDisplayMode is set to true the search for DisplayInfo will only
      /// start with the currentDisplayMode.
      /// </summary>
      public DisplayInfo GetDisplayInfoForVirtualPath(string virtualPath, HttpContextBase httpContext, Func<string, bool> virtualPathExists, IDisplayMode currentDisplayMode)
      {
      //默認RequireConsistentDisplayMode為false
      return GetDisplayInfoForVirtualPath(virtualPath, httpContext, virtualPathExists, currentDisplayMode, RequireConsistentDisplayMode);
      }
      internal DisplayInfo GetDisplayInfoForVirtualPath(string virtualPath, HttpContextBase httpContext, Func<string, bool> virtualPathExists, IDisplayMode currentDisplayMode,
      bool requireConsistentDisplayMode)
      {
      // Performance sensitive
      int first = FindFirstAvailableDisplayMode(currentDisplayMode, requireConsistentDisplayMode);
      for (int i = first; i < _displayModes.Count; i++)
      {
      IDisplayMode mode = _displayModes[i];
      if (mode.CanHandleContext(httpContext))
      {
      DisplayInfo info = mode.GetDisplayInfo(httpContext, virtualPath, virtualPathExists);
      if (info != null)
      {
      return info;
      }
      }
      }
      return null;
      }
      internal static IDisplayMode GetDisplayMode(HttpContextBase context)
      {
      return context != null  context.Items[_displayModeKey] as IDisplayMode : null;
      }
      internal static void SetDisplayMode(HttpContextBase context, IDisplayMode displayMode)
      {
      if (context != null)
      {
      context.Items[_displayModeKey] = displayMode;
      }
      }
      }
      }
      復制代碼
      復制代碼
      // Copyright (c) Microsoft Open Technologies, Inc. All rights reserved. See License.txt in the project root for license information.
      using System.IO;
      namespace System.Web.WebPages
      {
      public class DefaultDisplayMode : IDisplayMode
      {
      //通過構造函數(shù)賦值,MVC會創(chuàng)建兩個DefaultDisplayMode對象,將其中一個對象的該字段值設置為“Mobile”
      private readonly string _suffix;
      public DefaultDisplayMode()
      : this(DisplayModeProvider.DefaultDisplayModeId)
      {
      }
      public DefaultDisplayMode(string suffix)
      {
      _suffix = suffix ?? String.Empty;
      }
      public Func<HttpContextBase, bool> ContextCondition { get; set; }
      public virtual string DisplayModeId
      {
      get { return _suffix; }
      }
      public bool CanHandleContext(HttpContextBase httpContext)
      {
      return ContextCondition == null || ContextCondition(httpContext);
      }
      public virtual DisplayInfo GetDisplayInfo(HttpContextBase httpContext, string virtualPath, Func<string, bool> virtualPathExists)
      {
      //調用TransformPath方法,將尋找【View視圖頁】路徑設置為 xxx.Mobile.cshtml
      string transformedFilename = TransformPath(virtualPath, _suffix);
      if (transformedFilename != null && virtualPathExists(transformedFilename))
      {
      return new DisplayInfo(transformedFilename, this);
      }
      return null;
      }
      protected virtual string TransformPath(string virtualPath, string suffix)
      {
      if (String.IsNullOrEmpty(suffix))
      {
      return virtualPath;
      }
      string extension = Path.GetExtension(virtualPath);
      return Path.ChangeExtension(virtualPath, suffix + extension);
      }
      }
      }
      復制代碼

      由以上源碼可知,默認情況下,ASP.NET MVC4在DisplayModeProvider中定義了一個含有兩個DefaultDisplayMode對象(用于對地址再處理)的集合:

      1
      2
      3
      4
      5
      6
      7
      8
      9
      public static readonly string MobileDisplayModeId = "Mobile";
      private readonly List<IDisplayMode> _displayModes = new List<IDisplayMode>
      {
      new DefaultDisplayMode(MobileDisplayModeId)
      {
      ContextCondition = context => context.GetOverriddenBrowser().IsMobileDevice
      },
      new DefaultDisplayMode()
      };

      由于處理時,是按照遍歷執(zhí)行_displayModes集合中DefaultDisplayMode對象的GetDisplayInfo方法(索引值從0開始),所以無論是 PC 還是 Phone發(fā)送的請求,都會先執(zhí)集合中的第一個DefaultDisplayMode對象(判斷是否為手機的請求)。如果Phone端發(fā)送請求,會去尋找xxx.Mobile.cshtml,如果沒有的話,就繼續(xù)執(zhí)行第二個DefaultDisplayMode對象,去尋找xxx.cshtml。如果是PC端發(fā)送請求,也是首先執(zhí)行第一個DefaultDisplayMode對象,但是由于不滿足 context => context.GetOverriddenBrowser().IsMobileDevice 條件,所以還是需要去執(zhí)行第二個DefaultDisplayMode對象,去尋找xxx.cshtml。

      擴展:
      1、指定DisplayMode

      模擬需求:對Phone端用戶的某個Action請求,返回電腦版網(wǎng)頁。

      1
      2
      3
      4
      5
      6
      7
      public ActionResult Index()
      {
      //一些判斷條件
      this.ControllerContext.DisplayMode = DisplayModeProvider.Instance.Modes[1];
      DisplayModeProvider.Instance.RequireConsistentDisplayMode = true;
      return View();
      }

        根據(jù)上述設置,即使是Phone端的請求并且還存在Index.Mobile.cshtml文件,也會去執(zhí)行Index.cshtml,即:實現(xiàn)Phone用戶訪問電腦版網(wǎng)頁。

      2、自定義DisplayMode

      模擬需求:為Android 2.3用戶設置特定的頁面

      先創(chuàng)建一個類似于Index.Android23.cshtml 的頁面,然后在Global.asax中做如下設置即可:

      1
      2
      3
      4
      5
      6
      7
      8
      9
      10
      11
      12
      13
      14
      15
      16
      17
      18
      19
      public class MvcApplication : System.Web.HttpApplication
      {
      protected void Application_Start()
      {
      AreaRegistration.RegisterAllAreas();
      WebApiConfig.Register(GlobalConfiguration.Configuration);
      FilterConfig.RegisterGlobalFilters(GlobalFilters.Filters);
      RouteConfig.RegisterRoutes(RouteTable.Routes);
      BundleConfig.RegisterBundles(BundleTable.Bundles);
      AuthConfig.RegisterAuth();
      DisplayModeProvider.Instance.Modes.Insert(0, new DefaultDisplayMode("Android23")
      {
      ContextCondition = (context => context.GetOverriddenUserAgent().IndexOf
      ("Android 2.3", StringComparison.OrdinalIgnoreCase) >= 0)
      });
      }
      }

       

      以上就是所有內容,如有不適之處,請指正??!

        本站是提供個人知識管理的網(wǎng)絡存儲空間,所有內容均由用戶發(fā)布,不代表本站觀點。請注意甄別內容中的聯(lián)系方式、誘導購買等信息,謹防詐騙。如發(fā)現(xiàn)有害或侵權內容,請點擊一鍵舉報。
        轉藏 分享 獻花(0

        0條評論

        發(fā)表

        請遵守用戶 評論公約

        類似文章 更多