Skip to content

Releases: IEvangelist/blazorators

1.4.4

26 Mar 01:38
264d3b9
Compare
Choose a tag to compare

Test Colin's better workflow

What's Changed

New Contributors

Full Changelog: 1.4.3...1.4.4

Version 1.4.3

25 Mar 02:28
Compare
Choose a tag to compare
  • Source generate overloads to accept Action<T> - thanks @stephentoub for the suggestion

Example input

namespace Microsoft.JSInterop;

[JSAutoInterop(
    TypeName = "Geolocation",
    Implementation = "window.navigator.geolocation",
    Url = "https://developer.mozilla.org/docs/Web/API/Geolocation")]
public partial interface IGeolocationService
{
}

Example output

#nullable enable
namespace Microsoft.JSInterop;

/// <summary>
/// Source generated interface definition of the <c>Geolocation</c> type.
/// </summary>
public partial interface IGeolocationService
{
    /// <summary>
    /// Source generated implementation of <c>window.navigator.geolocation.clearWatch</c>.
    /// <a href="https://developer.mozilla.org/docs/Web/API/Geolocation/clearWatch"></a>
    /// </summary>
    void ClearWatch(double watchId);
    /// <summary>
    /// Source generated implementation of <c>window.navigator.geolocation.getCurrentPosition</c>.
    /// <a href="https://developer.mozilla.org/docs/Web/API/Geolocation/getCurrentPosition"></a>
    /// </summary>
    /// <param name = "component">The calling Razor (or Blazor) component.</param>
    /// <param name = "onSuccessCallbackMethodName">Expects the name of a <c>"JSInvokableAttribute"</c> C# method with the following <c>System.Action{GeolocationPosition}"</c>.</param>
    /// <param name = "onErrorCallbackMethodName">Expects the name of a <c>"JSInvokableAttribute"</c> C# method with the following <c>System.Action{GeolocationPositionError}"</c>.</param>
    /// <param name = "options">The <c>PositionOptions</c> value.</param>
    void GetCurrentPosition<TComponent>(
        TComponent component,
        string onSuccessCallbackMethodName,
        string? onErrorCallbackMethodName = null,
        PositionOptions? options = null)
        where TComponent : class;

    /// <summary>
    /// Source generated implementation of <c>window.navigator.geolocation.getCurrentPosition</c>.
    /// <a href="https://developer.mozilla.org/docs/Web/API/Geolocation/getCurrentPosition"></a>
    /// </summary>
    void GetCurrentPosition(
        Action<GeolocationPosition> onSuccessCallback,
        Action<GeolocationPositionError>? onErrorCallback = null,
        PositionOptions? options = null);

    /// <summary>
    /// Source generated implementation of <c>window.navigator.geolocation.watchPosition</c>.
    /// <a href="https://developer.mozilla.org/docs/Web/API/Geolocation/watchPosition"></a>
    /// </summary>
    /// <param name = "component">The calling Razor (or Blazor) component.</param>
    /// <param name = "onSuccessCallbackMethodName">Expects the name of a <c>"JSInvokableAttribute"</c> C# method with the following <c>System.Action{GeolocationPosition}"</c>.</param>
    /// <param name = "onErrorCallbackMethodName">Expects the name of a <c>"JSInvokableAttribute"</c> C# method with the following <c>System.Action{GeolocationPositionError}"</c>.</param>
    /// <param name = "options">The <c>PositionOptions</c> value.</param>
    double WatchPosition<TComponent>(
        TComponent component,
        string onSuccessCallbackMethodName, string?
        onErrorCallbackMethodName = null,
        PositionOptions? options = null)
        where TComponent : class;

    /// <summary>
    /// Source generated implementation of <c>window.navigator.geolocation.watchPosition</c>.
    /// <a href="https://developer.mozilla.org/docs/Web/API/Geolocation/watchPosition"></a>
    /// </summary>
    double WatchPosition(
        Action<GeolocationPosition> onSuccessCallback,
        Action<GeolocationPositionError>? onErrorCallback = null,
        PositionOptions? options = null);
}

Additionally, all of the dependent types are also generated. As well as the dependency injection hooks, and the corresponding implementation.

  • IGeolocationServices.g.cs
  • GeolocationServices.g.cs
  • GeolocationServiceCollectionExtensions.g.cs
  • GeolocationPosition.g.cs
  • GeolocationPositionError.g.cs
  • GeolocationCoordinates.g.cs
  • PositionOptions.g.cs

Full Changelog: 1.4.2...1.4.3

Release v1.4.2

23 Mar 15:48
Compare
Choose a tag to compare

New libs for session storage

Full Changelog: 1.4.0...1.4.2

Release 1.4.1 - New libs

23 Mar 15:40
Compare
Choose a tag to compare
  • Add session storage libs, and introduce Bing maps in example

Full Changelog: 1.4.0...1.4.1

Version 1.4.0

22 Mar 14:31
Compare
Choose a tag to compare
  • Target public partial interface instead of internal static partial class
  • More XML comments
  • Append Service suffix to interface and impls.

Full Changelog: 1.3.3...1.4.0

v1.3.3 (version 1.3.2, but better)

18 Mar 03:39
Compare
Choose a tag to compare
  • Implemented Geolocation server-side
  • Fixed attributes
  • More XML comments
  • Better serialization
  • Helpers for epoch time and DOMTimeStamp

Full Changelog: 1.3.1...1.3.3

1.3.2

18 Mar 03:34
Compare
Choose a tag to compare
  • Implemented Geolocation server-side
  • Fixed attributes
  • More XML comments
  • Better serialization
  • Helpers for epoch time and DOMTimeStamp

Full Changelog: 1.3.1...1.3.2

v1.3.1 bugs

16 Mar 12:44
Compare
Choose a tag to compare
Fix package name

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