View on GitHub

Acquaintance

Internal messaging framework for loosely-coupled .NET applications.

Acquaintance

Acquaintance is a .NET library for intra-process communications. It’s like an in-memory message bus that loosely-coupled parts of your application can use to communicate with each other. At the heart, Acquaintance implements 3 basic communication patterns: Publish/Subscribe, Request/Response and Scatter/Gather. In addition to these three basic patterns, Acquaintance has a few other tricks and features which can help some medium to large applications stay organized and safe.

Get Acquaintance from nuget:

Install-Package Acquaintance

When you’re ready to code, create a Message Bus:

var messageBus = new MessageBus();

Publish/Subscribe

Publish/Subscribe is a pattern where you have events of interest being generated by one part of the system and other parts need to be aware of them. Published messages are delivered to all interested subscribers.

    // Create a subscription
    messageBus.Subscribe<MyEvent>(s => s
        .WithTopic("test event")
        .Invoke(e => Console.WriteLine(e.Message)));

    // Publish a message
    messageBus.Publish("test event", new MyEvent {
        Message = "Hello World"
    });

Request/Response

Request/Response is essentially an abstracted method call or local RPC mechanism. One part of your code makes a request and a single listener fulfills it. This can be an improvement over Dependency Injection or Service Location patterns in some cases, such as when you only need a calculation result and do not want to manage and maintain an object hierarchy to calculate that result.

    // Setup a Listener
    messageBus.Listen<MyRequest, MyResponse>(l => l
        .WithTopic("test")
        .Invoke(req => new MyResponse {
            Message = "Hello " + req.Message"
        }));

    // Send a request and wait for the response
    var response = messageBus.RequestWait<MyRequest, MyResponse>("test",
        new MyRequest { Message = "World" });
    Console.WriteLine(response.Message);

Scatter/Gather

Scatter/Gather is conceptually similar to Request/Response except the channel may have many listeners or participants. Internally and in terms of API the two are significantly different, however. Because scatter/gather requests must wait on an unknown number of participants providing responses asynchronously, waiting and timeouts can become an issue. For best performance, when you do scatter/gather make sure you know how many responses you’d like to receive and how long are you willing to wait to get them.

    // Setup a Participant
    messageBus.Participate<MyRequest, MyResponse>(p => p
        .WithTopic("test")
        .Invoke(req => new[] { new MyResponse {
            Message = "Hello " + req.Message"
        }}));

    // Scatter the request message to all participants
    var scatter = messageBus.Scatter<MyRequest, MyResponse>("test",
        new MyRequest { Message = "World" });

    var responses = scatter.GatherResponses();
    foreach (var response in responses)
        Console.WriteLine(response.Response.Message);

Use-Cases

Here are some common use-cases which Acquaintance was explicitly designed to handle:

  1. Simplifying complex constructor signatures which may arise from use of Dependency Injection, and avoiding the creation of many redundant adaptor types.
  2. Providing serialized access to resources which are not intrinsically thread-safe, such as sockets and files
  3. Round-Robin dispatch and predicate-based routing of events and requests to multiple handlers
  4. Serving as an easy wiring mechanism for loosely-coupled and plugin-based applications
  5. Serving as an intermediate step for monolithic applications which are in the process of being decomposed into microservices
  6. Serving as an easy bridge for external resources, queues and Enterprise Service Buses
  7. Acting as the communication mechanism for domain events in a Domain-Driven solution
  8. Simplify the distribution of work among many threads while avoiding many common pitfalls of multi-threaded programming

Additional Features

Acquaintance provides several features which are extensions of the three basic messaging patterns above:

  1. Unit testing with built-in ability to mock channels and expect messages
  2. Message timer to generate application heartbeats on a set schedule
  3. Automatic polling of asynchronous event sources

Contraindications

There are situations where using Acquaintance is appropriate and situations where it is not. See the page on Contraindications for a discussion of these.