Servir les fichiers incorporés dans la bibliothèque .net au format HTML dans Blazor

.net-standard blazor c# embedded-resource javascript

Question

Je crée un Blazor projet v0.5.1 qui utilise une bibliothèque standard .NET fourni tous la logique métier. Cette bibliothèque contient plusieurs fichiers WAV stockés en tant que ressources incorporées.

Consommer l'une des ressources d'une technologie .NET typique (WinForms, WPF, etc.) faisant référence à cette bibliothèque peut être fait avec ceci:

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();

Je voudrais faire l'équivalent dans Blazor. À l’heure actuelle, certains sons fonctionnent dans l’application en copiant / collant les fichiers wav dans le dossier wwwroot\sounds du projet afin qu’il soit diffusé sous forme de contenu HTML statique. Ensuite, en JavaScript, je peux en jouer un comme ceci:

const audio = new Audio"\sounds\mysound.wave"]);
audio.currentTime = 0;
audio.play();

Mais ce que je voudrais vraiment faire, c’est éviter le copier-coller et, d’une manière ou d’une autre, servir les fichiers de manière dynamique en tant que points de terminaison, afin que ce soit transparent pour JS.

Réponse populaire

Eh bien, j'ai pu l'obtenir. Je ne suis pas sûr que ce soit la meilleure solution, mais cela semble bien fonctionner.

J'ai dû ajouter l'extension Blazor Storage:

https://github.com/BlazorExtensions/Storage

qui agit en tant que proxy pour JavaScript SessionStorage et LocalStorage à partir de .NET. Une fois chargé, j'ai ajouté chaque fichier wav intégré à partir de .NET comme ceci:

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 est une manipulation de flux .NET plutôt standard:

    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);
    }

Désormais, toutes les données sont stockées dans JavaScript SessionStorage sous forme de chaînes. L'astuce consiste maintenant à décoder cela en audio. Avec l'aide de cette méthode d'assistance JS (grâce à cet article StackOverflow ):

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 });
}

Mettez cela et cela dans le fichier JsInterop.js du BlazorComponent:

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;
    },
};

Et ENFIN, les sons peuvent être appelés par leur nom. 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]
    );
}



Sous licence: CC-BY-SA with attribution
Non affilié à Stack Overflow
Est-ce KB légal? Oui, apprenez pourquoi
Sous licence: CC-BY-SA with attribution
Non affilié à Stack Overflow
Est-ce KB légal? Oui, apprenez pourquoi