I am working with code that I have not written and am trying to understand why a particular piece of functionality is not working the way I intend. In particular, I have three projects within my solution:
API
Messages
Events
Processors
Events is a folder within Messages. API will communicate with Processors using NServiceBus via messages defined in Messages/Events. Each of the classes in Messages/Events extends IMessage.
Now within a configuration file for the bus that is shared by both Processors and API, I found these lines:
var conventionsBuilder = config.Conventions();
conventionsBuilder.DefiningEventsAs(t => t.Namespace != null && t.Namespace.StartsWith("DE.STEP.Messages") && t.Namespace.EndsWith("Events"));
return config;
This was implemented earlier, and the classes inside Messages/Events did NOT extend IMessage at an earlier time, instead the above code defined where and what a message could be qualified as. Now, since I have introduced IMessage, I figured I could remove those 3 lines of code. However, when I do, no messages ever make it to my queue from API. The code that attempts this publish is Bus.Publish<>();
How should I configure this so that I do not need to have a hard-coded string referencing the assembly where the messages are? I want my code to scan the solution for anything that extends IMessage and treat it as something that can be published and can be handled.
EDIT: As per the NServiceBus docs
By default, NServiceBus scans all assemblies in the endpoint
bin folder to find types implementing its interfaces so that
it can configure them automatically.
And Messages.dll appears in the bin of both API and Processors. So since Messages.dll contains all of my IMessages, shouldn't the default behavior suffice to make them available for publishing / subscribing? I.e. shouldn't removing the 3 lines in question have no effect?
The hierarchy of an event, if you're not using unobtrusive configuration, should be as follows:
ConcreteEvent : IEvent : IMessage
The reason for this is, after having had a look at the source code, your message endpoint mappings are processed as follows:
foreach (var mapping in messageEndpointMappings)
{
mapping.Configure((messageType, address) =>
{
var conventions = context.Settings.Get<Conventions>();
if (!(conventions.IsMessageType(messageType) || conventions.IsEventType(messageType) || conventions.IsCommandType(messageType)))
{
return;
}
if (conventions.IsEventType(messageType))
{
router.RegisterEventRoute(messageType, address);
return;
}
router.RegisterMessageRoute(messageType, address);
});
}
Conventions.IsEventType is a lookup implemented as follows:
EventsConventionCache.ApplyConvention(t, type => IsEventTypeAction(type));
I won't give you the full call stack but basically, you end up here:
t => typeof(IEvent).IsAssignableFrom(t) && typeof(IEvent) != t
This will evaluate as false for a concrete event only implementing IMessage, so RegisterEventRoute is never called for your event but rather it'll be treated as an IMessage, which follows different routing rules (only one route per IMessage).
In short, you must have IEvent interface on your event class to be able to use IBus.Publish if you are not using unobtrusive configuration.
Related
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 :)
I may me missing something basic here - but is it possible to retrieve the HttpContext.Current in a custom NLog event?
I am trying to give each request a unique Guid so that I can correlate logging messages to a single event (i.e, tie together each log event for a single request). So, I want to store this Guid in HttpContext.Current.Items, then retrieve it in the NLog target and include it in the log message.
Here is my example target where I'd like to access HttpContext.Current:
[Target("AzureTableTarget")]
public class AzureTableTarget : TargetWithLayout
{
public AzureTableTarget()
{
_appSettings = IoCResolver.Get<IAppSettings>();
}
protected override void Write(LogEventInfo logEvent)
{
var correlationId = HttpContext.Current; //This is always null
var batchOperation = new TableBatchOperation();
CxLogEventBuilder.Build(_appSettings, logEvent).ForEach(batchOperation.Insert);
_loggingTable.ExecuteBatchAsync(batchOperation);
}
}
Nowadays it's easier to retrieve the HTTP Context in a NLog target (works for ASP.NET and ASP.NET Core)
Install NLog.Web (ASP.NET) or NLog.Web.AspNetCore (ASP.NET Core) package
For ASP.NET core, follow the ASP.NET Core - NLog setup
Inherit from AspNetLayoutRendererBase (namespace NLog.Web.LayoutRenderers)
Get the request by calling var context = HttpContextAccessor.HttpContext;
Example:
[LayoutRenderer("aspnet-sessionid")]
[ThreadSafe]
public class AspNetSessionIdLayoutRenderer : AspNetLayoutRendererBase
{
protected override void DoAppend(StringBuilder builder, LogEventInfo logEvent)
{
var context = HttpContextAccessor.HttpContext;
var contextSession = context?.Session();
if (contextSession == null)
{
InternalLogger.Debug("HttpContext Session Lookup returned null");
return;
}
builder.Append(contextSession.SessionID); // ASP.NET Core: contextSession.Id
}
}
PS: there are currently many predefined renderers for ASP.NET (Core): https://nlog-project.org/config/?tab=layout-renderers&search=aspnet
If your custom target should capture one (or more) context-specific values, then I recommend that your target inherits from TargetWithContext (or AsyncTaskTarget).
It gives the ability to setup and capture contextproperty-items. Where the Layout can be assigned to capture context-details. Examples of possible context-details easily available from HttpContext:
https://nlog-project.org/config/?tab=layout-renderers&search=package:nlog.web.aspnetcore
For more details about writing custom-targets:
https://github.com/NLog/NLog/wiki/How-to-write-a-custom-target-for-structured-logging
https://github.com/NLog/NLog/wiki/How-to-write-a-custom-async-target
Btw. there already exists this custom target that nicely inherits from AsyncTaskTarget:
https://www.nuget.org/packages/NLog.Extensions.AzureCosmosTable/
This article about Working with HttpContext.Current might help. The key, for you, might be that when control passes from one thread to another HttpContext.Current in the new thread can be null.
Here is another question/answer from here on SO that describes HttpContext.Current being null in the context of a web service. The accepted answer suggests turning on ASP.Net compatibility in your web.config file.
I don't know of either of these will help, but they might. I found them by googling for "HttpContext.Current is null", which yielded quite a number of hits. I have done very little ASP.NET development, so I can't really comment on HttpContext.Current from my own personal experience.
Given your use case, I would suggest that you look into System.Diagnostics.CorrelationManager.ActivityId.
One nice feature of ActivityId is that it is "flowed" from parent threads to child threads (including thread pool threads). I think that it works well with Tasks and Parallel operations. Works well meaning that the ActivityId, as set in a parent thread, has the expected value in a child thread.
There is not a LayoutRenderer for ActivityId, but it easy enough to write one. See an example (written against NLog 1.0) here:
Most useful NLog configurations
I'm pretty sure that the "EstimatedBufferSize" stuff is no longer needed, so something like will probably work:
[LayoutRenderer("ActivityId")]
class ActivityIdLayoutRenderer : LayoutRenderer
{
protected override void Append(StringBuilder builder, LogEventInfo logEvent)
{
builder.Append(Trace.CorrelationManager.ActivityId);
}
}
If you go this route, you might consider adding a Format property to the ActivityIdLayoutRenderer to allow you to specify the guid format. See this answer (from me). It contains a lot of useful information about working with guids.
NewGuid vs System.Guid.NewGuid().ToString("D");
See this source file (in NLog's git repository) for an example of how you can implement and use such a Format property:
https://github.com/NLog/NLog/blob/master/src/NLog/LayoutRenderers/GuidLayoutRenderer.cs
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...
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.)
I have a client application that consumes a number of services. It's not always immediately obvious when a service is down or incorrectly configured. I own the service side code and hosting for most of the services, but not all of them. It's a real mixed bag of client proxies - different bindings (basichttp/wshttp/nettcp), some have been generated using svcutil.exe, while others are made programatically with ChannelFactory where the contract is in a common assembly. However, I always have access to the address, binding and contract.
I would like to have a single component in my client application that could perform a basic check of the binding/endpoint config and the service availability (to show in some diagnostic panel in the client). As a minimum I just want to know that there is an endpoint at the configured address, even better would be to find out if the endpoint is responsive and supports the binding the client is trying to use.
I tried googling and was surprised that I didn't find an example (already a bad sign perhaps) but I figured that it couldn't be that hard, all I had to do was to create a clientchannel and try to open() and close() catch any exceptions that occur and abort() if necessary.
I was wrong - in particular, with clients using BasicHttpBinding where I can specify any endpoint address and am able to open and close without any exceptions.
Here's a trimmed down version of my implementation, in reality I'm returning slightly more detailed info about the type of exception and the endpoint address but this is the basic structure.
public class GenericClientStatusChecker<TChannel> : ICanCheckServiceStatus where TChannel : class
{
public GenericClientStatusChecker(Binding binding, EndpointAddress endpoint)
{
_endpoint = endpoint;
_binding = binding;
}
public bool CheckServiceStatus()
{
bool isOk = false;
ChannelFactory<TChannel> clientChannelFactory = null;
IClientChannel clientChannel = null;
try
{
clientChannelFactory = new ChannelFactory<TChannel>(_binding, _endpoint);
}
catch
{
return isOk;
}
try
{
clientChannel = clientChannelFactory.CreateChannel() as IClientChannel;
clientChannel.Open();
clientChannel.Close();
isOk = true;
}
catch
{
if (clientChannel != null)
clientChannel.Abort();
}
return isOk;
}
}
[Test]
public void CheckServiceAtNonexistentEndpoint_ExpectFalse()
{
var checker = new GenericClientStatusChecker<IDateTimeService>(new BasicHttpBinding(), new Endpointaddress("http://nonexistenturl"));
// This assert fails, because according to my implementation, everything's ok
Assert.IsFalse(checker.CheckServiceStatus());
}
I also tried a similar technique with a dummy testclient class that implemented ClientBase with the same result. I suppose it might be possible if I knew that all my service contracts implemented a common CheckHealth() method, but because some of the services are outside my control, I can't even do that.
So, is it even possible to write such a simple general purpose generic service checker as this? And if so how? (And if not, why not?)
Thanks!
Have you looked at WCF Discovery?
WCF Discovery allows a client to search for a service based on
different criteria including contract types, binding elements,
namespace, scope, and keywords or version numbers. WCF Discovery
enables runtime and design time discovery. Adding discovery to your
application can be used to enable other scenarios such as fault
tolerance and auto configuration.
For a first attempt, you could query the endpoint to see if it supports the expected contract.
The big benefit is that you can have the client “discover” which service it wants to talk to at runtime. Which removes a lot of the client side configuration errors that you are likely used to seeing.
You need to check out SO-AWARE. It is a web service management tool that can manage SOAP or REST WCF-based service across your organization. Further it has a Test Workbench!
Here are a couple of videos that show it off too:
Part 1
Part 2
To put it in perspective, this is so complex that these people make a living doing it, I don't think it's something you want to realistically build on your own.