Alternative method for PublishRequest() in new Masstransit - c#

I'm trying to update my code from old version of Masstransit to newer version (v. 3) of it with RabbitMQ, and I want to use a request/response mode that my old code is:
public static void SendCommand<TCommand>(this IServiceBus bus, TCommand command, Action<InlineRequestConfigurator<TCommand>> callback) where TCommand : CommandBase
{
command.Validate();
bus.PublishRequest(command, callback); // Here is my problem
}
I can't find any alternative method for PublishRequest() in IBusControl that I think it is defined instead of IServiceBus.
Any help will appreciated.

Do you truly need to publish your request (versus sending it to a specific endpoint)? Requests should typically be sent to a specific endpoint.
This is well described in the documentation:
http://docs.masstransit-project.com/en/latest/usage/request_response.html
The fact that your method is called SendCommand makes this resonate pretty well.

I believe what you want is on the IBus interface as the IServiceBus was removed in MT 3. IBus is just a collection of interfaces, so you could use the lowest common interface that supports the methods you need.

Related

Does publishing a message on the same ConsumeContext that received it have any benefits?

I'm asking about a situation where the consumer gets the message, processes it and then the result of that processing is another message, so something like:
class MyConsumer : IConsumer<MyMessage> {
public async Task Consume(ConsumeContext<MyMessage> context) {
// ...do the processing and then:
await context.Publish<MyResponse>(new()
{
Data = "some data"
});
}
}
So the question is - does using context.Publish have any benefits over injecting IPublishEndpoint? It would be done if the processing would require another component to be separated from the consumer - another class. Then the result of that component processing would be a message which could be published by the injected IPublishEndpoint.
In a consumer (and any of the consumers dependencies), messages published and/or sent should use:
ConsumeContext - easiest in the consumer, since it already has it as part of the method signature.
ISendEndpointProvider or IPublishEndpoint - should be injected into any dependencies of the consumer that need to produce messages. MassTransit is essentially redirecting these two interfaces to the current ConsumeContext behind the scenes.
This is also covered in the documentation.

Hide service bus implementation behind interfaces

