masstransit and multiple bus instances - azure

According to MT documentation each bus instance should have a different queue name.
Am I right to assume that following is correct configuration?
What wires the WebApi and Backend queue together?
Consider even more advanced scenario
When I design my backend pipeline to use message processing as well I can later slice it and let it use over the wire transport quite easilly. Question is, can I somehow configure MT so the Azure configured Bus relays the messages to the bus configured with local transport?

I'm going to answer this in the context of MassTransit v3, which supports both Azure Service Bus and RabbitMQ. If you are going to use Azure, I'd highly recommend v3 over the transport for v2.
First, about requests. They should be sent, not published. They are usually commands by nature, and not events. The only reason I see people publishing requests is that they don't have the endpoint address of the service. So knowing the endpoint helps, a lot.
Secondly, in your example, every WebAPI instance should have it's own queue to receive responses, since they are sent back to the requestor. With MT3, every IBus instance has a unique auto-delete queue that is setup for this very purpose, to handle responses from requests.
There is a sample, Sample-RequestResponse, in the MassTransit repository on GitHub, that shows how this is setup with RabbitMQ. It's about the same with Azure Service Bus.
The "fabric" that brings it all together is the virtual host (in RabbitMQ) or the namespace (in ASB). The connections between topics and queues determine how it all works together to form a logical bus.

