Dateien in .net Bibliothek in HTML in Blazor enthalten

.net-standard blazor c# embedded-resource javascript

Frage

Ich erstelle ein Blazor- Projekt v0.5.1, das eine .NET-Standardbibliothek verwendet, um die gesamte Geschäftslogik bereitzustellen. Diese Bibliothek enthält mehrere WAV-Dateien, die als eingebettete Ressourcen gespeichert sind.

Das Verwenden einer der Ressourcen in einer typischen .NET-Technologie (WinForms, WPF usw.), die auf diese Bibliothek verweisen, kann folgendermaßen durchgeführt werden:

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

Ich würde gerne das Äquivalent in Blazor machen. Im Moment habe ich Sounds in der App arbeiten durch Kopieren / Einfügen der WAV-Dateien in wwwroot\sounds Ordner des Projekts, so dass es als statischer HTML-Inhalt serviert wird. Dann kann ich in JavaScript eines davon spielen:

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

Aber was ich wirklich gerne tun würde, ist das Kopieren-Einfügen zu vermeiden und irgendwie die Dateien dynamisch als diese Endpunkte zu dienen, so dass es für JS transparent ist.

Beliebte Antwort

Nun, ich konnte es bekommen. Nicht sicher, ob es der beste Weg ist, aber es scheint gut zu funktionieren.

Ich musste die Erweiterung blazor Storage hinzufügen:

https://github.com/BlazorExtensions/Storage

Dies dient als Proxy für das JavaScript SessionStorage und LocalStorage von .NET. Nach dem Laden habe ich jede eingebettete WAV-Datei wie folgt aus .NET hinzugefügt:

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

Die ToBase64 ist ziemlich Standard-.NET-Stream-Manipulation:

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

Jetzt werden alle Daten in JavaScript SessionStorage als Strings gespeichert. Trick ist jetzt, das zu Audio zu entschlüsseln. Mit Hilfe dieser JS-Hilfsmethode (dank dieses StackOverflow-Posts ):

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

Setze das und das in die JsInterop.js-Datei der 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;
    },
};

Und ENDLICH können die Sounds mit dem Namen von .Net aufgerufen werden:

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


Lizenziert unter: CC-BY-SA with attribution
Nicht verbunden mit Stack Overflow
Lizenziert unter: CC-BY-SA with attribution
Nicht verbunden mit Stack Overflow