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."
Related
I have a WCF Web Service hosted in a Windows Service.
The service is configured using the following attributes (VB)
<ServiceBehavior(ConcurrencyMode:=ConcurrencyMode.Multiple,
InstanceContextMode:=InstanceContextMode.PerCall,
UseSynchronizationContext:=False)>
I created a test client, which creates 50 threads at once and and I am starting them straight away, all querying an operation on the WCF Service. The first 30 or so openings (client.open()) work, but afterwards I get an error message on my client that the opening couldn't be done because there was a timeout while trying to open the service and thus I get an EndPointNotFoundException. (The operationss I am calling are all synchronous if that matters.)
Can I expect that sort of behaviour and thus simply have to live with these exceptions or do I have to look at some of my settings, either the above, or any other settings? (I am using a NetTcpBinding.)
What I see is that the client works on the request of the at once created threads simultaneously, so the above settings have the desired effect of making the service multi-user-at-the-same-time-enabled.
But ideally I wouldn't get timeout exceptions. Rather I would want the clients to wait longer to get their response than to time out.
Any ideas?
Thanks all!
Check settings such as these:
<behavior name="CommonServices_Behavior">
<serviceThrottling maxConcurrentCalls="100" maxConcurrentSessions="50"
maxConcurrentInstances="50" />
</behavior>
I seem to recall that some of these values have defaults set in your machine.config file. There is also a MaxConnections value to check for NetTcpBinding.
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
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.
I have a service I am trying to consume in a unit test. At this point I'm just trying to instantiate the thing. After suffering the "Could not find default endpoint element that references contract" error for hours and unable to figure it out, I completely deleted out the consumer and started from scratch. All I did was add a service reference to my test project, point it at my service, hit "GO" and that's it. Still doesn't work. I didn't touch a line of code, yet it doesn't work right after I let VS build the thing.
Here is the relevant line in my app.config for the test project:
<client>
<endpoint address="http://mike-laptop/kbs/FFEDI/Service.svc"
binding="basicHttpBinding" bindingConfiguration="BasicHttpBinding_IEdiService"
contract="ServiceReference2.IEdiService" name="BasicHttpBinding_IEdiService" />
</client>
In my unit test, here is my method:
public void CreateWebServiceInstance()
{
ServiceReference2.EdiServiceClient webService = new ServiceReference2.EdiServiceClient();
string svcAddress = webService.Endpoint.Address.ToString();
Console.WriteLine("Address is: " + svcAddress);
Assert.IsTrue(svcAddress.Equals("http://mike-laptop/kbs/FFEDI/Service.svc")); // test
}
The error I get is:
System.InvalidOperationException:
Could not find default endpoint
element that references contract
'ServiceReference2.IEdiService' in the
ServiceModel client configuration
section. This might be because no
configuration file was found for your
application, or because no endpoint
element matching this contract could
be found in the client element.
Again, I didn't change anything this time. Any ideas?
Is the service hosted in IIS? Can you hit it in a browser? Do you have a <binding name="BasicHttpBinding_IEdiService">... in your config? Did you try passing the binding config name into the constructor?
Seems fine at first sight to me... some ideas to check / ponder / verify:
does your test project's app.config get read at all? E.g. is it being interpreted at all? Is there a TestProject.exe.config in your bin\debug directory? I'm thinking maybe the test runner might be playing some tricks and not reading the config at all.
or what happens if you specify the name of the client endpoint when creating your service client?
ServiceReference2.EdiServiceClient webService =
new ServiceReference2.EdiServiceClient("BasicHttpBinding_IEdiService");
Does that change anything at all?
My silverlight application loads data fromt he SQL fine when I build locally but when I upload it to the live site it will just wait for data to be loaded but show no errors. It worked up until yesterday where I fear I may have changed a setting somewhere and now I cant access the data it seems?
UPDATE 1: it seems to be a problem with the service references. Everytime I update them, it will clear the ServiceReferences.ClientConfig file and then the program wont build.
UPDATE 2: I have tried cleaning and building but still the same problem.
UPDATE 3: Found an error when trying to access the service reference on the live site:
This collection already contains an address with scheme http. There can be at most one address per scheme in this collection.
Parameter name: item
Description: An unhandled exception occurred during the execution of the current web request. Please review the stack trace for more information about the error and where it originated in the code.
Exception Details: System.ArgumentException: This collection already contains an address with scheme http. There can be at most one address per scheme in this collection.
Parameter name: item
It sounds like your application is waiting for something, does it time out after 30 seconds? If so, check your SQL connection string.
If there is another tier between Silverlight and SQL (such as a web service), then set up a connection test to make sure that Silverlight is actually reaching SQL...
Did you accidentally replace your live web.config file? If so, try restoring the old web.config as it may have a setting that's not compatable with your server.
Re: Update 1:
Is there an error? If so please paste it. Also please paste the config file in question on pastebin and link to it from here.
Re: Update 3:
The error "This collection already contains an address with scheme http." is caused by not telling a WCF service explicitly what address you wish to bind to when there are many to chosoe from. In this case it looks like IIS is using multiple URLs, for example, consider these fictional addresses:
www.mysite.com
mysite.com
... so the WCF service has no idea which to use unless you tell it.
The solution, to this is to explictly define what URL to use with the following config lines in the web.config (within the system.serviceModel node) of your WCF service.
<serviceHostingEnvironment aspNetCompatibilityEnabled="true">
<baseAddressPrefixFilters>
<add prefix="http://www.mysite.com/SomeDirectory/MyService" />
</baseAddressPrefixFilters>
</serviceHostingEnvironment>
Important:
You should update your question title to indicate that WCF is involved in the solution you have created.