DI configuration for multiple RabbitMQ exchanges and queues - c#

I'm trying to configure DI for EventBusRabbitMQ implementation. It works perfectly fine for a single exchange, queue..
services.AddSingleton<IEventBus, EventBusRabbitMQ>(serviceProvider =>
{
...
return new EventBusRabbitMQ(connection, "exchange_EX1", "queue_Q1",..);
});
and in the application configuration
var eventBus = app.ApplicationServices.GetRequiredService<IEventBus>();
eventBus.Subscribe<FooEvent, FooEventHandler>;
I want to register multiple implementations with different configurations of EventBusRabbitMQ so i can pick and choose which exchange and queue to target when i resolve for IEventBus.
What i don't want is to be explicit about the implementations since the only thing that differs is just the exchange and queue.
services.AddSingleton<IEventBus, EventBusRabbitMQ_EX1_Q1>
services.AddSingleton<IEventBus, EventBusRabbitMQ_EX2_Q2>
what alternates do i have?

I think the best solution given you have a finit set of implementation is to consider a solution like this:
public interface IEventBusRabbitMQ_EX1_Q1:IEventBus
{
}
public interface IEventBusRabbitMQ_EX2_Q2:IEventBus
{
}
and then change your code to inject the right instance
services.AddSingleton<IEventBusRabbitMQ_EX1_Q1, EventBusRabbitMQ_EX1_Q1>
services.AddSingleton< IEventBusRabbitMQ_EX2_Q2, EventBusRabbitMQ_EX2_Q2>
But there is another solution which is described here
basically is an enricher kind pattern like but I don't recommend it because it reduces the readability of the code.

Related

Building intermediate IServiceProvider for use in custom IConfigurationProvider

Problem Statement: I have a custom IConfigurationProvider that requires a complex service to function properly. This complex service would, naturally be registered to the applications IServiceProvider. I want to use IServiceCollection/IServiceProvider facilities in conjunction with IConfigurationProvider to avoid manual new of this complex service, and to re-use registration code that would otherwise be written in the normal part of the DI container building portion of the app.
I've found plenty of documentation describing the troubles of needing an IServiceProvider in an IConfigurationProvider. This is the closest thing that felt ok to me, and is the inspiration for this post.
Here's my approach at a high level
Build the configuration up enough to construct the intermediate IServiceProvider
Build the intermediate IServiceProvider
Build the rest of the configuration via custom IConfigurationProvider's that require special services, retrieved via intermediateServiceProvider.GetRequiredService<T>();
Transfer the registrations and, specifically, singleton objects, from the intermediate IServiceCollection/IServiceProvider to the final IServiceCollection/IServiceProvider. This will help avoid re-registering things in step #5 and will help avoid second instances of singletons in the final IServiceProvider.
Register the final set of services to complete the final IServiceProvider, using configuration that was injected in step #4.
#1,#2,#3,#5 are simple enough. #4 is where I'm hitting roadblocks. My first attempt at #4 was the following
foreach (var sd in intermediateServiceCollection)
{
if (sd.Lifetime == ServiceLifetime.Singleton)
{
// Externally owned
if (sd.ImplementationInstance != null)
{
finalServiceCollection.AddSingleton(sd.ServiceType, sd.ImplementationInstance);
}
// Provide a factory function to delegate to intermediate service provider
else
{
finalServiceCollection.AddSingleton(sd.ServiceType,
s => intermediateServiceProvider.GetRequiredService(sd.ServiceType));
}
}
// Transient/scoped service descriptors can be forwarded along without issue
else
{
finalServiceCollection.Add(sd);
}
}
As documented here, registering open-generic types with a factory function is not supported.
After stumbling upon this limitation, my latest approach looks like:
foreach (var sd in intermediateServiceCollection)
{
if (sd.Lifetime == ServiceLifetime.Singleton)
{
// Externally owned
if (sd.ImplementationInstance != null)
{
finalServiceCollection.AddSingleton(sd.ServiceType, sd.ImplementationInstance);
}
// Provide a factory function to delegate to intermediate service provider
else if (!sd.ServiceType.IsGenericType)
{
finalServiceCollection.AddSingleton(sd.ServiceType,
s => intermediateServiceProvider.GetRequiredService(sd.ServiceType));
}
else
{
// Simply adding the service descriptor to the final service collection
// opens the door for singleton instances to be created again
//
// In reality, this may be configurable to raise an exception to signal
// to our developers they need to avoid registering open-generics in the
// bootstrapping portion of the app. But, this may serve it's purpose
// if you can live with multiple instances of a singleton.
finalServiceCollection.Add(sd);
}
}
// Transient/scoped service descriptors can be forwarded along without issue
else
{
finalServiceCollection.Add(sd);
}
}
Obviously, my current implementation is not perfect as it allows for multiple singleton instances if that singleton is registered as an open-generic. But, with an understood limitation of bootstrap registration being non open-generic types, I can "successfully" create an intermediate IServiceProvider for use within IConfigurationProvider's and transfer it to the final IServiceProvider.
Can anyone provide inspiration that can lead to a complete implementation for #4, specifically around transferring open-generic registrations?
Is the assumption that this approach is reasonable total nonsense and I should opt for a different pattern to configure my application?
If you use the same configuration provider for intermediate and final service provider and you need the same services in the final service provider as within the intermediate one, why don't you put your whole setup logic of the intermediate provider into a method that gets the target builder as parameter? Then you can first call it to setup your intermediate one and later another time to setup your final provider.
In that case you don't need any kind of reflection and you can use all available extension helper class or own logic to setup the configuration provider.

