i am going Nuts, i am using MVCContrib, to create pluggable site using Portable Areas, and everything is working well so far, except that when i started using MVC Templates, what is happening is if i put the The templates in the respective folder of the View it works, examples
HostApplication/Views/Home/DisplayTemplates/FirstName.cshtml
HostApplication/Areas/PortableArea_Blog/Views/Home/DisplayTemplates/Auther.cshtml
but what i want really is the ability to create common templates Set and utilize it from either Host Application or Portable Area, so to do that i created a new Portable Area Called DisplayTemplates(to utilize MVCContrib Ability to compile Views), here is the portable Area structure
DisplayTemplates
|-Views
|-CommentTemplate.cshtml
now in my host Application i have created a Test Model and added UIHint Attribute
public class HostModel
{
[UIHint("~/Areas/DisplayTemplates/Comment.cshtml")]
public string Name { get; set; }
}
but it is not working, so i thought it has something to do with Partial Views Location so i created a CustomView Engine to find Partial Views in that Location and registerd it in Global.asax, here is a short idea about so i wont bore you with full code
public class AreaViewEngine : RazorViewEngine
{
public AreaViewEngine()
{
// {0} = View name
// {1} = Controller name
// View locations
ViewLocationFormats = new[]
{
"~/Areas/DisplayTemplates/{0}.cshtml"
};
PartialViewLocationFormats = ViewLocationFormats;
AreaPartialViewLocationFormats = ViewLocationFormats;
}
protected override IView CreatePartialView(ControllerContext controllerContext, string partialPath)
{
return new RazorView(controllerContext, partialPath, null, true, new[] { "cshtml" });
}
protected override IView CreateView(ControllerContext controllerContext, string viewPath, string masterPath)
{
return new RazorView(controllerContext, viewPath, masterPath, true, new[] { "cshtml" });
}
}
what is even more weird, is that it seems that that UIHint with Explicit location to Display Template, does not work, here is an example
public class HostModel
{
//this works
[UIHint("FirstName")]
//this does not work
[UIHint("~/Views/Home/DisplayTemplates/FirstName.cshtml")]
public string Name { get; set; }
}
and yes
FirstName.cshtml is in HostApplication/Views/Home/DisplayTemplates/FirstName.cshtml
again sorry for the long post, but i gave up on finding a solution, so any help would be totally appreciated.
Danny is correct. The Templates are found the same way that Partial Views are found.
By default the WebFormViewEngine and RazorViewEngine are going to search the following locations for a template.
For display templates:
~/Views/{controller}/DisplayTemplates ~/Views/Shared/DisplayTemplates
For editor templates:
~/Views/{controller}/EditorTemplates ~/Views/Shared/EditorTemplates
I think the name of the sub-directories (i.e., "DisplayTemplates" and "EditorTemplates") are hard-coded into MVC somewhere (I know it's open source and I could find it, but I'm not going to).
I think the easiest way to change the location somewhat is to override the ViewEngine. My custom ViewEngine is pretty complicated at this point, but I suspect you could get away with the following.
Let's say you want your templates to be in ~/Views/Templates.
Create a class that inherits from the view engine you're using now (probably WebFormViewEngine or RazorViewEngine). Add an empty constructor. It should looks like this:
namespace MySite
{
public class MySiteViewEngine : RazorViewEngine // <<-- or WebFormViewEngine
{
public MySiteViewEngine()
{
// We'll put some code here in a later step
}
}
}
Now, add the following lines to the Application_Start method of Global.asax.cs:
ViewEngines.Engines.Clear();
ViewEngines.Engines.Add(new MySiteViewEngine());
At this point, compile and run your application. Everything should be running exactly like it is running now. You're basically using the same view engine you were using before.
But now, we want to add a location to search when looking for PartialViews. This is simply done by adding to the PartialViewLocationFormats. So, now in the constructor of your custom view engine, you want to add to the base class' array like so:
base.PartialViewLocationFormats = new string[] {
"~/Views/Templates/{0}.cshtml"
}.Union(base.PartialViewLocationFormats).ToArray<string>();
A couple of notes about the above:
Good luck.
Instead of creating a new ViewEngine you can easily modify the existing ones at runtime:
private void FixMvcTemplateAreaBug(string areaName)
{
foreach (BuildManagerViewEngine viewEngine in ViewEngines.Engines)
{
List<string> viewLocations =
new List<string>(viewEngine.PartialViewLocationFormats);
foreach (var extension in viewEngine.FileExtensions)
viewLocations.Add("~/Areas/" + areaName +
"/Views/Shared/{0}." + extension);
viewEngine.PartialViewLocationFormats = viewLocations.ToArray();
}
}
Place the above in an appropriate location (like area registration) and you'll be fine.
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With