NServiceBus configuration in netcore 3.1 Startup - nservicebus

I've gone through all the documentation and examples of setting up NServiceBuse in NetCore, however, all the examples have the configuration being done in the Program.cs (Host.CreateDefaultBuilder().UseNServiceBus()).
I would like to know if I can configure NServiceBus in the ConfigureServices method of Program.cs.
The reason is that in the HostBuilder I'm building up all of the IConfiguration options (e.g. reading from appsettings.json, EnvironmentVariables, AzureKeyVault, ConfigMaps, etc.) and the Logger implementation. By the time ConfigureServices is called, all of those have been resolved. I need to be able to get things like connection strings from the IConfiguration, and so I don't believe it will work to do it in the HostBuilder.
It looks like a lot of work might be being done under the covers to inject the IMessageSession and scan for IHandlMessages instances. That should be able to be done in the Service.
Edit: Forgot to add, because it is in the Program.cs and we are using Serilog, I do not have a LoggerFactory. The LoggerFactory is registered and injected by the Services, but I cannot get it at this point in startup.

Looks like this isn't an option. I was able to have a workaround to get it all working, which is just to put it in the Program() and just make sure it is called after all the other configuration is done. It doesn't seem ideal and seem to be an anti-pattern from where netcore 3 is going.

I'd like to add that this is a poor design choice. I should be able to register my stuff in startup and package scanning shouldn't be happening.
This is a neat project, but I think that for any non-trivial development it may be left lacking.
The reason is that I would like to have a web host with multiple endpoints and I cannot do that without running two full instances (https://docs.particular.net/samples/hosting/generic-multi-hosting/).
My workflow is
message comes in to do all the work
message #1 starts a saga with 100+ messages
each message publishes an update that it is done, so that the UI can check the status of the Saga
The messages from #3 are not handled until all 100+ messages are processed (FIFO).
What I'm wanting to do is have a second queue (we're using Azure service bus) to listen for the worker updates on and update the UI.

Although you already have a workaround I have build a similar setup as you described with with Serilog as logger and NServiceBus. You can access the configuration in Program.cs like so:
public static IHostBuilder CreateHostBuilder() =>
Host.CreateDefaultBuilder()
.ConfigureAppConfiguration()
.UseSerilog()
.UseNServiceBus(c => NServiceBusSetup.Configure(c.Configuration, c.HostingEnvironment))
In the self made method NServiceBus.Configure you can setup your endpoint.

Related

Check conditions on startup

I would like to test certain conditions on Startup of my ASP.Net Core 2.0 application. For example if my database server or other is running correctly. This is especially helpful for things that will only be instantiated after a request (like my repository).
Currently I have to do this request manually, but I would like to have my application fail early. At what moment and in what place is such a test recommended?
The Startup class is responsible for setting up your server, making it the perfect candidate for setting up one-time initialization stuff for your application.
You usually have two main methods in Startup: ConfigureServices and Configure. The former runs very early and is responsible for setting up the application services, dependencies and configuration. So you cannot use it to actually perform real work, especially since the dependency injection container is not ready yet.
However, the Configure method is different: While its main purpose is to set up the application middleware pipeline, the components that will later serve requests, you are able to fully use your dependencies here, making it possible to already do more extensive things here. So you could make your calls directly here.
It’s important to understand that Configure still runs rather early, way before your server is actually ready to serve requests. So if your initialization depends on the actual server being around already, you should probably further delay the execution.
The proper solution is likely to hook into the application lifecycle using IApplicationLifetime. This type basically offers you a way to register callbacks that are executed during the application lifecycle. In your case, you would be interested in the ApplicationStarted event which runs when the server just completed its setup phase and is now ready to serve requests. So basically the perfect idle moment to run some additional initialization.
In order to respond to a lifetime event, you need to register your handler inside the Configure method:
public void Configure(IApplicationBuilder app, IApplicationLifetime applicationLifetime)
{
// other…
// register lifetime event
applicationLifetime.ApplicationStarted.Register(InitializeApplication);
}
public void InitializeApplication()
{
// do stuff
}
One final note: Apparently, there is currently an open bug that prevents lifetime events from firing when hosting on IIS. In that case, executing your code directly in Configure is probably the best alternative.

Nservicebus disable default logger in web.config

