将 .net 库中嵌入的文件提供给 Blazor 中的 HTML
Serve files embedded in .net library to HTML in Blazor
我正在创建一个 Blazor 项目 v0.5.1,它使用 .NET Standard 库来提供所有业务逻辑。这个库有几个 WAV 文件存储为嵌入式资源。
使用引用此库的典型 .NET 技术(WinForms、WPF 等)中的资源之一:
var assemName = "MyLibName";
var assembly = AppDomain
.CurrentDomain
.GetAssemblies()
.First(a => a.GetName().Name == assemName);
//memory stream
var stream = assembly.GetManifestResourceStream($"{assemName}.mysound.wav");
//Can play the file at some point later
var player = new SoundPlayer(stream)
player.Play();
我想在 Blazor 中做同样的事情。现在,我通过 copy/pasting 将 wav 文件放入项目的 wwwroot\sounds
文件夹中,在应用程序中使用声音,因此它作为静态 HTML 内容提供。然后,在JavaScript,我可以这样玩:
const audio = new Audio"\sounds\mysound.wave"]);
audio.currentTime = 0;
audio.play();
但我真正想做的是避免复制粘贴,并以某种方式将文件作为那些端点动态提供,因此它对 JS 是透明的。
好吧,我能够得到它。不确定这是否是最好的方法,但它似乎运作良好。
我必须添加 blazor 存储扩展:
https://github.com/BlazorExtensions/Storage
作为 .NET 中 JavaScript SessionStorage 和 LocalStorage 的代理。加载后,我从 .NET 添加了每个嵌入式 wav 文件,如下所示:
foreach (var kvp in SoundStreamDictionary)
{
await sessionStorage.SetItem(
kvp.Key.ToString().ToLower() //Key is the name of the sound
, kvp.Value.ToBase64() //Value is a Stream object
);
}
ToBase64
是非常标准的 .NET 流操作:
public static string ToBase64(this Stream stream)
{
byte[] bytes;
using (var memoryStream = new MemoryStream())
{
stream.Position = 0;
stream.CopyTo(memoryStream);
bytes = memoryStream.ToArray();
}
return Convert.ToBase64String(bytes);
}
现在所有数据都作为字符串存储在 JavaScript SessionStorage 中。现在的技巧是将其解码为音频。借助这个 JS 辅助方法(感谢这个Whosebug post):
function b64toBlob(b64Data, contentType, sliceSize) {
contentType = contentType || '';
sliceSize = sliceSize || 512;
const byteCharacters = atob(b64Data);
const byteArrays = [];
for (let offset = 0; offset < byteCharacters.length; offset += sliceSize) {
const slice = byteCharacters.slice(offset, offset + sliceSize);
const byteNumbers = new Array(slice.length);
for (let i = 0; i < slice.length; i++) {
byteNumbers[i] = slice.charCodeAt(i);
}
const byteArray = new Uint8Array(byteNumbers);
byteArrays.push(byteArray);
}
return new Blob(byteArrays, { type: contentType });
}
将那个和这个放入 BlazorComponent 的 JsInterop.js 文件中:
const soundAudios = [];
window.JsSound = {
loadSounds: function (sounds) {
sounds.forEach(sound => {
//Blazor.Storage extension adds extra double quotes so trim
const str64 = sessionStorage.getItem(sound.path).slice(1, -1);
const blob = b64toBlob(str64, "audio/wav");
const blobUrl = URL.createObjectURL(blob);
const audio = new Audio(blobUrl);
soundAudios[sound.id] = audio;
});
return true;
},
play: function (id) {
const audio = soundAudios[id];
audio.currentTime = 0;
audio.play();
return true;
},
};
最后,声音可以通过 .Net 中的名称调用:
private IDictionary<string, int> soundDict = new Dictionary<string, int>();
public Task<string> LoadSounds(IEnumerable<string> fileNames)
{
var sounds = fileNames
.Select(name =>
{
var snd = new
{
id = soundDict.Count,
path = name
};
soundDict.Add(name, snd.id);
return snd;
})
.ToList();
return JSRuntime.Current.InvokeAsync<string>(
"JsSound.loadSounds"
, sounds
);
}
public Task<string> Play(string name)
{
return JSRuntime.Current.InvokeAsync<string>(
"JsSound.play"
, soundDict[name]
);
}
我正在创建一个 Blazor 项目 v0.5.1,它使用 .NET Standard 库来提供所有业务逻辑。这个库有几个 WAV 文件存储为嵌入式资源。
使用引用此库的典型 .NET 技术(WinForms、WPF 等)中的资源之一:
var assemName = "MyLibName";
var assembly = AppDomain
.CurrentDomain
.GetAssemblies()
.First(a => a.GetName().Name == assemName);
//memory stream
var stream = assembly.GetManifestResourceStream($"{assemName}.mysound.wav");
//Can play the file at some point later
var player = new SoundPlayer(stream)
player.Play();
我想在 Blazor 中做同样的事情。现在,我通过 copy/pasting 将 wav 文件放入项目的 wwwroot\sounds
文件夹中,在应用程序中使用声音,因此它作为静态 HTML 内容提供。然后,在JavaScript,我可以这样玩:
const audio = new Audio"\sounds\mysound.wave"]);
audio.currentTime = 0;
audio.play();
但我真正想做的是避免复制粘贴,并以某种方式将文件作为那些端点动态提供,因此它对 JS 是透明的。
好吧,我能够得到它。不确定这是否是最好的方法,但它似乎运作良好。
我必须添加 blazor 存储扩展:
https://github.com/BlazorExtensions/Storage
作为 .NET 中 JavaScript SessionStorage 和 LocalStorage 的代理。加载后,我从 .NET 添加了每个嵌入式 wav 文件,如下所示:
foreach (var kvp in SoundStreamDictionary)
{
await sessionStorage.SetItem(
kvp.Key.ToString().ToLower() //Key is the name of the sound
, kvp.Value.ToBase64() //Value is a Stream object
);
}
ToBase64
是非常标准的 .NET 流操作:
public static string ToBase64(this Stream stream)
{
byte[] bytes;
using (var memoryStream = new MemoryStream())
{
stream.Position = 0;
stream.CopyTo(memoryStream);
bytes = memoryStream.ToArray();
}
return Convert.ToBase64String(bytes);
}
现在所有数据都作为字符串存储在 JavaScript SessionStorage 中。现在的技巧是将其解码为音频。借助这个 JS 辅助方法(感谢这个Whosebug post):
function b64toBlob(b64Data, contentType, sliceSize) {
contentType = contentType || '';
sliceSize = sliceSize || 512;
const byteCharacters = atob(b64Data);
const byteArrays = [];
for (let offset = 0; offset < byteCharacters.length; offset += sliceSize) {
const slice = byteCharacters.slice(offset, offset + sliceSize);
const byteNumbers = new Array(slice.length);
for (let i = 0; i < slice.length; i++) {
byteNumbers[i] = slice.charCodeAt(i);
}
const byteArray = new Uint8Array(byteNumbers);
byteArrays.push(byteArray);
}
return new Blob(byteArrays, { type: contentType });
}
将那个和这个放入 BlazorComponent 的 JsInterop.js 文件中:
const soundAudios = [];
window.JsSound = {
loadSounds: function (sounds) {
sounds.forEach(sound => {
//Blazor.Storage extension adds extra double quotes so trim
const str64 = sessionStorage.getItem(sound.path).slice(1, -1);
const blob = b64toBlob(str64, "audio/wav");
const blobUrl = URL.createObjectURL(blob);
const audio = new Audio(blobUrl);
soundAudios[sound.id] = audio;
});
return true;
},
play: function (id) {
const audio = soundAudios[id];
audio.currentTime = 0;
audio.play();
return true;
},
};
最后,声音可以通过 .Net 中的名称调用:
private IDictionary<string, int> soundDict = new Dictionary<string, int>();
public Task<string> LoadSounds(IEnumerable<string> fileNames)
{
var sounds = fileNames
.Select(name =>
{
var snd = new
{
id = soundDict.Count,
path = name
};
soundDict.Add(name, snd.id);
return snd;
})
.ToList();
return JSRuntime.Current.InvokeAsync<string>(
"JsSound.loadSounds"
, sounds
);
}
public Task<string> Play(string name)
{
return JSRuntime.Current.InvokeAsync<string>(
"JsSound.play"
, soundDict[name]
);
}