Anixe.IO.Messaging.AspCore 2.2.0

There is a newer version of this package available.
See the version list below for details.
dotnet add package Anixe.IO.Messaging.AspCore --version 2.2.0
NuGet\Install-Package Anixe.IO.Messaging.AspCore -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="Anixe.IO.Messaging.AspCore" Version="2.2.0" />
For projects that support PackageReference, copy this XML node into the project file to reference the package.
paket add Anixe.IO.Messaging.AspCore --version 2.2.0
#r "nuget: Anixe.IO.Messaging.AspCore, 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 Anixe.IO.Messaging.AspCore as a Cake Addin
#addin nuget:?package=Anixe.IO.Messaging.AspCore&version=2.2.0

// Install Anixe.IO.Messaging.AspCore as a Cake Tool
#tool nuget:?package=Anixe.IO.Messaging.AspCore&version=2.2.0

Anixe.IO.Messaging.AspCore

Anixe.IO.Messaging.AspCore allows for quick integration of ASP.Core app with Anixe Messaging backed by RabbitMQ.

How to integrate

Add in csproj as a package reference

<PackageReference Include="Anixe.IO.Messaging.AspCore" Version="1.1.0" />

Register implementaion of IMessageFormatter, default formatter can be found in Anixe.IO.Messaging.Serializer

<PackageReference Include="Anixe.IO.Messaging.Serializer" Version="1.0.0" />

Producer config

Add section to appsettings.json

{
  ...,
  "Notifications": {
    "ProducerConfiguration": {
      "RabbitMqConfiguration": {
        "Url": "amqp://guest:guest@localhost:5672/",
        "AppName": "app_name"
      },
      "ExchangeConfiguration": {
        "Name": "example.topic",
        "Type": "topic",
        "Durable" : true, // or false, the exchange will survive a broker restart
        "ExchangeArguments": {  } // custom arguments passed to the exchange declaration
      },
      "TenantFieldName": "tenant",
      "Environment": "dev",
      "AppName": "app_name",
      "ContentEncoding": "gzip", // it will automatically gzip all messages.
      "RetryPolicy": {
        "Enabled": true,
        "RetryCount": 3,
        "SleepDurationMs": 200
      }
    }
  }
}

Register services in Startup.cs

public void ConfigureServices(IServiceCollection services)
{
    services.ConfigureProducerService(
        this.config, cfg => {
            // override NotificationsProducerConfiguration here
        }
    );
}

then in you business logic use INotificationService, provided by DI container

using Anixe.IO.Messaging.AspCore;

this.notificationService.SendNotification("routing.key", msg =>
    {
        msg.EntityId = "123";
        msg.EntityType = "entityType";
        msg.EntityUrl = "appName/entityType/123";
        msg.Data = new { id = 123 };
        // if operation is not provided, then based on REST convention by HTTP metod
        msg.Operation = Anixe.IO.Messaging.Core.OperationType.Create;
    });

In case of publish operation fail, exception is thrown.

Subscriber config

Add section to appsettings.json

{
  ...,
  "Notifications": {
    "SubscriberConfiguration": {
      "RabbitMqConfiguration": {
        "Url": "amqp://guest:guest@localhost:5672/",
        "AppName": "app_name",
        "Async": true // optional, to receive messages via AsyncEventingBasicConsumer
      },
      "QueueConfiguration": {
        "QueueName": "", // unnamed queue
        "Durable" : true, // or false, the queue will survive a broker restart
        "Exclusive" : true, // or false, queue that has had at least one consumer is deleted when last consumer unsubscribes
        "AutoDelete": true,  // or false, Optional, used by plugins and broker-specific features such as message TTL, queue length limit, etc
        "Bindings": [
          {
            "Exchange": "distro.topic",
            "RoutingKeys": ["tenant.*.resource.sales_profile"],
            "ExchangeArguments": {  } // custom arguments passed to the exchange declaration
          }
        ]
      },

    }
  }
}

Also build-in rabbitmq channels can be setup

