Skip to content

Commit 37b0305

Browse files
committedMar 23, 2025··
Understanding the Embedded Files in ABP Framework.
Resolve #22425
1 parent 38c9ba4 commit 37b0305

File tree

4 files changed

+248
-0
lines changed

4 files changed

+248
-0
lines changed
 
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,248 @@
1+
# Understanding the Embedded Files in ABP Framework
2+
3+
Embedded Files functionality in .NET applications allows external files (like configuration files, images, etc.) to be directly embedded into assemblies (.exe or .dll). This simplifies deployment, prevents file loss or tampering, improves security and performance, and reduces path and dependency management issues. Through embedded resources, programs can access these files more conveniently without additional file operations.
4+
5+
## Embedding Files in Your Project
6+
7+
We embed `Volo\Abp\MyModule\Localization\*.json` files into the assembly in our `MyModule.csproj`.
8+
9+
```xml
10+
<Project Sdk="Microsoft.NET.Sdk">
11+
12+
<PropertyGroup>
13+
<TargetFramework>net9.0</TargetFramework>
14+
<OutputType>Exe</OutputType>
15+
<Nullable>enable</Nullable>
16+
</PropertyGroup>
17+
18+
<ItemGroup>
19+
<PackageReference Include="Microsoft.Extensions.Hosting" Version="9.0.0" />
20+
<PackageReference Include="Volo.Abp.VirtualFileSystem" Version="9.0.0" />
21+
</ItemGroup>
22+
23+
<ItemGroup>
24+
<None Remove="Volo\Abp\MyModule\Localization\*.json" />
25+
<EmbeddedResource Include="Volo\Abp\MyModule\Localization\*.json" />
26+
</ItemGroup>
27+
28+
</Project>
29+
```
30+
31+
If we check the `en.json` file in our IDE, we'll see it's embedded in the assembly.
32+
33+
![image](1.png)
34+
35+
When we decompile the built `MyModule.dll` file, we can also see the `en.json` file.
36+
37+
![image](2.png)
38+
39+
## Accessing Embedded Files in Code
40+
41+
```csharp
42+
public class Program
43+
{
44+
public static async Task<int> Main(string[] args)
45+
{
46+
var embeddedFiles = typeof(Program).Assembly.GetManifestResourceNames();
47+
foreach (var embeddedFile in embeddedFiles)
48+
{
49+
Console.WriteLine(embeddedFile);
50+
var fileStream = typeof(Program).Assembly.GetManifestResourceStream(embeddedFile);
51+
if (fileStream != null)
52+
{
53+
using var reader = new System.IO.StreamReader(fileStream);
54+
var content = await reader.ReadToEndAsync();
55+
Console.WriteLine(content);
56+
}
57+
}
58+
}
59+
}
60+
```
61+
This code will output the embedded file names and their contents.
62+
63+
```
64+
MyModule.Volo.Abp.MyModule.Localization.en.json
65+
66+
{
67+
"key":"value"
68+
}
69+
```
70+
71+
## Integrating with ABP Virtual File System
72+
73+
The ABP Virtual File System makes it possible to manage files that don't 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.
74+
75+
The following code shows how to add embedded files from the current application assembly to the ABP virtual file system:
76+
77+
```csharp
78+
[DependsOn(typeof(AbpVirtualFileSystemModule))]
79+
public class MyModule : AbpModule
80+
{
81+
public override void ConfigureServices(ServiceConfigurationContext context)
82+
{
83+
Configure<AbpVirtualFileSystemOptions>(options =>
84+
{
85+
options.FileSets.AddEmbedded<MyModule>();
86+
});
87+
}
88+
}
89+
```
90+
91+
ABP creates an `AbpEmbeddedFileProvider` to access the embedded files.
92+
93+
The full name of `en.json` is `MyModule.Volo.Abp.MyModule.Localization.en.json`. Without directory information, ABP uses `.` to split and assume directory information. This creates the following directory structure in the virtual file system:
94+
95+
```
96+
[Dir] [/MyModule]
97+
[Dir] [/MyModule/Volo]
98+
[Dir] [/MyModule/Volo/Abp]
99+
[Dir] [/MyModule/Volo/Abp/MyModule]
100+
[Dir] [/MyModule/Volo/Abp/MyModule/Localization]
101+
[File] [/MyModule/Volo/Abp/MyModule/Localization/en.json]
102+
```
103+
104+
Now you can inject `IVirtualFileProvider` to access embedded files using the directory/file structure above.
105+
106+
## Manifest Embedded File Provider
107+
108+
You might have noticed that using `.` to split and assume directory information can cause confusion if filenames contain dots.
109+
110+
For example, if your filename is `zh.hans.json`, ABP will generate the following directory structure, which isn't what we want:
111+
112+
```
113+
[Dir] [/MyModule]
114+
[Dir] [/MyModule/Volo]
115+
[Dir] [/MyModule/Volo/Abp]
116+
[Dir] [/MyModule/Volo/Abp/MyModule]
117+
[Dir] [/MyModule/Volo/Abp/MyModule/Localization]
118+
[Dir] [/MyModule/Volo/Abp/MyModule/Localization/zh]
119+
[File] [/MyModule/Volo/Abp/MyModule/Localization/zh/hans.json]
120+
```
121+
122+
Microsoft provides the `Microsoft.Extensions.FileProviders.Manifest` library to solve this problem.
123+
124+
We need to add this package dependency and set `<GenerateEmbeddedFilesManifest>true</GenerateEmbeddedFilesManifest>` in our project:
125+
126+
```xml
127+
<Project Sdk="Microsoft.NET.Sdk">
128+
129+
<PropertyGroup>
130+
<TargetFramework>net9.0</TargetFramework>
131+
<OutputType>Exe</OutputType>
132+
<Nullable>enable</Nullable>
133+
<GenerateEmbeddedFilesManifest>true</GenerateEmbeddedFilesManifest>
134+
</PropertyGroup>
135+
136+
<ItemGroup>
137+
<PackageReference Include="Microsoft.Extensions.Hosting" Version="9.0.0" />
138+
<PackageReference Include="Volo.Abp.VirtualFileSystem" Version="9.0.0" />
139+
<PackageReference Include="Microsoft.Extensions.FileProviders.Manifest" Version="9.0.0" />
140+
</ItemGroup>
141+
142+
<ItemGroup>
143+
<None Remove="Volo\Abp\MyModule\Localization\*.json" />
144+
<EmbeddedResource Include="Volo\Abp\MyModule\Localization\*.json" />
145+
</ItemGroup>
146+
147+
</Project>
148+
```
149+
150+
After rebuilding the project, when we decompile `MyModule.dll`, we'll see an additional `Microsoft.Extensions.FileProviders.Embedded.Manifest.xml` file.
151+
152+
![image](3.png)
153+
154+
This manifest file stores all the directory and file information of embedded resources. When ABP finds this file, it will use `ManifestEmbeddedFileProvider` instead of `AbpEmbeddedFileProvider` to access embedded files:
155+
156+
```xml
157+
<?xml version="1.0" encoding="utf-8" standalone="yes"?>
158+
<Manifest>
159+
<ManifestVersion>1.0</ManifestVersion>
160+
<FileSystem>
161+
<File Name="Microsoft.Extensions.FileProviders.Embedded.Manifest.xml">
162+
<ResourcePath>Microsoft.Extensions.FileProviders.Embedded.Manifest.xml</ResourcePath>
163+
</File>
164+
<Directory Name="Volo">
165+
<Directory Name="Abp">
166+
<Directory Name="MyModule">
167+
<Directory Name="Localization">
168+
<File Name="zh.hans.json">
169+
<ResourcePath>MyModule.Volo.Abp.MyModule.Localization.zh.hans.json</ResourcePath>
170+
</File>
171+
</Directory>
172+
</Directory>
173+
</Directory>
174+
</Directory>
175+
</FileSystem>
176+
</Manifest>
177+
```
178+
179+
## Parameters of AddEmbedded Method
180+
181+
The `AddEmbedded` method can take two parameters:
182+
183+
### baseNamespace
184+
185+
This may only be needed if you haven't used the `Manifest Embedded File Provider` and your project's `root namespace` isn't empty. In this case, set your root namespace here.
186+
187+
The `root namespace` is your project's name by default. You can change it or set it to empty in the `csproj` file.
188+
189+
```xml
190+
<Project Sdk="Microsoft.NET.Sdk">
191+
<PropertyGroup>
192+
<RootNamespace>MyModule</RootNamespace>
193+
</PropertyGroup>
194+
</Project>
195+
```
196+
197+
```xml
198+
<Project Sdk="Microsoft.NET.Sdk">
199+
<PropertyGroup>
200+
<RootNamespace></RootNamespace>
201+
</PropertyGroup>
202+
</Project>
203+
```
204+
205+
```csharp
206+
Configure<AbpVirtualFileSystemOptions>(options =>
207+
{
208+
options.FileSets.AddEmbedded<MyModule>(baseNamespace: "MyModule");
209+
});
210+
```
211+
212+
```
213+
[Dir] [/Volo]
214+
[Dir] [/Volo/Abp]
215+
[Dir] [/Volo/Abp/MyModule]
216+
[Dir] [/Volo/Abp/MyModule/Localization]
217+
[File] [/Volo/Abp/MyModule/Localization/en.json]
218+
```
219+
220+
### baseFolder
221+
222+
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), you can set the base folder relative to your project root folder.
223+
224+
> baseFolder is only effective when using `Manifest Embedded File Provider`.
225+
226+
You can set the `baseFolder` parameter to `/Volo/Abp/MyModule`, resulting in this directory structure:
227+
228+
```csharp
229+
Configure<AbpVirtualFileSystemOptions>(options =>
230+
{
231+
options.FileSets.AddEmbedded<MyModule>(baseFolder: "/Volo/Abp/MyModule");
232+
});
233+
```
234+
235+
```
236+
[Dir] [Localization]
237+
[File] [Localization/en.json]
238+
```
239+
240+
## Summary
241+
242+
We recommend using the `Manifest Embedded File Provider` in your projects and libraries. Hope this article has been helpful.
243+
244+
## References
245+
246+
[ABP Virtual File System](https://abp.io/docs/latest/framework/infrastructure/virtual-file-system)
247+
248+
[Manifest Embedded File Provider](https://learn.microsoft.com/en-us/aspnet/core/fundamentals/file-providers#manifest-embedded-file-provider)

0 commit comments

Comments
 (0)
Please sign in to comment.