I'm using the DefaultFactory LogManager for Nservicebus v5. I'm happy with this but was hoping to be able to disable via the web.config.
I use web.config settings, as found in the help docs
<configSections>
<section name="Logging" type="NServiceBus.Config.Logging, NServiceBus.Core" />
</configSections>
<Logging Threshold="Debug" />
I'd prefer not to set the threshold as fatal. I was hoping for a "None" or Disabled="true"
Also can the directory path be set web.config?
Update: Why would we want to ignore errors?
The short is we don't really have write permission on the servers.
The long is this isn't 100% true.
Our systems is moving towards microservices, the problem with this is that decentralized logging is a tracing/visualization nightmare.
So we moved flow tracing, exceptions, and limited tracing to a centralized system.
Programming Entry points (aka message Handlers, web api endpoints, etc) are nearly always wrapped in a try catch log throw on each handler, this covers all our programming errors. This isn't anything really that different to normal.
The centralized logging location sets of all the nice red flashing real time alarms one could wish for.
Which leaves only configuration type error left like missing queues, bad assembly bindings, faulty config files, or more runtime style stuff like IoC wiring (outside of the handler code).
With the centralized logging and monitoring of the error quests, it is fairly easy to detect when the service is broken and if it is then we turn on logging, restart, try the faulty issue, and fix.
Guaranteed delivery will take care of everything else once it is up again :D Gone are the days of 150mb log files spread across 10 different servers.
The simplicity of DefaultFactory was nice, as was not needing another nuget package and associated configuration.
Is this the correct way forward. Many would argue no.
Could we have done it better? yes we could implement the common logger interface and pass it into NServiceBus but we arn't quiet there just yet and the win isn't critical atm.
A side note: One really really nice thing about the way we log is that in our backoffice tool we have been able to simply show the flow for each "order", similar to using a correlation id in greylog.
Since this was not considered a likely scenario it does not have a first class API. But you can achieve this via passing in a null logger from any of the common logging libraries (NLog, Log4net, CommonLogging). I assume you are using one of these in your website.
So take NLog for example.
Install-Package NServiceBus.NLog
The in your webconfig
<appSettings>
<add key="disableLogging" value="true"/>
</appSettings>
Then in your global startup
if (ConfigurationManager.AppSettings.Get("disableLogging") == "true")
{
LoggingConfiguration config = new LoggingConfiguration();
LogManager.Configuration = config;
NServiceBus.Logging.LogManager.Use<NLogFactory>();
}
This is leveraging the approach documented here http://docs.particular.net/nservicebus/logging-in-nservicebus#nlog

MassTransit Consumer never invoked when using Windsor Integration

I can't seem to get the Castle Windsor Integration working for Mass Transit over RabbitMQ. Everything was working fine until I introduced Windsor into the picture. I referenced Castle.Windsor 3.2 and MassTransit.WindsorIntegration 2.9 and configured the container for use within my application. I'm registering the MassTransit Consumers via:
Container.Register(..., Types.FromThisAssembly().BasedOn<IConsumer>());
When I debug and inspect the container after this line is ran, I can see that it successfully registered all of the consumers along with all of my other components. I then have the following code to initialize and register the service bus:
var serviceBus = ServiceBusFactory.New(sbc =>
{
sbc.UseRabbitMq();
sbc.ReceiveFrom(Config.ServiceBusEndpoint);
sbc.Subscribe(sc => sc.LoadFrom(Container));
});
Container.Register(Component.For<IServiceBus>().Instance(serviceBus));
I am using the LoadFrom(IWindsorContainer container) extension method provided by MassTransit.WindsorIntegration.
All of the examples I've found so far stop here and indicate that this is all you should have to do. Unfortunately for me my Consumers are never being called and messages are just piling up in the queue (eventually timing out and going to error queue). The fact that messages are showing up in the Consumer queue at all (+ I see a single consumer bound to the queue via the RabbitMQ Admin Tool) indicates to me that the consumers are probably being subscribed properly - so I'm not sure where the problem lies.
I added NLog logging for Windsor and MassTransit but no errors are showing up in the logs. I'm not sure how I should proceed troubleshooting at this point. Any ideas?
Also, this application is currently just a console application using Topshelf for development. Ultimately it will be installed as a Windows Service. Not sure if that is relevant or not but I thought I'd mention it just in case.
UPDATE
As a test I created a very simple Consumer with a parameter-less constructor for processing a very simple test message. This Consumer is successfully called! The "real" Consumers however have dependencies that need to be injected into them via the constructor. I was hoping the Container would resolve these but apparently it's having some sort of trouble. Weird that nothing is showing up in the logs about it. Stay tuned...
Okay I figured it out. Somewhere along the way when I was adding/removing NuGet packages I somehow managed to delete a reference to a DLL (ServiceStack.Text.dll) that one of my components needed (RedisClientsManager).
I started the debugger, let all my components get registered then popped open the Immediate Window and attempted to resolve each component one by one (by calling container.Resolve<RegisteredType>()) until I found the one that threw the exception when I attempted to resolve it.
The Exception message from Windsor at that point told me exactly what the problem was. I'm a little lost as to why this wasn't being logged or why the Exception was not raised when the container itself attempted to resolve it. Anyhow, moral of the story is make sure your components resolve.