I'm currently working on a project that allows 3rd parties to hook into our product's message broker. The task is to provide a library that these 3rd parties can consume. I want to be able to package either Mass Transit or NServiceBus along with it but I want to hide that detail behind interfaces.
I've got the service bus itself hidden like this...
public class MyServiceBus : IServiceBus {
private readonly MassTransit.IBus _bus;
private readonly MassTransit.IBusControl _busControl;
public PanelSawServiceBus(MassTransit.IBus bus, MassTransit.IBusControl busControl) {
_bus = bus;
_busControl = busControl;
}
public Task PublishAsync<T>(T message, CancellationToken token = default(CancellationToken)) where T : class =>
_bus.Publish(message, token);
public Task SendAsync<T>(T message, CancellationToken token = default(CancellationToken)) where T : class =>
(_bus as ISendEndpointProvider)?.Send(message, token);
public Task StartAsync() => _busControl.StartAsync();
public Task StopAsync() => _busControl.StopAsync();
}
A vendor should not be allowed to publish/send messages and should only be consuming. How can I hide consumption of the messages so I can package a service bus library and not expose what library is being used under the covers?
Edit 1
Consuming a message with Mass Transit looks like this
public class MyConsumer : IConsumer<SomeMessage> {
public Task Consume(ConsumeContext<SomeMessage> ctx) => Task.CompletedTask;
}
During bootstrapping when you are creating a service bus instance you can define your consumers (Mass Transit will construct them when a message comes in for you).
var busControl = Bus.Factory.CreateUsingInMemory(config => {
config.ReceiveEndpoint("queue_name", endpointCfg => {
endpointCfg.Consumer<MyConsumer>();
}
};
What I'd like the wrapper to do is allow the developer to say "Using a queue factory I want to construct an instance with this queue name and here are the names of the types that implement the consumer interface that is hiding the bus technology's interfaces." I just don't know if I can hide the consumers.
If I understand correctly, you want to keep your code from being coupled to either NServiceBus or MassTransit, and you don't want to expose which one you are using.
First, the decoupling:
You've accomplished part of this by defining your own IServiceBus interface. As long as your library depends only on that interface and not on any implementation, you shouldn't be coupled to either.
To ensure that you avoid such coupling, I'd keep concrete implementations in separate projects/libraries. Your "core" domain should not directly reference either. If you can unit test the code without either concrete implementation present then you're free to switch between implementations.
When you publish your library you can publish the composition of your core library along with the implementations of its interfaces that you have selected.
Then, hiding which implementation is used:
As for not exposing whether you use NServiceBus or MassTransit, you can't. If someone references your library and it depends on one of those packages, they'll have to add that package too. Assuming that your library is packaged for NuGet, that package will reveal its dependencies.

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.

Constructor not being called in type derieved from DuplexChannelFactory<T>

I have question about the article in here. The related code is as follow.
public CustomClientChannel(string configurationPath) : base(typeof(T))
{
this.configurationPath = configurationPath;
base.InitializeEndpoint((string)null, null);
}
protected override ServiceEndpoint CreateDescription()
{
ServiceEndpoint serviceEndpoint = base.CreateDescription();
ExeConfigurationFileMap map = new ExeConfigurationFileMap();
map.ExeConfigFilename = this.configurationPath;
Configuration config = ConfigurationManager.OpenMappedExeConfiguration(map, ConfigurationUserLevel.None);
ServiceModelSectionGroup group = ServiceModelSectionGroup.GetSectionGroup(config);
ChannelEndpointElement selectedEndpoint = null;
......
}
The first function is the constructor of the class and the second one overloads the CreateDescription function in DuplexChannelFactory since the class inherents from DuplexChannelFactory.
However, when I use this class to create an object, the code runs directly into CreateDescription().
Therefore, even though I pass a configurationPath to the constructor, the this.configurationPath is still null.
If I inherent CustomClientChannel class from ChannelFactory, then it works fine.
Please help to see what is wrong and what is the difference between ChannelFactory and DuplexChannelFactory? I am using netTcpBinding. Thank you.
Your constructor is calling into a base constructor that takes a single type.
: base(typeof(T))
Both ChannelFactory<T> and DuplexChannelFactory<T> implement a protected constructor that takes a single type, but they are different.
ChannelFactory<T> wants the channel type.
DuplexChannelFactory<T> want the callback instance type
In other words, they do completely different things and can have completely different code paths. Protected constructors are to be used by derived types only, and generally infer some level of knowledge of how the class hierarchy works.
You would be better picking the public constructor that you would normally use, and calling that instead. If that is not possible then you need to work out the appropriate DuplexChannelFactory constructor to call instead.
Let's start with
what is the difference between ChannelFactory and
DuplexChannelFactory?
First it is necessary to understand the difference between simplex and duplex communications in WCF.
A simplex connection is like sending a text message and then receiving a delivery notification - even though at a lower transport level there may be multiple calls between your phone and the carrier, from a communications level, you are sending the text message in one direction only.
A duplex connection is like making a phone call, you are able to send voice data to your carrier, and your carrier can send voice data in the other direction at the same time. This requires a simplex channel open in both directions.
Both ChannelFactory and DuplexChannelFactory can be used to create a client channel to a service.
Which one you choose is down to whether the service you are calling exposes simplex or duplex service operations, and whether you, as a comsumer, need to consume these operations.
If the service exposes normal (i.e, simplex) operations, for example:
void DoCoSomething(int x);
List<Things> GetThings();
etc...
...then you can consume these operations with ChannelFactory.
If the service exposes a callback contract:
public interface IMyDuplexCallback
{
[OperationContract(IsOneWay = true)]
void NotifyMeOf(string message);
}
for example, in order to send notifications or message of some kind to the consumers, and you as a consumer want to take advantage of this, you can use the DuplexChannelFactory to call the service (after implementing the callback contract on your client of course).
As a general rule, duplex communication in WCF is complex at best, and is therefore best avoided.
Appreciate this does not address your original question.

How to wait for a Task to complete in a WCF service operation

I apologize if a variation of this question has been asked before, but I'm struggling to find an answer that applies to my current situation.
I am working on a project where I've been asked to expose the operations of a Task based provider via a WCF service. The provider interface explicitly defines Task<T> as the return type of each method, here's an example:
public interface IContactProvider
{
Task<IEnumerable<Contact>> GetAllContacts();
}
In an attempt to expose this as a WCF service, I've basically defined a "synchronous" version of the provider interface to use as a service contract resulting in a service implementation that looks like this:
public class ContactService : IContactService
{
private IContactProvider contactProvider;
public IEnumerable<Contact> GetAllContacts()
{
return contactProvider.GetAllContacts().Result;
}
}
My instinct tells me that I'm doing something wrong here and that I should be "waiting" for the Result to be available some other way. Is there a better way to do this?
What you're doing should work fine (Result will block until the task completes), but are you using .NET 4.5? If so you could simply declare your service operation contract to return the async Task<T> directly. That way your clients would automatically get the option to call it synchronously or asynchronously (via the generated service client).
Here's a post I found more useful than the MSDN docs: http://blog.vuscode.com/malovicn/archive/2012/01/21/what-is-new-in-wcf-in-net-4-5-taskt-and-async.aspx

Categories