Reputation: 735
I have defined a custom IViewLocationExpander to check for site-specific Views in a multi-tenant web application.
Imagine there are two tenants WebsiteA and WebsiteB and the following file structure for a HomeController and Index View
My IViewLocationExpander will render Views/Home/WebSiteA/Index.cshtml for WebsiteA and Views/Home/Index.cshtml for WebsiteB - as there is no Index view specific to WebsiteB so it uses the default one.
I also have setup a folder in Views named "Common" to hold any partial views - the idea being that I can render a custom Partial View in the same manner (Say for instance a Header).
Here is the code for my IViewLocationExpander
public sealed class TenantViewLocationExpander : IViewLocationExpander
{
private ITenantService _tenantService;
private string _tenant;
public IEnumerable<string> ExpandViewLocations(ViewLocationExpanderContext context, IEnumerable<string> viewLocations)
{
string[] locations =
{
"/Views/{1}/" + _tenant + "/{0}.cshtml",
"/Views/Common/" + _tenant + "/{0}.cshtml",
"/Views/Shared/" + _tenant + "/{0}.cshtml",
"/Pages/Shared/" + _tenant + "/{0}.cshtml",
"/Views/{1}/{0}.cshtml",
"/Views/Common/{0}.cshtml",
"/Views/Shared/{0}.cshtml",
"/Pages/Shared/{0}.cshtml"
};
return locations;
}
public void PopulateValues(ViewLocationExpanderContext context)
{
_tenantService = context.ActionContext.HttpContext.RequestServices.GetRequiredService<ITenantService>();
_tenant = _tenantService.GetCurrentTenant();
}
}
Everything works perfectly for standard views, however when I attempt to render a partial view, I always get the default returned (e.g. Views/Common/_Header.cshtml from the example above)
I'm rendering the partial in my Layout like so ...
<partial name="_Header.cshtml" />
If I remove the Views/Common/_Header.cshtml file -leaving only the Site specific one- I get an exception stating that the view could not be found
InvalidOperationException: The partial view '_Header.cshtml' was not found. The following locations were searched:
/Views/Shared/_Header.cshtml
It seems as if the expander hasn't added in the extra locations for partial views. So my question is, how can I configure IViewLocationExpander to work with Partials?
In older versions of MVC I see you could define them specifically by setting ViewLocationFormats and PartialViewLocationFormats, but in MVC Core I can't see that option anywhere?
Apologies if this has been covered off elsewhere - I couldn't find an answer anywhere.
Thanks in advance!
Upvotes: 2
Views: 979
Reputation: 735
To anyone reading this who might be having the same problem - It seems you need to omit the '.cshtml' from the partial tag.
<!--- Works with all ViewLocations defined in IViewLocationExpander --->
<partial name="_Header" />
Whereas if you contain '.cshtml' like in the following, it seems to only search the default Partial View Location - 'Views/Shared'
<!--- Only looks in 'Views/Shared' --->
<partial name="_Header.cshtml" />
Not sure if this is intentional, but it definitely seems like a strange bug in MVC to me.
Upvotes: 6