it-swarm.asia

هل يمكنني تحديد موقع مخصص "للبحث عن طرق العرض" في ASP.NET MVC؟

لدي التصميم التالي لمشروع mvc الخاص بي:

  • /Controllers
    • / تجريبي
    • / عرض/DemoArea1Controller
    • / عرض/DemoArea2Controller
    • إلخ...
  • /الآراء
    • / تجريبي
    • /Demo/DemoArea1/Index.aspx
    • /Demo/DemoArea2/Index.aspx

ومع ذلك ، عندما يكون لدي هذا لـ DemoArea1Controller:

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

تظهر لي رسالة الخطأ "تعذر العثور على فهرس العرض" أو الرئيسية الخاصة به ، مع وجود مواقع البحث المعتادة.

كيف يمكنني تحديد أن وحدات التحكم في مساحة الاسم "Demo" تبحث في مجلد العرض الفرعي "Demo"؟

102
Daniel Schaffer

يمكنك بسهولة توسيع WebFormViewEngine لتحديد جميع المواقع التي تريد البحث فيها:

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;
    }
}

تأكد من أنك تتذكر تسجيل مشغل العرض عن طريق تعديل أسلوب Application_Start في Global.asax.cs

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

الآن في MVC 6 ، يمكنك تطبيق واجهة IViewLocationExpander دون العبث بمحركات العرض:

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} هو اسم عرض الهدف ، {1} - اسم وحدة التحكم و {2} - اسم المنطقة.

يمكنك إرجاع قائمة المواقع الخاصة بك ، ودمجها مع الافتراضي viewLocations (.Union(viewLocations)) أو مجرد تغييرها (viewLocations.Select(path => "/AnotherPath" + path)).

لتسجيل موسع موقع العرض المخصص الخاص بك في MVC ، أضف الأسطر التالية إلى طريقة ConfigureServices في ملف Startup.cs:

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

هناك بالفعل طريقة أسهل بكثير من ترميز المسارات في مُنشئك. فيما يلي مثال على تمديد محرك Razor لإضافة مسارات جديدة. شيء واحد لست متأكدًا منه هو ما إذا كانت المسارات التي تضيفها هنا سيتم تخزينها مؤقتًا:

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();
    }
}

و 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);
}

هناك شيء واحد يجب ملاحظته: سيحتاج موقعك المخصص إلى ملف ViewStart.cshtml في جذره.

40
Chris S

إذا كنت تريد فقط إضافة مسارات جديدة ، يمكنك إضافة محركات العرض الافتراضية وتجنب بعض أسطر التعليمات البرمجية:

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);

الأمر نفسه ينطبق على WebFormEngine

22
Marcelo De Zen

بدلاً من فئة فرعية في RazorViewEngine ، أو استبدالها مباشرة ، يمكنك فقط تغيير خاصية PartialViewLocationFormats الموجودة في RazorViewEngine. يذهب هذا الرمز في Application_Start:

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();
}
13
Simon Giles

ملاحظة: بالنسبة إلى ASP.NET MVC 2 لديهم مسارات مواقع إضافية ستحتاج إلى تعيينها لطرق العرض في "المناطق".

 AreaViewLocationFormats
 AreaPartialViewLocationFormats
 AreaMasterLocationFormats

إنشاء محرك عرض لمنطقة ما موصوف في مدونة Phil .

ملاحظة: هذا هو لمعاينة الإصدار 1 لذلك هو عرضة للتغيير.

3
Simon_Weaver

جرب شيئا مثل هذا:

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
Vitaliy Ulantikov

آخر ما راجعت ، وهذا يتطلب منك بناء ViewEngine الخاصة بك. أنا لا أعرف إذا ما جعلوا الأمر أسهل في RC1.

كان الأسلوب الأساسي الذي استخدمته قبل RC الأول ، في ViewEngine الخاص بي ، هو تقسيم مساحة اسم وحدة التحكم والبحث عن المجلدات التي تطابق الأجزاء.

تحرير:

عاد ووجد الكود. ها هي الفكرة العامة.

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;
}
3
Joel