ASP.NET MVC'de "görünüm aramak" için özel bir konum belirtebilir miyim?


105

Mvc projem için aşağıdaki düzene sahibim:

  • / Denetleyiciler
    • / Demo
    • / Demo / DemoArea1Controller
    • / Demo / DemoArea2Controller
    • vb...
  • /Görüntüleme
    • / Demo
    • /Demo/DemoArea1/Index.aspx
    • /Demo/DemoArea2/Index.aspx

Ancak, buna sahip olduğumda DemoArea1Controller:

public class DemoArea1Controller : Controller
{
    public ActionResult Index()
    {
        return View();
    }
}

Her zamanki arama konumlarında "Görünüm 'dizini' veya yöneticisi bulunamadı" hatası alıyorum.

Denetleyicileri, "Demo" görünüm alt klasöründeki "Demo" ad alanı aramasında nasıl belirtebilirim?


Rob Connery'nin MVC Commerce uygulamasından basit bir ViewEngine örneği: View Engine Code ve ViewEngine'i ayarlamak için Global.asax.cs kodu: Global.asax.cs Umarım bu yardımcı olur.
Robert Dean

Yanıtlar:


121

Bakmak istediğiniz tüm konumları belirtmek için WebFormViewEngine'i kolayca genişletebilirsiniz:

public class CustomViewEngine : WebFormViewEngine
{
    public CustomViewEngine()
    {
        var viewLocations =  new[] {  
            "~/Views/{1}/{0}.aspx",  
            "~/Views/{1}/{0}.ascx",  
            "~/Views/Shared/{0}.aspx",  
            "~/Views/Shared/{0}.ascx",  
            "~/AnotherPath/Views/{0}.ascx"
            // etc
        };

        this.PartialViewLocationFormats = viewLocations;
        this.ViewLocationFormats = viewLocations;
    }
}

Global.asax.cs dosyanızda Application_Start yöntemini değiştirerek görünüm motorunu kaydetmeyi unutmayın.

protected void Application_Start()
{
    ViewEngines.Engines.Clear();
    ViewEngines.Engines.Add(new CustomViewEngine());
}

İç içe geçmiş bir kalıp sayfadan bir ana sayfanın yoluna nasıl erişebilirsiniz?
CustomViewEngine

6
Halihazırda kayıtlı motorları temizlemeyi atlayıp sadece yenisini ekleyip, ViewLocations'ta yalnızca yenilerini alsak daha iyi olmaz mı?
Prasanna

3
ViewEngines.Engines.Clear () olmadan uygular; Hepsi iyi çalışıyor. * .Cshtml kullanmak istiyorsanız RazorViewEngine
KregHEk'ten

Denetleyicilerdeki "görünüm ekle" ve "görünüme git" seçeneklerini yeni görünüm konumlarına bağlayabileceğimiz bir yol var mı? visual studio 2012 kullanıyorum
Neville Nazerane

@Prasanna tarafından belirtildiği gibi, yeni konumlar eklemek için mevcut motorları temizlemeye gerek yoktur, daha fazla ayrıntı için bu yanıta bakın.
Hooman Bahreini

45

Artık MVC 6'da IViewLocationExpander, görünüm motorlarıyla uğraşmadan arabirim uygulayabilirsiniz :

public class MyViewLocationExpander : IViewLocationExpander
{
    public void PopulateValues(ViewLocationExpanderContext context) {}

    public IEnumerable<string> ExpandViewLocations(ViewLocationExpanderContext context, IEnumerable<string> viewLocations)
    {
        return new[]
        {
            "/AnotherPath/Views/{1}/{0}.cshtml",
            "/AnotherPath/Views/Shared/{0}.cshtml"
        }; // add `.Union(viewLocations)` to add default locations
    }
}

{0}hedef görünüm adı nerede , {1}- denetleyici adı ve {2}- alan adı.

Kendi konum listenizi iade edebilir, varsayılan ile birleştirebilir viewLocations( .Union(viewLocations)) veya sadece değiştirebilirsiniz ( viewLocations.Select(path => "/AnotherPath" + path)).

Özel görünüm konum genişleticinizi MVC'ye kaydetmek için ConfigureServices, Startup.csdosyadaki yönteme sonraki satırları ekleyin :

public void ConfigureServices(IServiceCollection services)
{
    services.Configure<RazorViewEngineOptions>(options =>
    {
        options.ViewLocationExpanders.Add(new MyViewLocationExpander());
    });
}

3
Keşke bunu 10 oyla oylayabilsem. Asp.net 5 / MVC 6'da tam olarak ihtiyaç duyulan şeydir. Güzel. Benim durumumda (ve diğerlerinde) alanları daha büyük siteler veya mantıksal gruplar için süper alanlar halinde gruplamak istediğinizde çok kullanışlıdır.
2015

