Servi i file incorporati nella libreria .net in HTML in Blazor

.net-standard blazor c# embedded-resource javascript

Domanda

Sto creando un Blazor v0.5.1 progetto che utilizza una libreria .NET Standard fornito tutta la logica di business. Questa libreria ha diversi file WAV memorizzati come risorse incorporate.

Consumare una delle risorse in una tipica tecnologia .NET (WinForms, WPF, ecc.) Che fa riferimento a questa libreria può essere fatta con questo:

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

Mi piacerebbe fare l'equivalente in Blazor. In questo momento, ho dei suoni che funzionano nell'app copiando / incollando i file wav nella cartella wwwroot\sounds del progetto, in modo che venga utilizzata come contenuto HTML statico. Quindi, in JavaScript, posso riprodurne uno come questo:

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

Ma quello che mi piacerebbe davvero fare è evitare il copia-incolla e in qualche modo distribuire i file dinamicamente come quegli endpoint in modo che sia trasparente per JS.

Risposta popolare

Bene, sono riuscito a capirlo. Non sono sicuro se il modo migliore, ma sembra funzionare bene.

Ho dovuto aggiungere l'estensione Storage blazor:

https://github.com/BlazorExtensions/Storage

che funge da proxy per JavaScript SessionStorage e LocalStorage da .NET. Una volta caricato, ho aggiunto ogni file wav incorporato da .NET in questo modo:

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 è una manipolazione di flusso .NET piuttosto 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);
    }

Ora tutti i dati sono archiviati in JavaScript SessionStorage come stringhe. Il trucco ora è quello di decodificarlo per l'audio. Con l'aiuto di questo metodo helper JS (grazie a questo post 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 });
}

Metti questo e questo nel file JsInterop.js del 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;
    },
};

E INFINE, i suoni possono essere richiamati per nome da .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]
    );
}



Autorizzato sotto: CC-BY-SA with attribution
Non affiliato con Stack Overflow
È legale questo KB? Sì, impara il perché
Autorizzato sotto: CC-BY-SA with attribution
Non affiliato con Stack Overflow
È legale questo KB? Sì, impara il perché