2009-05-26 16 views
30

Geçerli UI kültürüne dayalı çalışma saatlerinde görünüm konumlarını değiştirmek istiyorum. Bunu varsayılan Web Formu görüntüleme altyapısıyla nasıl başarabilirim?ASP.NET MVC'deki varsayılan görünüm konum şemasını nasıl değiştirebilirim?

Temel olarak, WebFormViewEngine ile Spark içinde custom IDescriptorFilter nedir?

Görüntüleme konumları üzerinde çalışma zamanı kontrolü sağlayan başka bir görünüm motoru var mı?


Düzenleme: Benim URL'ler görünüyor {lang}/{controller}/{action}/{id} aşağıdaki olmalıdır. Dil bağımlı denetleyicilere ihtiyacım yok ve görünümler kaynaklarla yerelleştiriliyor. Ancak bazı dillerde görüntülerin az bir kısmı farklı olacaktır. Bu yüzden, görüntü motoruna önce dile özgü klasöre bakmasını söylemeliyim.

cevap

31

basit bir çözüm ViewEngines.Engines koleksiyonundan uygun ViewEngine sizin Appication_Start olsun ambarındaki için hale gelmek ve ViewLocationFormats dizi ve PartialViewLocationFormats güncellemek olacaktır. Korsanlık yok: varsayılan olarak okunur/yazılır.

protected void Application_Start() 
{ 
    ... 
    // Allow looking up views in ~/Features/ directory 
    var razorEngine = ViewEngines.Engines.OfType<RazorViewEngine>().First(); 
    razorEngine.ViewLocationFormats = razorEngine.ViewLocationFormats.Concat(new string[] 
    { 
     "~/Features/{1}/{0}.cshtml" 
    }).ToArray(); 
    ... 
    // also: razorEngine.PartialViewLocationFormats if required 
} 

Razor looks like this için varsayılan bir: Ayrıca PartialViewLocationFormats güncellemek isteyebilirsiniz

ViewLocationFormats = new string[] 
{ 
    "~/Views/{1}/{0}.cshtml", 
    "~/Views/{1}/{0}.vbhtml", 
    "~/Views/Shared/{0}.cshtml", 
    "~/Views/Shared/{0}.vbhtml" 
}; 

Not.

+0

Bu, çalışma zamanında güzel çalıştı. Ancak, yeni özel konumu tanımak için VS 2013 (veya muhtemelen ReSharper) almak için görünmüyor olabilir. Tanımlamaya F12 yeteneğini kaybettim ve çağrı bir hata olarak işaretlendi. Aynı sorunu yaşıyor musunuz? Özel bir kısmi görünüm konumunu kullanıma sundum. Teşekkürler. –

+0

"Aynı sorunu yaşıyor musunuz" hayır, ama Resharper'ı kullanmıyorum, bu yüzden ne yapacağınızı bilemiyorum. –

+2

+1, en fazla – Brad

1

Bu çözümün, WebFormViewEngine'den gelen kendi ViewEngine'ınızı oluşturması gerektiğine inanıyorum. Yapıcıda, mevcut UI kültürünü mevcut iş parçacığından kontrol etmeli ve uygun yerleri eklemelidir. Sadece görünüm motorlarına eklemeyi unutma.

Bu şuna benzer olmalıdır:

public class ViewEngine : WebFormViewEngine 
{ 
    public ViewEngine() 
    { 
     if (CultureIsX()) 
      ViewLocationFormats = new string[]{"route1/controller.aspx"}; 
     if (CultureIsY()) 
      ViewLocationFormats = new string[]{"route2/controller.aspx"}; 
    } 
} 

Global.asax içinde:

ViewEngines.Engines.Add(new ViewEngine()); 
+1

Ayrıca, http://www.codeplex.com/oxite projesinde de uygulamayı görebilirsiniz. – pocheptsov

+2

Üzgünüm, bu ViewEngine örneği iş parçacıkları boyunca paylaşıldığından ve iş parçacığı UI kültürüne dayalı olarak farklı bir görünüm oluşturmamız gerektiğinden bu iyi bir çözüm değildir. –

+0

Belki de her kültür için viewEngine eklemek ve thread farklıysa onları kesmek için findView yöntemlerini geçersiz kılmak mümkündür. Sadece tuhaf bir fikir ... –

8

VirtualPathProviderViewEngine.GetPathFromGeneralName rotadan ek bir parametre izin değiştirilmelidir. Onun kamuya açık değil, bu yüzden kendi ViewEngine uygulamasına GetPath, GetPathFromGeneralName, IsSpecificPath kopyalamak zorunda.

Haklısınız: Bu tam bir yeniden yazmaya benziyor. GetPathFromGeneralName'un herkese açık olmasını istedim.

using System.Web.Mvc; 
using System; 
using System.Web.Hosting; 
using System.Globalization; 
using System.Linq; 

