Question

I've created the following virtual path provider to load views from a DB and when the view doesn't exist on disk, I am seeing my DB method in be called and return true for the FileExists method. After that, no other methods are called and the page returns as a 404. Views that are on disk are still rendering fine. The DB call GetByVirtualPath just returns a views content. I have validated that this object is hydrated with data.

VirtualPathProvider

public class CMSVirtualPathProvider : VirtualPathProvider
{
    public override bool FileExists(string virtualPath)
    {
        return base.FileExists(virtualPath) || MVCViewVersion.GetByVirtualPath(virtualPath) != null;
    }

    public override VirtualFile GetFile(string virtualPath)
    {
        if (base.FileExists(virtualPath))
        {
            return base.GetFile(virtualPath);
        }
        else
        {
            return new CMSVirtualFile(virtualPath, this);
        }
    }

    public override string GetFileHash(string virtualPath, IEnumerable virtualPathDependencies)
    {
        if (base.FileExists(virtualPath))
        {
            return base.GetFileHash(virtualPath, virtualPathDependencies);
        }
        else
        {
#if DEBUG
            return null;
#else
            return string.Format("{0}{1}", virtualPath, DateTime.UtcNow.ToString("dd HH"));
#endif
        }
    }

    public override CacheDependency GetCacheDependency(string virtualPath, IEnumerable virtualPathDependencies, DateTime utcStart)
    {
        if (!base.FileExists(virtualPath))
        {
            return null;
        }
        return Previous.GetCacheDependency(virtualPath, virtualPathDependencies, utcStart);
    }
}

VirtualFile This class is never hit.

public class CMSVirtualFile : VirtualFile
{
    private CMSVirtualPathProvider _ParentProvider;

    public CMSVirtualFile(string virtualPath, CMSVirtualPathProvider parentProvider)
        : base(virtualPath)
    {
        _ParentProvider = parentProvider;
    }

    public override System.IO.Stream Open()
    {
        string Content = string.Empty;
        MVCViewVersion Version = MVCViewVersion.GetByVirtualPath(this.VirtualPath);

        if (Version != null)
        {
            Content = Version.Content;
        }

        return new MemoryStream(ASCIIEncoding.Default.GetBytes(Content));
    }
}

In the global.asax, I added the following link in the Application_Start method.

HostingEnvironment.RegisterVirtualPathProvider(new CMSVirtualPathProvider());

I assume something has changed as this code works on my previous implementation for MVC4. I can't put my finger on what I am doing incorrectly.

Was it helpful?

Solution

Found the issue. This was interesting. When the FileExists check occurs the virtualPath is passed like this:

~/Views/Home/Index.cshml

When the GetFile is called the virtualPath is:

/Views/Home/Index.cshtml

This causes the DB query to try and pull using the wrong virtual path from the DB which returns a null value. This then throws a 404. What a simple fix for a nightmare to find problem.

Licensed under: CC-BY-SA with attribution
Not affiliated with StackOverflow
scroll top