Inject signalr hub only by interface

So recently I started a project with Ardalis Clean Architecture as template it was all nice but when signalR came into my project i can't figure it. I'm trying to inject interface that my hub implements and call it's method, but everytime when it's called it throws NullReferenceException, it seems like all of the signalR components are null within this injected interface. Registered all hubs and registered it's interfaces using AutoFac. Trying to avoid situation when I'm forced to reference signalR package within core layer.
Core layer:
public class UpdateTimerNotificationHandler : INotificationHandler<UpdateTimerNotification>
{
private readonly ITimerHub _timerHub;
public UpdateTimerNotificationHandler(ITimerHub timerHub)
{
_timerHub = timerHub;
}
public Task Handle(UpdateTimerNotification notification, CancellationToken cancellationToken)
{
return _timerHub.UpdateTimerAsync(notification);
}
}
public interface ITimerHub
{
Task UpdateTimerAsync(UpdateTimerNotification updateTimerNotification);
}
Infrastructure layer:
public class TimerHub : Microsoft.AspNetCore.SignalR.Hub, ITimerHub
{
private readonly IAccountRepository _accountRepository;
public TimerHub(IAccountRepository accountRepository)
{
_accountRepository = accountRepository;
}
public Task UpdateTimerAsync(UpdateTimerNotification updateTimerNotification)
{
return Clients.All.SendAsync("UpdateTimer", updateTimerNotification);
}
}
private void RegisterHubs(ContainerBuilder builder)
{
foreach (var assembly in _assemblies)
{
builder.RegisterHubs(assembly);
}
builder.RegisterType<TimerHub>().As<ITimerHub>();
}
Web layer:
builder.Host.ConfigureContainer<ContainerBuilder>(containerBuilder =>
{
containerBuilder.RegisterModule(new DefaultCoreModule());
containerBuilder.RegisterModule(
new DefaultInfrastructureModule(builder.Environment.EnvironmentName == "Development"));
});
builder.Logging.ClearProviders();
builder.Logging.AddConsole();
var app = builder.Build();
GlobalHost.DependencyResolver = new AutofacDependencyResolver(app.Services.GetAutofacRoot());
I was trying manually registering hubs with no luck, still same issue
The good news is SignalR already implements IHubContext<T> In your case you don't need to inject ITimerHub interface. If your TimerHub Already Implements ITimerHub that's good enough In your case it would look like this
public class HomeController : Controller
{
private readonly IHubContext<TimerHub> _hubContext;
public HomeController(IHubContext<TimerHub> hubContext)
{
_hubContext = hubContext;
}
}
Also you didn't show your startup.cs class.
public void ConfigureServices(IServiceCollection services)
{
...
services.AddSignalR();
...
}
and
public void Configure(IApplicationBuilder app, IWebHostEnvironment env)
{
...
app.MapHub<TimerHub>("/yourEndPointGoesHere");
}
If you really wanted to, which I don't recommend is [look at it here][1]
There is an example on using IHubContext in generic code.
I understand you're trying to learn something new. And yes, it's important to decouple application so you're headed in the right direction in what you want to achieve. However I wouldn't recommend this approach you are taking. His approach doesn't apply to 99% of the projects out there. Let me explain my point of view. Don't get pulled in by the buzz words in his videos and blogs. It's important to understand that these principals are SUBJECTIVE to your application.
You don't have 15,000 classes, services, views, and N Layers etc... in your app.
You don't need the flexibility of a domain driven approach. I've seen massive and I mean massive projects, ones that are 25 years old and have millions of lines of code. Let me tell you you're not swapping out your data layer all willy nilly like he makes it seem to be. On a big project there is no "it makes it easy" way to do that. Putting it in Repos and a data access layer doesn't really help. You can put in a data access layer, or in your services. You still need to test out 150,000 lines of code. The only time it's been useful for me is when I've had 4 data sources all having a getBy... function that needs to aggregate info from 4 sources. You don't need it for unit testing either. Just create a mock variable in your unit tests no need to mock your db connection. I find it more useful to have your unit tests actually hooked up to a database even though it's a dependency, it's actually useful.
He said it himself "You can go with a minimalist API and work your way up from there" Which is what you should do. What's the point of SOLID and Repos in a project with no code? For example the I in solid is implementation of interfaces. Interfaces do 2 things -
A. Tell your application what it should and shouldn't do. so, what are you enforcing that could break or needs this kind of abstraction?
B. Decouple the application. Where do you have 3+ different classes being injected in one piece of code with the same DoSomething() based on the type?
He touches over other things that only apply when you have 500 different things going on, and his case it's still overkill.
If you want to break it up you can take a simple approach.
-MainApiProject
-ServicesProject (you can also put interfaces in here)
-InterfacesProject(if you need them between multiple projects and have a lot of them)
-UtilitiesProject
Then look at what he's doing and if you see you need it take it.
I can go on but this is getting long as is.
[1]: https://learn.microsoft.com/en-us/aspnet/core/signalr/hubcontext?view=aspnetcore-6.0