namespace MvcLocalization 
{ 
    public class LocalizationWebFormViewEngine : WebFormViewEngine 
    { 
     private const string _cacheKeyFormat = ":ViewCacheEntry:{0}:{1}:{2}:{3}:"; 
     private const string _cacheKeyPrefix_Master = "Master"; 
     private const string _cacheKeyPrefix_Partial = "Partial"; 
     private const string _cacheKeyPrefix_View = "View"; 
     private static readonly string[] _emptyLocations = new string[0]; 

     public LocalizationWebFormViewEngine() 
     { 
      base.ViewLocationFormats = new string[] { 
        "~/Views/{1}/{2}/{0}.aspx", 
        "~/Views/{1}/{2}/{0}.ascx", 
        "~/Views/Shared/{2}/{0}.aspx", 
        "~/Views/Shared/{2}/{0}.ascx" , 
        "~/Views/{1}/{0}.aspx", 
        "~/Views/{1}/{0}.ascx", 
        "~/Views/Shared/{0}.aspx", 
        "~/Views/Shared/{0}.ascx" 

      }; 

     } 

     private VirtualPathProvider _vpp; 

     public override ViewEngineResult FindView(ControllerContext controllerContext, string viewName, string masterName, bool useCache) 
     { 
      if (controllerContext == null) 
       throw new ArgumentNullException("controllerContext"); 

      if (String.IsNullOrEmpty(viewName)) 
       throw new ArgumentException("viewName"); 

      string[] viewLocationsSearched; 
      string[] masterLocationsSearched; 

      string controllerName = controllerContext.RouteData.GetRequiredString("controller"); 
      string viewPath = GetPath(controllerContext, ViewLocationFormats, "ViewLocationFormats", viewName, controllerName, _cacheKeyPrefix_View, useCache, out viewLocationsSearched); 
      string masterPath = GetPath(controllerContext, MasterLocationFormats, "MasterLocationFormats", masterName, controllerName, _cacheKeyPrefix_Master, 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 locationsPropertyName, string name, string controllerName, string cacheKeyPrefix, bool useCache, out string[] searchedLocations) 
     { 
      searchedLocations = _emptyLocations; 

      if (String.IsNullOrEmpty(name)) 
       return String.Empty; 

      if (locations == null || locations.Length == 0) 
       throw new InvalidOperationException(); 

      bool nameRepresentsPath = IsSpecificPath(name); 
      string cacheKey = CreateCacheKey(cacheKeyPrefix, name, (nameRepresentsPath) ? String.Empty : controllerName); 

      if (useCache) 
      { 
       string result = ViewLocationCache.GetViewLocation(controllerContext.HttpContext, cacheKey); 
       if (result != null) 
       { 
        return result; 
       } 
      } 

      return (nameRepresentsPath) ? 
       GetPathFromSpecificName(controllerContext, name, cacheKey, ref searchedLocations) : 
       GetPathFromGeneralName(controllerContext, locations, name, controllerName, cacheKey, ref searchedLocations); 
     } 

     private string GetPathFromGeneralName(ControllerContext controllerContext, string[] locations, string name, string controllerName, string cacheKey, ref string[] searchedLocations) 
     { 
      string result = String.Empty; 
      searchedLocations = new string[locations.Length]; 
      string language = controllerContext.RouteData.Values["lang"].ToString(); 

      for (int i = 0; i < locations.Length; i++) 
      { 
       string virtualPath = String.Format(CultureInfo.InvariantCulture, locations[i], name, controllerName,language); 

       if (FileExists(controllerContext, virtualPath)) 
       { 
        searchedLocations = _emptyLocations; 
        result = virtualPath; 
        ViewLocationCache.InsertViewLocation(controllerContext.HttpContext, cacheKey, result); 
        break; 
       } 

       searchedLocations[i] = virtualPath; 
      } 

      return result; 
     } 

     private string CreateCacheKey(string prefix, string name, string controllerName) 
     { 
      return String.Format(CultureInfo.InvariantCulture, _cacheKeyFormat, 
       GetType().AssemblyQualifiedName, prefix, name, controllerName); 
     } 

     private string GetPathFromSpecificName(ControllerContext controllerContext, string name, string cacheKey, ref string[] searchedLocations) 
     { 
      string result = name; 

      if (!FileExists(controllerContext, name)) 
      { 
       result = String.Empty; 
       searchedLocations = new[] { name }; 
      } 

      ViewLocationCache.InsertViewLocation(controllerContext.HttpContext, cacheKey, result); 
      return result; 
     } 

     private static bool IsSpecificPath(string name) 
     { 
      char c = name[0]; 
      return (c == '~' || c == '/'); 
     } 

    } 
} 
+0

Bana tamamen WebFormViewEngine yeniden yazma gibi görünüyor. –

+1

Yukarıdaki gibi kod kullanan diğer kişilere bir not. FindPartialView'ı, ana sayfa dosyası/konumlarıyla ilgili kodun eksi olarak FindView uygulandığı şekilde de geçersiz kılmalısınız. – sdanna

3

1)

