Publishing to multiple Rebus queues with different stores - c#

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 :)

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.

DI configuration for multiple RabbitMQ exchanges and queues

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.

SignalR multiple hubs on different paths in same application?

I have an application which contains multiple hubs all on unique paths, so when calling the default :
routes.MapHubs("path", new HubConfiguration(...));
It blows up saying that the signalr.hubs is already defined (as mentioned here MapHubs not needed in SignalR 1.01?).
Now I can understand that it should only be called once, but then you will only get 1 path, so is there any way to handle a path per hub scenario? like how with MVC you specify the controller and action? so something like:
routes.MapHub<SomeHub>("path", new HubConfiguration(...));
== Edit for more info ==
It is mentioned often that you should never need to call this map hubs more than once, and in most scenarios I can agree, however I would not say that this is going to be the case for all applications.
In this scenario it is a website which at runtime loads any plugins which are available, each plugin is exposed the dependency injection framework to include its dependencies and the route table to include its routes. The hubs may have nothing to do with each other (other than the fact that they are both hub objects). So the hubs are not all known up front and are only known after the plugins are loaded, and yes I could wait until after this and try binding the hubs there, however then how do I have custom routes for each one then?
This seems to be a case of SignalR trying to abstract a little too much, as I dont see it being a bad idea to have custom routes rather than the default "/signalr", and as the routes all have different responsibilities it seems bad to have one entry route for them all.
So anyway I think the question still stands, as I dont see this as being a bad use case or bad design it just seems to be that I want to be able to have a route with a hub applied to it, much like in mvc you apply a controller and action to a route.
You shouldn't need more than the signalr.hubs route. If you point your browser to that route, you will see it automatically finds all public types assignable to IHub and creates a JavaScript proxy for them. You can interact with different hubs by name from JavaScript, i.e. if you have the following Hub:
public class GameHub : Hub
You can connect to that specific hub by doing:
var gameHubProxy = $.connection.gameHub;
You can also explicitly specify a name for your hub by adding the HubNameAttribute to the class:
[HubName("AwesomeHub")]
public class GameHub : Hub
You can then retrieve the specific proxy by doing
var awesomeHubProxy = $.connection.awesomeHub;
UPDATE:
I'm not sure whether SignalR will be able to run on multiple paths in the same application. It could potentially mess things up and the default assembly locator won't be able to pick up hubs loaded at runtime anyway.
However, there is a solution where you can implement your own IAssemblyLocator that will pick up hubs from your plugin assemblies:
public class PluginAssemblyLocator : DefaultAssemblyLocator
{
private readonly IEnumerable<Assembly> _pluginAssemblies;
public PluginAssemblyLocator(IEnumerable<Assembly> pluginAssemblies)
{
_pluginAssemblies = pluginAssemblies;
}
public override IList<Assembly> GetAssemblies()
{
return base.GetAssemblies().Union(_pluginAssemblies).ToList();
}
}
After you've loaded your plugins, you should call MapHubs and register an override of SignalRs IAssemblyLocator service:
protected void Application_Start(object sender, EventArgs e)
{
// Load plugins and let them specify their own routes (but not for hubs).
var pluginAssemblies = LoadPlugins(RouteTable.Routes);
RouteTable.Routes.MapHubs();
GlobalHost.DependencyResolver.Register(typeof(IAssemblyLocator), () => new PluginAssemblyLocator(pluginAssemblies));
}
NOTE: Register the IAssemblyLocator AFTER you've called MapHubs because it will also override it.
Now, there are issues with this approach. If you're using the static JavaScript proxy, it won't be re-generated every time it's accessed. This means that if your /signalr/hubs proxy is accessed before all plugins/hubs has been loaded, they won't be picked up. You can get around this by either making sure that all hubs are loaded by the time you map the route or by not using the static proxy at all.
This solution still requires you to get a reference to your plugin assemblies, I hope that's feasible...

How to register two WCF service contracts with autofac