WCF service operations not updated

I´m creating a new WCF service. I initially had only three operations. But after some time I decided to add two more. This operations doesn't appear in the Microsoft test client, neither in the list of operations when I try to add a service reference from my WPF client. Also I tried to comment one of the initial operations. It still apears in the Microsoft test client and can be invoked. I Tried also delete the dlls generated by the service and regenerate again. No luck. There are some kind of "cache" where Visual Studio stores the WCF services libraries that I can delete?
UPDATE: I'm working with the service running in the ASP.NET devolopment server.
You need to understand the order in which things happen.
You change your code, adding methods with [OperationContract] on them, or removing them, or changing their parameters or return values.
You then must build your service, producing a .DLL that contains the changes.
You must then deploy the changed DLL to the server it's going to run on
You must then restart the service (this may happen automatically depending on the server. For instance, IIS will recycle the service when it sees that the DLL changed)
You must then update your client, either the WCF Test Client, or "Add Service Reference", or the equivalent.
This last will have the effect of sending a request to the service for the new metadata or WSDL. Only then can the client see the changes you made to the definition of the service.
I don't know why, but I created a new project and copied the definitions of the operations from the problematic project and the problem is gone. One case more for Microsoft mysteries.
Make sure you are updating the services after adding the new operations.
Also make sure they have the attribute [OperationContract].
One thing we have discovered is that when you deploy the dlls that they must be in the bin, and cannot reside in the debug or release folder.
For me worked: just rebuild the wcf project
Did you close the client connection in client side
as showing your service
class Test
{
static void Main()
{
LocationClient client = new LocationClient();
// Use the 'client' variable to call operations on the service.
// Always close the client.
client.Close();
}
}
SOLUTION HERE :
Make sure your dataContract does NOT contain any enum
(You can use integer instead)
Be sure to reference a project in the solution and not a dll on your disk
Remove your "bin" and "obj" folders
Recompile
In IIS recycle the application pool
In IIS restart your service
In IIS "Browse" your service
=> You got it

Using wcf services in S#arp Architecture project