public class LocalizationWebFormViewEngine : RazorViewEngine

2) kısmen yer biçimleri

public LocalizationWebFormViewEngine() 
{ 
    base.PartialViewLocationFormats = new string[] { 
     "~/Views/{2}/{1}/{0}.cshtml", 
     "~/Views/{2}/{1}/{0}.aspx", 
     "~/Views/{2}/Shared/{0}.cshtml", 
     "~/Views/{2}/Shared/{0}.aspx" 
    }; 

    base.ViewLocationFormats = new string[] { 
     "~/Views/{2}/{1}/{0}.cshtml", 
     "~/Views/{2}/{1}/{0}.aspx", 
     "~/Views/{2}/Shared/{0}.cshtml", 
     "~/Views/{2}/Shared/{0}.aspx" 
    }; 
} 
)

işlemek kısmi görünümü geçersiz kılma yöntemi oluşturmak ekleme makinesi görünüşüdür motorundan sınıf uzatmak
public override ViewEngineResult FindPartialView(ControllerContext controllerContext, String partialViewName, Boolean useCache) 
{ 
    if (controllerContext == null) 
    { 
     throw new ArgumentNullException("controllerContext"); 
    } 
    if (String.IsNullOrEmpty(partialViewName)) 
    { 
     throw new ArgumentException("partialViewName"); 
    } 

    string[] partialViewLocationsSearched; 

    string controllerName = controllerContext.RouteData.GetRequiredString("controller"); 
    string partialPath = GetPath(controllerContext, PartialViewLocationFormats, "PartialViewLocationFormats", partialViewName, controllerName, _cacheKeyPrefix_Partial, useCache, out partialViewLocationsSearched); 

    return new ViewEngineResult(CreatePartialView(controllerContext, partialPath), this);} 
} 
+1

GetPath özel bir yöntemdir, böylece erişemezsiniz. –

1

Aşağıda, yeniden yazma işlemi olmayan yerelleştirilmiş bir görüntü motoru var. Özetle, motor görünüm konumlarına görünüm konumlarına yeni konumlar ekleyecektir. her zaman bir görünüm yukarı bakacaktır. Motor, görünümü bulmak için iki karakter dilini kullanacaktır. Geçerli dil es (İspanyolca) ise, ~/Views/Home/Index.es.cshtml'u arar.

Daha fazla ayrıntı için kod açıklamalarına bakın.

Görünüm konumlarının ayrıştırılma şeklini geçersiz kılmak daha iyi bir yaklaşım olabilir, ancak yöntemler geçersiz kılmayacaktır; belki de ASP.NET MVC 5?

public class LocalizedViewEngine : RazorViewEngine 
{ 
    private string[] _defaultViewLocationFormats; 

    public LocalizedViewEngine() 
     : base() 
    { 
     // Store the default locations which will be used to append 
     // the localized view locations based on the thread Culture 
     _defaultViewLocationFormats = base.ViewLocationFormats; 
    } 

    public override ViewEngineResult FindPartialView(ControllerContext controllerContext, string partialViewName, bool useCache) 
    { 
     AppendLocalizedLocations(); 
     return base.FindPartialView(controllerContext, partialViewName, useCache:fase); 
    } 

    public override ViewEngineResult FindView(ControllerContext controllerContext, string viewName, string masterName, bool useCache) 
    { 
     AppendLocalizedLocations(); 
     returnbase.FindView(controllerContext, viewName, masterName, useCache:false); 
    } 

    private void AppendLocalizedLocations() 
    { 
     // Use language two letter name to identify the localized view 
     string lang = Thread.CurrentThread.CurrentUICulture.TwoLetterISOLanguageName; 

     // Localized views will be in the format "{action}.{lang}.cshtml" 
     string localizedExtension = string.Format(".{0}.cshtml", lang); 

     // Create an entry for views and layouts using localized extension 
     string view = "~/Views/{1}/{0}.cshtml".Replace(".cshtml", localizedExtension); 
     string shared = "~/Views/{1}/Shared/{0}".Replace(".cshtml", localizedExtension); 

     // Create a copy of the default view locations to modify 
     var list = _defaultViewLocationFormats.ToList(); 

     // Insert the new locations at the top of the list of locations 
     // so they're used before non-localized views. 
     list.Insert(0, shared); 
     list.Insert(0, view); 
     base.ViewLocationFormats = list.ToArray(); 
    } 
} 
+1

Farklı kültürlerle ilgili birçok isteğiniz varsa, birbirinize adım atmakta zorluk çekmez misiniz? –

+0

Brian ne dedi. İş parçacığı güvenli görünmüyor. –

İlgili konular