<?xml version="1.0" encoding="utf-8"?><feed xmlns="http://www.w3.org/2005/Atom"><title type="text">Blog posts by Kristian Elmholt Kjær</title><link href="https://world.optimizely.com/blogs/kristian-elmholt-kjar/" /><updated>2018-05-19T12:31:00.0000000Z</updated><id>https://world.optimizely.com/blogs/kristian-elmholt-kjar/</id><generator uri="https://world.optimizely.com/blogs/kristian-elmholt-kjar/" version="2.0">Optimizely World</generator><entry><title>Custom View Locations for Pages, Blocks and more</title><link href="https://world.optimizely.com/blogs/kristian-elmholt-kjar/dates/2018/5/custom-view-locations-for-pages-blocks-and-more/" /><id>https://world.optimizely.com/blogs/kristian-elmholt-kjar/dates/2018/5/custom-view-locations-for-pages-blocks-and-more/</id><published>2018-05-19T12:31:00.0000000Z</published><updated>2018-05-19T12:31:00.0000000Z</updated><author><name>kristianbak@gmail.com</name></author><category term="Blog post" /><summary type="html">&lt;!DOCTYPE html&gt;
&lt;html&gt;
&lt;head&gt;
&lt;/head&gt;
&lt;body&gt;
&lt;h2&gt;Background&lt;/h2&gt;
&lt;p&gt;In a typical Episerver, or MVC Applicaton for that matter, the Views specified in a Controller are resolved by paths defined in the System.Web.Mvc.RazorViewEngine.&lt;/p&gt;
&lt;p&gt;The paths for Views are:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;span&gt;"~/Views/{1}/{0}.cshtml"&lt;/span&gt;&lt;/li&gt;
&lt;li&gt;&lt;span&gt;"~/Views/Shared/{0}.cshtml"&lt;/span&gt;&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;In Episerver Page Controllers, we need to specify an Index-method with the Page-type as method parameter, like this:&lt;/p&gt;
&lt;pre class="language-csharp"&gt;&lt;code&gt;public class StartPageController : PageController&amp;lt;StartPage&amp;gt;
{
&amp;nbsp; &amp;nbsp; public ActionResult Index(StartPage currentPage)
&amp;nbsp; &amp;nbsp; {
&amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; return View(currentPage);
&amp;nbsp; &amp;nbsp; }
}&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;If we take a look at the paths above, the name of the Controller (except -"Controller") will be used at "{1}", and the name of the Action is used at "{0}", meaning default View path for our Controller above will be:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;span&gt;"~/Views/StartPage/Index.cshtml"&lt;/span&gt;&lt;/li&gt;
&lt;/ul&gt;
&lt;h2&gt;&lt;span&gt;Flooding of "Index.cshtml" files&lt;/span&gt;&lt;/h2&gt;
&lt;p&gt;If you like me, use ReSharper and namely the "Navigation -&amp;gt; Search Everywhere/Go to Type" function to navigate/find your Views files, the amount of Index.cshtml files you'd end up - by default - becomes annoying. You probably already know this, but the files and folders in your Website project, will be something like this:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;Views
&lt;ul&gt;
&lt;li&gt;StartPage
&lt;ul&gt;
&lt;li&gt;Index.cshtml&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;LandingPage
&lt;ul&gt;
&lt;li&gt;Index.cshtml&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;CasePage
&lt;ul&gt;
&lt;li&gt;Index.cshtml&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;ArticlePage
&lt;ul&gt;
&lt;li&gt;Index.cshtml&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;Etc. etc.&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;Thankfully, we can make up for that!&lt;/p&gt;
&lt;h2&gt;Creating a custom ViewEngine&lt;/h2&gt;
&lt;p&gt;Go ahead and create a new class that inherits System.Web.Mvc.RazorViewEngine. Like this:&lt;/p&gt;
&lt;pre class="language-csharp"&gt;&lt;code&gt;public class EpiserverViewEngine : System.Web.Mvc.RazorViewEngine
{
}&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;To define your own paths for Views (Pages and Catalog-nodes) and PartialViews (Blocks, Partials), add a constructor and set the value of ViewLocationFormats and PartialViewLocationFormats. Like this:&lt;/p&gt;
&lt;pre class="language-csharp"&gt;&lt;code&gt;public class EpiserverViewEngine : System.Web.Mvc.RazorViewEngine
{
    public EpiserverViewEngine()
    {
        var partialViewLocations = new[]
        {
            "~/Views/Blocks/{1}.cshtml",
            "~/Views/Shared/{0}.cshtml",

            "~/Views/Blocks/{1}/{0}.cshtml",
            "~/Views/Shared/{1}/{0}.cshtml"
        };

        var viewLocations = new[]
        {
            "~/Views/Pages/{1}.cshtml",
            "~/Views/Nodes/{1}.cshtml",
            "~/Views/Catalog/{1}.cshtml",

            "~/Views/Pages/{1}/{0}.cshtml",
            "~/Views/Nodes/{1}/{0}.cshtml",
            "~/Views/Catalog/{1}/{0}.cshtml"
        };

        PartialViewLocationFormats = partialViewLocations;
        ViewLocationFormats = viewLocations;
    }
}&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;The above paths are the ones I use, and it gives much more flexibility.&amp;nbsp;&lt;/p&gt;
&lt;h3&gt;Potential problem&lt;/h3&gt;
&lt;p&gt;I've seen other examples of this where the paths above, are all set to the ViewLocationFormats property - and that includes both Views and PartialViews. This results in Episerver/MVC potentially resolving PartialViews as regular Views. And as we know, a PartialView should not be rendered with a Layout, which also includes model inheriting being a requirement.&lt;/p&gt;
&lt;p&gt;I was trying to render a ContentArea in which I had inserted a Block of mine, and that resulted in an exception with the message:&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;The model item passed into the dictionary is of type 'EPiServer.Core.ContentArea', but this dictionary requires a model item of type 'Namespace.IPageViewModel&amp;lt;T&amp;gt;'&lt;/strong&gt;&lt;/p&gt;
&lt;p&gt;It took me quite some time debugging why this became a problem suddenly. When it finally struck me, that the PartialView belonging to my Block was being resolved as a regular View. So talk about a eureka-experience!&lt;/p&gt;
&lt;h2&gt;Register your ViewEngine&lt;/h2&gt;
&lt;p&gt;To register your new EpiserverViewEngine, create an InitializationModule - like this:&lt;/p&gt;
&lt;pre class="language-csharp"&gt;&lt;code&gt;[InitializableModule]
[ModuleDependency(typeof(EPiServer.Web.InitializationModule))]
public class ViewEngineInitializationModule : IInitializableModule
{
    public void Initialize(InitializationEngine context)
    {
        System.Web.Mvc.ViewEngines.Engines.Add(new EpiserverViewEngine());
    }

    public void Uninitialize(InitializationEngine context) {}
}&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;You are now ready to use it. You can leave your StartPageController (example above), and use paths like these instead:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;Views/
&lt;ul&gt;
&lt;li&gt;Pages/
&lt;ul&gt;
&lt;li&gt;StartPage.cshtml&lt;/li&gt;
&lt;li&gt;LandingPage.cshtml&lt;/li&gt;
&lt;li&gt;CasePage.cshtml&lt;/li&gt;
&lt;li&gt;ArticlePage/ &lt;em&gt;(Folder to bundle stuff together)&lt;/em&gt;
&lt;ul&gt;
&lt;li&gt;Index.cshtml&lt;/li&gt;
&lt;li&gt;_MyArticlePagePartial.cshtml&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;Blocks/
&lt;ul&gt;
&lt;li&gt;NewsletterBlock.cshtml&lt;/li&gt;
&lt;li&gt;TeaserBlock.cshtml&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;Feel free to use this, modify it and happy coding!&lt;/p&gt;
&lt;p&gt;/Kristian&lt;/p&gt;
&lt;/body&gt;
&lt;/html&gt;</summary></entry></feed>