I have a sharp architecture project and I am making use of ApplicationServices in it as well.
There is requirement to provide a winform client that will use a wcf service. The wcf service will in turn use the ApplicationServices. I have not started working on the winform client yet but I am working on the wcf service.
Following the Northwind sample. I have created a "Wcf Service library" project and a "Wcf Service Application" project in my solution.
I am new to wcf but i know all the basics and have worked with web services alot in the past. I have following questions:-
1) I would like to know why there is a need of two projects, wcf library and wcf application?
2) I have noticed that the ITerritoriesWcfService interface in the Northwind sample inherits ICloseableAndAbortable.
public interface ITerritoriesWcfService : ICloseableAndAbortable
What is the purpose of ICloseableAndAbortable?
3) There is another class TerritoriesWcfServiceClient
public partial class TerritoriesWcfServiceClient : ClientBase<ITerritoriesWcfService>, ITerritoriesWcfService
What is the purpose of this class?
4) In the TerritoriesService.svc file, what is the purpose of Factory="SharpArch.Wcf.NHibernate.ServiceHostFactory, SharpArch.Wcf" ? Usually in a normal wcf service application, I use codebehind attribute, but since the .cs file actually resides int the wcf service library project, I would like to know what following code is doing?
<%# ServiceHost Language="C#" Debug="true"
Service="Northwind.Wcf.TerritoriesWcfService"
Factory="SharpArch.Wcf.NHibernate.ServiceHostFactory, SharpArch.Wcf" %>
Even if I remove the above Factory attribute, I can still run the service app project and test the service using WcfTestClient utility.
6) When i run my service and using WcfTestClient If I run a method twice that accesses a repository, then on the second call, I get an ObjectDisposedException.
{"Session is closed!\r\nObject name: 'ISession'."}
I believe the NHibernate Session is getting disposed after the first call. How can reinitialise for each call or should I keep it open? I would like to know the best practice?
7) Also If I run the Northwind.Wcf.Web project and click on TerritoriesService.svc
file on the Directory Listing screen, I get the following error
{"Method 'Generate' in type 'Northwind.Data.NHibernateMaps.AutoPersistenceModelGenerator' from assembly 'Northwind.Data, Version=1.0.0.0, Culture=neutral, PublicKeyToken=null' does not have an implementation.":"Northwind.Data.NHibernateMaps.AutoPersistenceModelGenerator"}
I don't understand why is it throwing this error, when i already got the method and the Northwind.Web works fine too.
Awaiting
Nabeel
1) Strictly, you can combine the WCF library and the WCF application
in one assembly. This would mean that you would combine the contracts
and the implementations in one assembly.
If you are using svcutil.exe or Visual Studio (which uses svcutil.exe
in turn) to generate proxy classes for your client, you'd be fine
because the proxy classes are generated from discovery of your
services.
If however, you want to use your own classes for transport, which is
quite common in DTO scenarios and the like, you'd need to reference a
shared library from both the client and the server. If that shared
library would be your combined library/application assembly, the
client would get the application implementation in scope (because it
references the assembly that contains the contracts) and that's really
not something you'd want. The client needs to know as little as
possible about the server, just as much as the contracts expose --
that's what the contracts are for in the first place.
I think it is best practice to separate interfaces/contracts from
implementation anyway because it leads to better separation of
concerns. It's just that most parts of your solution don't need (and
shouldn't) know HOW something is done, just WHAT that something can
do. There are many more advantages over this, such as improved
testability.
2) Taken from the code documentation of ICloseableAndAbortable:
"When implemented by your WCF contracts, they are then interchangable
with WCF client proxies. This makes it simpler to use dependency
injection and to mock the WCF services without having to worry about
if it's a WCF client when you go to close/abort it.".
I think that says it all.
3) The client class is, like the code documentation says, a strongly
typed client proxy. It can be used by clients to talk to the server,
providing a strongly typed class that has members that correspond to
the service operations that can be called on the server.
The advantage of this class is that you don't need to use the
svcutil.exe generated proxy classes. This what they mean by not having
to configure it via WCF configuration. This allows you to ship proxy
classes to your clients so they can immediately talk to your server
instead of generating proxy classes first. It allows for more control
as well, changing the code that is generated by the proxy class is
really not something you'd want to do.
This again is a good reason to put the interfaces/contracts in a
separate assembly because you don't want to ship the service
implementation code to your clients.
4) The service host factory creates a service instance based on the
provided service type. This can come in handy if you want to put the
service code somewhere other than in the code behind file. You'd also
need it if you are using Depency Injection, you'd provide the service
contract interface as the type and the SharpArch.Wcf service host
factory resolves it to the correct implementation class type by means
of the DI framework (Castle Windsor in SA). You can think of this as a
means of getting hold of a service implementation while not caring
about where it actually is coming from.
In this case, the service will run when you remove the factory
attribute, because the default factory is able to resolve the service
type. You're bypassing on stuff like DI and session management though,
exactly that what makes SA valueable.
5) I'll have to skip this one because apparently there is no question number 5 :-)
6) As in the Northwind sample project, you are probably using the ServiceHostFactory that comes with SA. With this service host factory, each created service instance is extended by a behavior that closes the NHibernate session directly after it's called. That okay by itself but chances are that your proxy clients are not managed in a transient way by Castle Windsor. Therefore instances get reused, including the closed sessions they (still) contain. Decorate your client proxy classes with the Transient attribute (Castle.Core.TransientAttribute) and Castle Windsor will create a fresh instance every time a service call is performed.
Apparently, there is a second way to solve this but it requires modification of the S#arpArchitecture code base. See WCF connections which process more than one request fail because the nhibernate session is closed and isn't re-opened. on GitHub.
7) I'm sorry, I seriously have no idea. I might look into this later.