Startup.cs bölümü şu şekilde olmalıdır: services.Configure <RazorViewEngineOptions> Bu yönteme uygun: public void ConfigureServices (IServiceCollection services)
OrangeKing89

42

Yolları kurucunuza sabit kodlamadan çok daha kolay bir yöntem var. Aşağıda, Razor motorunu yeni yollar eklemek için genişletmenin bir örneği verilmiştir. Tamamen emin olmadığım bir şey, buraya eklediğiniz yolların önbelleğe alınıp alınmayacağı:

public class ExtendedRazorViewEngine : RazorViewEngine
{
    public void AddViewLocationFormat(string paths)
    {
        List<string> existingPaths = new List<string>(ViewLocationFormats);
        existingPaths.Add(paths);

        ViewLocationFormats = existingPaths.ToArray();
    }

    public void AddPartialViewLocationFormat(string paths)
    {
        List<string> existingPaths = new List<string>(PartialViewLocationFormats);
        existingPaths.Add(paths);

        PartialViewLocationFormats = existingPaths.ToArray();
    }
}

Ve Global.asax.cs

protected void Application_Start()
{
    ViewEngines.Engines.Clear();

    ExtendedRazorViewEngine engine = new ExtendedRazorViewEngine();
    engine.AddViewLocationFormat("~/MyThemes/{1}/{0}.cshtml");
    engine.AddViewLocationFormat("~/MyThemes/{1}/{0}.vbhtml");

    // Add a shared location too, as the lines above are controller specific
    engine.AddPartialViewLocationFormat("~/MyThemes/{0}.cshtml");
    engine.AddPartialViewLocationFormat("~/MyThemes/{0}.vbhtml");

    ViewEngines.Engines.Add(engine);

    AreaRegistration.RegisterAllAreas();
    RegisterRoutes(RouteTable.Routes);
}

Unutulmaması gereken bir şey: özel konumunuzun, kökünde ViewStart.cshtml dosyasına ihtiyacı olacaktır.


23

Yalnızca yeni yollar eklemek istiyorsanız, varsayılan görünüm motorlarına ekleyebilir ve bazı kod satırlarını yedekleyebilirsiniz:

ViewEngines.Engines.Clear();
var razorEngine = new RazorViewEngine();
razorEngine.MasterLocationFormats = razorEngine.MasterLocationFormats
      .Concat(new[] { 
          "~/custom/path/{0}.cshtml" 
      }).ToArray();

razorEngine.PartialViewLocationFormats = razorEngine.PartialViewLocationFormats
      .Concat(new[] { 
          "~/custom/path/{1}/{0}.cshtml",   // {1} = controller name
          "~/custom/path/Shared/{0}.cshtml" 
      }).ToArray();

ViewEngines.Engines.Add(razorEngine);

Aynısı için de geçerlidir WebFormEngine


2
Görünümler için: razorEngine.ViewLocationFormats kullanın.
Aldentev

13

RazorViewEngine'i alt sınıflandırmak veya doğrudan değiştirmek yerine, yalnızca mevcut RazorViewEngine'in PartialViewLocationFormats özelliğini değiştirebilirsiniz. Bu kod Application_Start'a giriyor:

System.Web.Mvc.RazorViewEngine rve = (RazorViewEngine)ViewEngines.Engines
  .Where(e=>e.GetType()==typeof(RazorViewEngine))
  .FirstOrDefault();

string[] additionalPartialViewLocations = new[] { 
  "~/Views/[YourCustomPathHere]"
};

if(rve!=null)
{
  rve.PartialViewLocationFormats = rve.PartialViewLocationFormats
    .Union( additionalPartialViewLocations )
    .ToArray();
}

2
Bu, jilet motor türünün 'RazorViewEngine' yerine 'FixedRazorViewEngine' olması dışında benim için çalıştı. Ayrıca, uygulamamın başarılı bir şekilde başlatılmasını engellediği için motor bulunmazsa bir istisna atarım.
Rob

3

Son kontrol ettiğimde, bu kendi ViewEngine'inizi oluşturmanızı gerektiriyor. RC1'de bunu daha kolay hale getirip getirmediklerini bilmiyorum.

İlk RC'den önce kullandığım temel yaklaşım, kendi ViewEngine'imde, denetleyicinin ad alanını bölmek ve parçalarla eşleşen klasörleri aramaktı.

DÜZENLE:

Geri dönüp kodu buldum. İşte genel fikir.