I have a WCF service that implements two service contracts...
public class MyService : IService1, IService2
and I am self-hosting the service...
host = new ServiceHost(typeof(MyService));
Everything was working fine when the service implemented only one service contract, but when I attempt to set up autofac to register both like this:
host.AddDependencyInjectionBehavior<IService1>(_container);
host.AddDependencyInjectionBehavior<IService2>(_container);
... it throws an exception on the second one, reporting:
The value could not be added to the collection, as the collection already contains an item of the same type: 'Autofac.Integration.Wcf.AutofacDependencyInjectionServiceBehavior'. This collection only supports one instance of each type.
At first glance I thought this was saying my two contracts were somehow being seen as the same type but on second reading I believe it is saying that the
AutofacDependencyInjectionServiceBehavior is the type in question, i.e. I cannot use it twice!
And yet, I found this post that explicitly showed using it multiple times in a slightly different form:
foreach (var endpoint in host.Description.Endpoints)
{
var contract = endpoint.Contract;
Type t = contract.ContractType;
host.AddDependencyInjectionBehavior(t, container);
}
Unfortunately, that gave the very same error message.
Is it possible to register more than one service contract on one service and, if so, how?
In fact you can register multiple endpoint for a single host with Autofac.
That is true that you cannot add multiple AutofacDependencyInjectionServiceBehavior but this behaviour iterates through all the endpoints and registers them in the ApplyDispatchBehavior method: source
In order to make this work you need to register your service AsSelf()
builder.RegisterType<MyService>();
Then you can configure your endpoint normally:
host = new ServiceHost(typeof(MyService));
host.AddServiceEndpoint(typeof(IService1), binding, string.Empty);
host.AddServiceEndpoint(typeof(IService2), binding, string.Empty);
And finally you need to call the AddDependencyInjectionBehavior with the sevicehost type itself:
host.AddDependencyInjectionBehavior<MyService>(container);
Here is a small sample project (based on the documentation) which demonstrates this behavior.
Update (the bold text) based on #nemesv's answer:
Further investigation revealed that with autofac one cannot register multiple endpoints on a single ServiceHost if one registers the WCF service contracts.
(See #nemesv's answer for the correct way to do it.)
Here is why:
Either form of this extension method...
host.AddDependencyInjectionBehavior<IService1>(_container);
host.AddDependencyInjectionBehavior(t, container);
...resolves down to adding a ServiceBehavior (according to Alex Meyer-Gleaves initial announcement of WCF integration in autofac)...
host.Description.Behaviors.Add(behavior);
Now this Behaviors property is an instance of KeyedByTypeCollection<TItem>, which can hold only only one object of a given type. Since the behavior being added will always be an instance of AutofacDependencyInjectionServiceBehavior, one can therefore only add one endpoint.
QED
The workaround is to use multiple ServiceHosts, each with a single endpoint.
(As a point of interest, I would be curious to know the impact on performance and scalability between those two approaches.)

Injecting host from HttpContext into Service layer

I need to apply filtering by requesting host name on all database calls in my Web API service.
This filtering works like so:
lookup the Site to profile against based on the requesting hostname
Apply Site.Id on all subsequent data access calls made in the request
Essentially a global filter so so that data returned by the API service is always contained to the host.
One solution would be to pass the host name in as an argument on all my service methods like so:
public IEnumerable<Profiles> GetProfiles ()
{
var host = HttpContext.Current.Request.ServerVariables["SERVER_NAME"];
return profilesService.Get(host);
}
But since this is a consistent rule on all requests I would like to come up with a more elegant way to handle this so my service calls are just profileSerivce.Get();
I think I need to inject a ISiteLocator into my service layer that has either the host name or even better the Id already retrieved from the database that I can then apply. But I'm struggling with this on how and where I can reference the HttpContext to get the host name and also if it was possible to optimise this using StructureMap lifecycles.
I think I need to inject a ISiteLocator into my service layer
It seems to me you are heading into the right direction.
I'm struggling with this on how and where I can reference the
HttpContext
This is really simple actually. Define the ISiteLocator in your business layer and define an AspNetSiteLocator implementation into your ASP.NET web application, preferably close to (or inside) your Composition Root. That implementation might look like this:
public class AspNetSiteLocator : ISiteLocator
{
private readonly ISiteRepository siteRepository;
public AspNetSiteLocator(ISiteRepository siteRepository)
{
this.siteRepository = siteRepository;
}
Site ISiteLocator.GetCurrentSite()
{
return this.siteRepository.GetById(CurrentHostName);
}
private static string CurrentHostName
{
get
{
return HttpContext.Current.Request
.ServerVariables["SERVER_NAME"];
}
}
}
that has either the host name or even better the Id already retrieved
from the database
Try to let your ISiteLocator return data in a way that is most convenient to the consumers of that locator. In my example I returned a Site entity (if you have such an entity in your domain). This is probably more convenient than the host name or the Id, since consumers possibly have to query for the site again thereselves. However, perhaps Id is the most convenient, but that's up to you to find out.
how [...] to optimise this using StructureMap lifecycles
The implementation above doesn't have any state, so it can be registered with any lifetime; singleton for instance. However, every call to ISiteLocator.GetCurrentSite() will result in a new request to the ISiteRepository, which can cause too much overhead. In that case you probably want an implementation that stores the Site in a private field and always returns that instance. In that case you shoud register that implementation on a 'Per Web Request' basis (since the SERVER_NAME will not change during the request).

Categories