The Virtual File System makes it possible to manage files that do not physically exist on the file system (disk). It's mainly used to embed (js, css, image..) files into assemblies and use them like physical files at runtime.
### Volo.Abp.VirtualFileSystem Package
## Installation
Volo.Abp.VirtualFileSystem is the core package of the virtual file system. Install it in your project using the package manager console (PMC):
> Most of the times you don't need to manually install this package since it comes pre-installed with the [application startup template](Startup-Templates/Application.md).
```
Install-Package Volo.Abp.VirtualFileSystem
```
[Volo.Abp.VirtualFileSystem](https://www.nuget.org/packages/Volo.Abp.VirtualFileSystem) is the main page of the Virtual File System.
> This package is already installed by default with the startup template. So, most of the time, you will not need to install it manually.
Use the ABP CLI to add this package to your project:
Then you can add **AbpVirtualFileSystemModule** dependency to your module:
* Install the [ABP CLI](https://docs.abp.io/en/abp/latest/CLI), if you haven't installed it.
* Open a command line (terminal) in the directory of the `.csproj` file you want to add the `Volo.Abp.VirtualFileSystem` package.
* Run `abp add-package Volo.Abp.VirtualFileSystem` command.
```c#
using Volo.Abp.Modularity;
using Volo.Abp.VirtualFileSystem;
If you want to do it manually, install the [Volo.Abp.VirtualFileSystem](https://www.nuget.org/packages/Volo.Abp.VirtualFileSystem) NuGet package to your project and add `[DependsOn(typeof(AbpVirtualFileSystemModule))]` to the [ABP module](Module-Development-Basics.md) class inside your project.
namespace MyCompany.MyProject
{
[DependsOn(typeof(AbpVirtualFileSystemModule))]
public class MyModule : AbpModule
{
//...
}
}
```
## Working with the Embedded Files
#### Registering Embedded Files
### Embed the Files
A file should be first marked as an embedded resource to embed the file into the assembly. The easiest way to do it is to select the file from the **Solution Explorer** and set **Build Action** to **Embedded Resource** from the **Properties** window. Example:
A file should be first marked as an **embedded resource** to embed the file into the assembly. The easiest way to do it is to select the file from the **Solution Explorer** and set **Build Action** to **Embedded Resource** from the **Properties** window. Example:
If you want to add multiple files, this can be tedious. Alternatively, you can directly edit your **.csproj** file:
If you want to add multiple files, this can be tedious. Alternatively, you can directly edit your `.csproj` file:
````C#
<ItemGroup>
@ -45,76 +35,60 @@ If you want to add multiple files, this can be tedious. Alternatively, you can d
This configuration recursively adds all files under the **MyResources** folder of the project (including the files you will add in the future).
Then the module needs to be configured using `AbpVirtualFileSystemOptions` to register the embedded files to the virtual file system. Example:
Embedding a file in the project/assembly may cause problems if a file name contains some special chars. To overcome this limitation;
````C#
using Microsoft.Extensions.DependencyInjection;
using Volo.Abp.Modularity;
using Volo.Abp.VirtualFileSystem;
1. Add [Microsoft.Extensions.FileProviders.Embedded](https://www.nuget.org/packages/Microsoft.Extensions.FileProviders.Embedded) NuGet package to the project that contains the embedded resource(s).
2. Add `<GenerateEmbeddedFilesManifest>true</GenerateEmbeddedFilesManifest>` into the `<PropertyConfig>...</PropertyConfig>` section of your `.csproj` file.
namespace MyCompany.MyProject
{
[DependsOn(typeof(AbpVirtualFileSystemModule))]
public class MyModule : AbpModule
{
public override void ConfigureServices(ServiceConfigurationContext context)
{
Configure<AbpVirtualFileSystemOptions>(options =>
{
//Register all embedded files of this assembly to the virtual file system
> While these two steps are optional and ABP can work without these configuration, it is strongly suggested to make it.
//...
}
}
}
````
### Configure the AbpVirtualFileSystemOptions
The `AddEmbedded` extension method takes a class, finds all embedded files from the assembly of the given class and registers them to the virtual file system. More concisely it could be written as follows:
Use `AbpVirtualFileSystemOptions` [options class](Options.md) to register the embedded files to the virtual file system in the `ConfigureServices` method of your [module](Module-Development-Basics.md).
````C#
options.FileSets.Add(
new EmbeddedFileSet(typeof(MyModule).Assembly), "YourRootNameSpace");
**Example: Add embedded files to the virtual file system**
````csharp
Configure<AbpVirtualFileSystemOptions>(options =>
{
options.FileSets.AddEmbedded<MyModule>();
});
````
> "YourRootNameSpace" is the root namespace of your project. It can be empty if your root namespace is empty.
The `AddEmbedded` extension method takes a class, finds all embedded files from the **assembly of the given class** and registers them to the virtual file system. It is common to pass the module class as the generic argument.
#### Getting Virtual Files: IVirtualFileProvider
`AddEmbedded` can get two optional parameters;
After embedding a file into an assembly and registering it to the virtual file system, the `IVirtualFileProvider` interface can be used to get files or directory contents:
* `baseNamespace`: This may only needed if you didn't configure the `GenerateEmbeddedFilesManifest` step explained above and your root namespace is not empty. In this case, set your root namespace here.
* `baseFolder`: If you don't want to expose all embedded files in the project, but only want to expose a specific folder (and sub folders/files), then you can set the base folder relative to your project root page.
````C#
public class MyService
**Example: Add files under the `MyFiles` folder in the project**
public MyService(IVirtualFileProvider virtualFileProvider)
{
_virtualFileProvider = virtualFileProvider;
}
This example assumes;
public void Foo()
{
//Getting a single file
var file = _virtualFileProvider.GetFileInfo("/MyResources/js/test.js");
var fileContent = file.ReadAsString(); //ReadAsString is an extension method of ABP
* Your project root (default) namespace is `Acme.BookStore`.
* Your project has a folder, named `MyFiles`
* You only want to add `MyFiles` folder to the virtual file system.
//Getting all files/directories under a directory
var directoryContents = _virtualFileProvider.GetDirectoryContents("/MyResources/js");
}
}
````
### Dealing With Embedded Files During Development
#### Dealing With Embedded Files During Development
Embedding a file into a module assembly and being able to use it from another project just by referencing the assembly (or adding a nuget package) is invaluable for creating a re-usable module. However, it does make it a little bit harder to develop the module itself.
Embedding a file into an assembly and being able to use it from another project just by referencing the assembly (or adding a NuGet package) is invaluable for creating a re-usable module. However, it makes it a little bit harder to develop the module itself.
Let's assume that you're developing a module that contains an embedded JavaScript file. Whenever you change this file you must re-compile the project, re-start the application and refresh the browser page to take the change. Obviously, this is very time consuming and tedious.
What is needed is the ability for the application to directly use the physical file at development time and a have a browser refresh reflect any change made in the JavaScript file. The `ReplaceEmbeddedByPhysical` method makes all this possible.
The example below shows an application that depends on a module (`MyModule`) that itself contains embedded files. The application can reach the source code of the module at development time.
The example below shows an application that depends on a module (`MyModule`) that itself contains embedded files. The application can reach the source code of the module at development time.
````C#
[DependsOn(typeof(MyModule))]
@ -128,29 +102,63 @@ public class MyWebAppModule : AbpModule
{
Configure<AbpVirtualFileSystemOptions>(options =>
{
//ReplaceEmbeddedByPhysical gets the root folder of the MyModule project
The code above assumes that `MyWebAppModule` and `MyModule` are two different projects in a Visual Studio solution and `MyWebAppModule` depends on the `MyModule`.
### ASP.NET Core Integration
> The [application startup template](Startup-Templates/Application.md) already uses this technique for the localization files. So, when you change a localization file it automatically detects the change.
## IVirtualFileProvider
After embedding a file into an assembly and registering it to the virtual file system, the `IVirtualFileProvider` interface can be used to get files or directory contents:
public MyService(IVirtualFileProvider virtualFileProvider)
{
_virtualFileProvider = virtualFileProvider;
}
public void Foo()
{
//Getting a single file
var file = _virtualFileProvider
.GetFileInfo("/MyResources/js/test.js");
var fileContent = file.ReadAsString();
//Getting all files/directories under a directory
var directoryContents = _virtualFileProvider
.GetDirectoryContents("/MyResources/js");
}
}
````
## ASP.NET Core Integration
The Virtual File System is well integrated to ASP.NET Core:
* Virtual files can be used just like physical (static) files in a web application.
* Js, css, image files and all other web content types can be embedded into assemblies and used just like the physical files.
* An application (or another module) can override a virtual file of a module just like placing a file with the same name and extension into the same folder of the virtual file.
* An application (or another module) can **override a virtual file** of a module just like placing a file with the same name and extension into the same folder of the virtual file.
#### Virtual Files Middleware
### UseVirtualFiles Middleware
The Virtual Files Middleware is used to serve embedded (js, css, image...) files to clients/browsers just like physical files in the **wwwroot** folder. Add it just after the static file middleware as shown below:
@ -160,4 +168,14 @@ app.UseVirtualFiles();
Adding virtual files middleware after the static files middleware makes it possible to override a virtual file with a real physical file simply by placing it in the same location as the virtual file.
>The Virtual File Middleware only serves the virtual wwwroot folder contents - just like the other static files.
> `UseVirtualFiles()` is already configured for the [application startup template](Startup-Templates/Application.md).
#### Static Virtual File Folders
By default, ASP.NET Core only allows the `wwwroot` folder to contain the static files consumed by the clients. When you use the `UseVirtualFiles` middleware, the following folders also can contain static files:
* Pages
* Views
* Themes
This allows to add `.js`, `.css`... files near to your `.cshtml` file that is easier to develop and maintain your project.