VirtualFileSystem

物理的文件有wwwroot下文件(JSCSShtml居多),DLL嵌入的资源(json文件居多),Razor文件,

如何操作这些文件呢,首先先表示这个文件抽象(IFileInfo )

IFileInfo 表示给定文件提供程序中的某个文件。它是文件一个抽象(名称、物理路径,是否存在,IsDirectory:如果 TryGetDirectoryContents 枚举了子目录,则为 True。 ,返回只读流文件string,bytes),

其次,提供文件的操作,IFileProvider,得到目录内容(IFileInfo列表,如果有),得到文件IFileInfo,以及监视

针对以上文件,提供有physicalFileProvider(磁盘)、EmbeddedFileProvider(程序集中)、CompositeFileProvider(IFileProvider 的集合)

针对这些ABP创建了IVirtualFileProvider,它还是基于CompositeFileProvider进行IFileProvider遍历,因此存在优先级。Dymanic>physical?Embedded

下面创建CompositeFileProvider,它由下面组成

dynamicFileProvider:自创建的文件,基于InMemoryFileInfo

PhysicalFileProvider:物理文件,由配置文件AbpVirtualFileSystemOptions导入,如果PhysicalPath存在

InternalVirtualFileProvider:嵌入的文件,基于DictionaryBasedFileProvider,由配置文件AbpVirtualFileSystemOptions导入

 protected virtual IFileProvider CreateHybridProvider(IDynamicFileProvider dynamicFileProvider)
        {
            var fileProviders = new List<IFileProvider>();
            fileProviders.Add(dynamicFileProvider);
            if (_options.FileSets.PhysicalPaths.Any())
            {
                fileProviders.AddRange(
                    _options.FileSets.PhysicalPaths
                        .Select(rootPath => new PhysicalFileProvider(rootPath))
                        .Reverse()
                );
            }
            fileProviders.Add(new InternalVirtualFileProvider(_options));
            return new CompositeFileProvider(fileProviders);
        }

回到配置文件AbpVirtualFileSystemOptions的FileSets列表,其使用的拓展方法有

AddEmbedded:引入Assembly,注意baseNamespace

 list.Add(
                new EmbeddedFileSet(
                    typeof(T).Assembly,
                    baseNamespace,
                    baseFolderInProject
                )
            );

 ReplaceEmbeddedByPhysical:

我们需要的是应用程序在开发时直接使用物理文件的能力, 让浏览器刷新时同步JavaScript文件的任何更改. ReplaceEmbeddedByPhysical 方法使其成为可能.

 分析基于IFileProvider的IVirtualFileProvider实现方法,它的基类型是DictionaryBasedFileProvider,它实现基于IDictionary<string, IFileInfo> Files

它在Options的Add方法EmbeddedFileSet,调用AddFiles方法,它去除BaseNamespace,目的是填充了IDictionary字典

 foreach (var resourcePath in Assembly.GetManifestResourceNames())
            {
                
                if (!BaseNamespace.IsNullOrEmpty() && !resourcePath.StartsWith(BaseNamespace))
                {
                    continue;
                }
                //上面BaseNamespace不为空或与BaseNamespace开头任一条件都执行以下
                //去掉BaseNamespace.开始部分,split('.')成数组,后两项是文件名,前面是文件夹,join起来成完全的路径
                var fullPath = ConvertToRelativePath(resourcePath).EnsureStartsWith('/');
                //如果包括/,说明有目录,则添加目录VirtualDirectoryFileInfo,然后递归,逐层去掉/,直到没有/
                if (fullPath.Contains("/"))
                {
                    AddDirectoriesRecursively(files, fullPath.Substring(0, fullPath.LastIndexOf('/')), lastModificationTime);
                }
                //添加文件EmbeddedResourceFileInfo
                files[fullPath] = new EmbeddedResourceFileInfo(
                    Assembly,
                    resourcePath,
                    fullPath,
                    CalculateFileName(fullPath),
                    lastModificationTime
                );
            }

GetFileInfo方法,输入不能为空的,则根据字典GetOrDefault(路径),它可以得到文件EmbeddedResourceFileInfo,也可以得到VirtualDirectoryFileInfo

