1k0n.Pipeline 2.2.0

dotnet add package 1k0n.Pipeline --version 2.2.0
NuGet\Install-Package 1k0n.Pipeline -Version 2.2.0
This command is intended to be used within the Package Manager Console in Visual Studio, as it uses the NuGet module's version of Install-Package.
<PackageReference Include="1k0n.Pipeline" Version="2.2.0" />
For projects that support PackageReference, copy this XML node into the project file to reference the package.
paket add 1k0n.Pipeline --version 2.2.0
#r "nuget: 1k0n.Pipeline, 2.2.0"
#r directive can be used in F# Interactive and Polyglot Notebooks. Copy this into the interactive tool or source code of the script to reference the package.
// Install 1k0n.Pipeline as a Cake Addin
#addin nuget:?package=1k0n.Pipeline&version=2.2.0

// Install 1k0n.Pipeline as a Cake Tool
#tool nuget:?package=1k0n.Pipeline&version=2.2.0

1k0n Messaging Pipeline Library

Using 1k0n.Pipeline.StronglyTypedPipeline

Include the library and decalre a using to the _1k0n.Pipeline.StronglyTypedPipeline namespace.

 using _1k0n.Pipeline.StronglyTypedPipeline;

Creating a Contract

The library will dynamically build the code at runtime for an interface defined contract.

[GenerateMessages]
public interface IMyMessageHandler
{        
    Task NewChatMessage(string username, string? message);

    Task NewChatMessageResult(bool success, int? messageNum);

    Task GetChatMessages(int start, int count);
    
    Task ChatMessagesList(List<ChatMessage>? messages);
}

Decorate the interface with a GenerateMessagesAttribute so that the Pipeline will auto generate the messages needed for the contract.

All methods must return a Task

Create the Message Handler Client class

Create a class that implements the interface created above. The members of this class will be called when a message is received from the pipeline. The method that the sender calls, is the method that will be called on the receiver.

public class MyMessageHandlerClient : IMyMessageHandler
{
    public MyMessageHandlerClient()
    {
        // you can use dependency injection to pass in any dependencies
    }
            
    public Task NewChatMessageResult(bool success, int? messageNum)
    {
        // Do something with the returned data
        if (success)
        {
            ...
        }
    }

    public Task ChatMessagesList(List<ChatMessage>? messages)
    {
        // Do something with the returned data

        ProcessMessages(messages);
    }


    // Don't implement messages we don't expect to receive
    public Task NewChatMessage(string username, string? message) =>
        throw new NotImplementedException();
    

    public Task GetChatMessages(int start, int count) =>
        throw new NotImplementedException();
    
    
}

Any messages that the client will not be receiving should throw an exception so that they are not accidently called by the program.

Create the client

To create a client that sends and recieves messages using a strongly-typed pipeline, it is easiest to use Dependency Injection.

Use the AddMessagePipeline<TContract, THandler> extension method provided by the library to setup the pipeline.

services.AddMessagePipeline<IMyMessageHandler, MyMessageHandlerClient>();

The pipeline can now be passed to other classes using Dependency Injection.

public class MyWorker
{
    MessagePipeline<IMyMessageHandler> _pipeline;

    public MyWorker(MessagePipeline<IMyMessageHandler> pipeline)
    {
        _pipeline = pipeline;
    }
}

Create the Message Handler Server class

To create a server handler, create a class that implements the contract interface and the IPipelineAccess< TContract > interface. For each connection to the server the library will create a new scoped handler. When the IPipelineAccess interface is used, the library will pass in the pipeline object for the current connection. This allows the handler to reply to the correct client.

public class MyMessageHandlerServer : IMyMessageHandler, IPipelineAccess<IMyMessageHandler>
{
    public MessagePipeline<IMyMessageHandler>? Pipeline { get; set; }

    public MyMessageHandlerServer()
    {
        // you can use dependency injection to pass in any dependencies
    }

    public Task NewChatMessage(string username, string? message)
    {
         // process message
        int messageId = AddMessageToDb(message);

        // Send response
         await Pipeline.Send.NewChatMessageResult(true, messageId);
    }
            
    public Task GetChatMessages(int start, int count) 
    {
        // Lookup messages in a cache or database
        var messages = GetMessagesFromDb(start, count);

        // Send list back to client
        await Pipeline.Send.ChatMessageList(messages);
    }
    
    // Don't implement messages we don't expect to receive
    public Task NewChatMessageResult(bool success, int? messageNum) =>
        throw new NotImplementedException();

    public Task ChatMessagesList(List<ChatMessage>? messages) =>
        throw new NotImplementedException();

}

To communicate between clients, use dependency injection to pass in a global server object.

Create the server

To create a server that accepts pipeline connections, use Dependency Injection.

services.AddMessagePipelineServer<IMyMessageHandler, MyMessageHandler>();

The pipeline server can now be passed to another class using Dependency Injection.

public class MyServer
{
    MessagePipelineServer<IMyMessageHandler> _pipelineServer;

    public MyServer(MessagePipelineServer<IMyMessageHandler> pipelineServer)
    {
        _pipelineServer = pipelineServer;
    }
}

Then start the pipeline listening.

if (_pipelineServer.OpenServerIP("127.0.0.1", 10000) == false)
{
    // handle error
}

Sending messages through the pipeline

To send strongly typed messages on the pipeline, call the methods on the Send property of the pipeline object. The Send property is declared as the interface type of the contract.

// On the client
public async Task SendMessage(string? message)
{
    await _pipeline.Send.NewChatMessage("LocalUserName", message);
}


// On the server handler
public async Task NewChatMessage(string username, string? message)
{
    // process message
   ...

   // Send response if needed
   await Pipeline.Send.NewChatMessageResult(true, messageId++);
}

On the sever, the NewChatMessage(string username, string? message) method will be called on the handler with the data that was sent by the client. The server can then respond to the client if needed.

copyright © 2022 John Meyer Jr. - Usage instructions for the 1k0n.Pipeline library -

Product Compatible and additional computed target framework versions.
.NET net6.0 is compatible.  net6.0-android was computed.  net6.0-ios was computed.  net6.0-maccatalyst was computed.  net6.0-macos was computed.  net6.0-tvos was computed.  net6.0-windows was computed.  net7.0 was computed.  net7.0-android was computed.  net7.0-ios was computed.  net7.0-maccatalyst was computed.  net7.0-macos was computed.  net7.0-tvos was computed.  net7.0-windows was computed.  net8.0 was computed.  net8.0-android was computed.  net8.0-browser was computed.  net8.0-ios was computed.  net8.0-maccatalyst was computed.  net8.0-macos was computed.  net8.0-tvos was computed.  net8.0-windows was computed. 
Compatible target framework(s)
Included target framework(s) (in package)
Learn more about Target Frameworks and .NET Standard.

NuGet packages

This package is not used by any NuGet packages.

GitHub repositories

This package is not used by any popular GitHub repositories.

Version Downloads Last updated
2.2.0 381 11/13/2022
2.0.1 460 5/13/2022