I want to render views from a custom location, so for that I have implemented the
IViewLocationExpander interface in a class. I have registered the same class in Startup class as follows.
Startup Class
public void ConfigureServices(IServiceCollection services)
{
…
//Render view from custom location.
services.Configure<RazorViewEngineOptions>(options =>
{
options.ViewLocationExpanders.Add(new CustomViewLocationExpander());
});
…
}
CustomViewLocationExpander Class
public class CustomViewLocationExpander : IViewLocationExpander
{
public IEnumerable<string> ExpandViewLocations(ViewLocationExpanderContext context, IEnumerable<string> viewLocations)
{
var session = context.ActionContext.HttpContext.RequestServices.GetRequiredService<SessionServices>();
string folderName = session.GetSession<string>("ApplicationType");
viewLocations = viewLocations.Select(f => f.Replace("/Views/", "/" + folderName + "/"));
return viewLocations;
}
public void PopulateValues(ViewLocationExpanderContext context)
{
}
}
And, finally, my application’s views are organized as follows:

My issue: If I access the Views/Login view from the ViewsFrontend folder from the following URL:
http://localhost:56739/trainee/Login/myclientname
But then immediately change the URL in the browser to:
http://localhost:56739/admin/Login/myclientname
In this case, it still refers to the ViewsFrontend folder, even though it should now refer to the ViewsBackend folder, since URLs beginning with trainee should refer to the ViewsFrontend folder, while those beginning with admin should refer to the ViewsBackend folder.
Further, after changing the URL in the browser, it only calls the PopulateValues() method, but not the ExpandViewLocations() method.
How can I reconfigure this class to work for this other folder?
PopulateValues exists as a way to specify parameters that your view lookup would vary by on a per-request basis. Since you're not populating it, the view engine uses cached values from an earlier request.
To solve this, add your ApplicationType variable to the PopulateValues() method and the ExpandValues() method should get called whenever that value changes:
public class CustomViewLocationExpander : IViewLocationExpander
{
public IEnumerable<string> ExpandViewLocations(ViewLocationExpanderContext context, IEnumerable<string> viewLocations)
{
string folderName = context.Values["ApplicationType"];
viewLocations = viewLocations.Select(f => f.Replace("/Views/", "/" + folderName + "/"));
return viewLocations;
}
public void PopulateValues(ViewLocationExpanderContext context)
{
var session = context.ActionContext.HttpContext.RequestServices.GetRequiredService<SessionServices>();
string applicationType = session.GetSession<string>("ApplicationType");
context.Values["ApplicationType"] = applicationType;
}
}
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