GetDirectoryContents,它是基于GetFileInfo得到,输入也不能为空的,如果到是文件名,则直接返回没有找到目录,否则遍历字典的File,它去除输入目录,

找到路径不包含/,注意它可能是文件名,也可能是目录

foreach (var fileInfo in Files.Values)
            {
                var fullPath = fileInfo.GetVirtualOrPhysicalPathOrNull();
                if (!fullPath.StartsWith(directoryPath))
                {
                    continue;
                }

                var relativePath = fullPath.Substring(directoryPath.Length);
                if (relativePath.Contains("/"))
                {
                    continue;
                }

                fileList.Add(fileInfo);
            }

WebContentFileProvider实现

它是PhysicalFileProvider,以及_virtualFileProvider的复合FileProvider

 protected virtual IFileProvider CreateFileProvider()
        {
            return new CompositeFileProvider(
                new PhysicalFileProvider(_hostingEnvironment.ContentRootPath),
                _virtualFileProvider
            );
        }

1)GetFileInfo方法,要求以/Pages、/Views、/Themes开始,并且,拓展名以.js,.css,.png。.jpg,.jpeg结束等文件

   否则要加上/wwwroot

2) 同理是GetDirectoryContents,以以/Pages、/Views、/Themes开始

1、静态资源,使用MiddleWare

 public static IApplicationBuilder UseVirtualFiles(this IApplicationBuilder app)
        {
            return app.UseStaticFiles(
                new StaticFileOptions
                {
                    FileProvider = app.ApplicationServices.GetRequiredService<IWebContentFileProvider>()
                }
            );
        }

2、RazorEngine

     //Configure Razor
            context.Services.Insert(0,
                ServiceDescriptor.Singleton<IConfigureOptions<MvcRazorRuntimeCompilationOptions>>(
                    new ConfigureOptions<MvcRazorRuntimeCompilationOptions>(options =>
                        {
                            options.FileProviders.Add(
                                new RazorViewEngineVirtualFileProvider(
                                    context.Services.GetSingletonInstance<IObjectAccessor<IServiceProvider>>()
                                )
                            );
                        }
                    )
                )
            );

模块内添加嵌入式资源

1、AbpLocalizationModule下面有AbpValidation
2、
 Configure<AbpVirtualFileSystemOptions>(options =>
            {
                options.FileSets.AddEmbedded<AbpAspNetCoreMvcUiBootstrapModule>("Volo.Abp.AspNetCore.Mvc.UI.Bootstrap");
            });

  Configure<AbpVirtualFileSystemOptions>(options =>
            {
                options.FileSets.AddEmbedded<AbpAspNetCoreMvcUiMultiTenancyModule>();
            });

    Configure<AbpVirtualFileSystemOptions>(options =>
            {
                options.FileSets.AddEmbedded<AbpAspNetCoreMvcUiBasicThemeModule>("Volo.Abp.AspNetCore.Mvc.UI.Theme.Basic");
            });
      public override void ConfigureServices(ServiceConfigurationContext context)
        {
            Configure<AbpVirtualFileSystemOptions>(options =>
            {
                options.FileSets.AddEmbedded<AbpEmailingModule>();
            });       
        }

  Configure<AbpVirtualFileSystemOptions>(options =>
            {
                options.FileSets.AddEmbedded<AbpAspNetCoreMvcUiWidgetsModule>();
            });

 Configure<AbpVirtualFileSystemOptions>(options =>
            {
                options.FileSets.AddEmbedded<AbpLocalizationModule>("Volo.Abp", "Volo/Abp");
            });

    Configure<AbpVirtualFileSystemOptions>(options =>
            {
                options.FileSets.AddEmbedded<AbpUiNavigationModule>();
            });

   Configure<AbpVirtualFileSystemOptions>(options =>
            {
                options.FileSets.AddEmbedded<AbpUiNavigationModule>();
            });

  Configure<AbpVirtualFileSystemOptions>(options =>
            {
                options.FileSets.AddEmbedded<AbpUiModule>();
            });
原文地址:https://www.cnblogs.com/cloudsu/p/11919304.html