NServiceBus: Auditing endpoints on different servers - nservicebus

We are using NSB 5.
We have an NSB Endpoint ("BusinessEndpoint") on Server1 and an NSB Audit Endpoint ("AuditEndpoint") on Server2.
"BusinessEndpoint" is configured to send audit messages to "AuditEndpoint" using the following configuration:
<section name="AuditConfig" type="NServiceBus.Config.AuditConfig, NServiceBus.Core" />
...
<AuditConfig QueueName="AuditEndpoint#Server2" />
The AuditEndpoint is set up like so:
public class EndpointConfig : IConfigureThisEndpoint, AsA_Server
{
public void Customize(BusConfiguration configuration)
{
configuration.EndpointName("AuditEndpoint");
configuration.UseSerialization<JsonSerializer>();
configuration.UsePersistence<NHibernatePersistence>();
// stop processing incoming subscription control messages
configuration.Pipeline.Remove("ProcessSubscriptionRequests");
var conventions = configuration.Conventions();
conventions.DefiningMessagesAs(t => t.Namespace != null && t.Namespace.Contains("Messages"));
}
}
Endpoints on Server1 can send normal (non audit) messages to endpoints on Server2 using NServiceBus.
Auditing works for all Endpoints installed on the Server2 (the same server as the AuditEndpoint).
However, the AuditEndpoint does not appear to receive any audit messages from the BusinessEndpoint.
Is it possible to Audit across different servers with just one AuditEndpoint?
Thanks for your help.

From your code it looks like the AuditEndpoint's name is auditingissue (and that is the name of the endpoint's input queue?)
This means the audit messages are being sent to the wrong queue, what sounds wrong is
Auditing works for all Endpoints installed on the Server2 (the same server as the AuditEndpoint).
Can you check that?
Another thing to check is your outgoing queues, in MSMQ's out going queue you should have audit messages stuck trying to be sent to:
a. the wrong machine name
b. the wrong queue on that machine (server2)
Does that help?

Related

Configure multiple instances of rebus for a single process with autofac

I ran into a situation where my application need to send messages to 2 queues that are in two different virtual hosts in rabbit and read from one of them. Moving those 2 queues into one virtual host (which is the perfect solution) not possible. Therefore, I need to run 2 rebus instances in a single process.
I'm using autofac for dependency injection. Could you please redirect me to some resource explaining how I can setup multiple instances in rebus with autofac in a single process?
thank you very much!
You should configure the bus instance, that you intend to use to send/publish messages on the other vhost, as a one-way client, which you then access through a dedicated service you create for this purpose.
Something along the lines of this:
public class OtherVhostBusClient : IDisposable
{
readonly IBus _bus;
public OtherVhostBusClient(string amqpConnectionString)
{
_bus = Configure.With(new BuiltinHandlerActivator())
.Transport(t => {
t.UseRabbitMqAsOneWayClient(amqpConnectionString);
})
.Start();
}
public Task Publish(object e) => _bus.Publish(e);
public void Dispose() => _bus.Dispose();
}
If you then configure OtherVhostBusClient as a singleton in your Autofac container, you can have it injected and use it to publish stuff on the other vhost.
This way, you are essentially treating this as a "foreign network" of sorts, implementing the integration with it as you would any other type of integration between "networks" (could be Rebus on any other transport, HTTP, etc.)
I hope that makes sense :)

Do I need to be configured as a publisher to do request/response (full dupllex) between endpoints configured AsA_Server in NServiceBus?

