I am trying to put together a prototype using Nservicebus using the unobtrusive mode by defining custom conventions. I started trying to run my endpoint in the NServicebus host but had no luck with it picking up a message that I publish. I took the Unobtrusive sample application available from Nservicebus and replaced its contents with my messages and handlers. It appears to detect the messages based on convention (I see it in the console output when the app is running), but does not appear to register for those messages based on the handlers I have in the Server application. I don't see the message being put in the queue and I cannot see an active or inactive endpoint in service pulse either when the application is running.
I have tried many different "fixes" and have scoured the internet, stack overflow, and the Nservicebus documentation and have not found any information to point me in the right direction.
Here is my server endpoint config:
BusConfiguration busConfiguration = new BusConfiguration();
busConfiguration.EnableInstallers();
busConfiguration.UsePersistence<InMemoryPersistence>();
busConfiguration.UseDataBus<FileShareDataBus>()
.BasePath(#"..\..\..\DataBusShare\");
busConfiguration.RijndaelEncryptionService();
busConfiguration.ApplyCustomConventions();
using (IBus bus = Bus.Create(busConfiguration).Start())
{
Console.WriteLine("Press any key to exit.");
Console.ReadKey();
}
public static void ApplyCustomConventions(this BusConfiguration busConfiguration)
{
ConventionsBuilder conventions = busConfiguration.Conventions();
conventions.DefiningCommandsAs(t => t.Namespace != null && t.Namespace.EndsWith("Commands"));
conventions.DefiningEventsAs(t => t.Namespace != null && t.Namespace.EndsWith("Events"));
conventions.DefiningMessagesAs(t => t.Namespace != null && t.Namespace == "Messages");
conventions.DefiningEncryptedPropertiesAs(p => p.Name.StartsWith("Encrypted"));
//conventions.DefiningDataBusPropertiesAs(p => p.Name.EndsWith("DataBus"));
conventions.DefiningExpressMessagesAs(t => t.Name.EndsWith("Express"));
conventions
.DefiningTimeToBeReceivedAs(t => t.Name.EndsWith("Expires")
? TimeSpan.FromSeconds(30)
: TimeSpan.MaxValue
);
}
The ApplyCustomConventions method is shared between my message publisher and the Server endpoint.
Here is my Server endpoint .exe app.config:
<configuration>
<configSections>
<section name="RijndaelEncryptionServiceConfig" type="NServiceBus.Config.RijndaelEncryptionServiceConfig, NServiceBus.Core"/>
</configSections>
<RijndaelEncryptionServiceConfig Key="gdDbqRpqdRbTs3mhdZh8qCaDaxJXl+e7"/>
</configuration>
There is no error on publish and the message is never received.
Update: I have narrowed this down to it not working when i try to publish events and the endpoint will not subscribe unless I do an endpoint mapping. Furthermore, even after I publish an event with the endpoint mapping in place it is still not picked up by my endpoint handlers.
I have a questions here. In the unobtrusive example from Particular it does not set up any endpoint mappings to be able to send commands and messages, it sets up a endpoint based on the assembly name. Does this not work with events and publish? I took the unobtrusive example and put one event message in Messages.dll, and added one handler for that event in the Server.exe, and changed the Client.exe to be able to publish that event and it does not work.
I will try to post my code somewhere when i get a chance. Thanks guys.
When running an endpoint with unobtrusive mode, make sure you are doing the definitions in both the sender and receiver.
Also, post some of your endpoint configuration code here, that might help troubleshooting.
Do you get any errors when doing the send at the receiving endpoint? Much of the time some type of error is thrown that can help troubleshoot this.
I noticed that in your app.config you do not have the endpoint mappings defined. This is needed on both the "frontend" and "backend" projects to route the messages to right spot. Here is a snippet of what mine is for an application called "myapplication":
<UnicastBusConfig>
<MessageEndpointMappings>
<add Messages="myapplication.Commands" Endpoint="myapplication.Backend" />
</MessageEndpointMappings>
</UnicastBusConfig>
More information about this can be found here: http://docs.particular.net/nservicebus/messaging/specify-message-destination
Both endpoints will require the unobtrusive mappings. The subscriber endpoint should be configured to subscribe to the messages. See here for how to configure the subscriber:
http://docs.particular.net/nservicebus/messaging/publish-subscribe/configuration
The App.config will looks something like this for your subscriber:
<?xml version="1.0" encoding="utf-8"?>
<configuration>
<configSections>
<section name="UnicastBusConfig" type="NServiceBus.Config.UnicastBusConfig, NServiceBus.Core"/>
</configSections>
<UnicastBusConfig>
<MessageEndpointMappings>
<add Assembly="Shared" Endpoint="Samples.PubSub.MyPublisher"/>
</MessageEndpointMappings>
</UnicastBusConfig>
</configuration>
Related
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
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."
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'm trying to get an error message when I try to register a component in Castle Windsor that points to WCF Service that has errors in the configuration. For registering the component I'm using:
container.Register(Component.For<MembershipService>().ImplementedBy<MembershipServiceClient>.LifeStyle.Transient);
The configuration file has the following two entries (bindings points to a non existing file):
<?xml version="1.0" encoding="utf-8" ?>
<configuration>
<system.serviceModel>
<bindings configSource="Configs\local\nonexistingbindingfile.xml"/>
<client configSource="Configs\local\system.serviceModel.client.xml"/>
</system.serviceModel>
</configuration>
What happens is that Castle won't fail registering my component but it won't resolve MembershipService for any dependency of other components, it would set the property as null, but at this point I don't have any error logs that points to the file with the problem and troubleshooting becomes very hard.
Thanks.
If a valid instance is essential then I believe it should be done via Constructor injection rather than Property injection. This way Castle will throw if it can't resolve.
I've got a duplex WCF service which hangs after the magic 10 proxy instantiations. The specific error on the client is:
"System.TimeoutException: This request operation sent to net.tcp://localhost:8080/RoomService/netTcp did not receive a reply within the configured timeout (00:00:59.9960000)".
There aren't any apparent error messages on the server.
Note that this isn't the standard, obvious problem, i.e., failing to close my proxy connections, as I'm closing every instance of my proxy connection appropriately before opening the next one:
try
{
client.Close();
}
catch (CommunicationException)
{
client.Abort();
}
catch (TimeoutException)
{
client.Abort();
}
catch (Exception)
{
client.Abort();
throw;
}
And I've set my throttling behavior to 500 simultaneous everything:
ServiceThrottlingBehavior throttlingBehavior = new ServiceThrottlingBehavior()
{
MaxConcurrentCalls = 500,
MaxConcurrentSessions = 500,
MaxConcurrentInstances = 500
};
I've set the ConcurrencyMode of my service to Multiple, and I've tried all three possible values for InstanceContextMode.
[ServiceBehavior(InstanceContextMode=InstanceContextMode.PerSession, ConcurrencyMode = ConcurrencyMode.Multiple)]
I've tried self-hosting the service, and hosting it within IIS, and I get the same results on each.
I've tried the NetTcpBinding, the WSDualHttpBinding, and the PollingDuplexBinding (on Silverlight), with the same results on each. I can't try the BasicHttpBinding or the WSHttpBinding, as this is a duplex service.
There was one place in my code where I was launching multiple threads (to execute multiple callbacks simultaneously), but for troubleshooting purposes I've commented that bit out, and it hasn't made a difference.
On the client, I've tried using new proxies for each test, and reusing the same proxy across all tests, but without any luck. I've tried creating a new InstanceContext for each proxy, and reusing the same InstanceContext across all proxies, and again, no luck.
Whatever I do, after the 10th test executed in my test harness, the next call to the service hangs.
Any thoughts on what I might be doing wrong?
OK, so I made at least one stupid mistake: I was creating the throttling behavior, but was neglecting to add it to the service proper. It's now added correctly:
ServiceThrottlingBehavior throttlingBehavior = new ServiceThrottlingBehavior()
{
MaxConcurrentCalls = 500,
MaxConcurrentSessions = 500,
MaxConcurrentInstances = 500
};
base.Description.Behaviors.Add(throttlingBehavior);
And now I can run more than 10 tests, and hence my immediate problem is solved.
But I'm still puzzled as to why I'm running into this problem at all, since I'm specifically closing one proxy before moving on to the next. A MaxConcurrentXXX of 2 ought to be working in this scenario; I shouldn't need a MaxConcurrentXXX of 500. I'm a tad worried about scalability if every client that connects to the server continues to chew up a connection beyond the time that it's actually connected.
Maybe I'm making a stupid mistake somewhere else -- it wouldn't be the first time -- but I've specifically stepped through the code that's closing the proxy, and it's definitely getting called.
I've had this happen when I had a semaphore on the server-side which wasn't being released after a client was done being serviced.
Are any server-side resources or locks not being released properly? Since your service instance is per session, I'd suspect that the server object is hanging around and holding a lock. What if you change the behavior to per call?
I don't have an answer but I do have some debugging advice.
1) Attach the visual studio debugger to the service process and see if it can catch whatever is going on.
2) Configure the service behavior to pass exception information back to the client and see if the service is throwing an exception that isn't being reported:
<behaviors>
<serviceBehaviors>
<behavior name="ServiceBehavior">
<serviceDebug includeExceptionDetailInFaults="True"/>
</behavior>
</serviceBehaviors>
</behaviors>
3) Turn on service logging with ActivityTracing enabled and use the Service Trace Viewer (from Windows SDK) to analyze the log and see if anything pops up
<system.diagnostics>
<trace autoflush="true" />
<sources>
<source name="System.ServiceModel" switchValue="Information, ActivityTracing" propagateActivity="true">
<listeners>
<add name="sdt" type="System.Diagnostics.XmlWriterTraceListener" initializeData="Service.svclog" />
</listeners>
</source>
</sources>
</system.diagnostics>
4) Isolate the service wrapper from the functional code and see if the service still hangs. If it doesn't then incrementally add functionality back until you figure out what is making it hang
5) If you are using an HTTP binding, proxy the service with fiddler and log the http traffic.
6) Try Hosting the WCF service in a Managed Windows Service and attach a debugger to the service process after you start it up.
Take a look at ServiceBehavior.AutomaticSessionShutdown.
At the begining of the Callback function in the client use
OperationContext.Current.Channel.Close();
This will solev the problem.