Skip to content
This repository has been archived by the owner on Dec 14, 2018. It is now read-only.

Working with IViewLocationExpander in mvc #5279

Closed
rpundlik opened this issue Sep 14, 2016 · 5 comments
Closed

Working with IViewLocationExpander in mvc #5279

rpundlik opened this issue Sep 14, 2016 · 5 comments
Labels
Milestone

Comments

@rpundlik
Copy link

rpundlik commented Sep 14, 2016

I want to render the view from custom location, so for that I have implemented IViewLocationExpanderinterface in a class. I have registered the same class in startup file as follows.

Startup.cs file

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 my application views structure is as follows

http://i.stack.imgur.com/HyOhW.png

My issue is if I access the Views/Login view from ViewsFrontend folder from the url
http://localhost:56739/trainee/Login/myclientname
and immediately change the url in browser as http://localhost:56739/admin/Login/myclientname, then in this case it still refers and renders views from ViewsFrontend folder, which is a previous folder and it should refer to ViewsBackend folder.

Url with trainee should refer to ViewsFrontend folder and with admin should refer to ViewsBackend folder.

And after changing the url in browser it only calls PopulateValues method but not the ExpandViewLocations method. My view names are same in both of the folders. I know this is happening because of caching, it seems it only caching the view name and not the entire path of the view.

So how can re-configure this class OR make ViewLocationExpanderContext null to work it for other folder ?

Thanks for the help !

@rynowak
Copy link
Member

rynowak commented Sep 14, 2016

/cc @pranavkm

@dougbu
Copy link
Member

dougbu commented Sep 14, 2016

Caching includes the Values dictionary in its lookup. Unless the PopulateValues() method adds distinct information to ViewLocationExpanderContext.Values, the ExpandViewLocations() method will be called just once per original file name i.e. the initial information is cached from then on.

Move the folderName calculation into PopulateValues() and add that to the Values dictionary w/ a constant key.

@pranavkm
Copy link
Contributor

Copying my answer from SO:

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. Add application type to PopulateValues and ExpandValues should get called:

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

@danroth27 danroth27 added this to the Discussions milestone Sep 14, 2016
@BrainCrumbz
Copy link

BrainCrumbz commented Jan 3, 2017

@dougbu thanks for your comment. That was somehow expanded in a SO answer. The net result is that this point should be made more clear in official documentation. For example, current sentence found in code comments is not totally clear:

The calculated values are used to determine if the view location has changed since the last time it was located.

Not sure how/to who submit an issue/PR for this.

EDIT I now see that description on actual doc page is more comprehensive:

The populated values are used to determine a cache key - if all values are identical to the last time PopulateValues(ViewLocationExpanderContext) was invoked, the cached result is used as the view location.

@dougbu
Copy link
Member

dougbu commented Jan 3, 2017

@BrainCrumbz this is a closed issue. If you think the IViewLocationExpander docs need further improvement, please open a new issue in this repo.

Sign up for free to subscribe to this conversation on GitHub. Already have an account? Sign in.
Labels
Projects
None yet
Development

No branches or pull requests

6 participants