ASP.NET MVC - VirtualPathProvider не работает с локальным IIS

Я пытаюсь создать веб-сайт MVC с некоторыми представлениями, обслуживаемыми из базы данных. Я начал реализовывать всю логику, используя VirtualFiles и VirtualPathProviders, и все отлично работает на IISExpress... проблема возникает, когда я переключаюсь на локальный IIS. Виртуальный файл найден, но ничего не происходит, я получаю ошибку 404. Я предполагаю, что это IIS, ожидающий, что файл физически существует, но я понятия не имею, как заставить его работать, если это не так.

Я использую следующий пример для тестирования:

DynamicPages.cs

public class Page
{
    public string Name { get; set; }
    public string UrlName { get; set; }
    public string View { get; set; }
}
public class PageService
{
    private List<Page> pages;
    public PageService()
    {
        pages = new List<Page>();
        pages.Add(new Page() { Name = "test2", UrlName = "test2.cshtml", View = "test2" });
        pages.Add(new Page() { Name = "test3", UrlName = "test3.cshtml", View = "test3" });
    }
    public List<Page> GetAllPages()
    {
        return pages;
    }
}
public class PageVirtualFile : VirtualFile
{
    private string data;

    public PageVirtualFile(string virtualPath, string data)
        : base(virtualPath)
    {
        this.data = data;
    }
    public bool Exists { get { return true; } }
    public override System.IO.Stream Open()
    {
        byte[] byteArray = Encoding.UTF8.GetBytes(data);
        MemoryStream stream = new MemoryStream(byteArray);
        return stream;
    }
}
public class CmsRouteHandler : IRouteHandler
{
    public class CmsVirtualPathProvider : VirtualPathProvider
    {
        public IEnumerable<Page> pages
        {
            get
            {
                return (new PageService()).GetAllPages();
            }
        }

        public override bool FileExists(string virtualPath)
        {
            if (IsVirtualPath(virtualPath))
            {
                if (FindPage(virtualPath) != null)
                {
                    PageVirtualFile file = (PageVirtualFile)GetFile(virtualPath);
                    return file.Exists;
                }
            }

            return Previous.FileExists(virtualPath);
        }

        public override VirtualFile GetFile(string virtualPath)
        {
            if (IsVirtualPath(virtualPath))
            {
                Page oPage = FindPage(virtualPath);
                if (oPage != null)
                    return new PageVirtualFile(virtualPath, oPage.View);
            }

            return Previous.GetFile(virtualPath);
        }

        public override System.Web.Caching.CacheDependency GetCacheDependency(string virtualPath, System.Collections.IEnumerable virtualPathDependencies, DateTime utcStart)
        {
            if (IsVirtualPath(virtualPath))
                return null;

            return Previous.GetCacheDependency(virtualPath, virtualPathDependencies, utcStart);
        }

        public override string GetFileHash(string virtualPath, System.Collections.IEnumerable virtualPathDependencies)
        {
            if (IsVirtualPath(virtualPath))
                return Guid.NewGuid().ToString();

            return Previous.GetFileHash(virtualPath, virtualPathDependencies);
        }

        private Page FindPage(string virtualPath)
        {
            string VirtualName = VirtualPathUtility.GetFileName(virtualPath).ToLower();

            if (pages != null)
            {
                Page oPage = pages.SingleOrDefault(page => string.Equals(page.UrlName, VirtualName, StringComparison.InvariantCultureIgnoreCase));
                return oPage;
            }
            else
                return null;
        }

        private bool IsVirtualPath(string virtualPath)
        {
            string Path = (VirtualPathUtility.GetDirectory(virtualPath) != "~/") ? VirtualPathUtility.RemoveTrailingSlash(VirtualPathUtility.GetDirectory(virtualPath)) : VirtualPathUtility.GetDirectory(virtualPath);
            if (Path.StartsWith("/Views/_Cms", StringComparison.InvariantCultureIgnoreCase) || Path.StartsWith("~/Views/_Cms", StringComparison.InvariantCultureIgnoreCase))
                return true;
            else
                return false;
        }
    }
    public IHttpHandler GetHttpHandler(RequestContext requestContext)
    {
        return new CmsHandler(requestContext);
    }
    class CmsHandler : MvcHandler
    {
        public CmsHandler(RequestContext requestContext)
            : base(requestContext)
        {
        }

        protected override IAsyncResult BeginProcessRequest(HttpContext httpContext, AsyncCallback callback, object state)
        {
            return base.BeginProcessRequest(httpContext, callback, state);
        }


        protected override IAsyncResult BeginProcessRequest(HttpContextBase httpContext, AsyncCallback callback, object state)
        {
            try
            {
                var vpp = new CmsVirtualPathProvider();
                var requestContext = ((MvcHandler)httpContext.Handler).RequestContext;
                string path = requestContext.HttpContext.Request.Url.AbsolutePath;
                if (path != null)
                {
                    IEnumerable<Page> pages = vpp.pages;
                    if (pages != null)
                    {
                        Page oPage = pages.SingleOrDefault(page => string.Equals((requestContext.HttpContext.Request.ApplicationPath + "/").Replace("//","/") + page.Name, path, StringComparison.InvariantCultureIgnoreCase)); // Select the page matching our requested path (if any)
                        if (oPage != null)
                        {
                            requestContext.RouteData.Values["controller"] = "_Cms"; 
                            requestContext.RouteData.Values["action"] = "Index";
                        }
                    }
                }

                return base.BeginProcessRequest(httpContext, callback, state);
            }
            catch (Exception ex)
            {
                throw new Exception(ex.Message);
            }
        }

        protected override void ProcessRequest(HttpContext httpContext)
        {
            base.ProcessRequest(httpContext);
        }
    }
}

Затем я регистрирую свой VirtualPathProvider в Global.asax.

    void Application_Start(object sender, EventArgs e)
    {
        HostingEnvironment.RegisterVirtualPathProvider(new CmsHandlerSandBox.CmsRouteHandler.CmsVirtualPathProvider());
    }

Если я использую IISExpress, будет работать следующая ссылка:

http://localhost:<port>/test2

Однако в локальном IIS он изменится на:

http://localhost/<websitename>/test2

и это выдаст ошибку 404.

Любые идеи, как это решить. Я нахожу много более или менее похожих случаев в Google, но ни один из них не работает.

Спасибо заранее!


person s08c21    schedule 11.09.2014    source источник
comment
sunali.com/2008/01/09/   -  person Donal    schedule 12.09.2014
comment
возможный дубликат Пользовательского поставщика виртуального пути в IIS   -  person Donal    schedule 12.09.2014
comment
@Donal - спасибо за ваши комментарии - я видел этот пост до того, как задал свой вопрос, попробовал ответы, и ни один из них не помог. Переключение с IISExpress на локальный IIS не делает веб-сайт предварительно скомпилированным, он все еще находится в режиме отладки, поэтому не думайте, что решение Coskun Sunali актуально в этом случае (я все равно пробовал, без разницы).   -  person s08c21    schedule 12.09.2014