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

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.

Related

NServiceBus: Auditing endpoints on different servers

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?

Rhino ESB publish/subscribe backend

I have 2 applications, Desktop app the clients use, Win Service that does the backend processing. I want to be able to trigger the backend processing via a message using Rhino Service Bus. This message may come from the client app, it may come from the win service, I don't really care who triggers it. So I need pub sub. The problem is that I can trigger it just fine from my console app, when I try to trigger from my service I get an error there are no subscribers for the message. What is wrong in my configs?
Console app.config
<rhino.esb>
<bus threadCount="1" numberOfRetries="5" endpoint="msmq://localhost/console.debug" />
<messages>
<add name="MyMessages" endpoint="msmq://localhost/host.debug" />
</messages>
Win Service app.config
<rhino.esb>
<bus threadCount="1" numberOfRetries="5" endpoint="msmq://localhost/host.debug" />
<messages />
The code for sending a message is the same in both apps:
private IServiceBus _serviceBus;
....
public void Trigger()
{
_serviceBus.Publish(new myTriggerCommand());
}
So it seems RSB is unable to handle publishing messages to itself. I found this blog for publishing and consuming in the same process, which appears to be a reasonable solution. However, in the end I opted just to not use messaging for triggering within the host.
http://blog.irm.se/blogs/eric/archive/2011/06/19/Consuming-Events-in-the-Same-Process-as-the-Publisher-with-Rhino-Service-Bus.aspx

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."

Impersonating caller prevents connection to database (not an obvious permissions issue)

I have a web service hosted in IIS running under a domain account which also has permissions to a SQL Server. All the users mentioned below have access to this SQL Server.
Here is a fragment of the service config:
<basicHttpBinding>
<binding name="SecureWebBinding">
<security mode="TransportCredentialOnly">
<transport clientCredentialType="Windows" />
... etc.
During a particular service method, I make one call to the database as the service account and wish to make another as the user who called the service (we are returning a FILESTREAM transaction context created by the calling user - these are user-specific). The first call completes but the second is wrapped as follows:
using (ServiceSecurityContext.Current.Impersonate())
{
using (var connection = new SqlConnection(...Integrated Security = true...)
{
connection.Open(); //<---Exception
After the call to Impersonate, WindowsIdentity.GetCurrent() correctly returns the calling user rather than the service account with ImpersonationLevel == Identification.
If I remove the first 2 lines, the operation completes as the identity of the service account. Of course the later call to FILESTREAM subsequently fails.
You need to setup an SPN for the server to DB as its using kerberos when you are impersonating. But it depends on the error message you are getting. This resource should help you, although im still running into issues for a similar process, but your process seems like it should work with this:
http://blogs.msdn.com/b/sql_protocols/archive/2006/12/02/understanding-kerberos-and-ntlm-authentication-in-sql-server-connections.aspx

Delay invoking method in WCF web service - the first time

I have a WCF Web Service Framework 4 that exposes a very simple method for authentication in BasicHttpBinding
Nothing special:
[ServiceContract]
public interface IAutorizedUser
{
[OperationContract
GetAuthentication bool (string UserName, string Password
}
The problem is that when I call that method from a remote pc, before the response I have a delay of 20 seconds, the first time. The cause is not the code inside the method: even if I comment completely that code, I have the same delay. From the second time then, the method is invoked normally and quickly.
Other html pages hosted in that server are quick.
If the call of the method starts from the server hosting the web service, there's no problem. With other remote pcs in our office lan, the problem always occurs, with the only exception of another server, where the delay is limited to 5 seconds.
I realize that the terms of the problem are very generics, but instinctively I think that the issue may reside in some WCF settings. What do you think? Could you help me?
Thank you in advance,
Pileggi
The problem is useDefaultWebProxy in the client web.config, I had to set it to false:
<basicHttpBinding>
<binding name="pippo" ... useDefaultWebProxy="false">
...
Now my problems are here:
Visual Studio "Add Service Reference" - not gets all service settings
and here:
Set useDefaultWebProxy=false on WCF Client with the Web-References
Pileggi