is it possible to create base EF DbContext and use it in many services?

I try to implement Microservice Architecture in my project. I was wondering can i create 1 method for Depedency Injection there is to implement EntityFrameworkCore in many services so i didnt DRY.
So what iam thinking is i still create my own DbContext, and than when i want to register this i just put it in my json file and add something like services.UseSql() in my startup.cs and inside UseSql is using Configuration from .json file.
what i try to say is something like generic DbContext.
I have some example to this but is using MongoDb :
Example
public static void AddMongo(this ContainerBuilder builder)
{
builder.Register(context =>
{
var configuration = context.Resolve<IConfiguration>();
var options = configuration.GetOptions<MongoDbOptions>("mongo");
return options;
}).SingleInstance();
builder.Register(context =>
{
var options = context.Resolve<MongoDbOptions>();
return new MongoClient(options.ConnectionString);
}).SingleInstance();
builder.Register(context =>
{
var options = context.Resolve<MongoDbOptions>();
var client = context.Resolve<MongoClient>();
return client.GetDatabase(options.Database);
}).InstancePerLifetimeScope();
builder.RegisterType<MongoDbInitializer>()
.As<IMongoDbInitializer>()
.InstancePerLifetimeScope();
builder.RegisterType<MongoDbSeeder>()
.As<IMongoDbSeeder>()
.InstancePerLifetimeScope();
}
If I understand your problem statement correctly, you want multiple microservices to connect to the same database. As comments above suggest, you really shouldn't do that as you'd essentially be coupling your microsrvices through your data layer - which can be messy if your microservices grow into incompatible data layers. This would eliminate a lot of benefits of the architecture and leave you to deal with pains. So if that is indeed the case you might want to consider revisiting your arсhitecture and trying to figure out whether you need a new microservice that fronts this common data store and provides it to others.
In reality however you sometimes must share code between projects and there's a official way to do that: extract the common code into a nuget package, host it somewhere in your private enterprise repository (if you care) and reference it from your other projects.

How should I use appsettings.json config key/values in my ConfigurationServices ASP.NET Core 2.0 on startup?

