Category: .NET

Watch2–part 4–CI and CD

Now I want to do build and auto-deployment as a Nuget Package( at https://www.nuget.org/packages/watch2 )

The most simple build action on GitHub Actions is simple example of how to do it.

name: .NET

on:
  push:
    branches: [ main ]
  pull_request:
    branches: [ main ]
  workflow_dispatch:

jobs:
  build:
    runs-on: ubuntu-latest
    
    steps:
    - uses: actions/checkout@v3
      with:
        fetch-depth: 0

    - name: Setup .NET 8
      uses: actions/setup-dotnet@v3
      with:
        dotnet-version: 8.0.x
    
    - name: build
      run: |
        cd src 
        cd Watch2
        dotnet restore
        dotnet build 
        
        

However, I want to do more than that. I want to build , test and deploy on demand the Nuget package to Nuget.org.

However , the building should be done first on local – and then with GitHub Actions – the deployment should be done.

For this I do like https://github.com/xt0rted/dotnet-run-script

This is how I use to do test and pack, by using a global.json file

{
  "scripts": {
    "build": "dotnet build --configuration Release",
    "test": "dotnet test --configuration Release",
    "ci": "dotnet r build && dotnet r test",
    "pack":"dotnet r ci && cd Watch2 && dotnet pack -o ../../nugetPackages"
  }
}

So the github action now looks like this

name: compile and deploy with tag v*

on:
  push:
    branches: [ "main" ]
    tags: [ 'v*' ] # Listen for tag pushes that match version tags
  pull_request:
    branches: [ "main" ]

jobs:
  build:
    # runs-on: windows-latest
    runs-on: ubuntu-latest

    steps:
    - uses: actions/checkout@v3
    
    - name: Setup .NET
      uses: actions/setup-dotnet@v3
      with:
        dotnet-version: 8.0.x

    - name: Restore dependencies
      run: |
        dotnet tool install --global PowerShell
        cd src 
        cd Watch2
        dotnet restore
        
    - name: Build
      run: |
        cd src
        cd Watch2
        dotnet tool restore
        dotnet r pack

    - name: 'Upload nuget'
      uses: actions/upload-artifact@v4
      with:
        name: Nuget_${{github.run_number}}
        path: src/nugetPackages
        retention-days: 1
  
    - name: push to nuget
      if: startsWith(github.ref, 'refs/tags/v') # This line ensures the step runs only if a tag version is present
      run: |
        dir src/nugetPackages/*.*
        echo '1'
        dir src/nugetPackages/*.symbols.nupkg  
        echo '2'
        cd src
        cd nugetPackages
        dotnet nuget push "*.symbols.nupkg" --api-key  ${{ secrets.NUGET_KEY  }} --source https://api.nuget.org/v3/index.json
    

More, we should add to github Settings => Secrets and variables => Actions secrets a new secret with name NUGET_KEY

The build and test are made automatically . More, if I want to deploy also, then
1. I modify the version in the csproj file

	<PropertyGroup>
		<Version>8.2024.1102.950</Version>
	</PropertyGroup>

2. I push the changes to the repository with a tag ( e.g. v8.2024.1102.950)

So this achieves the CI/CD basic .

Watch2- part 3 -refactoring to interfaces and test

The Watch2 just intercepts the dotnet watch, adds a clear console, and a delay to give a breather between running the app and the tests.

So I need to have tests – if I want to be sure what the software does and to modify it without summoning the coding gremlins. More importantly, the output from dotnet watch could be different – so I need more tests .

The solution evolved from

to

The main points learned from the process of refactoring:

1. GitHub Copilot is like having a coding sidekick. Some modifications I made manually, but most of the code was generated by my new best friend.

2. For each class that doesn’t have an interface (like ProcessStartInfo, Process, Console), a Wrapper interface must be created. Because who doesn’t love wrapping things up?

3. It is very hard to make interfaces dependent just on interfaces – not on implementations.

4. Static variables could impact the test !

5. The Rocks nuget package really rocks for generating mocks

[assembly: Rock(typeof(IProcessWrapper), BuildType.Create)]
[assembly: Rock(typeof(IConsoleWrapper), BuildType.Create)]
[assembly: Rock(typeof(IDataReceivedEventArgs), BuildType.Make)]
[TestMethod]
public void TestRestart()
{
    // Arrange
    var mockProcess = new IProcessWrapperCreateExpectations();
    var mockConsole = new IConsoleWrapperCreateExpectations();
    var mockDataReceivedEventArgs = new IDataReceivedEventArgsMakeExpectations();
    mockProcess.Methods.Kill().ExpectedCallCount ( 1);
    mockConsole.Methods.WriteLine(Rocks.Arg.Any<string>()).Callback(it=> { });
    

    // Act
    (new ProcessManager()).HandleOutput(("Waiting for a file to change before"), mockConsole.Instance());

    // Assert
    mockProcess.Verify();
}

Watch2- part 2- first fast implementation

The first attempt to writing the code was very fast – and, surely, not testable. (Speedy Gonzales would be proud!)

Some observations:

1. If you start any process inside a console application, you should intercept the cancel signal and stop the process.
This is done by using the CancelKeyPress event of the Console class.
This is important because the user can cancel the process by pressing Ctrl+C.
(Because who doesn’t love a good Ctrl+C in the morning?)

Console.CancelKeyPress += delegate {
    // call methods to clean up
    Kill(proc);
};

2. If you want to stop the dotnet watch after it detects a change in the file system, you cannot. You need to kill the process and start it again. So, you need to kill the process and start it again.
(It’s like a phoenix, it must die to be reborn!)

3. Spectre.Console is a really good library to create console applications with a lot of features. I used it to create messages with different colors and styles.
(Because plain text is so last century.)

4. The code is very simple and easy to understand. I used the Process class to start the dotnet watch process and the Console class to write messages to the console.
(Simple and easy, just like making a cup of coffee… if you have a coffee machine.)

This is the final code:

using Spectre.Console;
using System.Diagnostics;
Process? proc = null;
Console.CancelKeyPress += delegate {
    // call methods to clean up
    Kill(proc);
};
bool shouldWait = false;
while (true)
{
    ProcessStartInfo startInfo = new ProcessStartInfo();
    startInfo.FileName = "dotnet";
    startInfo.Arguments = "watch " + string.Join(' ', args);
    //startInfo.LoadUserProfile = true;
    startInfo.WorkingDirectory = Environment.CurrentDirectory;

    startInfo.RedirectStandardOutput = true;
    startInfo.RedirectStandardInput = true;
    startInfo.RedirectStandardError = true;
    startInfo.UseShellExecute = false;
    startInfo.CreateNoWindow = true;

    proc = new Process();
    proc.StartInfo = startInfo;
    proc.OutputDataReceived += (sender, e) =>
    {
        if (shouldWait)
        {
            shouldWait = false;
            Kill(proc);
            Thread.Sleep(15_000);
            return;

        }
        var line = e.Data;
        if (line == null) return;
        if (line.Contains("dotnet watch"))
        {
            if (line.Contains("Started"))
            {
                Console.Clear();
            }
            if (line.Contains("Building"))
            {

            }
        }

        if (line.Contains(": error "))
        {
            AnsiConsole.MarkupLineInterpolated($"->[bold red]:cross_mark: {e.Data}[/]");
            return;
        }
        if (line.Contains("Waiting for a file to change before"))
        {
            Console.WriteLine("wain");
            shouldWait = true;

        }

        Console.WriteLine("->" + e.Data);


    };
    proc.ErrorDataReceived += (sender, e) =>
    {
        if (e.Data != null)
        {
            AnsiConsole.MarkupLineInterpolated($"->[bold red]:cross_mark: {e.Data}[/]");
            return;

        }
    };

    AnsiConsole.MarkupLineInterpolated($"[bold green]Starting...[/]");
    proc.Start();
    Console.Clear();
    proc.BeginOutputReadLine();
    proc.BeginErrorReadLine();
    await proc.WaitForExitAsync();
}

static void Kill(Process? proc)
{
    if (proc == null) return;
    if (proc.HasExited) return;
    proc.Kill(true);
    proc.Close();
    proc = null;
}

Watch2–part 1–idea

I frequently use .NET Watch for two main reasons:

  1. Running .NET applications during development.

  2. Executing tests.

Seriously, if you haven’t tried .NET Watch, you’re missing out. It’s like having a personal assistant who never sleeps compiling code . For more info, check out Microsoft’s documentation  at https://learn.microsoft.com/en-us/dotnet/core/tools/dotnet-watch

But, like all good things, it comes with a couple of quirks:

  1. The console output scrolls faster than a cat on a hot tin roof, making it hard to keep up. A Console.Clear (or cls command) would be a lifesaver to reset the console after each file change.

  2. Running dotnet watch for both the application and tests at the same time is like trying to juggle flaming torches—compilation conflicts galore! You’ll often find yourself stopping one of the watches to keep things from going up in flames.

To tackle these issues, I whipped up a simple .NET tool, named Watch2.  This little gem can clear the console and run the watch command with an optional delay. It’s built with .NET Core and can be installed as a global tool.

For more laughs and details, visit the NuGet package page  at https://www.nuget.org/packages/watch2 .

RSCG – RazorSlices

RSCG – RazorSlices
 
 

name RazorSlices
nuget https://www.nuget.org/packages/RazorSlices/
link https://github.com/DamianEdwards/RazorSlices
author Damiam Edwards

Generating html from razor templates. Attention: generates IHttpResult, not html string.

 

This is how you can use RazorSlices .

The code that you start with is


<Project Sdk="Microsoft.NET.Sdk.Web">

  <PropertyGroup>
    <TargetFramework>net8.0</TargetFramework>
    <Nullable>enable</Nullable>
    <ImplicitUsings>enable</ImplicitUsings>
  </PropertyGroup>

  <ItemGroup>
    <PackageReference Include="Microsoft.AspNetCore.OpenApi" Version="8.0.10" />
    <PackageReference Include="RazorSlices" Version="0.8.1" />
    <PackageReference Include="Swashbuckle.AspNetCore" Version="6.6.2" />
  </ItemGroup>
	<PropertyGroup>
		<EmitCompilerGeneratedFiles>true</EmitCompilerGeneratedFiles>
		<CompilerGeneratedFilesOutputPath>$(BaseIntermediateOutputPath)\GX</CompilerGeneratedFilesOutputPath>
	</PropertyGroup>
</Project>


The code that you will use is


using RazorDemoSlices;

var builder = WebApplication.CreateBuilder(args);

// Add services to the container.
// Learn more about configuring Swagger/OpenAPI at https://aka.ms/aspnetcore/swashbuckle
builder.Services.AddEndpointsApiExplorer();
builder.Services.AddSwaggerGen();

var app = builder.Build();

// Configure the HTTP request pipeline.
//if (app.Environment.IsDevelopment())
{
    app.UseSwagger();
    app.UseSwaggerUI();
}

var summaries = new[]
{
    "Freezing", "Bracing", "Chilly", "Cool", "Mild", "Warm", "Balmy", "Hot", "Sweltering", "Scorching"
};
app.MapGet("/hello", (string firstName,string lastName) 
    => Results.Extensions.RazorSlice<RazorDemoSlices.Slices.PersonHTML, Person>(
        new Person { FirstName = firstName, LastName = lastName }
    ));

app.MapGet("/weatherforecast", () =>
{
    var forecast = Enumerable.Range(1, 5).Select(index =>
        new WeatherForecast
        (
            DateOnly.FromDateTime(DateTime.Now.AddDays(index)),
            Random.Shared.Next(-20, 55),
            summaries[Random.Shared.Next(summaries.Length)]
        ))
        .ToArray();
    return forecast;
})
.WithName("GetWeatherForecast")
.WithOpenApi();

app.Run();

internal record WeatherForecast(DateOnly Date, int TemperatureC, string? Summary)
{
    public int TemperatureF => 32 + (int)(TemperatureC / 0.5556);
}



@inherits RazorSliceHttpResult<RazorDemoSlices.Person>
<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="utf-8">
    <title>Hello from Razor Slices!</title>
</head>
<body>
    <p>
        My name is @Model.FirstName @Model.LastName
    </p>
</body>
</html>


namespace RazorDemoSlices;

public class Person
{
    public string FirstName { get; set; }=string.Empty;
    public string LastName { get; set; }= string.Empty;
}


 

The code that is generated is

#pragma checksum "D:\gth\RSCG_Examples\v2\rscg_examples\EmbeddedResourcePropertyGenerator\src\RazorDemoSlices\RazorDemoSlices\Slices\PersonHTML.cshtml" "{8829d00f-11b8-4213-878b-770e8597ac16}" "6b3710e80836b438a5d8935ea469d238fc095e46298456ca847e09519393bb5e"
// <auto-generated/>
#pragma warning disable 1591
[assembly: global::Microsoft.AspNetCore.Razor.Hosting.RazorCompiledItemAttribute(typeof(AspNetCoreGeneratedDocument.Slices_PersonHTML), @"mvc.1.0.view", @"/Slices/PersonHTML.cshtml")]
namespace AspNetCoreGeneratedDocument
{
    #line default
    using global::System;
    using global::System.Collections.Generic;
    using global::System.Linq;
    using global::System.Threading.Tasks;
    using global::Microsoft.AspNetCore.Mvc;
    using global::Microsoft.AspNetCore.Mvc.Rendering;
    using global::Microsoft.AspNetCore.Mvc.ViewFeatures;
#nullable restore
#line (3,2)-(4,1) "D:\gth\RSCG_Examples\v2\rscg_examples\EmbeddedResourcePropertyGenerator\src\RazorDemoSlices\RazorDemoSlices\Slices\_ViewImports.cshtml"
using System.Globalization;

#nullable disable
#nullable restore
#line (4,2)-(5,1) "D:\gth\RSCG_Examples\v2\rscg_examples\EmbeddedResourcePropertyGenerator\src\RazorDemoSlices\RazorDemoSlices\Slices\_ViewImports.cshtml"
using Microsoft.AspNetCore.Razor;

#nullable disable
#nullable restore
#line (5,2)-(6,1) "D:\gth\RSCG_Examples\v2\rscg_examples\EmbeddedResourcePropertyGenerator\src\RazorDemoSlices\RazorDemoSlices\Slices\_ViewImports.cshtml"
using Microsoft.AspNetCore.Http.HttpResults;

#line default
#line hidden
#nullable disable
    [global::Microsoft.AspNetCore.Razor.Hosting.RazorCompiledItemMetadataAttribute("Identifier", "/Slices/PersonHTML.cshtml")]
    [global::System.Runtime.CompilerServices.CreateNewOnMetadataUpdateAttribute]
    #nullable restore
    internal sealed class Slices_PersonHTML : RazorSliceHttpResult<RazorDemoSlices.Person>
    #nullable disable
    {
        #pragma warning disable 1998
        public async override global::System.Threading.Tasks.Task ExecuteAsync()
        {
            WriteLiteral("<!DOCTYPE html>\r\n<html lang=\"en\">\r\n<head>\r\n    <meta charset=\"utf-8\">\r\n    <title>Hello from Razor Slices!</title>\r\n</head>\r\n<body>\r\n    <p>\r\n        My name is ");
            Write(
#nullable restore
#line (10,21)-(10,36) "D:\gth\RSCG_Examples\v2\rscg_examples\EmbeddedResourcePropertyGenerator\src\RazorDemoSlices\RazorDemoSlices\Slices\PersonHTML.cshtml"
Model.FirstName

#line default
#line hidden
#nullable disable
            );
            WriteLiteral(" ");
            Write(
#nullable restore
#line (10,38)-(10,52) "D:\gth\RSCG_Examples\v2\rscg_examples\EmbeddedResourcePropertyGenerator\src\RazorDemoSlices\RazorDemoSlices\Slices\PersonHTML.cshtml"
Model.LastName

#line default
#line hidden
#nullable disable
            );
            WriteLiteral("\r\n    </p>\r\n</body>\r\n</html>");
        }
        #pragma warning restore 1998
        #nullable restore
        [global::Microsoft.AspNetCore.Mvc.Razor.Internal.RazorInjectAttribute]
        public global::Microsoft.AspNetCore.Mvc.ViewFeatures.IModelExpressionProvider ModelExpressionProvider { get; private set; } = default!;
        #nullable disable
        #nullable restore
        [global::Microsoft.AspNetCore.Mvc.Razor.Internal.RazorInjectAttribute]
        public global::Microsoft.AspNetCore.Mvc.IUrlHelper Url { get; private set; } = default!;
        #nullable disable
        #nullable restore
        [global::Microsoft.AspNetCore.Mvc.Razor.Internal.RazorInjectAttribute]
        public global::Microsoft.AspNetCore.Mvc.IViewComponentHelper Component { get; private set; } = default!;
        #nullable disable
        #nullable restore
        [global::Microsoft.AspNetCore.Mvc.Razor.Internal.RazorInjectAttribute]
        public global::Microsoft.AspNetCore.Mvc.Rendering.IJsonHelper Json { get; private set; } = default!;
        #nullable disable
        #nullable restore
        [global::Microsoft.AspNetCore.Mvc.Razor.Internal.RazorInjectAttribute]
        public global::Microsoft.AspNetCore.Mvc.Rendering.IHtmlHelper<dynamic> Html { get; private set; } = default!;
        #nullable disable
    }
}
#pragma warning restore 1591

#pragma checksum "D:\gth\RSCG_Examples\v2\rscg_examples\EmbeddedResourcePropertyGenerator\src\RazorDemoSlices\RazorDemoSlices\Slices\_ViewImports.cshtml" "{8829d00f-11b8-4213-878b-770e8597ac16}" "95493514af34e5705fffb1e5c7121f0e7abde13ee7a1cff8fbafa2085da18fff"
// <auto-generated/>
#pragma warning disable 1591
[assembly: global::Microsoft.AspNetCore.Razor.Hosting.RazorCompiledItemAttribute(typeof(AspNetCoreGeneratedDocument.Slices__ViewImports), @"mvc.1.0.view", @"/Slices/_ViewImports.cshtml")]
namespace AspNetCoreGeneratedDocument
{
    #line default
    using global::System;
    using global::System.Collections.Generic;
    using global::System.Linq;
    using global::System.Threading.Tasks;
    using global::Microsoft.AspNetCore.Mvc;
    using global::Microsoft.AspNetCore.Mvc.Rendering;
    using global::Microsoft.AspNetCore.Mvc.ViewFeatures;
#nullable restore
#line (3,2)-(4,1) "D:\gth\RSCG_Examples\v2\rscg_examples\EmbeddedResourcePropertyGenerator\src\RazorDemoSlices\RazorDemoSlices\Slices\_ViewImports.cshtml"
using System.Globalization;

#nullable disable
#nullable restore
#line (4,2)-(5,1) "D:\gth\RSCG_Examples\v2\rscg_examples\EmbeddedResourcePropertyGenerator\src\RazorDemoSlices\RazorDemoSlices\Slices\_ViewImports.cshtml"
using Microsoft.AspNetCore.Razor;

#nullable disable
#nullable restore
#line (5,2)-(6,1) "D:\gth\RSCG_Examples\v2\rscg_examples\EmbeddedResourcePropertyGenerator\src\RazorDemoSlices\RazorDemoSlices\Slices\_ViewImports.cshtml"
using Microsoft.AspNetCore.Http.HttpResults;

#line default
#line hidden
#nullable disable
    [global::Microsoft.AspNetCore.Razor.Hosting.RazorCompiledItemMetadataAttribute("Identifier", "/Slices/_ViewImports.cshtml")]
    [global::System.Runtime.CompilerServices.CreateNewOnMetadataUpdateAttribute]
    #nullable restore
    internal sealed class Slices__ViewImports : RazorSliceHttpResult
    #nullable disable
    {
        #pragma warning disable 1998
        public async override global::System.Threading.Tasks.Task ExecuteAsync()
        {
            WriteLiteral("\r\n");
            WriteLiteral("\r\n");
        }
        #pragma warning restore 1998
        #nullable restore
        [global::Microsoft.AspNetCore.Mvc.Razor.Internal.RazorInjectAttribute]
        public global::Microsoft.AspNetCore.Mvc.ViewFeatures.IModelExpressionProvider ModelExpressionProvider { get; private set; } = default!;
        #nullable disable
        #nullable restore
        [global::Microsoft.AspNetCore.Mvc.Razor.Internal.RazorInjectAttribute]
        public global::Microsoft.AspNetCore.Mvc.IUrlHelper Url { get; private set; } = default!;
        #nullable disable
        #nullable restore
        [global::Microsoft.AspNetCore.Mvc.Razor.Internal.RazorInjectAttribute]
        public global::Microsoft.AspNetCore.Mvc.IViewComponentHelper Component { get; private set; } = default!;
        #nullable disable
        #nullable restore
        [global::Microsoft.AspNetCore.Mvc.Razor.Internal.RazorInjectAttribute]
        public global::Microsoft.AspNetCore.Mvc.Rendering.IJsonHelper Json { get; private set; } = default!;
        #nullable disable
        #nullable restore
        [global::Microsoft.AspNetCore.Mvc.Razor.Internal.RazorInjectAttribute]
        public global::Microsoft.AspNetCore.Mvc.Rendering.IHtmlHelper<dynamic> Html { get; private set; } = default!;
        #nullable disable
    }
}
#pragma warning restore 1591

// <auto-generated/>

using global::System.Diagnostics.CodeAnalysis;
using global::RazorSlices;

#nullable enable

namespace RazorDemoSlices
{
    /// <summary>
    /// All calls to create Razor Slices instances via the generated <see cref="global::RazorSlices.IRazorSliceProxy"/> classes
    /// go through this factory to ensure that the generated types' Create methods are always invoked via the static abstract
    /// methods defined in the <see cref="global::RazorSlices.IRazorSliceProxy"/> interface. This ensures that the interface
    /// implementation is never trimmed from the generated types.
    /// </summary>
    /// <remarks>
    /// Workaround for https://github.com/dotnet/runtime/issues/102796
    /// </remarks>
    [global::System.ComponentModel.EditorBrowsable(global::System.ComponentModel.EditorBrowsableState.Never)] // Hide from IntelliSense.
    internal static class RazorSlicesGenericFactory
    {
        public static RazorSlice CreateSlice<TProxy>() where TProxy : IRazorSliceProxy => TProxy.CreateSlice();

        public static RazorSlice<TModel> CreateSlice<TProxy, TModel>(TModel model) where TProxy : IRazorSliceProxy => TProxy.CreateSlice(model);
    }
}
namespace RazorDemoSlices.Slices
{
    /// <summary>
    /// Static proxy for the Razor Slice defined in <c>Slices\PersonHTML.cshtml</c>.
    /// </summary>
    public sealed class PersonHTML : global::RazorSlices.IRazorSliceProxy
    {
        [global::System.Diagnostics.CodeAnalysis.DynamicDependency(global::System.Diagnostics.CodeAnalysis.DynamicallyAccessedMemberTypes.All, TypeName, "RazorDemoSlices")]
        private const string TypeName = "AspNetCoreGeneratedDocument.Slices_PersonHTML, RazorDemoSlices";
        [global::System.Diagnostics.CodeAnalysis.DynamicallyAccessedMembers(global::System.Diagnostics.CodeAnalysis.DynamicallyAccessedMemberTypes.All)]
        private static readonly global::System.Type _sliceType = global::System.Type.GetType(TypeName)
            ?? throw new global::System.InvalidOperationException($"Razor view type '{TypeName}' was not found. This is likely a bug in the RazorSlices source generator.");
        private static readonly global::RazorSlices.SliceDefinition _sliceDefinition = new(_sliceType);

        /// <summary>
        /// Creates a new instance of the Razor Slice defined in <c>Slices\PersonHTML.cshtml</c> .
        /// </summary>
        public static global::RazorSlices.RazorSlice Create()
            => global::RazorDemoSlices.RazorSlicesGenericFactory.CreateSlice<global::RazorDemoSlices.Slices.PersonHTML>();

        /// <summary>
        /// Creates a new instance of the Razor Slice defined in <c>Slices\PersonHTML.cshtml</c> with the given model.
        /// </summary>
        public static global::RazorSlices.RazorSlice<TModel> Create<TModel>(TModel model)
            => global::RazorDemoSlices.RazorSlicesGenericFactory.CreateSlice<global::RazorDemoSlices.Slices.PersonHTML, TModel>(model);

        // Explicit interface implementation
        static global::RazorSlices.RazorSlice global::RazorSlices.IRazorSliceProxy.CreateSlice() => _sliceDefinition.CreateSlice();

        // Explicit interface implementation
        static global::RazorSlices.RazorSlice<TModel> global::RazorSlices.IRazorSliceProxy.CreateSlice<TModel>(TModel model) => _sliceDefinition.CreateSlice(model);
    }
}


Code and pdf at

https://ignatandrei.github.io/RSCG_Examples/v2/docs/RazorSlices

RSCG – TypedSignalR.Client

RSCG – TypedSignalR.Client
 
 

name TypedSignalR.Client
nuget https://www.nuget.org/packages/TypedSignalR.Client/
link https://github.com/nenoNaninu/TypedSignalR.Client
author nenoNaninu

Creating typed Signal R clients

 

This is how you can use TypedSignalR.Client .

The code that you start with is


<Project Sdk="Microsoft.NET.Sdk">

  <PropertyGroup>
    <OutputType>Exe</OutputType>
    <TargetFramework>net8.0</TargetFramework>
    <ImplicitUsings>enable</ImplicitUsings>
    <Nullable>enable</Nullable>
  </PropertyGroup>

	<ItemGroup>
		<PackageReference Include="Microsoft.AspNetCore.SignalR.Client" Version="6.0.1" />
		<PackageReference Include="TypedSignalR.Client" Version="3.6.0">
		  <PrivateAssets>all</PrivateAssets>
		  <IncludeAssets>runtime; build; native; contentfiles; analyzers; buildtransitive</IncludeAssets>
		</PackageReference>
	</ItemGroup>

	<ItemGroup>
	  <ProjectReference Include="..\TestSignalRCommon\TestSignalRCommon.csproj" />
	</ItemGroup>

	<PropertyGroup>
		<EmitCompilerGeneratedFiles>true</EmitCompilerGeneratedFiles>
		<CompilerGeneratedFilesOutputPath>$(BaseIntermediateOutputPath)\GX</CompilerGeneratedFilesOutputPath>
	</PropertyGroup>
	
</Project>


The code that you will use is


// See https://aka.ms/new-console-template for more information
using Microsoft.AspNetCore.SignalR.Client;
using TestSignalRCommon;
using TestSignalRConsole;

Console.WriteLine("Hello, World!");
await Task.Delay(5_000);
HubConnection _connection = new HubConnectionBuilder()
    .WithUrl("https://localhost:7302/ChatHub")
    .Build();
await _connection.StartAsync();

_connection.On<string, string>("ReceiveMessage", (user, message) =>
{
    Console.WriteLine($" from not typed {user}: {message}");
});

await Task.Delay(30_000);
var h = TypedSignalR.Client.HubConnectionExtensions.CreateHubProxy<IHubMessage>(_connection);
await h.SendMessage("console", "message");
//TypedSignalR.Client.HubConnectionExtensions.Register<IHubMessage>(_connection,new ReceiverMessage());

Console.WriteLine("waiting for messages from Windows App");
var message = Console.ReadLine();




 

The code that is generated is

// <auto-generated>
// THIS (.cs) FILE IS GENERATED BY TypedSignalR.Client
// </auto-generated>
#nullable enable
#pragma warning disable CS1591
namespace TypedSignalR.Client
{
    internal interface IHubConnectionObserver
    {
        global::System.Threading.Tasks.Task OnClosed(global::System.Exception? exception);
        global::System.Threading.Tasks.Task OnReconnected(string? connectionId);
        global::System.Threading.Tasks.Task OnReconnecting(global::System.Exception? exception);
    }

    internal interface IHubInvoker
    {
    }

    internal interface IHubInvokerFactory
    {
    }

    internal interface IHubInvokerFactory<out T> : IHubInvokerFactory
    {
        T CreateHubInvoker(global::Microsoft.AspNetCore.SignalR.Client.HubConnection connection, global::System.Threading.CancellationToken cancellationToken);
    }

    internal interface IReceiverBinder
    {
    }

    internal interface IReceiverBinder<in T> : IReceiverBinder
    {
        global::System.IDisposable Bind(global::Microsoft.AspNetCore.SignalR.Client.HubConnection connection, T receiver);
    }
}
#pragma warning restore CS1591

// <auto-generated>
// THIS (.cs) FILE IS GENERATED BY TypedSignalR.Client
// </auto-generated>
#nullable enable
#pragma warning disable CS1591
#pragma warning disable CS8767
#pragma warning disable CS8613
namespace TypedSignalR.Client
{
    internal static partial class HubConnectionExtensions
    {
        private static partial global::System.Collections.Generic.Dictionary<global::System.Type, IReceiverBinder> CreateBinders()
        {
            var binders = new global::System.Collections.Generic.Dictionary<global::System.Type, IReceiverBinder>();


            return binders;
        }
    }
}
#pragma warning restore CS8613
#pragma warning restore CS8767
#pragma warning restore CS1591

// <auto-generated>
// THIS (.cs) FILE IS GENERATED BY TypedSignalR.Client
// </auto-generated>
#nullable enable
#pragma warning disable CS1591
namespace TypedSignalR.Client
{
    internal static partial class HubConnectionExtensions
    {
        public static THub CreateHubProxy<THub>(this global::Microsoft.AspNetCore.SignalR.Client.HubConnection connection, global::System.Threading.CancellationToken cancellationToken = default)
        {
            var factory = HubInvokerFactoryProvider.GetHubInvokerFactory<THub>();

            if (factory is null)
            {
                throw new global::System.InvalidOperationException($"Failed to create a hub proxy. TypedSignalR.Client did not generate source code to create a hub proxy, which type is {typeof(THub)}.");
            }

            return factory.CreateHubInvoker(connection, cancellationToken);
        }

        public static global::System.IDisposable Register<TReceiver>(this global::Microsoft.AspNetCore.SignalR.Client.HubConnection connection, TReceiver receiver)
        {
            if (receiver is null)
            {
                throw new global::System.ArgumentNullException(nameof(receiver));
            }

            if (typeof(TReceiver) == typeof(IHubConnectionObserver))
            {
                return new HubConnectionObserverSubscription(connection, (IHubConnectionObserver)receiver);
            }

            var binder = ReceiverBinderProvider.GetReceiverBinder<TReceiver>();

            if (binder is null)
            {
                throw new global::System.InvalidOperationException($"Failed to register a receiver. TypedSignalR.Client did not generate source code to register a receiver, which type is {typeof(TReceiver)}.");
            }

            var subscription = binder.Bind(connection, receiver);

            if (receiver is IHubConnectionObserver hubConnectionObserver)
            {
                subscription = new CompositeDisposable(new[] { subscription, new HubConnectionObserverSubscription(connection, hubConnectionObserver) });
            }

            return subscription;
        }
    }

    internal static partial class HubConnectionExtensions
    {
        private static partial global::System.Collections.Generic.Dictionary<global::System.Type, IHubInvokerFactory> CreateFactories();
        private static partial global::System.Collections.Generic.Dictionary<global::System.Type, IReceiverBinder> CreateBinders();

        private static class HubInvokerFactoryProvider
        {
            private static readonly global::System.Collections.Generic.Dictionary<global::System.Type, IHubInvokerFactory> Factories;

            static HubInvokerFactoryProvider()
            {
                Factories = CreateFactories();
            }

            public static IHubInvokerFactory<T>? GetHubInvokerFactory<T>()
            {
                return Cache<T>.HubInvokerFactory;
            }

            private static class Cache<T>
            {
                public static readonly IHubInvokerFactory<T>? HubInvokerFactory = default;

                static Cache()
                {
                    if (Factories.TryGetValue(typeof(T), out var hubInvokerFactory))
                    {
                        HubInvokerFactory = hubInvokerFactory as IHubInvokerFactory<T>;
                    }
                }
            }
        }

        private static class ReceiverBinderProvider
        {
            private static readonly global::System.Collections.Generic.Dictionary<global::System.Type, IReceiverBinder> Binders;

            static ReceiverBinderProvider()
            {
                Binders = CreateBinders();
            }

            public static IReceiverBinder<T>? GetReceiverBinder<T>()
            {
                return Cache<T>.ReceiverBinder;
            }

            private static class Cache<T>
            {
                public static readonly IReceiverBinder<T>? ReceiverBinder = default;

                static Cache()
                {
                    if (Binders.TryGetValue(typeof(T), out var receiverBinder))
                    {
                        ReceiverBinder = receiverBinder as IReceiverBinder<T>;
                    }
                }
            }
        }

        private sealed class HubConnectionObserverSubscription : global::System.IDisposable
        {
            private readonly global::Microsoft.AspNetCore.SignalR.Client.HubConnection _connection;
            private readonly IHubConnectionObserver _hubConnectionObserver;

            private int _disposed = 0;

            public HubConnectionObserverSubscription(global::Microsoft.AspNetCore.SignalR.Client.HubConnection connection, IHubConnectionObserver hubConnectionObserver)
            {
                _connection = connection;
                _hubConnectionObserver = hubConnectionObserver;

                _connection.Closed += hubConnectionObserver.OnClosed;
                _connection.Reconnected += hubConnectionObserver.OnReconnected;
                _connection.Reconnecting += hubConnectionObserver.OnReconnecting;
            }

            public void Dispose()
            {
                if (global::System.Threading.Interlocked.Exchange(ref _disposed, 1) == 0)
                {
                    _connection.Closed -= _hubConnectionObserver.OnClosed;
                    _connection.Reconnected -= _hubConnectionObserver.OnReconnected;
                    _connection.Reconnecting -= _hubConnectionObserver.OnReconnecting;
                }
            }
        }

        private sealed class CompositeDisposable : global::System.IDisposable
        {
            private readonly object _gate = new object();
            private readonly global::System.Collections.Generic.List<global::System.IDisposable> _disposables;

            private bool _disposed;

            public CompositeDisposable()
            {
                _disposables = new global::System.Collections.Generic.List<global::System.IDisposable>();
            }

            public CompositeDisposable(global::System.IDisposable[] disposables)
            {
                _disposables = new global::System.Collections.Generic.List<global::System.IDisposable>(disposables);
            }

            public CompositeDisposable(int capacity)
            {
                if (capacity < 0)
                {
                    throw new global::System.ArgumentOutOfRangeException(nameof(capacity));
                }

                _disposables = new global::System.Collections.Generic.List<global::System.IDisposable>(capacity);
            }

            public void Add(global::System.IDisposable item)
            {
                bool shouldDispose = false;

                lock (_gate)
                {
                    shouldDispose = _disposed;

                    if (!_disposed)
                    {
                        _disposables.Add(item);
                    }
                }

                if (shouldDispose)
                {
                    item.Dispose();
                }
            }

            public void Dispose()
            {
                var currentDisposables = default(global::System.Collections.Generic.List<global::System.IDisposable>);

                lock (_gate)
                {
                    if (_disposed)
                    {
                        return;
                    }

                    _disposed = true;
                    currentDisposables = _disposables;
                }

                foreach (var item in currentDisposables)
                {
                    if (item is not null)
                    {
                        item.Dispose();
                    }
                }

                currentDisposables.Clear();
            }
        }

        // It is not possible to avoid boxing.
        // This is a limitation caused by the SignalR implementation.
        private static class HandlerConverter
        {
            public static global::System.Func<object?[], global::System.Threading.Tasks.Task> Convert(global::System.Func<global::System.Threading.Tasks.Task> handler)
            {
                return args => handler();
            }

            public static global::System.Func<object?[], global::System.Threading.Tasks.Task> Convert<T1>(global::System.Func<T1, global::System.Threading.Tasks.Task> handler)
            {
                return args => handler((T1)args[0]!);
            }

            public static global::System.Func<object?[], global::System.Threading.Tasks.Task> Convert<T1, T2>(global::System.Func<T1, T2, global::System.Threading.Tasks.Task> handler)
            {
                return args => handler((T1)args[0]!, (T2)args[1]!);
            }

            public static global::System.Func<object?[], global::System.Threading.Tasks.Task> Convert<T1, T2, T3>(global::System.Func<T1, T2, T3, global::System.Threading.Tasks.Task> handler)
            {
                return args => handler((T1)args[0]!, (T2)args[1]!, (T3)args[2]!);
            }

            public static global::System.Func<object?[], global::System.Threading.Tasks.Task> Convert<T1, T2, T3, T4>(global::System.Func<T1, T2, T3, T4, global::System.Threading.Tasks.Task> handler)
            {
                return args => handler((T1)args[0]!, (T2)args[1]!, (T3)args[2]!, (T4)args[3]!);
            }

            public static global::System.Func<object?[], global::System.Threading.Tasks.Task> Convert<T1, T2, T3, T4, T5>(global::System.Func<T1, T2, T3, T4, T5, global::System.Threading.Tasks.Task> handler)
            {
                return args => handler((T1)args[0]!, (T2)args[1]!, (T3)args[2]!, (T4)args[3]!, (T5)args[4]!);
            }

            public static global::System.Func<object?[], global::System.Threading.Tasks.Task> Convert<T1, T2, T3, T4, T5, T6>(global::System.Func<T1, T2, T3, T4, T5, T6, global::System.Threading.Tasks.Task> handler)
            {
                return args => handler((T1)args[0]!, (T2)args[1]!, (T3)args[2]!, (T4)args[3]!, (T5)args[4]!, (T6)args[5]!);
            }

            public static global::System.Func<object?[], global::System.Threading.Tasks.Task> Convert<T1, T2, T3, T4, T5, T6, T7>(global::System.Func<T1, T2, T3, T4, T5, T6, T7, global::System.Threading.Tasks.Task> handler)
            {
                return args => handler((T1)args[0]!, (T2)args[1]!, (T3)args[2]!, (T4)args[3]!, (T5)args[4]!, (T6)args[5]!, (T7)args[6]!);
            }

            public static global::System.Func<object?[], global::System.Threading.Tasks.Task> Convert<T1, T2, T3, T4, T5, T6, T7, T8>(global::System.Func<T1, T2, T3, T4, T5, T6, T7, T8, global::System.Threading.Tasks.Task> handler)
            {
                return args => handler((T1)args[0]!, (T2)args[1]!, (T3)args[2]!, (T4)args[3]!, (T5)args[4]!, (T6)args[5]!, (T7)args[6]!, (T8)args[7]!);
            }

            public static global::System.Func<object?[], global::System.Threading.Tasks.Task> Convert<T1, T2, T3, T4, T5, T6, T7, T8, T9>(global::System.Func<T1, T2, T3, T4, T5, T6, T7, T8, T9, global::System.Threading.Tasks.Task> handler)
            {
                return args => handler((T1)args[0]!, (T2)args[1]!, (T3)args[2]!, (T4)args[3]!, (T5)args[4]!, (T6)args[5]!, (T7)args[6]!, (T8)args[7]!, (T9)args[8]!);
            }

            public static global::System.Func<object?[], global::System.Threading.Tasks.Task> Convert<T1, T2, T3, T4, T5, T6, T7, T8, T9, T10>(global::System.Func<T1, T2, T3, T4, T5, T6, T7, T8, T9, T10, global::System.Threading.Tasks.Task> handler)
            {
                return args => handler((T1)args[0]!, (T2)args[1]!, (T3)args[2]!, (T4)args[3]!, (T5)args[4]!, (T6)args[5]!, (T7)args[6]!, (T8)args[7]!, (T9)args[8]!, (T10)args[9]!);
            }

            public static global::System.Func<object?[], global::System.Threading.Tasks.Task> Convert<T1, T2, T3, T4, T5, T6, T7, T8, T9, T10, T11>(global::System.Func<T1, T2, T3, T4, T5, T6, T7, T8, T9, T10, T11, global::System.Threading.Tasks.Task> handler)
            {
                return args => handler((T1)args[0]!, (T2)args[1]!, (T3)args[2]!, (T4)args[3]!, (T5)args[4]!, (T6)args[5]!, (T7)args[6]!, (T8)args[7]!, (T9)args[8]!, (T10)args[9]!, (T11)args[10]!);
            }

            public static global::System.Func<object?[], global::System.Threading.Tasks.Task> Convert<T1, T2, T3, T4, T5, T6, T7, T8, T9, T10, T11, T12>(global::System.Func<T1, T2, T3, T4, T5, T6, T7, T8, T9, T10, T11, T12, global::System.Threading.Tasks.Task> handler)
            {
                return args => handler((T1)args[0]!, (T2)args[1]!, (T3)args[2]!, (T4)args[3]!, (T5)args[4]!, (T6)args[5]!, (T7)args[6]!, (T8)args[7]!, (T9)args[8]!, (T10)args[9]!, (T11)args[10]!, (T12)args[11]!);
            }

            public static global::System.Func<object?[], global::System.Threading.Tasks.Task> Convert<T1, T2, T3, T4, T5, T6, T7, T8, T9, T10, T11, T12, T13>(global::System.Func<T1, T2, T3, T4, T5, T6, T7, T8, T9, T10, T11, T12, T13, global::System.Threading.Tasks.Task> handler)
            {
                return args => handler((T1)args[0]!, (T2)args[1]!, (T3)args[2]!, (T4)args[3]!, (T5)args[4]!, (T6)args[5]!, (T7)args[6]!, (T8)args[7]!, (T9)args[8]!, (T10)args[9]!, (T11)args[10]!, (T12)args[11]!, (T13)args[12]!);
            }

            public static global::System.Func<object?[], global::System.Threading.Tasks.Task> Convert<T1, T2, T3, T4, T5, T6, T7, T8, T9, T10, T11, T12, T13, T14>(global::System.Func<T1, T2, T3, T4, T5, T6, T7, T8, T9, T10, T11, T12, T13, T14, global::System.Threading.Tasks.Task> handler)
            {
                return args => handler((T1)args[0]!, (T2)args[1]!, (T3)args[2]!, (T4)args[3]!, (T5)args[4]!, (T6)args[5]!, (T7)args[6]!, (T8)args[7]!, (T9)args[8]!, (T10)args[9]!, (T11)args[10]!, (T12)args[11]!, (T13)args[12]!, (T14)args[13]!);
            }

            public static global::System.Func<object?[], global::System.Threading.Tasks.Task> Convert<T1, T2, T3, T4, T5, T6, T7, T8, T9, T10, T11, T12, T13, T14, T15>(global::System.Func<T1, T2, T3, T4, T5, T6, T7, T8, T9, T10, T11, T12, T13, T14, T15, global::System.Threading.Tasks.Task> handler)
            {
                return args => handler((T1)args[0]!, (T2)args[1]!, (T3)args[2]!, (T4)args[3]!, (T5)args[4]!, (T6)args[5]!, (T7)args[6]!, (T8)args[7]!, (T9)args[8]!, (T10)args[9]!, (T11)args[10]!, (T12)args[11]!, (T13)args[12]!, (T14)args[13]!, (T15)args[14]!);
            }

            public static global::System.Func<object?[], global::System.Threading.Tasks.Task> Convert<T1, T2, T3, T4, T5, T6, T7, T8, T9, T10, T11, T12, T13, T14, T15, T16>(global::System.Func<T1, T2, T3, T4, T5, T6, T7, T8, T9, T10, T11, T12, T13, T14, T15, T16, global::System.Threading.Tasks.Task> handler)
            {
                return args => handler((T1)args[0]!, (T2)args[1]!, (T3)args[2]!, (T4)args[3]!, (T5)args[4]!, (T6)args[5]!, (T7)args[6]!, (T8)args[7]!, (T9)args[8]!, (T10)args[9]!, (T11)args[10]!, (T12)args[11]!, (T13)args[12]!, (T14)args[13]!, (T15)args[14]!, (T16)args[15]!);
            }

            public static global::System.Func<object?[], global::System.Threading.Tasks.Task> Convert(global::System.Func<global::System.Threading.CancellationToken, global::System.Threading.Tasks.Task> handler)
            {
                return args => handler(default);
            }

            public static global::System.Func<object?[], global::System.Threading.Tasks.Task> Convert<T1>(global::System.Func<T1, global::System.Threading.CancellationToken, global::System.Threading.Tasks.Task> handler)
            {
                return args => handler((T1)args[0]!, default);
            }

            public static global::System.Func<object?[], global::System.Threading.Tasks.Task> Convert<T1, T2>(global::System.Func<T1, T2, global::System.Threading.CancellationToken, global::System.Threading.Tasks.Task> handler)
            {
                return args => handler((T1)args[0]!, (T2)args[1]!, default);
            }

            public static global::System.Func<object?[], global::System.Threading.Tasks.Task> Convert<T1, T2, T3>(global::System.Func<T1, T2, T3, global::System.Threading.CancellationToken, global::System.Threading.Tasks.Task> handler)
            {
                return args => handler((T1)args[0]!, (T2)args[1]!, (T3)args[2]!, default);
            }

            public static global::System.Func<object?[], global::System.Threading.Tasks.Task> Convert<T1, T2, T3, T4>(global::System.Func<T1, T2, T3, T4, global::System.Threading.CancellationToken, global::System.Threading.Tasks.Task> handler)
            {
                return args => handler((T1)args[0]!, (T2)args[1]!, (T3)args[2]!, (T4)args[3]!, default);
            }

            public static global::System.Func<object?[], global::System.Threading.Tasks.Task> Convert<T1, T2, T3, T4, T5>(global::System.Func<T1, T2, T3, T4, T5, global::System.Threading.CancellationToken, global::System.Threading.Tasks.Task> handler)
            {
                return args => handler((T1)args[0]!, (T2)args[1]!, (T3)args[2]!, (T4)args[3]!, (T5)args[4]!, default);
            }

            public static global::System.Func<object?[], global::System.Threading.Tasks.Task> Convert<T1, T2, T3, T4, T5, T6>(global::System.Func<T1, T2, T3, T4, T5, T6, global::System.Threading.CancellationToken, global::System.Threading.Tasks.Task> handler)
            {
                return args => handler((T1)args[0]!, (T2)args[1]!, (T3)args[2]!, (T4)args[3]!, (T5)args[4]!, (T6)args[5]!, default);
            }

            public static global::System.Func<object?[], global::System.Threading.Tasks.Task> Convert<T1, T2, T3, T4, T5, T6, T7>(global::System.Func<T1, T2, T3, T4, T5, T6, T7, global::System.Threading.CancellationToken, global::System.Threading.Tasks.Task> handler)
            {
                return args => handler((T1)args[0]!, (T2)args[1]!, (T3)args[2]!, (T4)args[3]!, (T5)args[4]!, (T6)args[5]!, (T7)args[6]!, default);
            }

            public static global::System.Func<object?[], global::System.Threading.Tasks.Task> Convert<T1, T2, T3, T4, T5, T6, T7, T8>(global::System.Func<T1, T2, T3, T4, T5, T6, T7, T8, global::System.Threading.CancellationToken, global::System.Threading.Tasks.Task> handler)
            {
                return args => handler((T1)args[0]!, (T2)args[1]!, (T3)args[2]!, (T4)args[3]!, (T5)args[4]!, (T6)args[5]!, (T7)args[6]!, (T8)args[7]!, default);
            }

            public static global::System.Func<object?[], global::System.Threading.Tasks.Task> Convert<T1, T2, T3, T4, T5, T6, T7, T8, T9>(global::System.Func<T1, T2, T3, T4, T5, T6, T7, T8, T9, global::System.Threading.CancellationToken, global::System.Threading.Tasks.Task> handler)
            {
                return args => handler((T1)args[0]!, (T2)args[1]!, (T3)args[2]!, (T4)args[3]!, (T5)args[4]!, (T6)args[5]!, (T7)args[6]!, (T8)args[7]!, (T9)args[8]!, default);
            }

            public static global::System.Func<object?[], global::System.Threading.Tasks.Task> Convert<T1, T2, T3, T4, T5, T6, T7, T8, T9, T10>(global::System.Func<T1, T2, T3, T4, T5, T6, T7, T8, T9, T10, global::System.Threading.CancellationToken, global::System.Threading.Tasks.Task> handler)
            {
                return args => handler((T1)args[0]!, (T2)args[1]!, (T3)args[2]!, (T4)args[3]!, (T5)args[4]!, (T6)args[5]!, (T7)args[6]!, (T8)args[7]!, (T9)args[8]!, (T10)args[9]!, default);
            }

            public static global::System.Func<object?[], global::System.Threading.Tasks.Task> Convert<T1, T2, T3, T4, T5, T6, T7, T8, T9, T10, T11>(global::System.Func<T1, T2, T3, T4, T5, T6, T7, T8, T9, T10, T11, global::System.Threading.CancellationToken, global::System.Threading.Tasks.Task> handler)
            {
                return args => handler((T1)args[0]!, (T2)args[1]!, (T3)args[2]!, (T4)args[3]!, (T5)args[4]!, (T6)args[5]!, (T7)args[6]!, (T8)args[7]!, (T9)args[8]!, (T10)args[9]!, (T11)args[10]!, default);
            }

            public static global::System.Func<object?[], global::System.Threading.Tasks.Task> Convert<T1, T2, T3, T4, T5, T6, T7, T8, T9, T10, T11, T12>(global::System.Func<T1, T2, T3, T4, T5, T6, T7, T8, T9, T10, T11, T12, global::System.Threading.CancellationToken, global::System.Threading.Tasks.Task> handler)
            {
                return args => handler((T1)args[0]!, (T2)args[1]!, (T3)args[2]!, (T4)args[3]!, (T5)args[4]!, (T6)args[5]!, (T7)args[6]!, (T8)args[7]!, (T9)args[8]!, (T10)args[9]!, (T11)args[10]!, (T12)args[11]!, default);
            }

            public static global::System.Func<object?[], global::System.Threading.Tasks.Task> Convert<T1, T2, T3, T4, T5, T6, T7, T8, T9, T10, T11, T12, T13>(global::System.Func<T1, T2, T3, T4, T5, T6, T7, T8, T9, T10, T11, T12, T13, global::System.Threading.CancellationToken, global::System.Threading.Tasks.Task> handler)
            {
                return args => handler((T1)args[0]!, (T2)args[1]!, (T3)args[2]!, (T4)args[3]!, (T5)args[4]!, (T6)args[5]!, (T7)args[6]!, (T8)args[7]!, (T9)args[8]!, (T10)args[9]!, (T11)args[10]!, (T12)args[11]!, (T13)args[12]!, default);
            }

            public static global::System.Func<object?[], global::System.Threading.Tasks.Task> Convert<T1, T2, T3, T4, T5, T6, T7, T8, T9, T10, T11, T12, T13, T14>(global::System.Func<T1, T2, T3, T4, T5, T6, T7, T8, T9, T10, T11, T12, T13, T14, global::System.Threading.CancellationToken, global::System.Threading.Tasks.Task> handler)
            {
                return args => handler((T1)args[0]!, (T2)args[1]!, (T3)args[2]!, (T4)args[3]!, (T5)args[4]!, (T6)args[5]!, (T7)args[6]!, (T8)args[7]!, (T9)args[8]!, (T10)args[9]!, (T11)args[10]!, (T12)args[11]!, (T13)args[12]!, (T14)args[13]!, default);
            }

            public static global::System.Func<object?[], global::System.Threading.Tasks.Task> Convert<T1, T2, T3, T4, T5, T6, T7, T8, T9, T10, T11, T12, T13, T14, T15>(global::System.Func<T1, T2, T3, T4, T5, T6, T7, T8, T9, T10, T11, T12, T13, T14, T15, global::System.Threading.CancellationToken, global::System.Threading.Tasks.Task> handler)
            {
                return args => handler((T1)args[0]!, (T2)args[1]!, (T3)args[2]!, (T4)args[3]!, (T5)args[4]!, (T6)args[5]!, (T7)args[6]!, (T8)args[7]!, (T9)args[8]!, (T10)args[9]!, (T11)args[10]!, (T12)args[11]!, (T13)args[12]!, (T14)args[13]!, (T15)args[14]!, default);
            }

            public static global::System.Func<object?[], global::System.Threading.Tasks.Task<TResult>> Convert<TResult>(global::System.Func<global::System.Threading.Tasks.Task<TResult>> handler)
            {
                return async args =>
                {
                    var result = await handler().ConfigureAwait(false);
                    return result;
                };
            }

            public static global::System.Func<object?[], global::System.Threading.Tasks.Task<TResult>> Convert<T1, TResult>(global::System.Func<T1, global::System.Threading.Tasks.Task<TResult>> handler)
            {
                return async args =>
                {
                    var result = await handler((T1)args[0]!).ConfigureAwait(false);
                    return result;
                };
            }

            public static global::System.Func<object?[], global::System.Threading.Tasks.Task<TResult>> Convert<T1, T2, TResult>(global::System.Func<T1, T2, global::System.Threading.Tasks.Task<TResult>> handler)
            {
                return async args =>
                {
                    var result = await handler((T1)args[0]!, (T2)args[1]!).ConfigureAwait(false);
                    return result;
                };
            }

            public static global::System.Func<object?[], global::System.Threading.Tasks.Task<TResult>> Convert<T1, T2, T3, TResult>(global::System.Func<T1, T2, T3, global::System.Threading.Tasks.Task<TResult>> handler)
            {
                return async args =>
                {
                    var result = await handler((T1)args[0]!, (T2)args[1]!, (T3)args[2]!).ConfigureAwait(false);
                    return result;
                };
            }

            public static global::System.Func<object?[], global::System.Threading.Tasks.Task<TResult>> Convert<T1, T2, T3, T4, TResult>(global::System.Func<T1, T2, T3, T4, global::System.Threading.Tasks.Task<TResult>> handler)
            {
                return async args =>
                {
                    var result = await handler((T1)args[0]!, (T2)args[1]!, (T3)args[2]!, (T4)args[3]!).ConfigureAwait(false);
                    return result;
                };
            }

            public static global::System.Func<object?[], global::System.Threading.Tasks.Task<TResult>> Convert<T1, T2, T3, T4, T5, TResult>(global::System.Func<T1, T2, T3, T4, T5, global::System.Threading.Tasks.Task<TResult>> handler)
            {
                return async args =>
                {
                    var result = await handler((T1)args[0]!, (T2)args[1]!, (T3)args[2]!, (T4)args[3]!, (T5)args[4]!).ConfigureAwait(false);
                    return result;
                };
            }

            public static global::System.Func<object?[], global::System.Threading.Tasks.Task<TResult>> Convert<T1, T2, T3, T4, T5, T6, TResult>(global::System.Func<T1, T2, T3, T4, T5, T6, global::System.Threading.Tasks.Task<TResult>> handler)
            {
                return async args =>
                {
                    var result = await handler((T1)args[0]!, (T2)args[1]!, (T3)args[2]!, (T4)args[3]!, (T5)args[4]!, (T6)args[5]!).ConfigureAwait(false);
                    return result;
                };
            }

            public static global::System.Func<object?[], global::System.Threading.Tasks.Task<TResult>> Convert<T1, T2, T3, T4, T5, T6, T7, TResult>(global::System.Func<T1, T2, T3, T4, T5, T6, T7, global::System.Threading.Tasks.Task<TResult>> handler)
            {
                return async args =>
                {
                    var result = await handler((T1)args[0]!, (T2)args[1]!, (T3)args[2]!, (T4)args[3]!, (T5)args[4]!, (T6)args[5]!, (T7)args[6]!).ConfigureAwait(false);
                    return result;
                };
            }

            public static global::System.Func<object?[], global::System.Threading.Tasks.Task<TResult>> Convert<T1, T2, T3, T4, T5, T6, T7, T8, TResult>(global::System.Func<T1, T2, T3, T4, T5, T6, T7, T8, global::System.Threading.Tasks.Task<TResult>> handler)
            {
                return async args =>
                {
                    var result = await handler((T1)args[0]!, (T2)args[1]!, (T3)args[2]!, (T4)args[3]!, (T5)args[4]!, (T6)args[5]!, (T7)args[6]!, (T8)args[7]!).ConfigureAwait(false);
                    return result;
                };
            }

            public static global::System.Func<object?[], global::System.Threading.Tasks.Task<TResult>> Convert<T1, T2, T3, T4, T5, T6, T7, T8, T9, TResult>(global::System.Func<T1, T2, T3, T4, T5, T6, T7, T8, T9, global::System.Threading.Tasks.Task<TResult>> handler)
            {
                return async args =>
                {
                    var result = await handler((T1)args[0]!, (T2)args[1]!, (T3)args[2]!, (T4)args[3]!, (T5)args[4]!, (T6)args[5]!, (T7)args[6]!, (T8)args[7]!, (T9)args[8]!).ConfigureAwait(false);
                    return result;
                };
            }

            public static global::System.Func<object?[], global::System.Threading.Tasks.Task<TResult>> Convert<T1, T2, T3, T4, T5, T6, T7, T8, T9, T10, TResult>(global::System.Func<T1, T2, T3, T4, T5, T6, T7, T8, T9, T10, global::System.Threading.Tasks.Task<TResult>> handler)
            {
                return async args =>
                {
                    var result = await handler((T1)args[0]!, (T2)args[1]!, (T3)args[2]!, (T4)args[3]!, (T5)args[4]!, (T6)args[5]!, (T7)args[6]!, (T8)args[7]!, (T9)args[8]!, (T10)args[9]!).ConfigureAwait(false);
                    return result;
                };
            }

            public static global::System.Func<object?[], global::System.Threading.Tasks.Task<TResult>> Convert<T1, T2, T3, T4, T5, T6, T7, T8, T9, T10, T11, TResult>(global::System.Func<T1, T2, T3, T4, T5, T6, T7, T8, T9, T10, T11, global::System.Threading.Tasks.Task<TResult>> handler)
            {
                return async args =>
                {
                    var result = await handler((T1)args[0]!, (T2)args[1]!, (T3)args[2]!, (T4)args[3]!, (T5)args[4]!, (T6)args[5]!, (T7)args[6]!, (T8)args[7]!, (T9)args[8]!, (T10)args[9]!, (T11)args[10]!).ConfigureAwait(false);
                    return result;
                };
            }

            public static global::System.Func<object?[], global::System.Threading.Tasks.Task<TResult>> Convert<T1, T2, T3, T4, T5, T6, T7, T8, T9, T10, T11, T12, TResult>(global::System.Func<T1, T2, T3, T4, T5, T6, T7, T8, T9, T10, T11, T12, global::System.Threading.Tasks.Task<TResult>> handler)
            {
                return async args =>
                {
                    var result = await handler((T1)args[0]!, (T2)args[1]!, (T3)args[2]!, (T4)args[3]!, (T5)args[4]!, (T6)args[5]!, (T7)args[6]!, (T8)args[7]!, (T9)args[8]!, (T10)args[9]!, (T11)args[10]!, (T12)args[11]!).ConfigureAwait(false);
                    return result;
                };
            }

            public static global::System.Func<object?[], global::System.Threading.Tasks.Task<TResult>> Convert<T1, T2, T3, T4, T5, T6, T7, T8, T9, T10, T11, T12, T13, TResult>(global::System.Func<T1, T2, T3, T4, T5, T6, T7, T8, T9, T10, T11, T12, T13, global::System.Threading.Tasks.Task<TResult>> handler)
            {
                return async args =>
                {
                    var result = await handler((T1)args[0]!, (T2)args[1]!, (T3)args[2]!, (T4)args[3]!, (T5)args[4]!, (T6)args[5]!, (T7)args[6]!, (T8)args[7]!, (T9)args[8]!, (T10)args[9]!, (T11)args[10]!, (T12)args[11]!, (T13)args[12]!).ConfigureAwait(false);
                    return result;
                };
            }

            public static global::System.Func<object?[], global::System.Threading.Tasks.Task<TResult>> Convert<T1, T2, T3, T4, T5, T6, T7, T8, T9, T10, T11, T12, T13, T14, TResult>(global::System.Func<T1, T2, T3, T4, T5, T6, T7, T8, T9, T10, T11, T12, T13, T14, global::System.Threading.Tasks.Task<TResult>> handler)
            {
                return async args =>
                {
                    var result = await handler((T1)args[0]!, (T2)args[1]!, (T3)args[2]!, (T4)args[3]!, (T5)args[4]!, (T6)args[5]!, (T7)args[6]!, (T8)args[7]!, (T9)args[8]!, (T10)args[9]!, (T11)args[10]!, (T12)args[11]!, (T13)args[12]!, (T14)args[13]!).ConfigureAwait(false);
                    return result;
                };
            }

            public static global::System.Func<object?[], global::System.Threading.Tasks.Task<TResult>> Convert<T1, T2, T3, T4, T5, T6, T7, T8, T9, T10, T11, T12, T13, T14, T15, TResult>(global::System.Func<T1, T2, T3, T4, T5, T6, T7, T8, T9, T10, T11, T12, T13, T14, T15, global::System.Threading.Tasks.Task<TResult>> handler)
            {
                return async args =>
                {
                    var result = await handler((T1)args[0]!, (T2)args[1]!, (T3)args[2]!, (T4)args[3]!, (T5)args[4]!, (T6)args[5]!, (T7)args[6]!, (T8)args[7]!, (T9)args[8]!, (T10)args[9]!, (T11)args[10]!, (T12)args[11]!, (T13)args[12]!, (T14)args[13]!, (T15)args[14]!).ConfigureAwait(false);
                    return result;
                };
            }

            public static global::System.Func<object?[], global::System.Threading.Tasks.Task<TResult>> Convert<T1, T2, T3, T4, T5, T6, T7, T8, T9, T10, T11, T12, T13, T14, T15, T16, TResult>(global::System.Func<T1, T2, T3, T4, T5, T6, T7, T8, T9, T10, T11, T12, T13, T14, T15, T16, global::System.Threading.Tasks.Task<TResult>> handler)
            {
                return async args =>
                {
                    var result = await handler((T1)args[0]!, (T2)args[1]!, (T3)args[2]!, (T4)args[3]!, (T5)args[4]!, (T6)args[5]!, (T7)args[6]!, (T8)args[7]!, (T9)args[8]!, (T10)args[9]!, (T11)args[10]!, (T12)args[11]!, (T13)args[12]!, (T14)args[13]!, (T15)args[14]!, (T16)args[15]!).ConfigureAwait(false);
                    return result;
                };
            }

            public static global::System.Func<object?[], global::System.Threading.Tasks.Task<TResult>> Convert<TResult>(global::System.Func<global::System.Threading.CancellationToken, global::System.Threading.Tasks.Task<TResult>> handler)
            {
                return async args =>
                {
                    var result = await handler(default).ConfigureAwait(false);
                    return result;
                };
            }

            public static global::System.Func<object?[], global::System.Threading.Tasks.Task<TResult>> Convert<T1, TResult>(global::System.Func<T1, global::System.Threading.CancellationToken, global::System.Threading.Tasks.Task<TResult>> handler)
            {
                return async args =>
                {
                    var result = await handler((T1)args[0]!, default).ConfigureAwait(false);
                    return result;
                };
            }

            public static global::System.Func<object?[], global::System.Threading.Tasks.Task<TResult>> Convert<T1, T2, TResult>(global::System.Func<T1, T2, global::System.Threading.CancellationToken, global::System.Threading.Tasks.Task<TResult>> handler)
            {
                return async args =>
                {
                    var result = await handler((T1)args[0]!, (T2)args[1]!, default).ConfigureAwait(false);
                    return result;
                };
            }

            public static global::System.Func<object?[], global::System.Threading.Tasks.Task<TResult>> Convert<T1, T2, T3, TResult>(global::System.Func<T1, T2, T3, global::System.Threading.CancellationToken, global::System.Threading.Tasks.Task<TResult>> handler)
            {
                return async args =>
                {
                    var result = await handler((T1)args[0]!, (T2)args[1]!, (T3)args[2]!, default).ConfigureAwait(false);
                    return result;
                };
            }

            public static global::System.Func<object?[], global::System.Threading.Tasks.Task<TResult>> Convert<T1, T2, T3, T4, TResult>(global::System.Func<T1, T2, T3, T4, global::System.Threading.CancellationToken, global::System.Threading.Tasks.Task<TResult>> handler)
            {
                return async args =>
                {
                    var result = await handler((T1)args[0]!, (T2)args[1]!, (T3)args[2]!, (T4)args[3]!, default).ConfigureAwait(false);
                    return result;
                };
            }

            public static global::System.Func<object?[], global::System.Threading.Tasks.Task<TResult>> Convert<T1, T2, T3, T4, T5, TResult>(global::System.Func<T1, T2, T3, T4, T5, global::System.Threading.CancellationToken, global::System.Threading.Tasks.Task<TResult>> handler)
            {
                return async args =>
                {
                    var result = await handler((T1)args[0]!, (T2)args[1]!, (T3)args[2]!, (T4)args[3]!, (T5)args[4]!, default).ConfigureAwait(false);
                    return result;
                };
            }

            public static global::System.Func<object?[], global::System.Threading.Tasks.Task<TResult>> Convert<T1, T2, T3, T4, T5, T6, TResult>(global::System.Func<T1, T2, T3, T4, T5, T6, global::System.Threading.CancellationToken, global::System.Threading.Tasks.Task<TResult>> handler)
            {
                return async args =>
                {
                    var result = await handler((T1)args[0]!, (T2)args[1]!, (T3)args[2]!, (T4)args[3]!, (T5)args[4]!, (T6)args[5]!, default).ConfigureAwait(false);
                    return result;
                };
            }

            public static global::System.Func<object?[], global::System.Threading.Tasks.Task<TResult>> Convert<T1, T2, T3, T4, T5, T6, T7, TResult>(global::System.Func<T1, T2, T3, T4, T5, T6, T7, global::System.Threading.CancellationToken, global::System.Threading.Tasks.Task<TResult>> handler)
            {
                return async args =>
                {
                    var result = await handler((T1)args[0]!, (T2)args[1]!, (T3)args[2]!, (T4)args[3]!, (T5)args[4]!, (T6)args[5]!, (T7)args[6]!, default).ConfigureAwait(false);
                    return result;
                };
            }

            public static global::System.Func<object?[], global::System.Threading.Tasks.Task<TResult>> Convert<T1, T2, T3, T4, T5, T6, T7, T8, TResult>(global::System.Func<T1, T2, T3, T4, T5, T6, T7, T8, global::System.Threading.CancellationToken, global::System.Threading.Tasks.Task<TResult>> handler)
            {
                return async args =>
                {
                    var result = await handler((T1)args[0]!, (T2)args[1]!, (T3)args[2]!, (T4)args[3]!, (T5)args[4]!, (T6)args[5]!, (T7)args[6]!, (T8)args[7]!, default).ConfigureAwait(false);
                    return result;
                };
            }

            public static global::System.Func<object?[], global::System.Threading.Tasks.Task<TResult>> Convert<T1, T2, T3, T4, T5, T6, T7, T8, T9, TResult>(global::System.Func<T1, T2, T3, T4, T5, T6, T7, T8, T9, global::System.Threading.CancellationToken, global::System.Threading.Tasks.Task<TResult>> handler)
            {
                return async args =>
                {
                    var result = await handler((T1)args[0]!, (T2)args[1]!, (T3)args[2]!, (T4)args[3]!, (T5)args[4]!, (T6)args[5]!, (T7)args[6]!, (T8)args[7]!, (T9)args[8]!, default).ConfigureAwait(false);
                    return result;
                };
            }

            public static global::System.Func<object?[], global::System.Threading.Tasks.Task<TResult>> Convert<T1, T2, T3, T4, T5, T6, T7, T8, T9, T10, TResult>(global::System.Func<T1, T2, T3, T4, T5, T6, T7, T8, T9, T10, global::System.Threading.CancellationToken, global::System.Threading.Tasks.Task<TResult>> handler)
            {
                return async args =>
                {
                    var result = await handler((T1)args[0]!, (T2)args[1]!, (T3)args[2]!, (T4)args[3]!, (T5)args[4]!, (T6)args[5]!, (T7)args[6]!, (T8)args[7]!, (T9)args[8]!, (T10)args[9]!, default).ConfigureAwait(false);
                    return result;
                };
            }

            public static global::System.Func<object?[], global::System.Threading.Tasks.Task<TResult>> Convert<T1, T2, T3, T4, T5, T6, T7, T8, T9, T10, T11, TResult>(global::System.Func<T1, T2, T3, T4, T5, T6, T7, T8, T9, T10, T11, global::System.Threading.CancellationToken, global::System.Threading.Tasks.Task<TResult>> handler)
            {
                return async args =>
                {
                    var result = await handler((T1)args[0]!, (T2)args[1]!, (T3)args[2]!, (T4)args[3]!, (T5)args[4]!, (T6)args[5]!, (T7)args[6]!, (T8)args[7]!, (T9)args[8]!, (T10)args[9]!, (T11)args[10]!, default).ConfigureAwait(false);
                    return result;
                };
            }

            public static global::System.Func<object?[], global::System.Threading.Tasks.Task<TResult>> Convert<T1, T2, T3, T4, T5, T6, T7, T8, T9, T10, T11, T12, TResult>(global::System.Func<T1, T2, T3, T4, T5, T6, T7, T8, T9, T10, T11, T12, global::System.Threading.CancellationToken, global::System.Threading.Tasks.Task<TResult>> handler)
            {
                return async args =>
                {
                    var result = await handler((T1)args[0]!, (T2)args[1]!, (T3)args[2]!, (T4)args[3]!, (T5)args[4]!, (T6)args[5]!, (T7)args[6]!, (T8)args[7]!, (T9)args[8]!, (T10)args[9]!, (T11)args[10]!, (T12)args[11]!, default).ConfigureAwait(false);
                    return result;
                };
            }

            public static global::System.Func<object?[], global::System.Threading.Tasks.Task<TResult>> Convert<T1, T2, T3, T4, T5, T6, T7, T8, T9, T10, T11, T12, T13, TResult>(global::System.Func<T1, T2, T3, T4, T5, T6, T7, T8, T9, T10, T11, T12, T13, global::System.Threading.CancellationToken, global::System.Threading.Tasks.Task<TResult>> handler)
            {
                return async args =>
                {
                    var result = await handler((T1)args[0]!, (T2)args[1]!, (T3)args[2]!, (T4)args[3]!, (T5)args[4]!, (T6)args[5]!, (T7)args[6]!, (T8)args[7]!, (T9)args[8]!, (T10)args[9]!, (T11)args[10]!, (T12)args[11]!, (T13)args[12]!, default).ConfigureAwait(false);
                    return result;
                };
            }

            public static global::System.Func<object?[], global::System.Threading.Tasks.Task<TResult>> Convert<T1, T2, T3, T4, T5, T6, T7, T8, T9, T10, T11, T12, T13, T14, TResult>(global::System.Func<T1, T2, T3, T4, T5, T6, T7, T8, T9, T10, T11, T12, T13, T14, global::System.Threading.CancellationToken, global::System.Threading.Tasks.Task<TResult>> handler)
            {
                return async args =>
                {
                    var result = await handler((T1)args[0]!, (T2)args[1]!, (T3)args[2]!, (T4)args[3]!, (T5)args[4]!, (T6)args[5]!, (T7)args[6]!, (T8)args[7]!, (T9)args[8]!, (T10)args[9]!, (T11)args[10]!, (T12)args[11]!, (T13)args[12]!, (T14)args[13]!, default).ConfigureAwait(false);
                    return result;
                };
            }

            public static global::System.Func<object?[], global::System.Threading.Tasks.Task<TResult>> Convert<T1, T2, T3, T4, T5, T6, T7, T8, T9, T10, T11, T12, T13, T14, T15, TResult>(global::System.Func<T1, T2, T3, T4, T5, T6, T7, T8, T9, T10, T11, T12, T13, T14, T15, global::System.Threading.CancellationToken, global::System.Threading.Tasks.Task<TResult>> handler)
            {
                return async args =>
                {
                    var result = await handler((T1)args[0]!, (T2)args[1]!, (T3)args[2]!, (T4)args[3]!, (T5)args[4]!, (T6)args[5]!, (T7)args[6]!, (T8)args[7]!, (T9)args[8]!, (T10)args[9]!, (T11)args[10]!, (T12)args[11]!, (T13)args[12]!, (T14)args[13]!, (T15)args[14]!, default).ConfigureAwait(false);
                    return result;
                };
            }
        }
    }
}
#pragma warning restore CS1591

// <auto-generated>
// THIS (.cs) FILE IS GENERATED BY TypedSignalR.Client
// </auto-generated>
#nullable enable
#pragma warning disable CS1591
#pragma warning disable CS8767
#pragma warning disable CS8613
namespace TypedSignalR.Client
{
    internal static partial class HubConnectionExtensions
    {
        private sealed class HubInvokerFor_global__TestSignalRCommon_IHubMessage : global::TestSignalRCommon.IHubMessage, IHubInvoker
        {
            private readonly global::Microsoft.AspNetCore.SignalR.Client.HubConnection _connection;
            private readonly global::System.Threading.CancellationToken _cancellationToken;

            public HubInvokerFor_global__TestSignalRCommon_IHubMessage(global::Microsoft.AspNetCore.SignalR.Client.HubConnection connection, global::System.Threading.CancellationToken cancellationToken)
            {
                _connection = connection;
                _cancellationToken = cancellationToken;
            }

            public global::System.Threading.Tasks.Task SendMessage(string user, string message)
            {
                return global::Microsoft.AspNetCore.SignalR.Client.HubConnectionExtensions.InvokeCoreAsync(_connection, nameof(SendMessage), new object?[] { user, message }, _cancellationToken);
            }
        }

        private sealed class HubInvokerFactoryFor_global__TestSignalRCommon_IHubMessage : IHubInvokerFactory<global::TestSignalRCommon.IHubMessage>
        {
            public global::TestSignalRCommon.IHubMessage CreateHubInvoker(global::Microsoft.AspNetCore.SignalR.Client.HubConnection connection, global::System.Threading.CancellationToken cancellationToken)
            {
                return new HubInvokerFor_global__TestSignalRCommon_IHubMessage(connection, cancellationToken);
            }
        }

        private static partial global::System.Collections.Generic.Dictionary<global::System.Type, IHubInvokerFactory> CreateFactories()
        {
            var factories = new global::System.Collections.Generic.Dictionary<global::System.Type, IHubInvokerFactory>();

            factories.Add(typeof(global::TestSignalRCommon.IHubMessage), new HubInvokerFactoryFor_global__TestSignalRCommon_IHubMessage());

            return factories;
        }
    }
}
#pragma warning restore CS8613
#pragma warning restore CS8767
#pragma warning restore CS1591

Code and pdf at

https://ignatandrei.github.io/RSCG_Examples/v2/docs/TypedSignalR.Client

RSCG – MinimalHelpers.Routing.Analyzers

RSCG – MinimalHelpers.Routing.Analyzers
 
 

name MinimalHelpers.Routing.Analyzers
nuget https://www.nuget.org/packages/MinimalHelpers.Routing.Analyzers/
link https://github.com/marcominerva/MinimalHelpers
author Maroc Minerva

Controller like API registering

 

This is how you can use MinimalHelpers.Routing.Analyzers .

The code that you start with is


<Project Sdk="Microsoft.NET.Sdk.Web">

  <PropertyGroup>
    <TargetFramework>net8.0</TargetFramework>
    <Nullable>enable</Nullable>
    <ImplicitUsings>enable</ImplicitUsings>
  </PropertyGroup>

  <ItemGroup>
    <PackageReference Include="Microsoft.AspNetCore.OpenApi" Version="8.0.4" />
    <PackageReference Include="MinimalHelpers.Routing.Analyzers" Version="1.0.13" />
    <PackageReference Include="Swashbuckle.AspNetCore" Version="6.5.0" />
  </ItemGroup>
	<PropertyGroup>
		<EmitCompilerGeneratedFiles>true</EmitCompilerGeneratedFiles>
		<CompilerGeneratedFilesOutputPath>$(BaseIntermediateOutputPath)\GX</CompilerGeneratedFilesOutputPath>
	</PropertyGroup>
</Project>


The code that you will use is


using Microsoft.AspNetCore.Http.HttpResults;
namespace APIDemo;

public class PersonAPI : IEndpointRouteHandlerBuilder
{
    public static void MapEndpoints(IEndpointRouteBuilder endpoints)
    {
        var grp = endpoints.MapGroup("/api/Person");
        grp.MapGet("", GetFromId);
        grp.MapGet("{id:int}", GetFromId);
        //todo: add more routes
    }
    public static async Task<Person[]> GetAll()
    {       
        await Task.Delay(1000);
        return new[] { new Person { FirstName = "Ignat", LastName = "Andrei" } };
    }

    public static async Task<Results<Ok<Person>,NotFound<string>>> GetFromId(int id)
    {
        await Task.Delay(1000);
        if (id == 1)
        {
            return TypedResults.Ok<Person>(new Person { FirstName = "Ignat", LastName = "Andrei" });
        }
        return TypedResults.NotFound<string>("Person not found");
    }


}



namespace APIDemo;

public class Person
{
    public string? FirstName { get; set; }
    public string? LastName { get; set; }
}



var builder = WebApplication.CreateBuilder(args);

// Add services to the container.
// Learn more about configuring Swagger/OpenAPI at https://aka.ms/aspnetcore/swashbuckle
builder.Services.AddEndpointsApiExplorer();
builder.Services.AddSwaggerGen();

var app = builder.Build();

// Configure the HTTP request pipeline.
//if (app.Environment.IsDevelopment())
{
    app.UseSwagger();
    app.UseSwaggerUI();
}

//app.UseHttpsRedirection();

var summaries = new[]
{
    "Freezing", "Bracing", "Chilly", "Cool", "Mild", "Warm", "Balmy", "Hot", "Sweltering", "Scorching"
};

app.MapGet("/weatherforecast", () =>
{
    var forecast = Enumerable.Range(1, 5).Select(index =>
        new WeatherForecast
        (
            DateOnly.FromDateTime(DateTime.Now.AddDays(index)),
            Random.Shared.Next(-20, 55),
            summaries[Random.Shared.Next(summaries.Length)]
        ))
        .ToArray();
    return forecast;
})
.WithName("GetWeatherForecast")
.WithOpenApi();

app.MapEndpoints();

app.Run();

internal record WeatherForecast(DateOnly Date, int TemperatureC, string? Summary)
{
    public int TemperatureF => 32 + (int)(TemperatureC / 0.5556);
}


 

The code that is generated is

// <auto-generated />
namespace Microsoft.AspNetCore.Routing;

#nullable enable annotations
#nullable disable warnings

/// <summary>
/// Provides extension methods for <see cref="IEndpointRouteBuilder" /> to add route handlers.
/// </summary>
public static class EndpointRouteBuilderExtensions
{
    /// <summary>
    /// Automatically registers all the route endpoints defined in classes that implement the <see cref="IEndpointRouteHandlerBuilder "/> interface.
    /// </summary>
    /// <param name="endpoints">The <see cref="IEndpointRouteBuilder" /> to add routes to.</param>
    public static IEndpointRouteBuilder MapEndpoints(this IEndpointRouteBuilder endpoints)
    {            
        global::APIDemo.PersonAPI.MapEndpoints(endpoints);

        return endpoints;
    }
}

// <auto-generated />
namespace Microsoft.AspNetCore.Routing;

#nullable enable annotations
#nullable disable warnings                

/// <summary>
/// Defines a contract for a class that holds one or more route handlers that must be registered by the application.
/// </summary>
public interface IEndpointRouteHandlerBuilder
{
    /// <summary>
    /// Maps route endpoints to the corresponding handlers.
    /// </summary>
    static abstract void MapEndpoints(IEndpointRouteBuilder endpoints);
}

Code and pdf at

https://ignatandrei.github.io/RSCG_Examples/v2/docs/MinimalHelpers.Routing.Analyzers

RSCG – Dusharp

RSCG – Dusharp
 
 

name Dusharp
nuget https://www.nuget.org/packages/Dusharp/
link https://github.com/kolebynov/Dusharp
author Vitali

Generate tagged union

 

This is how you can use Dusharp .

The code that you start with is


<Project Sdk="Microsoft.NET.Sdk">

  <PropertyGroup>
    <OutputType>Exe</OutputType>
    <TargetFramework>net8.0</TargetFramework>
    <ImplicitUsings>enable</ImplicitUsings>
    <Nullable>enable</Nullable>
  </PropertyGroup>

	<PropertyGroup>
		<EmitCompilerGeneratedFiles>true</EmitCompilerGeneratedFiles>
		<CompilerGeneratedFilesOutputPath>$(BaseIntermediateOutputPath)\GX</CompilerGeneratedFilesOutputPath>
	</PropertyGroup>

	<ItemGroup>
	  <PackageReference Include="Dusharp" Version="0.4.0">
	    <PrivateAssets>all</PrivateAssets>
	    <IncludeAssets>runtime; build; native; contentfiles; analyzers; buildtransitive</IncludeAssets>
	  </PackageReference>
	</ItemGroup>

	

</Project>


The code that you will use is


using UnionTypesDemo;

Console.WriteLine("Save or not");
var data = SaveToDatabase.Save(0);
data.Match(
    ok => Console.WriteLine(ok),
    ()=> Console.WriteLine("Not found")
);

data = SaveToDatabase.Save(1);
data.Match(
    ok => Console.WriteLine(ok),
    () => Console.WriteLine("Not found")
);



using Dusharp;
namespace UnionTypesDemo;


[Union]
public partial class ResultSave
{
    [UnionCase]
    public static partial ResultSave Ok(int i);
    [UnionCase]
    public static partial ResultSave NotFound();
    
}




namespace UnionTypesDemo;

public class SaveToDatabase
{
    public static ResultSave Save(int i)
    {

        if (i == 0)
        {
            return ResultSave.NotFound();
        }
        return ResultSave.Ok(i); ;
    }
}




 

The code that is generated is

// <auto-generated> This file has been auto generated. </auto-generated>
#nullable enable
using System;
using System.Runtime.CompilerServices;

namespace Dusharp
{
	public static class ExceptionUtils
	{
		[MethodImpl(MethodImplOptions.AggressiveInlining)]
		public static void ThrowIfNull<T>(this T value, string paramName)
			where T : class
		{
			if (value == null)
			{
				ThrowArgumentNull(paramName);
			}
		}

		[MethodImpl(MethodImplOptions.NoInlining)]
		public static void ThrowUnionInInvalidState() =>
			throw new InvalidOperationException("Union in invalid state.");

		[MethodImpl(MethodImplOptions.NoInlining)]
		private static void ThrowArgumentNull(string paramName) => throw new ArgumentNullException(paramName);
	}
}
// <auto-generated> This file has been auto generated. </auto-generated>
#nullable enable
using System;

namespace Dusharp
{
	[AttributeUsage(AttributeTargets.Class)]
	public sealed class UnionAttribute : Attribute
	{
	}
}
// <auto-generated> This file has been auto generated. </auto-generated>
#nullable enable
using System;

namespace Dusharp
{
	[AttributeUsage(AttributeTargets.Method)]
	public sealed class UnionCaseAttribute : Attribute
	{
	}
}
// <auto-generated> This file has been auto generated. </auto-generated>
#nullable enable
namespace UnionTypesDemo
{
	[System.Diagnostics.CodeAnalysis.SuppressMessage("", "CA1000", Justification = "For generic unions.")]
	abstract partial class ResultSave : System.IEquatable<ResultSave>
	{
		private ResultSave() {}

		public void Match(System.Action<int> okCase, System.Action notFoundCase)
		{
			Dusharp.ExceptionUtils.ThrowIfNull(okCase, "okCase");
			Dusharp.ExceptionUtils.ThrowIfNull(notFoundCase, "notFoundCase");

			{
				var unionCase = this as OkCase;
				if (!object.ReferenceEquals(unionCase, null)) { okCase(unionCase.i); return; }
			}

			{
				var unionCase = this as NotFoundCase;
				if (!object.ReferenceEquals(unionCase, null)) { notFoundCase(); return; }
			}

			Dusharp.ExceptionUtils.ThrowUnionInInvalidState();
		}

		public TRet Match<TRet>(System.Func<int, TRet> okCase, System.Func<TRet> notFoundCase)
		{
			Dusharp.ExceptionUtils.ThrowIfNull(okCase, "okCase");
			Dusharp.ExceptionUtils.ThrowIfNull(notFoundCase, "notFoundCase");

			{
				var unionCase = this as OkCase;
				if (!object.ReferenceEquals(unionCase, null)) { return okCase(unionCase.i); }
			}

			{
				var unionCase = this as NotFoundCase;
				if (!object.ReferenceEquals(unionCase, null)) { return notFoundCase(); }
			}

			Dusharp.ExceptionUtils.ThrowUnionInInvalidState();
			return default!;
		}

		public void Match<TState>(TState state, System.Action<TState, int> okCase, System.Action<TState> notFoundCase)
		{
			Dusharp.ExceptionUtils.ThrowIfNull(okCase, "okCase");
			Dusharp.ExceptionUtils.ThrowIfNull(notFoundCase, "notFoundCase");

			{
				var unionCase = this as OkCase;
				if (!object.ReferenceEquals(unionCase, null)) { okCase(state, unionCase.i); return; }
			}

			{
				var unionCase = this as NotFoundCase;
				if (!object.ReferenceEquals(unionCase, null)) { notFoundCase(state); return; }
			}

			Dusharp.ExceptionUtils.ThrowUnionInInvalidState();
		}

		public TRet Match<TState, TRet>(TState state, System.Func<TState, int, TRet> okCase, System.Func<TState, TRet> notFoundCase)
		{
			Dusharp.ExceptionUtils.ThrowIfNull(okCase, "okCase");
			Dusharp.ExceptionUtils.ThrowIfNull(notFoundCase, "notFoundCase");

			{
				var unionCase = this as OkCase;
				if (!object.ReferenceEquals(unionCase, null)) { return okCase(state, unionCase.i); }
			}

			{
				var unionCase = this as NotFoundCase;
				if (!object.ReferenceEquals(unionCase, null)) { return notFoundCase(state); }
			}

			Dusharp.ExceptionUtils.ThrowUnionInInvalidState();
			return default!;
		}

		public virtual bool Equals(ResultSave? other) { return object.ReferenceEquals(this, other); }
		public override bool Equals(object? other) { return object.ReferenceEquals(this, other); }
		public override int GetHashCode() { return System.Runtime.CompilerServices.RuntimeHelpers.GetHashCode(this); }
		public static bool operator ==(ResultSave? left, ResultSave? right)
		{
			return !object.ReferenceEquals(left, null) ? left.Equals(right) : object.ReferenceEquals(left, right);
		}

		public static bool operator !=(ResultSave? left, ResultSave? right)
		{
			return !object.ReferenceEquals(left, null) ? !left.Equals(right) : !object.ReferenceEquals(left, right);
		}

		private sealed class OkCase : ResultSave
		{
			public readonly int i;
			public OkCase(int i)
			{
				this.i = i;
			}

			public override string ToString()
			{
				return $"Ok {{ i = {i} }}";
			}

			public override bool Equals(ResultSave? other)
			{
				if (object.ReferenceEquals(this, other)) return true;
				var otherCasted = other as OkCase;
				if (object.ReferenceEquals(otherCasted, null)) return false;
				return StructuralEquals(otherCasted);
			}

			public override bool Equals(object? other)
			{
				if (object.ReferenceEquals(this, other)) return true;
				var otherCasted = other as OkCase;
				if (object.ReferenceEquals(otherCasted, null)) return false;
				return StructuralEquals(otherCasted);
			}

			public override int GetHashCode()
			{
				unchecked { return System.Collections.Generic.EqualityComparer<int>.Default.GetHashCode(i!) * -1521134295 + "Ok".GetHashCode(); }
			}

			private bool StructuralEquals(OkCase other)
			{
				return System.Collections.Generic.EqualityComparer<int>.Default.Equals(i, other.i);
			}
		}

		public static partial ResultSave Ok(int i)
		{
			return new OkCase(i);
		}

		private sealed class NotFoundCase : ResultSave
		{
			public static readonly NotFoundCase Instance = new NotFoundCase();
			public NotFoundCase()
			{
			}

			public override string ToString()
			{
				return "NotFound";
			}
		}

		public static partial ResultSave NotFound()
		{
			return NotFoundCase.Instance;
		}
	}
}

// <auto-generated/>

#nullable enable

using Sera.TaggedUnion;

namespace UnionTypesDemo {

public partial struct ResultSave
    : global::Sera.TaggedUnion.ITaggedUnion
    , global::System.IEquatable<ResultSave>
    , global::System.IComparable<ResultSave>
#if NET7_0_OR_GREATER
    , global::System.Numerics.IEqualityOperators<ResultSave, ResultSave, bool>
    , global::System.Numerics.IComparisonOperators<ResultSave, ResultSave, bool>
#endif
{
    private __impl_ _impl;
    private ResultSave(__impl_ _impl) { this._impl = _impl; }

    public readonly Tags Tag
    {
        [global::System.Runtime.CompilerServices.MethodImpl(global::System.Runtime.CompilerServices.MethodImplOptions.AggressiveInlining)]
        get => this._impl._tag;
    }

    public enum Tags : byte
    {
        Ok = 1,
        NotFound = 2,
    }

    [global::System.Runtime.CompilerServices.CompilerGenerated]
    private struct __impl_
    {
        public __unmanaged_ _unmanaged_;
        public readonly Tags _tag;

        [global::System.Runtime.CompilerServices.CompilerGenerated]
        [global::System.Runtime.InteropServices.StructLayout(global::System.Runtime.InteropServices.LayoutKind.Explicit)]
        internal struct __unmanaged_
        {
            [global::System.Runtime.InteropServices.FieldOffset(0)]
            public int _0;
        }

        public __impl_(Tags _tag)
        {
            global::System.Runtime.CompilerServices.Unsafe.SkipInit(out this._unmanaged_);
            this._tag = _tag;
        }
    }

    [global::System.Runtime.CompilerServices.MethodImpl(global::System.Runtime.CompilerServices.MethodImplOptions.AggressiveInlining)]
    public static ResultSave MakeOk(int value)
    {
        var _impl = new __impl_(Tags.Ok);
        _impl._unmanaged_._0 = value;
        return new ResultSave(_impl);
    }
    [global::System.Runtime.CompilerServices.MethodImpl(global::System.Runtime.CompilerServices.MethodImplOptions.AggressiveInlining)]
    public static ResultSave MakeNotFound()
    {
        var _impl = new __impl_(Tags.NotFound);
        return new ResultSave(_impl);
    }

    public readonly bool IsOk
    {
        [global::System.Runtime.CompilerServices.MethodImpl(global::System.Runtime.CompilerServices.MethodImplOptions.AggressiveInlining)]
        get => this._impl._tag == Tags.Ok;
    }
    public readonly bool IsNotFound
    {
        [global::System.Runtime.CompilerServices.MethodImpl(global::System.Runtime.CompilerServices.MethodImplOptions.AggressiveInlining)]
        get => this._impl._tag == Tags.NotFound;
    }

    public int Ok
    {
        [global::System.Runtime.CompilerServices.MethodImpl(global::System.Runtime.CompilerServices.MethodImplOptions.AggressiveInlining)]
        readonly get => !this.IsOk ? default! : this._impl._unmanaged_._0!;
        [global::System.Runtime.CompilerServices.MethodImpl(global::System.Runtime.CompilerServices.MethodImplOptions.AggressiveInlining)]
        set { if (this.IsOk) { this._impl._unmanaged_._0 = value; } }
    }

    [global::System.Runtime.CompilerServices.MethodImpl(global::System.Runtime.CompilerServices.MethodImplOptions.AggressiveInlining)]
    public readonly bool Equals(ResultSave other) => this.Tag != other.Tag ? false : this.Tag switch
    {
        Tags.Ok => global::System.Collections.Generic.EqualityComparer<int>.Default.Equals(this.Ok, other.Ok),
        _ => true,
    };

    [global::System.Runtime.CompilerServices.MethodImpl(global::System.Runtime.CompilerServices.MethodImplOptions.AggressiveInlining)]
    public readonly override int GetHashCode() => this.Tag switch
    {
        Tags.Ok => global::System.HashCode.Combine(this.Tag, this.Ok),
        _ => global::System.HashCode.Combine(this.Tag),
    };

    [global::System.Runtime.CompilerServices.MethodImpl(global::System.Runtime.CompilerServices.MethodImplOptions.AggressiveInlining)]
    public readonly override bool Equals(object? obj) => obj is ResultSave other && Equals(other);

    [global::System.Runtime.CompilerServices.MethodImpl(global::System.Runtime.CompilerServices.MethodImplOptions.AggressiveInlining)]
    public static bool operator ==(ResultSave left, ResultSave right) => Equals(left, right);
    [global::System.Runtime.CompilerServices.MethodImpl(global::System.Runtime.CompilerServices.MethodImplOptions.AggressiveInlining)]
    public static bool operator !=(ResultSave left, ResultSave right) => !Equals(left, right);

    [global::System.Runtime.CompilerServices.MethodImpl(global::System.Runtime.CompilerServices.MethodImplOptions.AggressiveInlining)]
    public readonly int CompareTo(ResultSave other) => this.Tag != other.Tag ? global::System.Collections.Generic.Comparer<Tags>.Default.Compare(this.Tag, other.Tag) : this.Tag switch
    {
        Tags.Ok => global::System.Collections.Generic.Comparer<int>.Default.Compare(this.Ok, other.Ok),
        _ => 0,
    };

    [global::System.Runtime.CompilerServices.MethodImpl(global::System.Runtime.CompilerServices.MethodImplOptions.AggressiveInlining)]
    public static bool operator <(ResultSave left, ResultSave right) => left.CompareTo(right) < 0;
    [global::System.Runtime.CompilerServices.MethodImpl(global::System.Runtime.CompilerServices.MethodImplOptions.AggressiveInlining)]
    public static bool operator >(ResultSave left, ResultSave right) => left.CompareTo(right) > 0;
    [global::System.Runtime.CompilerServices.MethodImpl(global::System.Runtime.CompilerServices.MethodImplOptions.AggressiveInlining)]
    public static bool operator <=(ResultSave left, ResultSave right) => left.CompareTo(right) <= 0;
    [global::System.Runtime.CompilerServices.MethodImpl(global::System.Runtime.CompilerServices.MethodImplOptions.AggressiveInlining)]
    public static bool operator >=(ResultSave left, ResultSave right) => left.CompareTo(right) >= 0;

    [global::System.Runtime.CompilerServices.MethodImpl(global::System.Runtime.CompilerServices.MethodImplOptions.AggressiveInlining)]
    public readonly override string ToString() => this.Tag switch
    {
        Tags.Ok => $"{nameof(ResultSave)}.{nameof(Tags.Ok)} {{ {this.Ok} }}",
        Tags.NotFound => $"{nameof(ResultSave)}.{nameof(Tags.NotFound)}",
        _ => nameof(ResultSave),
    };
}

} // namespace UnionTypesDemo

Code and pdf at

https://ignatandrei.github.io/RSCG_Examples/v2/docs/Dusharp

RSCG – LightweightObjectMapper

RSCG – LightweightObjectMapper
 
 

name LightweightObjectMapper
nuget https://www.nuget.org/packages/LightweightObjectMapper/
link https://github.com/stratosblue/LightweightObjectMapper
author Stratos

Generating function to map DTOs

 

This is how you can use LightweightObjectMapper .

The code that you start with is


<Project Sdk="Microsoft.NET.Sdk">

  <PropertyGroup>
    <OutputType>Exe</OutputType>
    <TargetFramework>net8.0</TargetFramework>
    <ImplicitUsings>enable</ImplicitUsings>
    <Nullable>enable</Nullable>
  </PropertyGroup>

	<PropertyGroup>
		<EmitCompilerGeneratedFiles>true</EmitCompilerGeneratedFiles>
		<CompilerGeneratedFilesOutputPath>$(BaseIntermediateOutputPath)\GX</CompilerGeneratedFilesOutputPath>
	</PropertyGroup>

	<ItemGroup>
	  <PackageReference Include="LightweightObjectMapper" Version="1.0.2" />
	</ItemGroup>

	<!--<PropertyGroup>
		<NoLightweightObjectMapperPreCodes>true</NoLightweightObjectMapperPreCodes>
		<LOMappingMethodAccessibility>public</LOMappingMethodAccessibility>
	</PropertyGroup>-->

	
</Project>


The code that you will use is


using mapperDemo;
using LightweightObjectMapper;
var p=new Person();
p.FirstName = "Andrei";
p.LastName = "Ignat";
PersonDTO dto= p.MapTo<PersonDTO>();
Console.WriteLine(dto.FullName);




public partial class Person
{
    public int ID { get; set; }
    public string? FirstName { get; set; }
    public string? LastName { get; set; }
}





namespace mapperDemo;
public partial class PersonDTO
{
    public int ID { get; set; }
    public string? FirstName { get; set; }
    public string? LastName { get; set; }
    public string FullName { 
        get
        {
            return FirstName + " " + LastName;
        }
    }
}



using LightweightObjectMapper;
using System;
namespace mapperDemo;

[MappingProfile]
internal partial class Extensions:
    IPostMapping<Person, PersonDTO>
{
    

    public PersonDTO PostMapping(Person source, PersonDTO target)
    {
        target.ID = source.ID;
        return target;
    }
}


 

The code that is generated is

// <Auto-Generated/>
#pragma warning disable IDE0005
#pragma warning disable CS0105
using LightweightObjectMapper;
using System;
using System;
using System.Linq;
using System.Runtime.CompilerServices;

namespace mapperDemo
{
    sealed partial class Extensions
    {
        public static partial class Generated
        {
            /// <summary>
            /// PostMappingDeclaration for <see cref = "global::Person"/> to <see cref = "global::mapperDemo.PersonDTO"/>
            /// </summary>
            [MethodImpl(MethodImplOptions.AggressiveInlining)]
            [MappingMetadata(MappingMetadataType.PostMappingDeclaration, typeof(global::Person), typeof(global::mapperDemo.PersonDTO))]
            public static global::mapperDemo.PersonDTO PostMapping_D275C37F33F4AFBD(global::Person source, global::mapperDemo.PersonDTO target)
            {
                target.ID = source.ID;
                return target;
            }
        }
    }
}
#if !NO_LIGHTWEIGHT_OBJECT_MAPPER_PRE_CODES

// <Auto-Generated/>

#pragma warning disable IDE0161 // 转换为文件范围限定的 namespace

using System;
using System.Collections.Generic;

namespace LightweightObjectMapper
{
    /// <summary>
    /// 映射配置接口
    /// </summary>
    internal interface IMappingProfile { }

    /// <summary>
    /// 映射后执行的动作
    /// </summary>
    /// <typeparam name="TIn"></typeparam>
    /// <typeparam name="TOut"></typeparam>
    internal interface IPostMapping<TIn, TOut> : IMappingProfile
    {
        /// <summary>
        /// 映射后执行的动作
        /// </summary>
        /// <param name="source"></param>
        /// <param name="target"></param>
        /// <returns></returns>
        TOut PostMapping(TIn source, TOut target);
    }

    /// <summary>
    /// 映射前准备
    /// </summary>
    /// <typeparam name="TIn"></typeparam>
    /// <typeparam name="TOut"></typeparam>
    internal interface IMappingPrepare<TIn, TOut> : IMappingProfile
    {
        /// <summary>
        /// 映射前准备
        /// </summary>
        /// <param name="source"></param>
        /// <returns></returns>
        TOut MappingPrepare(TIn source);
    }

    /// <summary>
    /// 接管完整的类型映射(仅非目标实例映射)
    /// </summary>
    /// <typeparam name="TIn"></typeparam>
    /// <typeparam name="TOut"></typeparam>
    internal interface ITypeMapping<TIn, TOut> : IMappingProfile
    {
        /// <summary>
        /// 接管完整的类型映射(仅非目标实例映射)
        /// </summary>
        /// <param name="source"></param>
        /// <returns></returns>
        TOut TypeMapping(TIn source);
    }

    /// <summary>
    /// 类型成员忽略映射
    /// </summary>
    /// <typeparam name="T"></typeparam>
    internal interface ITypeMemberIgnoreMapping<T> : IMappingProfile
    {
        /// <summary>
        /// 类型成员忽略映射<br/>
        /// 方法体内访问过的 <paramref name="target"/> 所有成员,将在映射时被忽略
        /// </summary>
        /// <param name="target"></param>
        /// <returns></returns>
        object? IgnoreMapping(T target);
    }

    /// <summary>
    /// 标记一个方法为集合映射方法<br/>
    /// 集合映射方法应包含唯一泛型参数 T ,以及唯一参数 <see cref="IEnumerable{T}"/> ,返回类型应该为 <see cref="IEnumerable{T}"/> 的派生类型
    /// </summary>
    [AttributeUsage(AttributeTargets.Method, Inherited = false, AllowMultiple = false)]
    internal sealed class CollectionMappingAttribute : Attribute
    {
    }

    /// <summary>
    /// 标记类为映射配置类
    /// </summary>
    [AttributeUsage(AttributeTargets.Class, Inherited = false, AllowMultiple = false)]
    internal sealed class MappingProfileAttribute : Attribute
    {
        /// <inheritdoc cref="MappingProfileAttribute"/>
        public MappingProfileAttribute() { }
    }

    /// <summary>
    /// 映射元数据
    /// </summary>
    [AttributeUsage(AttributeTargets.All, Inherited = false, AllowMultiple = true)]
    internal sealed class MappingMetadataAttribute : Attribute
    {
        /// <inheritdoc cref="MappingMetadataAttribute"/>
        public MappingMetadataAttribute(MappingMetadataType type, params object[] data) { }
    }

    /// <summary>
    /// 映射元数据类型
    /// </summary>
    internal enum MappingMetadataType
    {
        /// <summary>
        /// 声明 MappingPrepare
        /// </summary>
        MappingPrepareDeclaration,

        /// <summary>
        /// 声明 PostMapping
        /// </summary>
        PostMappingDeclaration,

        /// <summary>
        /// 声明 TypeMapping
        /// </summary>
        TypeMappingDeclaration,

        /// <summary>
        /// 声明 CollectionMapping
        /// </summary>
        CollectionMappingDeclaration,

        /// <summary>
        /// 忽略成员声明
        /// </summary>
        IgnoreMembersDeclaration,

        /// <summary>
        /// 类型忽略成员声明
        /// </summary>
        TypeIgnoreMembersDeclaration,
    }

    /// <summary>
    /// 引用其它映射配置类
    /// </summary>
    [AttributeUsage(AttributeTargets.Class, Inherited = false, AllowMultiple = true)]
    internal sealed class MappingProfileIncludeAttribute : Attribute
    {
        /// <inheritdoc cref="MappingProfileIncludeAttribute"/>
        public MappingProfileIncludeAttribute(params Type[] profileTypes) { }
    }

    /// <summary>
    /// 对象映射 MapTo 占位方法
    /// </summary>
    [Obsolete("Do not use the placeholder extension class.", true)]
    internal static class LightweightObjectMapperPlaceholderExtensions
    {
        private const string ErrorCallPlaceholderMethodMessage = "Do not use the placeholder extension method. If not redirect to the right mapper extension method please try fix other errors and rebuild the project.";

        /// <summary>
        /// 对象映射 MapTo 占位方法<br/>
        /// 生成 无需目标对象 的泛型映射方法,映射到 <typeparamref name="TOut"/>
        /// </summary>
        /// <typeparam name="TOut"></typeparam>
        /// <param name="source"></param>
        /// <returns></returns>
        [Obsolete(ErrorCallPlaceholderMethodMessage, true)]
        public static TOut MapTo<TOut>(this object source)
        {
            throw new NotImplementedException();
        }

        /// <summary>
        /// 对象映射 MapTo 占位方法<br/>
        /// 生成 需要目标对象 的泛型映射方法,映射到 <typeparamref name="TOut"/>
        /// </summary>
        /// <typeparam name="TOut"></typeparam>
        /// <param name="source"></param>
        /// <returns></returns>
        [Obsolete(ErrorCallPlaceholderMethodMessage, true)]
        public static TOut MapTo<TOut>(this object source, TOut target)
        {
            throw new NotImplementedException();
        }

        /// <summary>
        /// 值类型 对象映射 MapTo 占位方法<br/>
        /// 生成 需要目标值类型对象 的泛型映射方法,映射到 <typeparamref name="TOut"/>
        /// </summary>
        /// <typeparam name="TOut"></typeparam>
        /// <param name="source"></param>
        /// <returns></returns>
        [Obsolete(ErrorCallPlaceholderMethodMessage, true)]
        public static TOut MapTo<TOut>(this object source, ref TOut target)
            where TOut : struct
        {
            throw new NotImplementedException();
        }
    }
}

#endif

#if !NO_LIGHTWEIGHT_OBJECT_MAPPER_PRE_CODES

// <Auto-Generated/>

#pragma warning disable IDE0161 // 转换为文件范围限定的 namespace

using System;
using System.Collections.Generic;
using System.Linq;
using System.Runtime.CompilerServices;

namespace LightweightObjectMapper
{
    /// <summary>
    /// 预定义的类型映射
    /// </summary>
    [MappingProfile]
    internal sealed partial class PredefinedSpecialTypeMapping
        : ITypeMapping<int, bool>
        , ITypeMapping<short, bool>
        , ITypeMapping<long, bool>
    {
        public bool TypeMapping(int source)
        {
            return source != 0;
        }

        public bool TypeMapping(short source)
        {
            return source != 0;
        }

        bool ITypeMapping<long, bool>.TypeMapping(long source)
        {
            return source != 0;
        }

        [CollectionMapping]
        public static IEnumerable<T>? ToIEnumerable<T>(IEnumerable<T>? items)
        {
            return items?.ToList();
        }

        [CollectionMapping]
        public static ICollection<T>? ToICollection<T>(IEnumerable<T>? items)
        {
            return items?.ToList();
        }

        [CollectionMapping]
        public static IReadOnlyCollection<T>? ToIReadOnlyCollection<T>(IEnumerable<T>? items)
        {
            return items?.ToList();
        }

        [CollectionMapping]
        public static IList<T>? ToIList<T>(IEnumerable<T>? items)
        {
            return items?.ToList();
        }

        [CollectionMapping]
        public static IReadOnlyList<T>? ToIReadOnlyList<T>(IEnumerable<T>? items)
        {
            return items?.ToList();
        }

        [CollectionMapping]
        public static List<T>? ToList<T>(IEnumerable<T>? items)
        {
            return items?.ToList();
        }
    }
}

#endif

// <Auto-Generated/>
#pragma warning disable IDE0005
#pragma warning disable CS0105
using System;
using System.Linq;
using System.Runtime.CompilerServices;

namespace LightweightObjectMapper
{
    internal static partial class LOMMapExtensions_mapperDemo
    {
        /// <summary>
        /// Map <see cref = "global::Person"/> to the following types:<br/>
        /// <see cref = "global::mapperDemo.PersonDTO"/><br/>
        /// </summary>
        [MethodImpl(MethodImplOptions.AggressiveInlining)]
        public static TOut MapTo<TOut>(this global::Person source)
        {
            if (source == null)
            {
                throw new ArgumentNullException(nameof(source));
            }

            if (typeof(TOut) == typeof(global::mapperDemo.PersonDTO))
            {
                var target = new global::mapperDemo.PersonDTO()
                {
                    LastName = source.LastName,
                    ID = source.ID,
                    FirstName = source.FirstName,
                };
                target = global::mapperDemo.Extensions.Generated.PostMapping_D275C37F33F4AFBD(source, target);
                return (TOut)(target as object);
            }

            throw new global::System.NotImplementedException($"No mapping code for {typeof(TOut)}.");
        }
    }
}
// <Auto-Generated/>
#pragma warning disable IDE0005
#pragma warning disable CS0105
using System;
using System.Collections.Generic;
using System.Linq;
using System.Runtime.CompilerServices;
using System;
using System.Linq;
using System.Runtime.CompilerServices;

namespace LightweightObjectMapper
{
    sealed partial class PredefinedSpecialTypeMapping
    {
        public static partial class Generated
        {
            /// <summary>
            /// TypeMappingDeclaration for <see cref = "int "/> to <see cref = "bool "/>
            /// </summary>
            [MethodImpl(MethodImplOptions.AggressiveInlining)]
            [MappingMetadata(MappingMetadataType.TypeMappingDeclaration, typeof(int), typeof(bool))]
            public static bool TypeMapping_A07AFC9A322FFA04(int source)
            {
                return source != 0;
            }

            /// <summary>
            /// TypeMappingDeclaration for <see cref = "short "/> to <see cref = "bool "/>
            /// </summary>
            [MethodImpl(MethodImplOptions.AggressiveInlining)]
            [MappingMetadata(MappingMetadataType.TypeMappingDeclaration, typeof(short), typeof(bool))]
            public static bool TypeMapping_946949E7222BC174(short source)
            {
                return source != 0;
            }

            /// <summary>
            /// TypeMappingDeclaration for <see cref = "long "/> to <see cref = "bool "/>
            /// </summary>
            [MethodImpl(MethodImplOptions.AggressiveInlining)]
            [MappingMetadata(MappingMetadataType.TypeMappingDeclaration, typeof(long), typeof(bool))]
            public static bool TypeMapping_3C4D395B4EF43E87(long source)
            {
                return source != 0;
            }

            /// <summary>
            /// CollectionMappingDeclaration for <see cref = "global::System.Collections.Generic.IEnumerable{T}"/>
            /// </summary>
            [MethodImpl(MethodImplOptions.AggressiveInlining)]
            [MappingMetadata(MappingMetadataType.CollectionMappingDeclaration, typeof(global::System.Collections.Generic.IEnumerable<>))]
            public static global::System.Collections.Generic.IEnumerable<T> CollectionMapping_CEFAD35E246FD0F7<T>(global::System.Collections.Generic.IEnumerable<T> items)
            {
                return items?.ToList();
            }

            /// <summary>
            /// CollectionMappingDeclaration for <see cref = "global::System.Collections.Generic.ICollection{T}"/>
            /// </summary>
            [MethodImpl(MethodImplOptions.AggressiveInlining)]
            [MappingMetadata(MappingMetadataType.CollectionMappingDeclaration, typeof(global::System.Collections.Generic.ICollection<>))]
            public static global::System.Collections.Generic.ICollection<T> CollectionMapping_37FFD1A2226B51E9<T>(global::System.Collections.Generic.IEnumerable<T> items)
            {
                return items?.ToList();
            }

            /// <summary>
            /// CollectionMappingDeclaration for <see cref = "global::System.Collections.Generic.IReadOnlyCollection{T}"/>
            /// </summary>
            [MethodImpl(MethodImplOptions.AggressiveInlining)]
            [MappingMetadata(MappingMetadataType.CollectionMappingDeclaration, typeof(global::System.Collections.Generic.IReadOnlyCollection<>))]
            public static global::System.Collections.Generic.IReadOnlyCollection<T> CollectionMapping_AF82A9960EE0C495<T>(global::System.Collections.Generic.IEnumerable<T> items)
            {
                return items?.ToList();
            }

            /// <summary>
            /// CollectionMappingDeclaration for <see cref = "global::System.Collections.Generic.IList{T}"/>
            /// </summary>
            [MethodImpl(MethodImplOptions.AggressiveInlining)]
            [MappingMetadata(MappingMetadataType.CollectionMappingDeclaration, typeof(global::System.Collections.Generic.IList<>))]
            public static global::System.Collections.Generic.IList<T> CollectionMapping_284BCB723CA17B0E<T>(global::System.Collections.Generic.IEnumerable<T> items)
            {
                return items?.ToList();
            }

            /// <summary>
            /// CollectionMappingDeclaration for <see cref = "global::System.Collections.Generic.IReadOnlyList{T}"/>
            /// </summary>
            [MethodImpl(MethodImplOptions.AggressiveInlining)]
            [MappingMetadata(MappingMetadataType.CollectionMappingDeclaration, typeof(global::System.Collections.Generic.IReadOnlyList<>))]
            public static global::System.Collections.Generic.IReadOnlyList<T> CollectionMapping_976EA1DB5B772C59<T>(global::System.Collections.Generic.IEnumerable<T> items)
            {
                return items?.ToList();
            }

            /// <summary>
            /// CollectionMappingDeclaration for <see cref = "global::System.Collections.Generic.List{T}"/>
            /// </summary>
            [MethodImpl(MethodImplOptions.AggressiveInlining)]
            [MappingMetadata(MappingMetadataType.CollectionMappingDeclaration, typeof(global::System.Collections.Generic.List<>))]
            public static global::System.Collections.Generic.List<T> CollectionMapping_070F0D0F908DAF14<T>(global::System.Collections.Generic.IEnumerable<T> items)
            {
                return items?.ToList();
            }
        }
    }
}

Code and pdf at

https://ignatandrei.github.io/RSCG_Examples/v2/docs/LightweightObjectMapper

RSCG – Enhanced.GetTypes

RSCG – Enhanced.GetTypes
 
 

name Enhanced.GetTypes
nuget https://www.nuget.org/packages/Enhanced.GetTypes/
link https://github.com/duskembayev/Enhanced.GetTypes
author duskembayev

Generating list of PUBLIC classes that implements an interface

 

This is how you can use Enhanced.GetTypes .

The code that you start with is


<Project Sdk="Microsoft.NET.Sdk">

  <PropertyGroup>
    <OutputType>Exe</OutputType>
    <TargetFramework>net8.0</TargetFramework>
    <ImplicitUsings>enable</ImplicitUsings>
    <Nullable>enable</Nullable>
  </PropertyGroup>

  <ItemGroup>
    <PackageReference Include="Enhanced.GetTypes" Version="1.0.0" />
  </ItemGroup>
	<PropertyGroup>
		<EmitCompilerGeneratedFiles>true</EmitCompilerGeneratedFiles>
		<CompilerGeneratedFilesOutputPath>$(BaseIntermediateOutputPath)\GX</CompilerGeneratedFilesOutputPath>
	</PropertyGroup>
</Project>


The code that you will use is


// See https://aka.ms/new-console-template for more information
using GetTypesForInterface;

Console.WriteLine("Hello, World!");
foreach (var type in ProjectTypes.GetIPersonTypes())
{
    Console.WriteLine(type.Name);
}


using Enhanced.GetTypes.Annotation;

namespace GetTypesForInterface;
public partial class ProjectTypes
{
    [DerivedTypes(typeof(IPerson))]
    public  static partial IEnumerable<Type> GetIPersonTypes();
}




namespace GetTypesForInterface;
internal interface IPerson
{
    public string Name { get; set; }
}




namespace GetTypesForInterface;
public class Student : IPerson
{
    public string Name { get; set; } = "";
}
    



namespace GetTypesForInterface;
public class Teacher:IPerson
{
    public string Name { get; set; } = "";
}



 

The code that is generated is

// <auto-generated />
namespace GetTypesForInterface
{
    partial class ProjectTypes
    {
        public static partial System.Collections.Generic.IEnumerable<System.Type> GetIPersonTypes()
        {
            yield return typeof(GetTypesForInterface.Student);
            yield return typeof(GetTypesForInterface.Teacher);
            yield break;
        }
    }
}

Code and pdf at

https://ignatandrei.github.io/RSCG_Examples/v2/docs/Enhanced.GetTypes

Andrei Ignat weekly software news(mostly .NET)

* indicates required

Please select all the ways you would like to hear from me:

You can unsubscribe at any time by clicking the link in the footer of our emails. For information about our privacy practices, please visit our website.

We use Mailchimp as our marketing platform. By clicking below to subscribe, you acknowledge that your information will be transferred to Mailchimp for processing. Learn more about Mailchimp's privacy practices here.