2009-03-11 31 views
90

Tôi có cách bố trí sau cho dự án MVC của tôi:Tôi có thể chỉ định vị trí tùy chỉnh để "tìm kiếm chế độ xem" trong ASP.NET MVC không?

  • /Bộ xử lý
    • /Demo
    • /Demo/DemoArea1Controller
    • /Demo/DemoArea2Controller
    • vv ...
  • /Lượt xem
    • /Demo
    • /Demo/DemoArea1/Index.aspx
    • /Demo/DemoArea2/Index.aspx

Tuy nhiên, khi tôi có điều này cho DemoArea1Controller:

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

Tôi nhận được lỗi "Chỉ mục 'hoặc chỉ số không thể tìm thấy", với các vị trí tìm kiếm thông thường.

Làm cách nào tôi có thể chỉ định bộ điều khiển đó trong tìm kiếm không gian tên "Demo" trong thư mục con của chế độ xem "Demo"?

+0

Dưới đây là một mẫu của một ViewEngine đơn giản từ ứng dụng MVC Thương mại Rob Connery: [View Engine Mã] (http://mvcsamples.codeplex.com/SourceControl/changeset/view/17126#286681) Và mã Global.asax.cs để đặt ViewEngine: [Global.asax.cs] (http: //mvcsamples.codeplex. com/SourceControl/changeset/view/17126 # 286569) Hy vọng điều này sẽ giúp. –

Trả lời

111

Bạn có thể dễ dàng mở rộng WebFormViewEngine để xác định tất cả các vị trí bạn muốn tìm trong:

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

Hãy chắc chắn rằng bạn nhớ đăng ký công cụ xem bằng cách thay đổi phương pháp Application_Start trong Global.asax của bạn cs

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

Làm cách nào bạn có thể truy cập đường dẫn của Trang chính từ trang Chính được lồng ghép? Như trong việc thiết lập bố trí trang cái lồng nhau để tìm kiếm trong các đường dẫn của CustomViewEngine – Drahcir

+4

Có tốt hơn nếu chúng ta bỏ qua Xoá các công cụ đã đăng ký và chỉ thêm một công cụ mới và các khung nhìn sẽ chỉ có những cái mới? – Prasanna

+2

Thực hiện mà không có ViewEngines.Engines.Clear(); Tất cả đều ổn. Nếu bạn muốn sử dụng * .cshtml, bạn phải kế thừa từ RazorViewEngine – KregHEk

3

Cuối cùng tôi đã kiểm tra, điều này đòi hỏi bạn phải xây dựng ViewEngine của riêng bạn. Tôi không biết nếu họ làm cho nó dễ dàng hơn trong RC1 mặc dù.

Cách tiếp cận cơ bản mà tôi đã sử dụng trước RC đầu tiên là trong ViewEngine của riêng tôi, để tách không gian tên của bộ điều khiển và tìm các thư mục khớp với các phần.

EDIT:

Went trở lại và tìm thấy mã. Đây là ý tưởng chung.

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

Nó thực sự dễ dàng hơn nhiều. Lớp con WebFormsViewEngine và sau đó chỉ cần thêm vào mảng các đường dẫn mà nó đã tìm kiếm trong hàm tạo của bạn. –

+0

Vâng, những gì Craig nói! – Haacked

+0

Điều cần biết. Lần cuối cùng tôi cần phải sửa đổi bộ sưu tập đó, nó không thể theo cách đó. – Joel

3

Hãy thử một cái gì đó như thế này:

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

Lưu ý: đối với ASP.NET MVC 2 họ có thêm đường dẫn vị trí, bạn sẽ cần đặt cho chế độ xem trong 'Khu vực'.

AreaViewLocationFormats 
AreaPartialViewLocationFormats 
AreaMasterLocationFormats 

Tạo công cụ xem cho một Khu vực là described on Phil's blog.

Lưu ý: Đây là phiên bản xem trước 1 nên có thể thay đổi.

36

Có phương pháp dễ dàng hơn rất nhiều so với việc mã hóa cứng đường dẫn vào hàm tạo của bạn. Dưới đây là một ví dụ về việc mở rộng công cụ Razor để thêm các đường dẫn mới. Một điều tôi không hoàn toàn chắc chắn về là liệu những con đường bạn thêm tại đây sẽ được lưu trữ:

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

Và Global.asax.cs của bạn

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

Một điều cần lưu ý: vị trí tùy chỉnh của bạn sẽ cần tệp ViewStart.cshtml trong thư mục gốc của nó.

20

Nếu bạn muốn chỉ cần thêm những con đường mới, bạn có thể thêm vào các công cụ giao diện mặc định và một số phụ tùng dòng mã:

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

cũng áp dụng như WebFormEngine

+2

Đối với Chế độ xem: sử dụng razorEngine.ViewLocationFormats. – Aldentev

12

Thay vì subclassing RazorViewEngine, hoặc thay thế nó hoàn toàn, bạn chỉ có thể thay đổi thuộc tính PartialViewLocationFormats hiện tại của RazorViewEngine. Mã này đi trong 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(); 
} 
+2

Điều này làm việc cho tôi, ngoại trừ loại dao cạo là 'FixedRazorViewEngine' thay vì 'RazorViewEngine'. Ngoài ra tôi ném một ngoại lệ nếu động cơ không được tìm thấy vì nó ngăn cản ứng dụng của tôi khởi tạo thành công. – Rob

26

Bây giờ trong MVC 6 bạn có thể thực hiện giao diện IViewLocationExpander mà không rối tung xung quanh với cơ quan điểm:

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

nơi {0} là mục tiêu của tên xem, {1} - bộ điều khiển tên và {2} - tên khu vực.

Bạn có thể trả lại danh sách vị trí của riêng mình, hợp nhất địa chỉ đó với mặc định viewLocations (.Union(viewLocations)) hoặc chỉ thay đổi chúng (viewLocations.Select(path => "/AnotherPath" + path)).

Để đăng ký xem vị trí tùy chỉnh giãn nở của bạn trong MVC, thêm dòng bên cạnh ConfigureServices phương pháp trong Startup.cs file:

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

Tôi ước tôi có thể bỏ phiếu cho 10 phiếu bầu này. Là chính xác những gì là cần thiết trong Asp.net 5/MVC 6. Beautiful. Rất hữu ích trong trường hợp của tôi (và những người khác) khi bạn muốn nhóm các khu vực thành các khu vực siêu cho các trang web lớn hơn hoặc nhóm hợp lý. – drewid

+0

Phần Startup.cs phải là: services.Configure Nó đi theo phương pháp này: public void ConfigureServices (dịch vụ IServiceCollection) – OrangeKing89

Các vấn đề liên quan