I'm trying to configure my services for an ASP.NET Core 2.0 app/website.
I wish to reference some key/values from my appsettings.json file, in this method.
I'm not sure if what I'm going is OK or not:
public void ConfigureServices(IServiceCollection services)
{
services.AddMvcCore()
.AddJsonFormatters()
.AddCors();
var applicationSettings = Configuration.GetSection("Settings").Get<ApplicationSettings>();
services.AddSingleton(applicationSettings);
// ** THIS IS WHAT I ORIGINALLY HAD, BUT IT'S ONLY SETTING
// THE VALUE IN DI/IOC.
//services.Configure<ApplicationSettings>(options => Configuration.GetSection("Settings")
// .Bind(options));
var foo = new Foo(applicationSettings.SomeSetting);
services.AddSingleton(foo);
}
See how i'm manually adding a singleton and then later, referring a value from the app settings instance?
vs
just configuring ...
So, is either way OK or is there a specific reason for either/or?
Remember -> i'm going to need to inject my settings into controllers, etc...
Technically, you can do either. In both cases, you have the configuration registered and available through dependency injection, so everything can depend on it and will get the configuration instance.
You are also using the centrally set up Configuration there, so you have all the benefits from the configuration stack there, e.g. multiple providers or environment specific overrides.
However, the favor has definitely moved to the IOptions way of consuming custom configuration. It’s the “state of the art” and used throughout ASP.NET Core for literally everything. It also allows you to switch to options that can be updated at runtime. That’s very powerful and might become useful eventually (not necessarily for your specific situation with the singleton, but maybe for something else).
It’s also really easy to set this up, actually shorter than what you tried:
services.Configure<ApplicationSettings>(Configuration.GetSection("Settings"));
services.AddSingleton<Foo>();
Note that, even for singletons, you shouldn’t explicitly create a new instance of it, but let DI handle that. If your class has the correct constructor, dependencies will be automatically injected anyway:
public class Foo
{
private readonly ApplicationSettings _settings;
public Foo (IOptions<ApplicationSettings> settings)
{
_settings = settings.Value;
}
}
Of course, Foo can also have more dependencies here. Since it’s going to be constructed by DI, you can just add more dependencies in the constructor, without having to update some new call somewhere.
If you need to configure certain services with settings that depend on your configuration, you still should not bind your configuration there directly. All of configuration is DI-based, so you just need to inject the right thing; a IConfigureOptions<T>. That’s basically the thing that provides the IOptions<T> to services later. In your JWT case, this could look like this:
// instead of passing an option configuration delegate here…
services.AddAuthentication().AddJwtBearer();
// … we register a IConfigureOptions<JwtBearerOptions> instead
services.AddSingleton<IConfigureOptions<JwtBearerOptions>, ConfigureJwtBearerOptions>();
// … ConfigureJwtBearerOptions could look like this:
class ConfigureJwtBearerOptions : IConfigureOptions<JwtBearerOptions>
{
private readonly ApplicationSettings _settings;
public ConfigureJwtBearerOptions(IOptions<ApplicationSettings> settings)
{
_settings = settings.Value;
}
public void Configure(JwtBearerOptions options)
{
// configure JwtBearerOptions here, and use your ApplicationSettings
options.MetadataAddress = _settings.JwtMetadataAddress;
}
}
This might seem unnecessarily verbose compared to just passing a delegate to AddJwtBearer() but note that this is exactly what happens under the hood when you pass that delegate: An IConfigureOptions<JwtBearerOptions> object will be created that calls your delegate in the Configure() call. So this is really just the same.
Note that for authentication schemes, you might actually set up a IConfigureNamedOptions<T> instead, which is almost the same thing except it can configure the options based on a name. For authentication schemes, that is the scheme name, so basically you check the scheme name in Configure() and then decide how to configure your options.
As for creating singleton instances, especially expensive ones, I would argue that ConfigureServices is the wrong place for such a thing. ConfigureServices is called very early in the application startup phase, when the whole DI infrastructure does not exist yet. So you could not rely on anything when creating your instance. I would also argue that it is still not your job to create the object but you should DI handle the creation of it and as such give it also control over its lifecycle.
If you absolutely need to control when the instance is created, I would suggest you to use the lifecycle events for this: Basically, after the application has set up properly but before a first request comes in, you request the instance of your services and initialize it. That way, you can still have it fully depend on DI, and it won’t be created lazily with the first request.
You can register lifecycle handlers in the Configure method:
public void Configure(IApplicationBuilder app, IApplicationLifetime applicationLifetime)
{
applicationLifetime.ApplicationStarted.Register(() =>
{
// application has started, request the singleton here to trigger DI to
// create the instance
app.ApplicationServices.GetService<ExpensiveSingleton>();
});
// …
}
}
Well the problem with that approach is that it will be impossible to load multiple configuration sections through DI. The Configuration API has many features, such as pluggable configuration provides, snapshots, etc.
I would suggest you at least use a class to bind you configuration section against, so DI can inject it based on its type. If you further down the line have need to another configuration class you won't run into issues.
https://learn.microsoft.com/en-us/aspnet/core/fundamentals/configuration

