Skip to content

Releases: IEvangelist/blazorators

v1.3.0 Dependency Generation

16 Mar 04:01
Compare
Choose a tag to compare
  • Add Blazor.Geolocation.WebAssembly library.
  • Update sample consuming project to show geolocation working.
  • Support generating dependencies from callbacks.

image

Full Changelog: 1.2.0...1.3.0

Release v1.2.0 services and DI

13 Mar 21:20
d3b3bc0
Compare
Choose a tag to compare

As an example, the official Blazor.LocalStorage.WebAssembly package consumes the Blazor.SourceGenerators package. It exposes extension methods specific to Blazor WebAssembly and the localStorage Web API.

Consider the SynchronousLocalStorageExtensions.cs C# file:

// Copyright (c) David Pine. All rights reserved.
// Licensed under the MIT License.

namespace Microsoft.JSInterop;

/// <summary>
/// Source generated extension methods on the <see cref="IJSInProcessRuntime"/> implementation.
/// </summary>
[JSAutoGenericInterop(
    TypeName = "Storage",
    Implementation = "window.localStorage",
    Url = "https://developer.mozilla.org/docs/Web/API/Window/localStorage",
    GenericMethodDescriptors = new[]
    {
        "getItem",
        "setItem:value"
    })]
internal static partial class SynchronousLocalStorageExtensions
{
}

This code designates itself into the Microsoft.JSInterop namespace, making all of the source generated extensions available to anyone consumer who uses types from this namespace. It uses the JSAutoInterop to specify:

  • TypeName = "Storage": sets the type to Storage.
  • Implementation = "window.localStorage": expresses how to locate the implementation of the specified type from the globally scoped window object, this is the localStorage implementation.
  • Url: sets the URL for the implementation.
  • GenericMethodDescriptors: Defines the methods that should support generics as part of their source-generation. The localStorage.getItem is specified to return a generic TResult type, and the localStorage.setItem has its parameter with a name of value specified as a generic TArg type.

The generic method descriptors syntax is:
"methodName" for generic return type and "methodName:parameterName" for generic parameter type.

