Skip to content

Commit a6de699

Browse files
Added BlazorFileProvider
Updated README Bumped version to 0.1.0-beta-4
1 parent ca4fa22 commit a6de699

File tree

8 files changed

+227
-4
lines changed

8 files changed

+227
-4
lines changed

Directory.Build.props

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -2,6 +2,6 @@
22
<PropertyGroup>
33
<BlazorVersion>0.9.0-preview3-19154-02</BlazorVersion>
44
<AspNetCoreVersion>3.0.0-preview3-19153-02</AspNetCoreVersion>
5-
<ReleaseVersion>0.1.0-beta-3</ReleaseVersion>
5+
<ReleaseVersion>0.1.0-beta-4</ReleaseVersion>
66
</PropertyGroup>
77
</Project>

README.md

Lines changed: 28 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -5,6 +5,10 @@ This is a component library that provides Blazor-style static file embedding for
55

66
Chanegelog:
77

8+
#### Version 0.1.0-beta-4
9+
- Add BlazorFileProvider : Static File Provider that serves embedded files from Blazor Libraries
10+
- Add usage example to RazorComponentSample to serve files from BlazorComponentSample
11+
812
#### Version 0.1.0-beta-3
913
- Restructure source folders
1014
- Add ability to handle multiple component assemblies in one go
@@ -24,14 +28,16 @@ Projects in this repo:
2428

2529
This is the component library that provides all the functionality.
2630

27-
It is a netstandard component library (i.e. a netstandard2.0 library) with one c# code file.
31+
It is a netstandard component library (i.e. a netstandard2.0 library).
2832

2933
## How to use this library
3034

3135
Add the nuget package BlazorEmbedLibrary
3236

3337
https://www.nuget.org/packages/BlazorEmbedLibrary/
3438

39+
#### Using the EmbeddedComponent to extract CSS/JS files
40+
3541
Add a *Using* and an *addTagHelper* to the __ViewImports file
3642

3743
```
@@ -92,6 +98,27 @@ List<System.Reflection.Assembly> Assemblies = new List<System.Reflection.Assembl
9298
9399
```
94100

101+
### Serve Static Files (images/data etc) using BlazorFileProvider
102+
103+
Available in 0.1.0-beta-4 is a new class that provides aspnetcore middleware to server embedded resources as static files in the pipeline.
104+
105+
To use this facility in a Razor Components project, add the nuget to your project and simply add the new BlazorFileProvider to your Configure method and pass it a list of Blazor Library assemblies.
106+
107+
```
108+
app.UseStaticFiles();
109+
app.UseStaticFiles(new StaticFileOptions()
110+
{
111+
FileProvider = new BlazorFileProvider(
112+
new List<Assembly>()
113+
{
114+
typeof(BlazorComponentSample.Component1).Assembly
115+
}
116+
)
117+
});
118+
119+
```
120+
121+
_Note: Currently, there is a restriction that this provider will not allow duplicate file names. This is because CSS files added via the EmbeddedComponent appear in the root of the application, so any images requested by a relative URL will need to come from the root path as well, which means there is no way to distinguish between files with the same name. If two libraries have a file with the same name, the first one found will be used._
95122
## Sample Projects
96123

97124
I have included Blazored.Toast and a simple custom component in the Razorcomponents and Blazor Apps

samples/BlazorEmbedContent/Properties/launchSettings.json

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -21,7 +21,7 @@
2121
"environmentVariables": {
2222
"ASPNETCORE_ENVIRONMENT": "Development"
2323
},
24-
"applicationUrl": "http://localhost:55428/"
24+
"applicationUrl": "http://localhost:5428/"
2525
}
2626
}
2727
}

samples/RazorComponentsSample/RazorComponentsSample.Server/Startup.cs

Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,11 +1,14 @@
11
using Blazored.LocalStorage;
22
using Blazored.Toast.Services;
3+
using BlazorEmbedLibrary;
34
using Microsoft.AspNetCore.Builder;
45
using Microsoft.AspNetCore.Hosting;
56
using Microsoft.Extensions.DependencyInjection;
67
using Microsoft.Extensions.Hosting;
78
using RazorComponentsSample.Server.Components;
89
using RazorComponentsSample.Server.Services;
10+
using System.Collections.Generic;
11+
using System.Reflection;
912

