Hide service bus implementation behind interfaces - c#

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.

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.

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

Alternative method for PublishRequest() in new Masstransit

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.

Best architecture design using service layer and interacting services?

I have several services that are currently highly decoupled. Now I have to extend them and they need to depend to access each other.
Let's say I have 4 services: EmailService, HouseService, UserService, PriceService. Each user has an email address and each user belongs to a house.
I want to send an email to each user about the price of the house that they are connected to. So in the EmailService I have SendEmailToAddress(string email, string text), in PriceService I have GetHousePrice(int id), in HouseService I have GetUsersInHouse(int id) and in UserService I have GetEmailOfUser(int id).
What would be the best approach to send an email to all the users from the HouseController? Should I just init all the services in the controller action and call each one in order or should I use the Mediator pattern? If I should use it, it would probably contain only one method so it seems a bit of an overkill. Also if I use it everywhere should I create different mediators for each service connection or should it be only one class that has all my services as private properties and then in the methods use only the once I need for a specific action? If I go with the Mediator pattern should I use it in every controller or should I stick with the bare services where they don't need to interact together (e.g. if I only need a list of houses I think it's probably best to just get them directly from the service object instead of the Mediator)?
Given that your services aren't actually needing to communicate with each other, you just need to call various methods on each and use the return values to complete a higher level task, I don't think the Mediator pattern is appropriate here.
For example, its not like you need the HouseService to manipulate the state of objects managed by the PriceService...you just need data from the PriceService that the HouseService provides input for:
var houseId = houseService.GetIdOfHouse(someCriteria);
var price = priceService.GetPriceOfHouse(houseId);
Instead, I think what you need to implement is the Facade pattern, which will:
Provide a unified interface to a set of interfaces in a subsystem. Façade defines a higher-level interface that makes the subsystem easier to use.
Good example of Facade pattern can be found on the dofactory.com site:
http://www.dofactory.com/net/facade-design-pattern
Here's what I would consider doing:
public class NotificationFacade
{
private IPriceService _priceService;
private IHouseService _houseService;
private IUserService _userService;
private IEmailService _emailService;
public NotificationFacade(IPriceService priceService, IHouseService houseService, IUserService userService, IEmailService emailService)
{
_priceService = priceService;
_houseService = houseService;
_userService = userService;
_emailSerice = emailSerice;
}
public void NotifyUsersAboutPriceForHouse(int houseId)
{
var price = _priceService.GetHousePrice(houseId);
var users = _houseService.GetUsersInHouse(houseId);
foreach(var user in users)
{
var emailAddress = _userService.GetEmailOfUser(user);
_emailService.SendEmailToAddress(emailAddress, "Your House Price is:" + price);
}
}
}
In your controller:
public HouseController
{
private NotificationFacade _notificationFacade;
public HouseController(NotificationFacade notificationFacade)
{
_notificationFacade = notificationFacade;
}
public void SomeActionMethod(int houseId)
{
_notificationFacade.NotifyUsersAboutPriceForHouse(houseId);
}
}
The dependencies should be resolved using Dependency Injection with a container such as Unity, Ninject, StructureMap or something similar...
You could create a workflow service that contains the actual logic to look up the information and send the mail using the existing services.
This service is then called from your HouseController. You could use the service directly as a class library or expose it as a WCF service; but it depends on your requirements.
This way your entity services remain loosely coupled, and all of your cross-service logic is in a dedicated component.
As I was looking for best practices since past couple of days in ASP.Net MVC and I concluded that our services should contain all business logic ( using repositories of different domain models) and expose public methods that are accessible by controller.
In your case you should create a new service and put the whole logic of calculation and sending email in a method of that service. So that your service will work like a black box. Other developers (who work on your project) don't need to know that how thing are managed in that method. All they need to know is to call that method with required parameter and handle response.
Just create HouseServiceFacade that contains the services you need. In this facade you can put all methods for the controller.

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