MVC 5 中的 VirtualPathProvider [英] VirtualPathProvider in MVC 5

查看:36
本文介绍了MVC 5 中的 VirtualPathProvider的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

我似乎无法在 asp.net MVC 5 中使用自定义 VirtualPathProvider.

I can't seem to get a custom VirtualPathProvider working in asp.net MVC 5.

FileExists 方法返回 true,但随后不会调用 GetFile 方法.我相信这是因为 IIS 接管了请求并且不让 .NET 处理它.

The FileExists method returns true but then the GetFile method isn't called. I believe this is because IIS takes over the request and does not let .NET handle it.

我尝试设置 RAMMFAR 并创建自定义处理程序,如本解决方案 https://stackoverflow.com/a/12151501/801189 但仍然没有运气.我收到错误 404.

I have tried setting RAMMFAR and creating a custom handler, as in this solution https://stackoverflow.com/a/12151501/801189 but still no luck. I get a error 404.

我的自定义提供商:

public class DbPathProvider : VirtualPathProvider
{
    public DbPathProvider() : base()
    {

    }

    private static bool IsContentPath(string virtualPath)
    {
        var checkPath = VirtualPathUtility.ToAppRelative(virtualPath);
        return checkPath.StartsWith("~/CMS/", StringComparison.InvariantCultureIgnoreCase);
    }

    public override bool FileExists(string virtualPath)
    {
        return IsContentPath(virtualPath) || base.FileExists(virtualPath);
    }

    public override VirtualFile GetFile(string virtualPath)
    {
        return IsContentPath(virtualPath) ? new DbVirtualFile(virtualPath) : base.GetFile(virtualPath);
    }

    public override CacheDependency GetCacheDependency(string virtualPath, IEnumerable virtualPathDependencies, DateTime utcStart)
    {
        return null;

    }

    public override String GetFileHash(String virtualPath, IEnumerable virtualPathDependencies)
    {
        return Guid.NewGuid().ToString();
    }
}

我的自定义虚拟文件:

public class DbVirtualFile : VirtualFile
{
    public DbVirtualFile(string path): base(path)
    {

    }

    public override System.IO.Stream Open()
    {
        string testPage = "This is a test!";
        return new System.IO.MemoryStream(System.Text.ASCIIEncoding.ASCII.GetBytes(testPage));
    }
}

web.config 处理程序我尝试使用,但没有成功.它目前给出错误 500 :

web.config handler I have tried to use, without success. It currently gives error 500 :

<system.webServer>
<modules runAllManagedModulesForAllRequests="true">
  <remove name="FormsAuthenticationModule" />
</modules>

<handlers>
  <add name="ApiURIs-ISAPI-Integrated-4.0"
 path="/CMS/*"
 verb="GET,HEAD,POST,DEBUG,PUT,DELETE,PATCH,OPTIONS"
 type="System.Web.Handlers.TransferRequestHandler"
 preCondition="runtimeVersionv4.0" />
</handlers>

如果我尝试导航到 site.com/CMS/Home/Index,则会调用 FileExists 方法,但奇怪的是,virtualPath 参数仅接收 ~/CMS/Home.

If I try to navigate to site.com/CMS/Home/Index, the FileExists method is called but strangely, the virtualPath parameter recieves only ~/CMS/Home.

添加断点,似乎对于url site.com/CMS/Home/Index,FileExists方法不断被重复调用.这可能会导致无限递归,从而导致内部服务器错误.

Adding breakpoints, it seems that for the url site.com/CMS/Home/Index, the FileExists method keeps getting repeatedly called. This may be causing an infinite recursion, giving the internal server error.

推荐答案

其实和 IIS 没什么关系,实际上是对事件顺序的混淆.似乎我不明白路由操作方法必须返回一个视图,VirtualPathProvider 将尝试解析,而不是直接转到 VirtualPathProvider.

It was actually nothing to do with IIS, and in fact confusion on the order of events. It seems I didn't understand that a routed action method must return a view, that the VirtualPathProvider will try to resolve, rather than going to the VirtualPathProvider directly.

我使用单个 GetPage 操作创建了一个名为 ContentPagesController 的简单控制器:

I create a simple controller called ContentPagesController with a single GetPage action:

public class ContentPagesController : Controller
    {
        [HttpGet]
        public ActionResult GetPage(string pageName)
        {
            return View(pageName);
        }
    }

然后我设置了我的路由来提供虚拟页面:

I then set up my route to serve virtual pages:

routes.MapRoute(
 name: "ContentPageRoute",
 url: "CMS/{*pageName}",
 defaults: new { controller = "ContentPages", action = "GetPage" },
 constraints: new { controller = "ContentPages", action = "GetPage" }
);

在注册我的路由之前,我在 globals.asax.cs 中注册了我的自定义 VirtualPathProvider.

I register my custom VirtualPathProvider before I register my routes, in globals.asax.cs.

现在假设我的数据库中有一个页面,其相对 url 为/CMS/Home/AboutUs.pageName 参数的值为 Home/AboutUs,返回的 View() 调用将指示 VirtualPathProvider 查找文件 ~/Views/ContentPages/Home/AboutUs.cshtml 的变体.

Now suppose I have a page in my database with the relative url /CMS/Home/AboutUs. The pageName parameter will have value Home/AboutUs and the return View() call will instruct the VirtualPathProvider to look for variations of the file ~/Views/ContentPages/Home/AboutUs.cshtml.

它将寻找的一些变体包括:

A few of the variations it will be look for include:

~/Views/ContentPages/Home/AboutUs.aspx
~/Views/ContentPages/Home/AboutUs.ascx
~/Views/ContentPages/Home/AboutUs.vbhtml

您现在需要做的就是使用数据库查找或类似方法检查传递给 GetFiles 方法的 virtualPath.这是一个简单的方法:

All you now need to do is check the virtualPath that is passed to the GetFiles method, using a database lookup or similar. Here is a simple way:

private bool IsCMSPath(string virtualPath)
        {
           return virtualPath == "/Views/ContentPages/Home/AboutUs.cshtml" || 
                virtualPath == "~/Views/ContentPages/Home/AboutUs.cshtml"; 
        }

        public override bool FileExists(string virtualPath)
        {
            return IsCMSPath(virtualPath) || base.FileExists(virtualPath);
        }

        public override VirtualFile GetFile(string virtualPath)
        {
            if (IsCMSPath(virtualPath))
            {
                return new DbVirtualFile(virtualPath);
            }

            return base.GetFile(virtualPath);
        }

自定义虚拟文件将在 GetFile 方法中制作并返回到浏览器.

The custom virtual file will be made and returned to the browser in the GetFile method.

最后,可以创建自定义视图引擎,以提供发送到 VirtualPathProvider 的不同虚拟视图路径.

Finally, a custom view engine can be created to give different virtual view paths that are sent to VirtualPathProvider.

希望这会有所帮助.

这篇关于MVC 5 中的 VirtualPathProvider的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