1013
namespace RazorComponentsSample.Server
1114
{
@@ -40,6 +43,10 @@ public void Configure(IApplicationBuilder app, IWebHostEnvironment env)
4043

4144
//app.UseHttpsRedirection();
4245
app.UseStaticFiles();
46+
app.UseStaticFiles(new StaticFileOptions()
47+
{
48+
FileProvider = new BlazorFileProvider(new List<Assembly>() { typeof(BlazorComponentSample.Component1).Assembly })
49+
});
4350

4451
app.UseRouting(routes =>
4552
{
Lines changed: 34 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,34 @@
1+
using System.Collections;
2+
using System.Collections.Generic;
3+
using System.IO;
4+
using System.Reflection;
5+
using Microsoft.Extensions.FileProviders;
6+
7+
namespace BlazorEmbedLibrary
8+
{
9+
internal class BlazorDirectoryContents : IDirectoryContents
10+
{
11+
private readonly Assembly assembly;
12+
13+
public BlazorDirectoryContents(Assembly assembly)
14+
{
15+
this.assembly = assembly;
16+
}
17+
public bool Exists => true;
18+
19+
public IEnumerator<IFileInfo> GetEnumerator()
20+
{
21+
var resources = assembly.GetManifestResourceNames();
22+
foreach (var item in resources)
23+
{
24+
var name = Path.GetFileName(item.Replace(":", "/"));
25+
yield return new BlazorFileInfo(item, name, assembly);
26+
}
27+
}
28+
29+
IEnumerator IEnumerable.GetEnumerator()
30+
{
31+
throw new System.NotImplementedException();
32+
}
33+
}
34+
}

src/BlazorEmbedLibrary/BlazorEmbedLibrary.csproj

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -8,7 +8,7 @@
88
https://dotnet.myget.org/f/blazor-dev/api/v3/index.json;
99
</RestoreAdditionalProjectSources>
1010
<LangVersion>latest</LangVersion>
11-
<BlazorLinkOnBuild>true</BlazorLinkOnBuild>
11+
<BlazorLinkOnBuild>false</BlazorLinkOnBuild>
1212
<Authors>Mister Magoo</Authors>
1313
<Company>MM</Company>
1414
<Description>A Blazor Component that brings Blazor-style static content to Razor Components</Description>
@@ -26,6 +26,7 @@
2626
<ItemGroup>
2727
<PackageReference Include="Microsoft.AspNetCore.Blazor" Version="$(BlazorVersion)" />
2828
<PackageReference Include="Microsoft.AspNetCore.Blazor.Build" Version="$(BlazorVersion)" PrivateAssets="all" />
29+
<PackageReference Include="Microsoft.Extensions.FileProviders.Abstractions" Version="2.2.0" />
2930

3031
<DotNetCliToolReference Include="Microsoft.AspNetCore.Blazor.Cli" Version="$(BlazorVersion)" />
3132
</ItemGroup>
Lines changed: 39 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,39 @@
1+
using System;
2+
using System.Collections.Generic;
3+
using System.IO;
4+
using System.Linq;
5+
using System.Reflection;
6+
using Microsoft.Extensions.FileProviders;
7+
8+
namespace BlazorEmbedLibrary
9+
{
10+
internal class BlazorFileInfo : IFileInfo
11+
{
12+
private readonly string subpath;
13+
private readonly string filename;
14+
private readonly Assembly assembly;
15+
public BlazorFileInfo(string path, string name, Assembly assembly)
16+
{
17+
this.subpath = path;
18+
this.filename = name;
19+
this.assembly = assembly;
20+
}
21+
22+
public bool Exists => true;
23+
24+
public long Length => assembly.GetManifestResourceStream(subpath).Length;
25+
26+
public string PhysicalPath => $"/{filename}";
27+
28+
public string Name => filename;
29+
30+
public DateTimeOffset LastModified => DateTimeOffset.FromFileTime( int.Parse(assembly.GetName().Version.ToString().Replace(".","")));
31+
32+
public bool IsDirectory => false;
33+
34+
public Stream CreateReadStream()
35+
{
36+
return assembly.GetManifestResourceStream(subpath);
37+
}
38+
}
39+
}
Lines changed: 115 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,115 @@
1+
using Microsoft.AspNetCore.Components;
2+
using Microsoft.AspNetCore.Components.RenderTree;
3+
using Microsoft.Extensions.FileProviders;
4+
using Microsoft.Extensions.Primitives;
5+
using Microsoft.JSInterop;
6+
using System;
7+
using System.Collections.Generic;
8+
using System.IO;
9+
using System.Linq;
10+
using System.Reflection;
11+
using System.Threading.Tasks;
12+
13+
namespace BlazorEmbedLibrary
14+
{
15+
public class BlazorFileProvider : IFileProvider
16+
{
17+
/// <summary>
18+
/// Displays a list of the embedded files for each assembly and extra console logging.
19+
/// </summary>
20+
public bool Debug { get; set; } = false;
21+
/// <summary>
22+
/// Allows multiple Assemblies to be passed as a list e.g. Assemblies=@ListOfAssemblies (where ListOfAssemblies is List<Assembly>
23+
/// </summary>
24+
private List<Assembly> Assemblies { get; set; }
25+
26+
private Dictionary<string, Assembly> fileMap;
27+
private Dictionary<string, Assembly> assMap;
28+
private Dictionary<string, string> nameMap;
29+
public BlazorFileProvider(List<Assembly> assemblies)
30+
{
31+
Assemblies = assemblies ?? new List<Assembly>();
32+
fileMap = new Dictionary<string, Assembly>();
33+
assMap = new Dictionary<string, Assembly>();
34+
nameMap = new Dictionary<string, string>();
35+
LoadEmbeddedResources();
36+
}
37+
private void LoadEmbeddedResources()
38+
{
39+
foreach (var assembly in Assemblies)
40+
{
41+
string name = assembly.GetName().Name;
42+
assMap.Add(name, assembly);
43+
foreach (var item in ListEmbeddedResources(assembly))
44+
{
45+
string key = Path.GetFileName(item.Replace(":","/"));
46+
if (nameMap.ContainsKey(key))
47+
{
48+
DebugLog($"BFP: Duplicate resource - unable to add {key} from {name}");
49+
}
50+
else
51+
{
52+
fileMap.Add(key, assembly);
53+
nameMap.Add(key, item);
54+
DebugLog($"BFP: Mapped {name}.{item} as {key}");
55+
}
56+
}
57+
}
58+
}
59+
60+
private void DebugLog(string message)
61+
{
62+
if (Debug) Console.WriteLine(message);
63+
}
64+
65+
private IEnumerable<string> ListEmbeddedResources(Assembly assembly)
66+
{
67+
var resources = assembly.GetManifestResourceNames();
68+
DebugLog($"Got resources: {string.Join(", ", resources)}");
69+
DebugLog($"Using assembly: {assembly.GetName().Name}");
70+
foreach (var item in resources)
71+
{
72+
yield return item;
73+
}
74+
}
75+
76+
public IFileInfo GetFileInfo(string subpath)
77+
{
78+
DebugLog($"BFP: GetFileInfo({subpath})");
79+
var key = Path.GetFileName(subpath);
80+
if (nameMap.ContainsKey(key))
81+
{
82+
return new BlazorFileInfo(nameMap[key], key, fileMap[key]);
83+
}
84+
return new NotFoundFileInfo(subpath);
85+
}
86+
87+
public IDirectoryContents GetDirectoryContents(string subpath)
88+
{
89+
DebugLog($"BFP: GetDirectoryContents({subpath})");
90+
var parts = subpath.Split('/');
91+
string root;
92+
if (string.IsNullOrEmpty(parts[0]) && parts.Length>2)
93+
{
94+
root = parts[1];
95+
} else
96+
{
97+
root = parts[0];
98+
}
99+
100+
if (root.Equals("_content"))
101+
{
102+
var name = parts[parts.Length-1];
103+
return new BlazorDirectoryContents(assMap[name]);
104+
105+
}
106+
return new NotFoundDirectoryContents();
107+
}
108+
109+
public IChangeToken Watch(string filter)
110+
{
111+
throw new NotImplementedException();
112+
}
113+
114+
}
115+
}

0 commit comments

Comments
 (0)