{
  ...,
  "Notifications": {
    "SubscriberConfiguration": {
      "RabbitMqConfiguration": {
        "Url": "amqp://guest:guest@localhost:5672/",
        "AppName": "app_name",
        "Async": true // optional, to receive messages via AsyncEventingBasicConsumer
      },
      "QueueConfiguration": {
        "QueueName": "", // unnamed queue
        "Bindings": [
          {
            "Exchange": "amq.fanout",
            "ExchangeType": "fanout",
            "RoutingKeys": []
          }
        ]
      }
    }
  }
}

Register services in Startup.cs.

Each ConfigureServices registers the following dependencies:

  • ISubscriberConnection singleton instance
  • ListenerHostedService hosted service
  • ISubscriberReloader singleton instance

The following subscrubtion scenarios are possible:

Register single subscription for common NotificationMessage model

public void ConfigureServices(IServiceCollection services)
{
  services.ConfigureSubscriberService(this.config);
  services.AddSingleton<IMessageReceiver<NotificationMessage>, MyNotificationHandler>(); // handle in my application
}

Optinally provide override configuration:

public void ConfigureServices(IServiceCollection services)
{
  services.ConfigureSubscriberService(this.config, opts => {
    opts.RabbitMqConfiguration.Url = "amqp://example.com";
  });
  services.AddSingleton<IMessageReceiver<NotificationMessage>, MyNotificationHandler>(); // handle in my application
}

Register single subscription for generic NotificationMessage<Geolocation> model

public void ConfigureServices(IServiceCollection services)
{
  services.ConfigureSubscriberService<NotificationMessage<Geolocation>>(this.config);
  services.AddSingleton<IMessageReceiver<NotificationMessage<Geolocation>>, MyNotificationHandler>(); // handle in my application
}

Register single subscription for many models, each per AMQP routing key

This scenario is usefull when many instances of the same subscriber must receive exact copy of published message (classic pub-sub)

public void ConfigureServices(IServiceCollection services)
{
  services.AddSingleton<IMessageReceiver<NotificationMessage<Person>>, PersonModelHandler>();
  services.AddSingleton<IMessageReceiver<NotificationMessage<List<Child>>>, ChildrenModelHandler>();
  services.AddSingleton<IMessageReceiver<NotificationMessage<Child>>, ChildModelHandler>();

  services.ConfigureSubscriberService(this.config, (builder) => {
    builder
      .AddMessageHandler<NotificationMessage<Person>>($"env.*.tenant.*.resource.person")
      .AddMessageHandler<NotificationMessage<List<Child>>>($"env.*.tenant.*.resource.children")
      .AddMessageHandler<NotificationMessage<Child>>($"env.*.tenant.*.resource.child");
  });
}

or

public void ConfigureServices(IServiceCollection services)
{
  services.ConfigureSubscriberService(this.config, (builder) => {
    builder
      .AddMessageHandler<NotificationMessage<Person>, PersonModelHandler>($"env.*.tenant.*.resource.person")
      .AddMessageHandler<NotificationMessage<List<Child>>, ChildrenModelHandler>($"env.*.tenant.*.resource.children")
      .AddMessageHandler<NotificationMessage<Child>, ChildModelHandler>($"env.*.tenant.*.resource.child");
  });
}

Register single subscription for many models with named queue, each per AMQP routing key

This scenario is usefull when many instances of the same subscriber must receive only one published message in round-robin manner. Here all instances of this subscriber will share the same queue queue1, so rabbitmq will distribute message in round-robin manner.

public void ConfigureServices(IServiceCollection services)
{
  services.ConfigureSubscriberService(this.config, (builder) => {
    builder
      .AddMessageHandler<NotificationMessage<Person>, PersonModelHandler>("queue1", $"env.*.tenant.*.resource.person")
      .AddMessageHandler<NotificationMessage<List<Child>>, ChildrenModelHandler>("queue1", $"env.*.tenant.*.resource.children")
      .AddMessageHandler<NotificationMessage<Child>, ChildModelHandler>("queue1", $"env.*.tenant.*.resource.child");
  });
}

Register many subscriptions for many models, each per AMQP routing key