I am only using Bus.Reply() (not Bus.Publish()) in my endpoints (all configured AsA_Server). When I fire one of them up, I get the following warning:
2013-02-27 14:11:02,574 [Worker.15] WARN NServiceBus.Unicast.UnicastBus [(null)
] <(null)> - Subscription message from [not the currently running endpoint's queue]#my machine arrived at this endpoint, yet this endpoint is not configured to be a publi
sher.
Do I need to be configured AsA_Publisher in order to do request/response between endpoints configured AsA_Server? The full duplex sample does not seem to give any additional guidance in this area.
Per Andreas Ohlund:
That's just a warning, turn off auto subscriptions to avoid it.
Code to do this:
Configure.UnicastBus().DoNotAutoSubscribe();
Also per Andreas, AutoSubscription will only apply to IEvent messages.

Can't get service to pull from (dead letter) queue

I have a queue named log on a remote machine. When I call that queue locally, I specify a custom dead-letter queue by modifying my NetMsmqBinding:
_binding.DeadLetterQueue = DeadLetterQueue.Custom;
_binding.CustomDeadLetterQueue = new Uri(
"net.msmq://localhost/private/Services/Logging/LogDeadLetterService.svc");
This works fine; when I force my message to fail to get to its destination, it appears in this queue.
Now, I have a service hosted in IIS/WAS to read the dead-letter queue. It it hosted in a site called Services, at Services/Logging/LogDeadLetterService.svc. Here's the service in my config:
<service name="Me.Logging.Service.LoggingDeadLetterService">
<endpoint binding="netMsmqBinding"
bindingNamespace="http://me.logging/services/2012/11"
contract="Me.Logging.Service.Shared.Service.Contracts.ILog" />
</service>
And here's my activation:
<add relativeAddress="LogDeadLetterService.svc"
service="Me.Logging.Service.LoggingDeadLetterService" />
My actual service is basically this:
[ServiceBehavior(AddressFilterMode = AddressFilterMode.Any, // Pick up any messages, regardless of To address.
InstanceContextMode = InstanceContextMode.Single, // Singleton instance of this class.
ConcurrencyMode = ConcurrencyMode.Multiple, // Multiple callers at a time.
Namespace = "http://me.logging/services/2012/11")]
public class LoggingDeadLetterService : ILog
{
public void LogApplication(ApplicationLog entry)
{
LogToEventLog(entry);
}
}
My queue is transactional and authenticated. I have net.msmq included as enabled protocols both on the Services site and on the Logging application, and I added a net.msmq binding to the Services site. If I have the binding information as appdev.me.com, I get the following error when browsing to http://appdev.me.com/Logging/LogDeadLetterService.svc (appdev.me.com is setup in my HOSTS file):
An error occurred while opening the queue:Access is denied. (-1072824283, 0xc00e0025).
If I have the binding information as localhost, I get the following error:
An error occurred while opening the queue:The queue does not exist or you do not have sufficient permissions to perform the operation. (-1072824317, 0xc00e0003).
No matter which way I have it set up, the service isn't picking up the dead letter, as it's still in the queue and not in my event log.
Now, I realize that both of these reference a permissions issue. However, in the interest of getting the code part of this tested before figuring out the authentication piece, I have given Full Control to everyone I could think of - to include Everyone, Authenticated Users, NETWORK SERVICE, IIS_USERS, ANONYMOUS LOGON, and myself. (The app pool is running as me.)
Any help as to how to get my service to be able to pull from this queue would be phenomenal. Thanks!
EDIT: According to this MSDN blog entry, 0xC00E0003 corresponds to MQ_ERROR_QUEUE_NOT_FOUND, and 0xc00e0025 corresponds to MQ_ERROR_ACCESS_DENIED, so it looks like I want to have the binding information as appdev.me.com. However, that still doesn't resolve the apparent permissions issue occurring.
EDIT2: It works if I host the service in a console app and provide the following endpoint:
<endpoint address="net.msmq://localhost/private/Services/Logging/LogDeadLetterService.svc"
binding="netMsmqBinding"
bindingNamespace="http://me.logging/services/2012/11"
contract="Me.Logging.Service.Shared.Service.Contracts.ILog" />
So what's going on differently in the console app than is going on in IIS? I'm pretty confident, due to EDIT above, that I'm hitting the queue. So why can't I get into it?
EDIT3: Changed Services/Logging/LogDeadLetterService.svc to Logging/LogDeadLetterService.svc per the advice given here, but no change.
//
[Bonus question: Do I need to handle poison messages in my dead letter queue?]
So, three things needed to be changed:
The binding does have to be localhost.
The queue has to be named Logging/LogDeadLetterService.svc to be found - it's the application and the service, not the site, application, and service.
I had something messed up with the application pool - I have no idea what it was, but using a different app pool worked, so I backed out all of my service-related changes and then recreated everything, and it works.
Well, that was a lot of banging my head against my desk for something as simple as "don't mess up your app pool."

WCF service inside an MVC-app that uses msmqIntegrationBinding does not receive messages from msmq

I have a MVC-app that has a controller with an action that is supposed to expose data from the latest message in a queue (msmq). I have added a private queue on my local machine. I want the application to automatically receive a message from the queue when one is added. For this i am using msmqIntegrationBinding on a WCF-service that has been added to the application. The method that takes the message in the contract i then supposed to save the message in the application cache so that it can be accessed when a client asks for the latest data.
The challenge I now face is that when I add a message to the queue, it's not being picked up by the WCF-service. I need guidance at what I might be doing wrong or feedback on my approach. Please help.
The following is the endpoint-config for the WCF-service:
<bindings>
<msmqIntegrationBinding>
<binding name="MsmqBinding">
<security mode="None" />
</binding>
</msmqIntegrationBinding>
</bindings>
<services>
<service name="TestApp.Web.Service.QueueMessageReceiver">
<endpoint address="msmq.formatname:DIRECT=OS:.\private$\testsmessagequeue"
binding="msmqIntegrationBinding"
bindingConfiguration="MsmqBinding"
contract="TestApp.Web.Service.IQueueMessageReceiver" />
</service>
</services>
And the following code is from the QueueMessageReceiver.cs WCF-service:
public class QueueMessageReceiver : IQueueMessageReceiver
{
private static readonly XmlSerializer Serializer = new XmlSerializer(typeof(ScrewInfoModel));
[OperationBehavior(TransactionScopeRequired = true, TransactionAutoComplete = true)]
public void PutScrewInfoMessage(System.ServiceModel.MsmqIntegration.MsmqMessage<System.Xml.XmlDocument> msg)
{
CacheScrewInfoModelFromScrewInfoXmlDoc(msg.Body);
}
private static void CacheScrewInfoModelFromScrewInfoXmlDoc(XmlNode screwInfoXmlDoc)
{
var reader = new StringReader(screwInfoXmlDoc.InnerXml);
var screwInfoModel = (ScrewInfoModel)Serializer.Deserialize(reader);
Common.Utils.CacheScrewInfo(screwInfoModel);
}
}
And here is the Interface for the WCF:
[ServiceContract]
public interface IQueueMessageReceiver
{
[OperationContract(IsOneWay = true, Action = "*")]
void PutScrewInfoMessage(MsmqMessage<XmlDocument> msg);
}
Try changing your operation contract to
void PutScrewInfoMessage(MsmqMessage<string> msg);
It's possible that the WCF stack is having difficulty with the deserialization to XmlDocument.
UPDATE
Things to try:
Make suer your queue "testsmessagequeue" have the correct permissions set. In this case the service account running the app pool hosting your controller needs to have the "Receive Message" permissions set.
Enable MSMQ logging (if you're on windows 2008 server or windows 7 and above) which can be found in Event Viewer under: Applications and Services Logs -> Microsoft -> Windows -> MSMQ -> End2End. This will capture everything that happens in MSMQ including any errors.
Try making the queue transactional (if it not already). This will ensure that an error condition will exist on message non-delivery.
Enable WCF tracing on your service endpoint to see any specific WCF errors happening with the dequeuing of the message.
UPDATE 2
I think the problem is queue permissions. Your app pool is running under the user ApplicationPoolIdentity (if it's running under the .net 4.0 app pool). The user which corresponds to this identity is called DefaultAppPool. You need to give this user receive message permissions on the queue. To select this user search for a local account called IIS AppPool\DefaultAppPool in the Select Users dialogue.
UPDATE 3
It just struck me that IIS is not an appropriate hosting container for a queue listener. The reason for this is that the app pool unloads after a period of inactivity. This is controlled by IIS and is not configurable. (see here)
I think you should create a new hosting container in a windows service (you can use a console host to spike this) to host the queue endpoint. The windows service will run under an actual service account so granting permissions will be less complicated.
This service can write either write directly into the cache, or if this is not possible, should write to a DB where the website controller can refresh the cache from.
Does this make sense?
UPDATE 4
Poison message means that the message cannot be dequeued because of some problem with it. Check the system queue called Transactional Dead Letter Queue and see if your message is in there.

WCF and MsmqBinding to remote private queue

We have a WCF log service that uses MsmqBinding and WAS. The issue is that I try to use it from remote computer and that message seems to never reach the destination queue. Here are the facts :
Server config
List item
destination machine name : logserver.domain.ext
destination queue : private$/logservice.svc (journaling enabled)
security on the queue : everyone : full control, NETWORK SERVICE : Full Control
IgnoreOSNameValidation registry key : set
Client config
client endpoint address : logserver.domain.ext/private/logservice.svc
Observed behaviour
the output queue is well created ans has status Connected and 0 message wainting
if I pause the output queue, I see messages appearing and then desapearing when resume the queue
no message can be seen in the remote queue or the journal
and the worth is :
var queue = new MessageQueue(#"FormatName:DIRECT=OS:logserver.domain.ext\private$\logservice.svc");
queue.Send("hello");
works !
You do not mention permissions for the ANONYMOUS LOGON account. This is the account that remote private queue access will happen under if you are not explicitly using Windows security on the binding.
I was facing the same issue, and it turned out that the issue was with Distributed Transaction Coordinator configuration. This MSDN document helped me solve it.