RossWright.MetalNexus
9.0.0-alpha001
dotnet add package RossWright.MetalNexus --version 9.0.0-alpha001
NuGet\Install-Package RossWright.MetalNexus -Version 9.0.0-alpha001
<PackageReference Include="RossWright.MetalNexus" Version="9.0.0-alpha001" />
paket add RossWright.MetalNexus --version 9.0.0-alpha001
#r "nuget: RossWright.MetalNexus, 9.0.0-alpha001"
// Install RossWright.MetalNexus as a Cake Addin #addin nuget:?package=RossWright.MetalNexus&version=9.0.0-alpha001&prerelease // Install RossWright.MetalNexus as a Cake Tool #tool nuget:?package=RossWright.MetalNexus&version=9.0.0-alpha001&prerelease
Ross Wright's Metal Nexus
by Ross Wright
Copyright 2023 Pross Co. All Rights Reserved.
Description
MetalNexus allows MediatR requests to magically tranverse the client-server connection. Imagine, sending a request in your Blazor client code and have it handled by a RequestHandler on the server with almost no extra code complete with Open API / Swagger document generation.
A note about quickstart
MetalNexus has been set with defaults to work as easily as possible out of the box for evaluation, but if you do decide to seriously use it, there are two recommendations you should really do to optimize the performance of initialization. Please checkout the Recommendations section near the end of this document. Otherwise, enjoy these quickstart instructions...
Setup
To setup MetalNexus and auto-detect request handlers on an ASP.NET Core project, add the RossWright.MetalNexus.Server package and call AddMetalNexusServer
on the ServiceCollection in your program.cs file and call app.UseMetalNexusServer()
after the Build call but before the Run call,
var builder = WebApplication.CreateBuilder(args);
builder.Services.AddMetalNexusServer(_ => _.ScanAssembliesStartingWith("MyCorp.MyApp");
...
var app = builder.Build();
...
app.UseMetalNexusServer();
...
app.Run();
For a client project (Blazor WASM or an ASP.NET Core Server using handlers on another server), add the RossWright.MetalNexus package and call AddMetalNexusClient
on the ServiceCollection in your program.cs file:
var builder = WebAssemblyHostBuilder.CreateDefault(args);
builder.Services.AddMetalNexusClient(_ => _.ScanAssembliesStartingWith("MyCorp.MyApp"));
Defining API Requests
To specify a Request should be handled on the server add the RossWright.MetalNexus.Abstractions package and decorate the class with the ApiRequest attribute as follows,
[ApiRequest]
public class MyRequest : IRequest<MyResponse[]>
Without parameters, an HTTP Verb and serialization will be chosen based on the complexity of the Request class and path is generated based on the Request. You can specify the HTTP Verb, serialization (Query or Body) and path explicitly using the protocol and path parameters of the ApiRequest attribute:
[ApiRequest(HttpProtocol.PostViaBody, "/api/request")]
public class MyRequest : IRequest<MyResponse>
Note Body is only supported for POST, PUT and PATCH verbs. Get and Delete verbs are also available. Serializing the request as query parameters limits the allowable complexity of the Request object considerably. Note when transmissing sensitive data you should always specify a body serialization protocol.
Anonymous and Authenticated attributes can be used with MetalNexus ApiRequest as normal. Such as:
[Anonymous, ApiRequest(HttpProtocol.Get, "/api/request")]
public class MyRequest : IRequest<MyResponse[]>
Open API and Swagger documentation
To enable Swagger generation of the MetalNexus endpoints, call UseMetalNexus on the AddSwaggerGen options object,
builder.Services.AddSwaggerGen(options => options.UseMetalNexus());
The swagger tag (commonly shows as the controller name) for ApiRequests can be customized using the swaggerTag paramter of the ApiRequest attribute,
[ApiRequest(path: "/api/request", swaggerTag: "My Special Requests")]
public class MyRequest : IRequest<MyResponse>
Using MetalNexus with multiple servers
To connect to APIs on multiple servers, setup names HttpClients for each server and specify those names in the ApiRequest attribute. When the request is marshaled, the call will be made using the specified named client
[ApiRequest(path: "doTheThing", httpClientName: "ApiOne")]
public class MyFirstRequest : IRequest<MyFirstResponse>
...
[ApiRequest(path: "doTheThing", httpClientName: "ApiTwo")]
public class MySecondRequest : IRequest<MySecondResponse>
...
//in program.cs
services.AddHttpClient("ApiOne", _ => _.BaseAddress = new Uri("https://server1.com/api"));
services.AddHttpClient("ApiTwo", _ => _.BaseAddress = new Uri("https://server2.com/api"));
...
var firstResponse = await mediator.Send(new MyFirstRequest()); //calls server1.com/api/doTheThing
var secondResponse = await mediator.Send(new MySecondRequest()); //calls server2.com/api/doTheThing
Endpoint Schema customization
On initialization MetalNexus discovers ApiRequests and defines API Endpoints in an Endpoint Schema. This schema specifies the protocol, path, authorization and Open API tag for each endpoint. The default behavior is to simply use the information specified in attributes. This behavior can be customized or completely overridden.
Customizing Endpoint Schema
To customize the schema building behavior, when configuring MetalNexus call ConfigureEndpointSchema
with a closure to configure the default endpoint schema. For example,
builder.Services.AddMetalNexusServer(_ =>
{
_.ScanAssembliesStartingWith("MyCorp.MyApp");
_.ConfigureEndpointSchema(_ =>
{
_.ApiPathPrefix = "/api/v1";
_.RequiresAuthenticationByDefault = true;
_.PathStrategy = new TrimFixedPreamblePathStrategy("MyCorp.MyApp.Endpoints");
});
});
Path Strategies are used to determine the API path from the Request class's namespace and name. Completely custom Path Strategies can be implemented and specified, but MetalNexus comes with 5 strategies out of the box. A request object with full type name MyCorp.MyApp.Endpoints.Users.GetUsers is used to illustrate the strategies. They are:
NoNamespacePathStrategy
- the typename is used and the namespace is discarded. ("/GetUsers")UseFullNamePathStrategy
- the full namespace and class name is used. ("/MyCorp/MyApp/Endpoints/Users/GetUsers")TrimFixedPreamblePathStrategy
- a specified prefix is trimmed if present. ("/Users/GetUsers" assuming "MyCorp.MyApp.Endpoints" was specified)TrimDefaultNamespacePathStrategy
- the most common root namespace for your projects is determined, assumed to be your root namespace and trimmed from request paths ("/Endpoints/Users/GetUsers" assuming "MyCorp.MyApp" is the root namespace of most of your types)TrimRequestNamespacePathStrategy
- similar toTrimDefaultNamespacePathStrategy
, but only classes decorated with the ApiRequest attribute are considered when determining the root namespace. Note this is the default strategy and will often have the same result as if you configuredTrimFixedPreamblePathStrategy
with your api request's namespace root, just slower since it uses reflection to try to figure out the root namespace. ("/Users/GetUsers")
Overriding Endpoint Schema
To completely override the endpoint, when configuring MetalNexus call UseCustomEndpointSchema
and pass an instance of your IEndpointSchema implementation. IEndpointSchema has one method to implement, DefineEndpoints
which takes a collection of IDiscoveredApiRequest
objects detailing information collected in the discovery process. The Endpoint Schema exposes a collection of IEndpoint objects your must contruct that is used by the MetalNexus middleware to call and/or handle requests. Note that IDiscoveredApiRequest has a property RequestMustUseBody
, and if you specify a protocol that does not allow for a request body or specify the endpoint uses query parameters for the request, it will fail on use.
Recommendations
Organize your solution with a project containing your API Request class definitions that is referenced by both your Blazor client project and ASP.NET Core server project. This is a common pattern for defining data transfer objects anyway no matter what method you use for APIs.
AddMetalNexusServer
andAddMetalNexusClient
use the same configuration object and in order for the system to function correctly the configuration for both sides of your client-server must be identical. The examples above use the closure override to configure the client and server, but there is an override that takes an instance ofIMetalNexusConfiguration
. The recommended pattern is to define your implementation of the configuration in a shared libary with your Api Requests and use an instance of that same class when configuring both the client and server.Use the
TrimFixedPreamblePathStrategy
and configure it with the root namespace for your API requests rather than rely on the default behavior provided byTrimRequestNamespacePathStrategy
. In the end they likely produce in the same result, butTrimRequestNamespacePathStrategy
uses reflection which can slow down your initialization quite a bit if your project is large.Be selective with what assemblies you scan. In the examples above I used
ScanAssembliesStartingWith
which is better than the default behavior of scanning all assemblies, but can usually be reduced to the single shared project containing your API Request definitions usingScanAssemblies
,ScanOnlyThisAssembly
orScanAssemblyContaining
. Be very cautious usingScanAssembliesInFolderStartingWith
as it looks for assmblies in your executable's file folder - which is useful for plug-in architectures, but should definitely be considered an attack vector to your program.
Licensing
A license must be purchased to use RossWright.Metal libaries in a production environment. For development enviroments, using the libraries without a license will show a console message on initialization and cease functioning after one hour. To install your license file include it in the executable project with the Build Action set to Embedded Resource. The file can be renamed as needed, but must end with the extension .license.
Product | Versions Compatible and additional computed target framework versions. |
---|---|
.NET | net9.0 is compatible. |
-
net9.0
- MediatR (>= 12.4.1)
- Microsoft.Extensions.Http (>= 9.0.0)
- RossWright.MetalCore (>= 9.0.0-alpha001)
- RossWright.MetalNexus.Abstractions (>= 9.0.0-alpha001)
NuGet packages (2)
Showing the top 2 NuGet packages that depend on RossWright.MetalNexus:
Package | Downloads |
---|---|
RossWright.MetalNexus.Server
MetalNexus Server-side |
|
RossWright.MetalNexus.Blazor
MetalNexus client-side library for Blazor apps |
GitHub repositories
This package is not used by any popular GitHub repositories.
Version | Downloads | Last updated |
---|---|---|
9.0.0-alpha001 | 0 | 12/1/2024 |
8.0.0 | 5 | 11/30/2024 |