public void ConfigureServices(IServiceCollection services)
{
  var geolinkSection = config.GetSection("GeolinkImporterNotifications");

  services.ConfigureSubscriberService<GeoLocation>(rescSection);
  services.AddSingleton<IMessageReceiver<GeoLocation>, GeoLocationNotificationHandler>();

  var rescSection = config.GetSection("RESCNotifications");
  services.ConfigureSubscriberService(this.config, (builder) => {
    builder
      .AddMessageHandler<NotificationMessage<Person>, PersonModelHandler>($"env.*.tenant.*.resource.person")
      .AddMessageHandler<NotificationMessage<List<Child>>, ChildrenModelHandler>($"env.*.tenant.*.resource.children")
      .AddMessageHandler<NotificationMessage<Child>, ChildModelHandler>($"env.*.tenant.*.resource.child");
  });
}

Routing keys from AddMessageHandler will replace these from appsettings.json

Register custom connection

public void ConfigureServices(IServiceCollection services)
{
  var conn = new MyCustomSubscriberConnection();
  services.ConfigureSubscriberService(this.config, (builder) => {
    builder
      .AddCustomConnection(conn)
      /*chain other registrations*/
      ;
  });
}

Register NewtonsoftJson deserializer

Add Anixe.IO.Messaging.Serializer assembly to csproj then:

public void ConfigureServices(IServiceCollection services)
{
  var conn = new MyCustomSubscriberConnection();
  services.ConfigureSubscriberService(this.config, (builder) => {
    builder
      .AddCustomFormatter<NewtonsoftMessageFormatter>()
      /*chain other registrations*/
      ;
  });
}

Deserializing notification messages

By default Anixe.IO.Messaging provides NotificationMessage and NotificationMessage<T> build-in classes which implelement Resfinity Entity Consistent System convention. These classes are envelopes for Data property which can provide custom data:

  • In NotificationMessage the Data is object and deserializes into .Net primitives like Dictionary<string, object>, List<T>, string and value typed
  • In NotificationMessage<T> the Data is instance of T and and deserializes into generic model

But you don't have to use NotificationMessage class, you can provide your own type.

Check src/Anixe.IO.Messaging.Test/Core/MessageFormatterTest.cs for serialization/deserialization examples

Example for NotificationMessage registration (implicit)

public void ConfigureServices(IServiceCollection services)
{
  services.ConfigureSubscriberService(this.config); // receive and deserialize
  services.AddSingleton<IMessageReceiver<NotificationMessage>, MyNotificationHandler>(); // handle in my application
}

Example for NotificationMessage<T> registration

public void ConfigureServices(IServiceCollection services)
{
  services.ConfigureSubscriberService<NotificationMessage<Person>>(this.config); // receive and deserialize
  services.AddSingleton<IMessageReceiver<NotificationMessage<Person>>, MyNotificationHandler>(); // handle in my application
}

Example for any model registration

public void ConfigureServices(IServiceCollection services)
{
  services.ConfigureSubscriberService<GeoLocation>(this.config); // receive and deserialize
  services.AddSingleton<IMessageReceiver<GeoLocation>, GeoLocationNotificationHandler>(); // handle in my application
}
Product Compatible and additional computed target framework versions.
.NET net5.0 was computed.  net5.0-windows was computed.  net6.0 was computed.  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. 
.NET Core netcoreapp3.0 is compatible.  netcoreapp3.1 is compatible. 
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
4.0.0 3,195 1/8/2024
3.0.1 723 12/4/2023
3.0.0 4,711 11/22/2022
2.2.1 667 11/21/2022
2.2.0 395 10/18/2022
2.1.1 964 10/18/2022
2.1.0 10,030 8/31/2021
2.0.1 1,556 7/8/2021
2.0.0 1,585 4/16/2021
1.1.14 964 1/27/2021
1.1.13 524 11/23/2020
1.1.12 402 11/16/2020
1.1.11 1,341 10/22/2020
1.1.9 566 9/29/2020
1.1.8 2,297 5/21/2020
1.1.7 653 5/19/2020
1.1.6 480 5/19/2020
1.1.5 566 5/8/2020
1.1.4 781 4/20/2020
1.1.3 516 4/17/2020
1.1.2 477 4/15/2020
1.1.1 619 4/2/2020
1.1.0 560 3/26/2020
1.0.4 490 3/20/2020
1.0.3 511 3/19/2020
1.0.2 582 3/13/2020
1.0.1 551 3/4/2020
0.1.0 556 2/27/2020