自定义 ControllerFactory 和 DBProvider 出现 asp.mvc 404 错误

发布于 2024-10-10 11:35:34 字数 2763 浏览 1 评论 0原文

我当前正在开发的应用程序是一个 MVC3 应用程序,它结合了标准视图实例化以及在物理视图不存在时从数据库检索视图。我在实现自定义控制器工厂和 virtualpathprovider 时遇到 404 错误的问题,并且不太确定我可能做错了什么。

我们想要的行为如下:

1)如果请求存在“物理”视图,则直接从文件系统提供服务(遵循标准 mvc 行为)。在这种情况下,磁盘上将有标准控制器/视图。 2)如果控制器/视图不存在,则检查数据库中是否存储了必要的信息并从数据库提供它。将调用名为 GenericController 的控制器,然后该控制器将从数据库获取视图数据。

我创建了一个自定义控制器工厂:

 public class ControllerFactory : DefaultControllerFactory, IControllerFactory
{
    protected override Type GetControllerType(RequestContext requestContext, string controllerName)
    {
        // check to see if this controller name can be resolved via DI.  If it can, then hand this off to the Default factory.
        Type returntype = base.GetControllerType(requestContext, controllerName);

        // see if this is a type that is handled via the database.  If it is, then send to the generic system controller for handling.
        if (returntype == null)
        {
            // already requested?
            if (requestContext.HttpContext.Items.Contains("vc"))
            {
                returntype = typeof(GenericSystemController);
            }
            else
            {

                    if (viewcanberetrievedfromdb())
                    {
                        // TODO: check to see if the account has access to the module.
                        returntype = typeof(GenericSystemController);
                        requestContext.HttpContext.Items["vc"] = viewcontext;
                    }

            }
        }

        return returntype;
    }

以及一个自定义虚拟路径提供程序:

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

    }

    public override bool FileExists(string virtualPath)
    {
        // first see if there is a physical version of the file.  If there is, then use that.  Otherwise, go to the database.
        // database calls are ALWAYS overridden by physical files.
        bool physicalFileExists = base.FileExists(virtualPath);

        if (!physicalFileExists)
            physicalFileExists = HttpContext.Current.Items.Contains("vc");


        return physicalFileExists;
    }

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

如果请求的页面在文件系统中不存在,则应用程序流程似乎可以正常工作: 1) 第一次调用 virtualpathprovider 中的 FileExists 返回 false,以便 IIS 不会尝试充当静态文件。 2)调用控制器工厂中的 GetControllerType 方法,它适当地返回我的通用控制器类型。 3)再次调用FileExists方法,这次返回true。 4) 调用所有控制器工厂方法,包括ControllerRelease方法。

然而,GenericController 实际上从未被调用。并且 IIS 返回 404 异常。

MVC 控制器实例化管道中是否还有其他地方需要捕获 MVC 请求?有没有更好的方法让我完成我想要完成的事情?

谢谢。

The app I am currently working on is an MVC3 app that combines standard view instantiation along with retrieving the view from a database if a physical view does not exist. I am running into a problem with 404 errors when implementing a custom controllerfactory and virtualpathprovider and am not quite sure what I may be doing wrong.

The behaviour we want is as follows:

1) if a "physical" view exists for a request, serve it directly from the file system (follow standard mvc behaviour). In this case, there will be the standard controller/view on disk.
2) if the controller/view does not exist, then check to see if the necessary info is stored in the database and serve it from the database. A controller called GenericController will be called and that in turn will get the view data from the database.

I have created a custom controller factory:

 public class ControllerFactory : DefaultControllerFactory, IControllerFactory
{
    protected override Type GetControllerType(RequestContext requestContext, string controllerName)
    {
        // check to see if this controller name can be resolved via DI.  If it can, then hand this off to the Default factory.
        Type returntype = base.GetControllerType(requestContext, controllerName);

        // see if this is a type that is handled via the database.  If it is, then send to the generic system controller for handling.
        if (returntype == null)
        {
            // already requested?
            if (requestContext.HttpContext.Items.Contains("vc"))
            {
                returntype = typeof(GenericSystemController);
            }
            else
            {

                    if (viewcanberetrievedfromdb())
                    {
                        // TODO: check to see if the account has access to the module.
                        returntype = typeof(GenericSystemController);
                        requestContext.HttpContext.Items["vc"] = viewcontext;
                    }

            }
        }

        return returntype;
    }

As well as a custom virtual path provider:

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

    }

    public override bool FileExists(string virtualPath)
    {
        // first see if there is a physical version of the file.  If there is, then use that.  Otherwise, go to the database.
        // database calls are ALWAYS overridden by physical files.
        bool physicalFileExists = base.FileExists(virtualPath);

        if (!physicalFileExists)
            physicalFileExists = HttpContext.Current.Items.Contains("vc");


        return physicalFileExists;
    }

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

The app flow seems to work correctly if a page is requested that does not exist in the file system:
1) first call to FileExists in the virtualpathprovider returns false so that IIS does not try to serve as static file.
2) the GetControllerType method in the controller factory is called and it appropriately returns my genericcontroller type.
3) the FileExists method is called again and this time returns true.
4) all the controller factory methods are called including the ControllerRelease method.

However, the GenericController is actually never called. And IIS returns a 404 exception.

Is there somewhere else in the MVC controller instantiation pipeline that I need to be capturing the MVC request? Is there a better way for me to accomplish what I am trying to accomplish?

Thanks.

如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。
列表为空,暂无数据
我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
原文