Publishing to multiple Rebus queues with different stores

We have one application that publishes messages - PublishApp.
The messages (MessageA and MessageB) are picked up by two different consumer apps (ConsumerA and ConsumerB).
All applications use SQL Server as a transport and Windsor configuration, but the two Consumers have different databases in SQL Server.
How can we configure PublishApp to publish MessageA for ConsumerA and MessageB for ConsumerB?
I have tried using DetermineMessageOwnership as described here, but that doesn't seem to actually be called (no breakpoints hit). I'm a little mystified as to what the string endpoints returned should be.
I was hoping that I could set up an IBus component in Windsor with a specific name, then reference that by name when setting up my MessageB-publishing class. However it's not clear how to set up an IBus in Windsor outside of the magic box that does it all for me.
Fiddling with Windsor configuration leads me to a Windsor error if I try to call Configure.With(new WindsorContainerAdapter(container)) twice, as it is interpreted as registering the IBus interface twice. I can't see an extension point here to give one of the IBus instances a name, and hence differentiate them in Windsor.
Alternatively, trying to reuse the Configure.With... call throws an error telling me I have called .Transport() on the configurer twice, which is also not allowed (but which would let me use a different connection string...)
Adding XML configuration will let me specify different endpoints for my different messages, but not different SQL connection strings.
What I would really like to end up with is something like:
// Set up Bus A
var busA = Configure.With(new WindsorContainerAdapter(container))
.Transport(tc => tc.UseSqlServerInOneWayClientMode("ConnectionStringA"))
.Subscriptions(sc => sc.StoreInSqlServer("ConnectionStringA", "RebusSubscriptions"))
.CreateBus()
.Start();
// Set up Bus B
var busB = Configure.With(new WindsorContainerAdapter(container))
.Transport(tc => tc.UseSqlServerInOneWayClientMode("ConnectionStringB"))
.Subscriptions(sc => sc.StoreInSqlServer("ConnectionStringB", "RebusSubscriptions"))
.CreateBus()
.Start();
// Register Bus A in Windsor
container.Register(Component.For<IBus>()
.Named("BusA")
.Instance(busA));
// Register a class that depends on IBus, and set it to use Bus A
container.Register(Component.For<IPublishA>()
.ImplementedBy<PublishA>()
.DependsOn(Dependency.OnComponent(typeof(IBus), "BusA"));
// And a registration also for IBus B, and for IPublishB to reference named "BusB"
Note: I do not want to listen to multiple buses, only publish events to them. Other applications are monitoring the queues, and each application only listens for one event on one queue.
We resolved this in the end by dropping the WindsorContainerAdaptor. Since we're not handling any messages, only publishing/sending, we don't need any of the 'handler' stuff in the container adaptor and we can switch the registration of the IBus component around to happen outside of the configuration/starting, rather than inside it. This gives us the control to name the IBus registration.
public static void ConfigureAndStartBus(IWindsorContainer container)
{
_RegisterBus(container, "ConnectionStringA" "BusA");
_RegisterBus(container, "ConnectionStringB" "BusB");
}
private static void _RegisterBus(IWindsorContainer container, string connectionString, string busName)
{
var bus = Configure.With(new BuiltinContainerAdapter())
.Transport(tc => tc.UseSqlServerInOneWayClientMode(connectionString))
.Subscriptions(sc => sc.StoreInSqlServer(connectionString, "RebusSubscriptions"))
.CreateBus()
.Start();
container.Register(
Component.For<IBus>()
.Named(busName)
.LifestyleSingleton()
.Instance(bus));
}
Then in class PublishA, we can register it with a dependency on BusA, and PublishB can be registered with a dependency on BusB. The messages go to separate databases, and are picked up by separate subscribers to do work in those different databases.
First off: There's no way (at least at the moment) to ship messages between two SQL Server databases. In order for messages to be sent/published between endpoints, you need to use one single table in one shared database.
Your setup hints at something being off there, since you're using "ConnectionStringA" and "ConnectionStringB" for the transports.
It's not clear to me whether you actually want/need to do pub/sub messaging - pub/sub is what you would usually use when you want multiple recipients of each message, which would usually be some kind of event (i.e. a message whose name is in the past tense, as in: "this and that happened").
If you want one specific recipient for a message, you want to bus.Send that message, and that is when your endpoint mappings will be hit in order to get a destination for the message.
If you tell me some more about exactly what you're trying to achieve, I am sure I can help you :)

Categories