public override ViewEngineResult FindView(ControllerContext controllerContext, string viewName, string masterName)
{
    string ns = controllerContext.Controller.GetType().Namespace;
    string controller = controllerContext.Controller.GetType().Name.Replace("Controller", "");

    //try to find the view
    string rel = "~/Views/" +
        (
            ns == baseControllerNamespace ? "" :
            ns.Substring(baseControllerNamespace.Length + 1).Replace(".", "/") + "/"
        )
        + controller;
    string[] pathsToSearch = new string[]{
        rel+"/"+viewName+".aspx",
        rel+"/"+viewName+".ascx"
    };

    string viewPath = null;
    foreach (var path in pathsToSearch)
    {
        if (this.VirtualPathProvider.FileExists(path))
        {
            viewPath = path;
            break;
        }
    }

    if (viewPath != null)
    {
        string masterPath = null;

        //try find the master
        if (!string.IsNullOrEmpty(masterName))
        {

            string[] masterPathsToSearch = new string[]{
                rel+"/"+masterName+".master",
                "~/Views/"+ controller +"/"+ masterName+".master",
                "~/Views/Shared/"+ masterName+".master"
            };


            foreach (var path in masterPathsToSearch)
            {
                if (this.VirtualPathProvider.FileExists(path))
                {
                    masterPath = path;
                    break;
                }
            }
        }

        if (string.IsNullOrEmpty(masterName) || masterPath != null)
        {
            return new ViewEngineResult(
                this.CreateView(controllerContext, viewPath, masterPath), this);
        }
    }

    //try default implementation
    var result = base.FindView(controllerContext, viewName, masterName);
    if (result.View == null)
    {
        //add the location searched
        return new ViewEngineResult(pathsToSearch);
    }
    return result;
}

1
Aslında çok daha kolay. Alt sınıf WebFormsViewEngine ve ardından kurucunuzda zaten aradığı yollar dizisine ekleyin.
Craig Stuntz

Bunu bildiğim iyi oldu. Bu koleksiyonu en son değiştirmem gerektiğinde, bu şekilde mümkün değildi.
Joel

"BaseControllerNamespace" değişkenini temel denetleyici ad alanınıza (örn. "Project.Controllers") ayarlamanız gerektiğini, ancak aksi takdirde gönderildikten 7 yıl sonra tam olarak ihtiyacım olan şeyi yaptığınızı belirtmek gerekir.
prototype14

3

Bunun gibi bir şey dene:

private static void RegisterViewEngines(ICollection<IViewEngine> engines)
{
    engines.Add(new WebFormViewEngine
    {
        MasterLocationFormats = new[] {"~/App/Views/Admin/{0}.master"},
        PartialViewLocationFormats = new[] {"~/App/Views/Admin//{1}/{0}.ascx"},
        ViewLocationFormats = new[] {"~/App/Views/Admin//{1}/{0}.aspx"}
    });
}

protected void Application_Start()
{
    RegisterViewEngines(ViewEngines.Engines);
}

3

Not: ASP.NET MVC 2 için, 'Alanlar'daki görünümler için ayarlamanız gereken ek konum yolları vardır.

 AreaViewLocationFormats
 AreaPartialViewLocationFormats
 AreaMasterLocationFormats

Bir Alan için bir görünüm motoru oluşturmak Phil'in blogunda anlatılmıştır .

Not: Bu önizleme sürümü 1 içindir, bu nedenle değiştirilebilir.


1

Buradaki yanıtların çoğu , mevcut konumları arayarak temizleyinViewEngines.Engines.Clear() ve ardından tekrar ekleyin ... Bunu yapmaya gerek yok.

Yeni konumları aşağıda gösterildiği gibi mevcut yerlere ekleyebiliriz:

// note that the base class is RazorViewEngine, NOT WebFormViewEngine
public class ExpandedViewEngine : RazorViewEngine
{
    public ExpandedViewEngine()
    {
        var customViewSubfolders = new[] 
        {
            // {1} is conroller name, {0} is action name
            "~/Areas/AreaName/Views/Subfolder1/{1}/{0}.cshtml",
            "~/Areas/AreaName/Views/Subfolder1/Shared/{0}.cshtml"
        };

        var customPartialViewSubfolders = new[] 
        {
            "~/Areas/MyAreaName/Views/Subfolder1/{1}/Partials/{0}.cshtml",
            "~/Areas/MyAreaName/Views/Subfolder1/Shared/Partials/{0}.cshtml"
        };

        ViewLocationFormats = ViewLocationFormats.Union(customViewSubfolders).ToArray();
        PartialViewLocationFormats = PartialViewLocationFormats.Union(customPartialViewSubfolders).ToArray();

        // use the following if you want to extend the master locations
        // MasterLocationFormats = MasterLocationFormats.Union(new[] { "new master location" }).ToArray();   
    }
}

Artık projenizi RazorViewEngineGlobal.asax'ta yukarıdakileri kullanacak şekilde yapılandırabilirsiniz :

protected void Application_Start()
{
    ViewEngines.Engines.Add(new ExpandedViewEngine());
    // more configurations
}

Daha fazla bilgi için bu eğiticiye bakın .

Sitemizi kullandığınızda şunları okuyup anladığınızı kabul etmiş olursunuz: Çerez Politikası ve Gizlilik Politikası.
Licensed under cc by-sa 3.0 with attribution required.