如果磁盘上已经存在cshtml文件,则ASP.Net Core 2 IFileProvider不执行

时间:2018-11-19 04:16:16

标签: .net asp.net-mvc core

我正在编写一个IFileProvider,打算从数据库中加载内容。我在下面改编了这段代码,作为概念验证,如果特定请求与“联系人”匹配,我只是对字符串进行硬编码。

在磁盘上,我的Pages文件夹中有一个文件contact.cshtml。如果我不使用新的DatabaseFileProvider,则contact.cshtml页面将按预期完美呈现。

当我在下面添加IFileProvider时,对contact.cshtml页的请求确实被覆盖-再次如预期的那样。

但是,如果尝试拦截对存在的cshtml文件的请求,则我的代码将永远不会遭到攻击。例如,您可以在我的评论中看到,如果将工作“联系人”替换为“动态”,则该工作将无法执行。

我确定这与我将IFileProvider与MVC的默认PhysicalFileProvider交织在一起的方式有关。

这是我的设置:

public class DatabaseFileProvider : IFileProvider
    {

        public IFileInfo GetFileInfo(string subpath)
        {
            var result = new DatabaseFileInfo(subpath);
            return result.Exists ? result as IFileInfo : new NotFoundFileInfo(subpath);
        }
    }

public class DatabaseFileInfo : IFileInfo
    {
        private string _viewPath;
        private byte[] _viewContent;
        private DateTimeOffset _lastModified;
        private bool _exists = false;

        public DatabaseFileInfo(string viewPath)
        {
            _viewPath = viewPath;
            GetView(viewPath);
        }
        public bool Exists => _exists;

        public bool IsDirectory => false;

        public DateTimeOffset LastModified => _lastModified;

        public long Length
        {
            get
            {
                using (var stream = new MemoryStream(_viewContent))
                {
                    return stream.Length;
                }
            }
        }

        public string Name => Path.GetFileName(_viewPath);

        public string PhysicalPath => null;

        public Stream CreateReadStream()
        {
            return new MemoryStream(_viewContent);
        }

        private void GetView(string viewPath)
        {
            if (viewPath == null) return;
            if (viewPath.ToLower().IndexOf("_view") != -1) return;

            // PROBLEM: this only works if the file EXISTS on disk ???!!!  Try switching out "contact" (works) with "dynamic" (doesn't work)
            // Not even the breakpoint gets hit?

            if (viewPath.ToLower().ToLower().IndexOf("contact") == -1) return;

            var html = "This is NOT cshtml";

            _viewContent = Encoding.UTF8.GetBytes(html);
            _lastModified = DateTime.Now;
            _exists = true;
        }
    }

`

...并在我的Startup.cs文件中:

public void ConfigureServices(IServiceCollection services)
        {
            services.AddMvc();

            services.Configure<RazorViewEngineOptions>(opts => {
                    opts.FileProviders.Clear();
                    opts.FileProviders.Add(new DatabaseFileProvider());
                    opts.FileProviders.Add(Environment.ContentRootFileProvider);

                    /*
                    opts.FileProviders.Clear();
                    opts.FileProviders.Add(new CompositeFileProvider(
                        Environment.ContentRootFileProvider,
                        new DatabaseFileProvider()
                    )); 
                    */
                }
            );

        }

如您所见,我使用CompositeFileProvider进行了第二次实现,但是问题仍然存在。我也改变了提供商的顺序。

我确定自己在做些愚蠢的事情-有人可以指出我正确的方向吗?非常感谢。

1 个答案:

答案 0 :(得分:0)

仅供参考,我最终找到了答案,那就是确保您实现IFileProvider.GetDirectoryContents方法。我一直无视此问题,因为我认为这只是为了方便目录浏览,但是看起来.Net Core在启动时会预先查询所有提供程序的内容,并且此方法用于准确地告诉您已经。