If somebody is trying to us .NET Core + DI to register multiple busses:
Do NOT use the build in AddBus call
No matter what you do it will never register more than one Bus due
This is because internally it calls TryAddSingleton call
TryAddSingleton only adds a new instance to the DI container if there is no instance registered for the interface yet
Note:
No exception or error is thrown
The solution we use
Since the various interfaces necessary are not generic:
Created generic Wrappers around the built in interfaces
Created an interfaces (used a generic parameters) that uniquely identify each RegisteredBus
When a new Wrapper instance is created, we pass the instance of the built in interface into its constructor
The Wrapper then holds the instance of the built in internal interface in a public property Instance
Instead of injecting eg. IBus, we now inject IBus<MyRegisteredBus>
We then use the Instance property of the wrapper to get access to the built in interface instance and store it for later use (the wrapper plays no role after that)
We would love to not have to use some sort of wrapper with a weird Instance property, but short of the built in interface becoming generic or using something like DynamicProxies we could not come up with a more elegant solution.
Ideas / Feedback is very welcome.
Code
Generic AddBus call (otherwise 100% same signature as built in call):
public static void AddBus<TBusType>(this IServiceCollection services, Func<IServiceProvider, IBusControl> busFactory)
where TBusType : class, IBusType
{
IBusControl<TBusType> BusFactory(IServiceProvider serviceProvider)
{
return new BusControl<TBusType>(busFactory(serviceProvider));
}
services.AddSingleton<IBusControl<TBusType>>(BusFactory);
services.AddSingleton<IBus<TBusType>>(provider => new Bus<TBusType>(provider.GetRequiredService<IBusControl<TBusType>>().Instance));
}
The various interfaces / classes we created to make this happen:
// the only purpose of the interfaces derived from `IBusType` is to uniquely idnetify a registered Bus
public interface IBusType { }
public interface IHosted : IBusType { }
public interface ILocal : IBusType { }
public interface IBusTypeWrapper<TBusType, TInterface>
where TBusType : IBusType
{
public TInterface Instance { get; }
}
public class BusTypeWrapper<TBusType, TInterface> : IBusTypeWrapper<TBusType, TInterface>
where TBusType : IBusType
{
public TInterface Instance { get; }
public BusTypeWrapper(TInterface instance)
{
Instance = instance;
}
}
public interface IBusControl<T> : IBusTypeWrapper<T, IBusControl> where T : IBusType { }
public class BusControl<T> : BusTypeWrapper<T, IBusControl>, IBusControl<T> where T : IBusType
{
public BusControl(IBusControl instance) : base(instance) { }
}
public interface IBus<T> : IBusTypeWrapper<T, IBus> where T : IBusType { }
public class Bus<T> : BusTypeWrapper<T, IBus>, IBus<T> where T : IBusType
{
public Bus(IBus instance) : base(instance) { }
}
public interface ISendEndpointProvider<T> : IBusTypeWrapper<T, ISendEndpointProvider> where T : IBusType { }
public class SendEndpointProvider<T> : BusTypeWrapper<T, ISendEndpointProvider>, ISendEndpointProvider<T> where T : IBusType
{
public SendEndpointProvider(ISendEndpointProvider instance) : base(instance) { }
}
How to register generic ISendEndpointProvider:
services.AddSingleton<ISendEndpointProvider<ILocal>>(provider => new SendEndpointProvider<ILocal>(provider.GetRequiredService<IBusControl<ILocal>>().Instance));
UPDATE
To an IHosted service for each Bus type:
- Create a generic HostedService<BusType> service
- Inject the IBusControl<BusType> in the constructor
- and use the injected instance to start stop the specific bus
Afterwards register a IHostedServicefor each bus type.
services.AddSingleton<IHostedService, HostedService<ILocal>>(); services.AddSingleton<IHostedService, HostedService<IHosted>>();`

Related

Logging into multiple instances of Acumatica

I have a development version of Acumatica running locally, and a QA version of Acumatica in the cloud.
I wrote c# program integrating with Acumatica through SOAP. I created WSDL file for Acumatica instance running locally at http://localhost/AcumaticaERP. Now I need to make the program to connect with Acumatica production instance in the cloud. soapClient.Login method does not have Acumatica URL as a parameter.
How do I allow users to dynamically chose an instance of Acumatica to use from within my program?
I would first suggest to look into the REST API since generally that's the recommended integration API to use.
Regarding dynamically changing the endpoint (i.e. Acumatica instance), note that the DefaultSoapClient has a number of overloaded constructors.
There is one where you can specify the endpointConfigurationName (see below). This would mean that your URL should be in your web.config/appsettings of the client application as explained in more detail here: https://help-2020r1.acumatica.com/(W(1))/Help?ScreenId=ShowWiki&pageid=37613e5f-7a72-4dec-b5d9-2525951e99cf
public partial class DefaultSoapClient : System.ServiceModel.ClientBase<ConsoleApp2.ServiceReference1.DefaultSoap>, ConsoleApp2.ServiceReference1.DefaultSoap {
public DefaultSoapClient() {
}
public DefaultSoapClient(string endpointConfigurationName) :
base(endpointConfigurationName) {
}
public DefaultSoapClient(string endpointConfigurationName, string remoteAddress) :
base(endpointConfigurationName, remoteAddress) {
}
public DefaultSoapClient(string endpointConfigurationName, System.ServiceModel.EndpointAddress remoteAddress) :
base(endpointConfigurationName, remoteAddress) {
}
public DefaultSoapClient(System.ServiceModel.Channels.Binding binding, System.ServiceModel.EndpointAddress remoteAddress) :
base(binding, remoteAddress) {
}
In case using configuration files will not work for you, you can refer to this example whereby it is done programmatically:
https://asiablog.acumatica.com/2019/01/dynamic-api-endpoint-url.html

Automatic binding to some service properties in Catel with Fody

Assuming there is some service:
public interface IDeviceManagerService
{
ISomeDeviceApi Api { get; }
}
It's purpose is to monitor external environment (USB, network, etc.), instantiate device API when the device detected and make property null when the device is no longer available.
Supposing there is a view model with this service injected, I would like to have change notifications for IDeviceManagerService.Api to make things like below possible (for example, having the button which is only active when the device API is available).
private Boolean OnSomeCommandCanExecute()
{
return _deviceManagerService.Api != null;
}
I wonder if there is a clean way to make this work without manual change notifications handling (with Catel.Fody or PropertyChanged.Fody). So far I have managed to get working result by making service implementation derived from ModelBase, registering it's injected instance as a [Model] inside the view model and exposing it's Api property using [ViewModelToModel] attribute, but this is very dirty way.
Is there some common approach or It would be better to go with implementing INotifyPropertyChanged and use notifications wrapper instead?
In most approaches, services don't implement INotifyPropertyChanged (they are not models), so my recommendation is to add manual events:
public interface IDeviceManagerService
{
ISomeDeviceApi Api { get; }
event EventHandler<DeviceApiEventArgs> ApiChanged;
}
This way you can deal with the stuff you are interested in (subscribe in InitializeAsync, unsubscribe in CloseAsync).

Servicestack - Grouping like services together

Was wondering if there's a recommended best-practice way of grouping similar services together in what's becoming a larger and larger project. Say that most of my services can be lumped in either dealing with "Pro" data or "Amateur" data (the data goes way beyond a simple flag in a table, the data itself is totally different, from different tables, on the pro or amateur side.
I know I can add routes to my classes...
/pro/service1
/am/service2
It looks like I can put the DTOs in namespaces....
What about the Service.Interface items (Service and Factory classes). Would you put those into namespaces also?
Finally, is there a way for the metadata page to reflect these groupings? I started to go down this road, but all the services listed out in alphabetical order, and you couldn't see the route or namespace differences between service1 and service2.
thank you
If you want, you can split multiple Service implementations across multiple dlls as described on the Modularizing Services wiki.
You can safely group service implementation classes into any nested folder groupings without having any impact to the external services. But changing the namespaces on DTO's can have an effect if your DTO's make use of object, interfaces or abstract classes which emit type info containing full namespaces.
In ServiceStack v4.09+ (now on MyGet) the MetadataFeature includes the ability to customize the ordering of the metadata page, e.g you can reverse the order of the metadata pages with:
var metadata = (MetadataFeature)Plugins.First(x => x is MetadataFeature);
metadata.IndexPageFilter = page => {
page.OperationNames.Sort((x,y) => y.CompareTo(x));
};
Organising your large project:
For a complex service(s) I setup 4 projects in one solution.
AppHost, This takes care of the configuration of the service. (References Model, Service and Types)
Model, This is the database model (Does not reference other projects)
Service, This is the implementation of the service only, not the interfaces or DTOs (References Model and Types)
Types, This includes my Interfaces, DTOs and routes. (Does not reference other projects)
Having a separate Types library allows the distribution to clients, for example for use with the ServiceStack JsonServiceClient.
Yes you can namespace the Interfaces, DTOs and factory classes, any way you want. They will work as long as they are referenced in your service correctly.
If you are trying to separate more than one service, you should consider separating your service code into logical folders within the Service project. i.e.
/Service/Pro
/Service/Amateur
Wrap the outer code of your Service methods in a public partial static class MyServiceStackApplication, with an appropriate name. Then reference this as the assembly in the AppHost constructor. So for example:
Pro Service (Service Project/Pro/UserActions.cs)
public partial static class MyServiceStackApplication
{
public partial class Pro
{
public class UserActionsService : Service
{
public User Get(GetUserRequest request)
{
}
}
// ...
}
}
Pro Service (Service Project/Pro/OtherActions.cs)
public partial static class MyServiceStackApplication
{
public partial class Pro
{
public class OtherActionsService : Service
{
public Other Get(GetOtherRequest request)
{
}
}
// ...
}
}
Amateur Service (Service Project/Am/UserActions.cs)
public partial static class MyServiceStackApplication
{
public partial class Amateur
{
public class UserActionsService : Service
{
public User Get(GetUserRequest request)
{
}
}
// ...
}
}
etc.
You can see from the above code we can have multiple files, all separated out and organised, but one assembly for ServiceStack to reference in the AppHost:
public AppHost() : base("Pro & Amateur Services", typeof(MyServiceStackApplication).Assembly) {}
Using the reference to the MyServiceStackApplication assembly, and using the partial keyword allows you to organise the code into manageable groupings.
Metadata:
Unfortunately separating the metadata by namespace isn't supported. You could try and customize the MetaDataFeature yourself, but it does seem like a useful feature, being able to separate multiple services where they are hosted in the one ServiceStack application. I would suggest you raise a feature request.
Mythz is bringing out features faster than lightning. :) Seems like he has that covered in the next release and you should be able to apply a custom filter to HostContext.Metadata.OperationNamesMap.

ServiceStack - Different server to main application

I wish to create a service which will be hosted on Server A (eg URL: http://servera:807). But my main application needs to be hosted on Server B (eg URL: http://serverb:801).
I am curious if this is possible or not? The reason my service and main application need to be on different servers are for reasons beyond my control. The current system uses WCF with the same setup and I'd like to move away from this.
In the examples the Service and Client all seem to be hosted in the same location / in the same solution
Below is a potential set up for solutions/projects. It's simplistic and incomplete but I think helps illustrate one possible set up. You would also need to consider how you want to handle Session information and Authentication since the MVC and ServiceStack handle this separately. See CustomAuthenticationMVC
ServerA.sln (ASP.NET Web Application)
ServiceModel project - holds requests objects and dtos (this can be shared between ServerA and ServerB solutions)
ServiceInterface project - has the Service implementations
Global.asx - has Application_Start method to configure ServiceStack
ServerB.sln (MV4 application)
ServiceModel project (shared)
Views
Models
Controllers
Example of classes in ServiceModel Project:
[Route("/Foos")]
public class Foos : IReturn<FoosResponse>
{}
public class FoosResponse
{
public FoosResponse()
{
this.ResponseStatus = new ResponseStatus();
}
public ResponseStatus ResponseStatus {get; set;}
}
Examples of classes in ServiceInterface project
public class FoosService : Service
{
public FoosResponse Get(Foos request)
{
return new FoosReponse();
}
}
Example how to call ServiceStack API within MVC4 application
public class FoosController
{
public ActionResult Index()
{
var client = new JsonServiceClient("http://servera:807");
var response = client.Get(new Foos());
return View(response);
}
}

NServiceBus Unit of Work For Multitenancy with Custom ORM

Here are my parameters:
Simple NServiceBus Saga implementation using the default builder
In-house ORM on top of SQL Server
Multitenancy - I have two ASP.NET MVC 4 domains running on the same website, each with their own databases
We configure our ORM using a static method like so:
public class EndpointConfig: IConfigureThisEndpoint, IWantCustomInitialization {
public void Init() {
var bus = Configure.With()
.AutofacBuilder()
.UnicastBus().LoadMessageHandlers().DoNotAutoSubscribe()
.XmlSerializer()
.MsmqTransport().IsTransactional(true).PurgeOnStartup(false)
.MsmqSubscriptionStorage()
.Sagas().RavenSagaPersister().InstallRavenIfNeeded()
.UseInMemoryTimeoutPersister()
.CreateBus()
.Start();
SlenderConfiguration.Init(bus);
}
}
public class SlenderCofnigruation {
private static ORMScope scope { get; set; }
public static void Init(IBus bus)
{
ORMConfig.GetScope = () =>
{
var environment = "dev";
if (bus.CurrentMessageContext.Headers.ContainsKey("Environment"))
environment = bus.CurrentMessageContext.Headers["Environment"];
if (scope == null)
scope = new SlenderScope(ConfigurationManager.ConnectionStrings[environment].ConnectionString);
return scope;
};
}
}
This works fine in our single-tenant Beta environment - it's fine for that static scope to get re-used because the environment header is always the same for a given deployment.
It's my understanding that this won't work for the multitenant situation described above, because NServiceBus will reuse threads across messages. The same scope would then be used, causing problems if the message was intended for a different environment.
What I think I want is a single scope per message, but I'm really not sure how to get there.
I've seen Unit Of Work Implementation for RavenDB, and the unit of work implementation in the full duplex sample, but I'm not sure that's the right path.
I've also seen the DependencyLifecycle enum, but I'm not sure how I can use that to resolve the scope given the way I have to set up the GetScope func.
Obviously I have no idea what's going on here. Any suggestions?
If you need to do something on a per-message basis, consider using message mutators (IMutateIncomingMessages) in addition to your unit-of-work management with some thread-static state.

Resources