The file needs to define an extension class and needs to be partial, for example; internal static partial class. Decorating the class with the JSAutoInterop (or `JSAutoGenericInterop) attribute will source generate the following C# code:

// Copyright (c) David Pine. All rights reserved.
// Licensed under the MIT License:
// https://github.com/IEvangelist/blazorators/blob/main/LICENSE
// Auto-generated by blazorators.

using Blazor.Serialization.Extensions;
using System.Text.Json;

#nullable enable
namespace Microsoft.JSInterop;

internal static partial class SynchronousLocalStorageExtensions
{
    /// <summary>
    /// Source generated extension method implementation of <c>window.localStorage.clear</c>.
    /// <a href="https://developer.mozilla.org/docs/Web/API/Storage/clear"></a>
    /// </summary>
    public static void Clear(
        this IJSInProcessRuntime javaScript) =>
        javaScript.InvokeVoid("window.localStorage.clear");

    /// <summary>
    /// Source generated extension method implementation of <c>window.localStorage.getItem</c>.
    /// <a href="https://developer.mozilla.org/docs/Web/API/Storage/getItem"></a>
    /// </summary>
    public static TResult? GetItem<TResult>(
        this IJSInProcessRuntime javaScript,
        string key,
        JsonSerializerOptions? options = null) =>
        javaScript.Invoke<string?>(
            "window.localStorage.getItem",
            key)
            .FromJson<TResult>(options);

    /// <summary>
    /// Source generated extension method implementation of <c>window.localStorage.key</c>.
    /// <a href="https://developer.mozilla.org/docs/Web/API/Storage/key"></a>
    /// </summary>
    public static string? Key(
        this IJSInProcessRuntime javaScript,
        double index) =>
        javaScript.Invoke<string?>(
            "window.localStorage.key",
            index);

    /// <summary>
    /// Source generated extension method implementation of <c>window.localStorage.removeItem</c>.
    /// <a href="https://developer.mozilla.org/docs/Web/API/Storage/removeItem"></a>
    /// </summary>
    public static void RemoveItem(
        this IJSInProcessRuntime javaScript,
        string key) =>
        javaScript.InvokeVoid(
            "window.localStorage.removeItem",
            key);

    /// <summary>
    /// Source generated extension method implementation of <c>window.localStorage.setItem</c>.
    /// <a href="https://developer.mozilla.org/docs/Web/API/Storage/setItem"></a>
    /// </summary>
    public static void SetItem<TArg>(
        this IJSInProcessRuntime javaScript,
        string key,
        TArg value,
        JsonSerializerOptions? options = null) =>
        javaScript.InvokeVoid(
            "window.localStorage.setItem",
            key,
            value.ToJson(options));

    /// <summary>
    /// Source generated extension method implementation of <c>window.localStorage.length</c>.
    /// <a href="https://developer.mozilla.org/docs/Web/API/Storage/length"></a>
    /// </summary>
    public static double Length(
        this IJSInProcessRuntime javaScript) =>
            javaScript.Invoke<double>(
                "eval", "window.localStorage.length");
}

These internal extension methods rely on the IJSInProcessRuntime to perform JavaScript interop. From the given TypeName and corresponding Implementation, the following code is also generated:

  • IStorage.g.cs: The interface for the corresponding Storage Web API surface area.
  • LocalStorge.g.cs: The internal implementation of the IStorage interface.
  • LocalStorageServiceCollectionExtensions.g.cs: Extension methods to add the IStorage service to the dependency injection IServiceCollection.

Here is the source generated IStorage.g.cs:

using Blazor.Serialization.Extensions;
using System.Text.Json;

#nullable enable
namespace Microsoft.JSInterop;

/// <summary>
/// Source generated interface definition of the <c>Storage</c> type.
/// </summary>
public interface IStorage
{
    /// <summary>
    /// Source generated implementation of <c>window.localStorage.clear</c>.
    /// <a href="https://developer.mozilla.org/docs/Web/API/Storage/clear"></a>
    /// </summary>
    void Clear();

    /// <summary>
    /// Source generated implementation of <c>window.localStorage.getItem</c>.
    /// <a href="https://developer.mozilla.org/docs/Web/API/Storage/getItem"></a>
    /// </summary>
    TResult? GetItem<TResult>(string key, JsonSerializerOptions? options = null);

    /// <summary>
    /// Source generated implementation of <c>window.localStorage.key</c>.
    /// <a href="https://developer.mozilla.org/docs/Web/API/Storage/key"></a>
    /// </summary>
    string? Key(double index);

    /// <summary>
    /// Source generated implementation of <c>window.localStorage.removeItem</c>.
    /// <a href="https://developer.mozilla.org/docs/Web/API/Storage/removeItem"></a>
    /// </summary>
    void RemoveItem(string key);

    /// <summary>
    /// Source generated implementation of <c>window.localStorage.setItem</c>.
    /// <a href="https://developer.mozilla.org/docs/Web/API/Storage/setItem"></a>
    /// </summary>
    void SetItem<TArg>(string key, TArg value, JsonSerializerOptions? options = null);

    /// <summary>
    /// Source generated implementation of <c>window.localStorage.length</c>.
    /// <a href="https://developer.mozilla.org/docs/Web/API/Storage/length"></a>
    /// </summary>
    double Length { get; }
}

Here is the source generated LocalStorage implementation:

using Blazor.Serialization.Extensions;
using System.Text.Json;

#nullable enable
namespace Microsoft.JSInterop;

/// <inheritdoc/>
internal class LocalStorage : IStorage
{
    private readonly IJSInProcessRuntime _javaScript = null!;

    public LocalStorage(IJSInProcessRuntime javaScript) => _javaScript = javaScript;

    /// <inheritdoc/>
    void IStorage.Clear() => _javaScript.Clear();

    /// <inheritdoc/>
    TResult? IStorage.GetItem<TResult>(string key, JsonSerializerOptions? options)
        where TResult : default => _javaScript.GetItem<TResult>(key, options);

    /// <inheritdoc/>
    string? IStorage.Key(double index) => _javaScript.Key(index);

    /// <inheritdoc/>
    void IStorage.RemoveItem(string key) => _javaScript.RemoveItem(key);

    /// <inheritdoc/>
    void IStorage.SetItem<TArg>(string key, TArg value, JsonSerializerOptions? options) =>
        _javaScript.SetItem(key, value, options);
    
    /// <inheritdoc/>
    double IStorage.Length => _javaScript.Length();
}

Finally, here is the source generated service collection extension methods:

using Microsoft.JSInterop;

namespace Microsoft.Extensions.DependencyInjection;

/// <summary></summary>
public static class LocalStorageServiceCollectionExtensions
{
    /// <summary>
    /// Adds the <see cref="IStorage" /> service to the service collection.
    /// </summary>
    public static IServiceCollection AddLocalStorageServices(
        this IServiceCollection services) =>
        services.AddSingleton<IJSInProcessRuntime>(serviceProvider =>
            (IJSInProcessRuntime)serviceProvider.GetRequiredService<IJSRuntime>())
            .AddSingleton<IStorage, LocalStorage>();
}

Putting this all together, the Blazor.LocalStorage.WebAssembly NuGet package is actually only 20 lines of code, and it generates full DI-ready services with JavaScript interop.

Full Changelog: 1.1.1...1.2.0

v1.1.1 Support properties

08 Mar 02:44
Compare
Choose a tag to compare

Add support for properties, for example; localStorage.length and "eval".

Full Changelog: 1.1.0...1.1.1

Release 1.1.0

05 Mar 20:25
Compare
Choose a tag to compare
  • Fix generated indentation.
  • Added generic support
  • Added serialization overload and support

Full Changelog: 1.0.5...1.1.0

Build v1.0.5

04 Mar 21:34
Compare
Choose a tag to compare

Fix issues introduced in 1.0.4

Full Changelog: 1.0.4...1.0.5

Build v1.0.4

03 Mar 14:33
Compare
Choose a tag to compare

Introduced the JSAutoGenericInterop which allows for API method descriptors, that specify which APIs should be generic instead of string based. This relies on the default JSON serialization native to Blazor JavaScript interop.

Full Changelog: 1.0.3...1.0.4

Build v1.0.3

24 Feb 02:18
Compare
Choose a tag to compare

Full Changelog: 1.0.2...1.0.3

Version 1.0.2

22 Feb 21:16
Compare
Choose a tag to compare

What's Changed

New Contributors

Full Changelog: 1.0.1...1.0.2

1.0.1

22 Feb 05:06
Compare
Choose a tag to compare

Full Changelog: 1.0.0...1.0.1

Initial bits... let's go! v1

22 Feb 04:35
Compare
Choose a tag to compare

What's Changed

New Contributors

Full Changelog: https://github.com/IEvangelist/blazorators/commits/1.0.0