One Way WCF Contract, MSMQ and Throwing Exceptions - wcf

I created a WCF service contract that works against MSMQ. Since it is MSMQ, I use one-way communication:
[OperationContract(IsOneWay = true)]
In my service implementation, I have OperationBehavior to automatically commit transactions:
[OperationBehavior(TransactionAutoComplete = true, TransactionScopeRequired = true)]
This makes sure WCF handles any exceptions by putting the message on a retry queue (per my configuration). It seems odd to be throwing an exception from a one-way operation. Is this the correct way to tell WCF not to commit the transaction?

After some research, I found that throwing an exception is the only way to tell WCF to use the built-in retry sub-queue. This exception is swallowed by WCF. It is also used to make sure the transaction isn't auto-completed.

Related

WCF duplex scenario - notifying server of client errors

In a client server WCF duplex scenario, what is the recommended way to let the server know that an error occurred on the client side? Let's say that the server notifies one of the clients that it needs to perform a certain operation and an exception is being thrown on the client side.
On the callback interface, I have something like this
[OperationContract(IsOneWay = true)]
void Work(...);
What's the best approach:
Implement a NotifyServer(int clientId, string message) message that the client can call to let the user know that the requested operation failed,
If I set IsOneWay = false on the operation contract, would I have to call every client on a BackgroundWorker thread in order to keep the UI responsive?
Implementing async operations on the server? How will this work? I can generate async operation on the client, will I have to use the same pattern (BeginWork, EndWork) for the client callback method?
Can't think of anything else, because throwing a FaultException on the client side when IsOneWay = true will not work.
Any advice?
Thank you in advance!
Ad 1. That is one way of doing it... recommended if the Work() may take unpredictable amount of time and you do not want your server thread hanging on that call.
Ad 2. You should always perform WCF operations in the background worker and never inside the UI thread.. If you set IsOneWay=False then obviously Work() method will block on the server until it has finished executing on the remote client and returns results. However even if you set isOneWay=true the method will still block on the low-level WCF communication. If WCF connection is dropped, this can be a long time, before you get notified.
Ad 3.
The pattern is up to you.
Example: MSDN: OperationContractAttribute.AsyncPattern Property
No best solution exists. It all depends on your setup (classes, threads, etc). The WCF layer you code should be easy and convenient to use - that is the main guide line.

Setting up MSMQ in a WCF application to ensure reliable mail delivery

So I have been tasked with setting up MSMQ so that if our mail server goes down (which is seems to often) the messages just end up in the Queue and will be delivered when they come back up. With that said I have to say I don't know much about this except what I have learned in the past 24 hours however I believe I know enough to take the right approach but I wanted to ask someone in the community because there is some confusion amongst my colleagues given some existing setup in our WCF application.
Currently we have some services that use msmq as the protocol for the endpoint. the endpoint looks like this
<endpoint address="net.msmq://localhost/private/Publisher"
behaviorConfiguration="BatchBehaviour"
binding="netMsmqBinding"
bindingConfiguration="MSMQNoSecurity"
contract="HumanArc.Compass.Shared.Publisher.Interfaces.Service.IPublisherSubscriber"
name="PublishSubscriber"/>
This of course lets the client make a service call and if for some reason the service wasn't up it will ensure that when the service comes back up the call will be processed. What I don't think that it will do is if you have something like the following in you service method.
try
{
smtp.Send(mail);
return true;
}
catch (System.Net.Mail.SmtpFailedRecipientException ex)
{
throw new Exception("User Credentials for sending the Email are Invalid",ex);
}
catch (System.Net.Mail.SmtpException smtpEx)
{
throw new Exception(string.Format("Application encountered a problem send a mail message to {0} ", smtpHostName),smtpEx);
}
WCF isn't going to retry and send the message again somehow, am I correct about this assumption?
What I think we should have is something that looks like the following in place of the call to smtp.send() above. (from http://www.bowu.org/it/microsoft/net/email-asp-net-mvc-msmq-2.html)
string queuePath = #".\private$\WebsiteEmails";
MessageQueue msgQ;
//if this queue doesn't exist we will create it
if(!MessageQueue.Exists(queuePath))
MessageQueue.Create(queuePath);
msgQ = new MessageQueue(queuePath);
msgQ.Formatter = new BinaryMessageFormatter();
msgQ.Send(msg);
Then somewhere in the startup of the service (I am not sure where yet) we set up an event handler that will actually call send() on the SmtpClient object. Something like this
msgQ.ReceiveCompleted += new ReceiveCompletedEventHandler(msgQ_ReceiveCompleted)
So to sum it all up my first question is which way is better? Create a service that uses net:msmq as the protocol or just change the email method to put messages in the queue and set up a handler for it? The next question, if my assumption about changing the method that calls SmtpClient.Send() is correct then where in the program should I wire up ReceiveCompleted? Out WCF service is hosted in a windows service, meaning there is actually a call to ServiceBase.Run(servicesToRun). Is there a place I could wire it up there? My experience with WCF is with much simpler IIS hosted services so I am not 100% sure.
Thanks - I realize this is a long question but I have been trying to research it and there is a lot of information and I can't seem to find a clear explanation of the benefits of doing things one way vs another.
Your approach to using msmq to address availability in a downstream dependency (in this case your smtp server) is valid. However, there are a couple of things you should understand about msmq first.
If you create a queue in msmq then by default it is non-transactional. In this mode the queue will not provide the kind of guaranteed delivery semantic you require. So create your queues as transactional.
Then you can tell WCF that your service operation will enlist in the transaction when it receives a message for processing. You do this by defining a behavior on your service operation implementation:
[OperationBehavior(TransactionScopeRequired = true, TransactionAutoComplete = true)]
public void SendEmail(Something mail)
{
....
smtp.Send(mail);
}
TransactionScopeRequired tells WCF that the service operation should enlist in the same transaction used to transmit the message from sender to receiver. TransactionAutoComplete states that the service method should commit the transaction once the operation has successfully completed. So in answer to your query above, a failure in the service operation will cause the transaction to rollback.
What happens at this point depends on your service bindings configuration.
<netMsmqBinding>
<binding name="netMsmqBinding_IMyServiceInterface"
exactlyOnce="true"
maxRetryCycles="3"
retryCycleDelay="00:01:00"
receiveErrorHandling="Move"> <-- this defines behavior after failure
...
</binding>
</netMsmqBinding>
When, for whatever reason the transaction is not committed (for example, an unhandled exception occurs), WCF will roll the message back onto the queue and retry processing once per minute up to 3 times (defined by maxRetryCycles and retryCycleDelay).
If the message still fails processing after this time then the receiveErrorHandling attribute tells WCF what to do next (The above binding specifies that the message be moved to the system poison message queue).
Note: exactlyOnce tells WCF that we require transactions, that each message will be delivered exactly once and in the order they were sent.
So your original approach is in fact correct and you just need to configure your service correctly to implement the behavior you want.

WPF Client - Should I make calls to WCF service in background thread?

I have a WPF client that makes calls to 2 WCF services.
One service is for querying only and one service is for commands (CQS pattern).
How should I make the calls to the commands service ?
I read somewhere that all the operations in the command service must be 'One-Way',
because they should not return any values. And that if something went wrong - the operation should throw a 'FaultException' to the client.
But if the commands are all One-Way - what do I do in the client ?
Say I have an 'AddProduct' window in the WPF client, and I enter information and press 'Save'.
I now call 'AddProduct(Product)' in the service, but :
Should it close the window ?
Should it wait for 10 seconds to see if there wasn't any FaultException ?
Should the operation not be 'One-Way' ? If so - should all operations in the command service return some type of generic 'Result' object with 'succeeded' or 'failed' ?
If section 3 is 'Yes' - should I call the service in a seperate thread and 'disable' all the controls on the window until I get a response back from the service ?
Thanks.
I would say option 3 is the way to go, but you probably do not need the generic Result object to communicate errors to the client. As you might know, exceptions are not serialized in the SOAP message so you won't get any of the usual .NET exceptions on the client side. On the other hand, you can still take advantage of SOAP Faults by catching FaultException on the client. Accordingly, if no exceptions were caught on the client, then everything went well.
For more information about fault exceptions and how you can use them to your benefit, take a look at:
Specifying and Handling Faults in Contracts and Services
I think using On-Way is fine but you have to be aware of some one-way call characteristic. If you care and can handle service exceptions then #4 is fine option.
One Way message - Once the client issues the call, WCF generates the request message but no correlated message will be ever returned to the client. Any exceptions thrown on the service side will not make it to the client.
One thing that you should have on is the reliability on your service so side so that you can insure that request has been delivered to the service.
When there is no transport session (basic or wsHttp binding) if exception occurs during the call of one-way operation client will be unaffected and it can continue sending calls on the same proxy instance.
If there is a presence of transport session - service side exception will fault the channel hence client will not be able to re-use proxy for sending more calls. This can give you an option to discover if something went wrong on the server side (but not what went wrong). Although, if service is using a FaultContracts you can still get into situation where client is unaware that something went wrong.
When service throws an exception listed in service side fault contract this will not fault the communication channel hence the client using one-way contract cannot detect communication failure.

Calling WCF with netMsmqBinding inside TransactionScope stopping transaction

I have a WCF logging service that runs operates over MSMQ. Items are logged to a Sql Server 2005 database. Every functions correctly if used outside a TransactionScope. When used inside a TransactionScope instance the call always causes the transaction to be aborted. Message = "The transaction has aborted".
What do I need to do to get this call to work inside a Transaction? Is it even possible. I've read that for a client transaction to flow across a service boundary the binding must support transaction flow, which immediately limits the bindings to only NetNamedPipeBinding, NetTcpBinding, WSHttpBinding, WSDualHttpBinding and WSFederationHttpBinding.
I'm not intimately knowledgeable about MSMQ, but there's a really good blog post series by Tom Hollander on MSMQ, IIS and WCF: Getting them to play nicely - in part 3 which is the link provided Tom talks about getting transactional.
MSMQ can be transactional - or not. And in WCF, you can decorate both the service contract as well as individual operation contracts (methods) with transaction-related attributes, such as whether to allow, disallow, or require a transaction context.
As far as I understand, in your setup, you don't want the MSMQ part to be transactional - but you should be able to use it even if an ambient transaction is present. In this case, you need to add the TransactionFlow="ALlowed" to your operation contract like this:
[ServiceContract]
public interface ILoggingService
{
[OperationContract]
[TransactionFlow(TransactionFlowOption.Allowed)]
void LogData(......);
}
That should do it!
Marc
Sorry for the needless question...
I have solved my problem. I needed to place
[TransactionFlow(TransactionFlowOption.Allowed)]
on the operation in the service contract and then
[OperationBehavior(TransactionScopeRequired=true)]
on the implementation of the contract (the service itself).
Works a treat.

How to make WCF service using nettcpbinding reconnect automaticlly?

I have an asynchronous WCF service using nettcpbinding. And I send a bunch of requests to it and get result by invoking EndDoWork() in my callback. If EndDonWork throw a exception once, all the invocation after that will throw exception said: communication object, System.ServiceModel.Channels.ServiceChannel, cannot be used for communication because it is in the Faulted state.
I think that's something close the connection because of the first exception. My question is:
1. what decide this behavior? If I use basicHttpBinding, the later invocation of EndDoWork work well. Is it related with keepAlive support?
2. Is there any property of configuration item I can set to ask service reconnect automatically?
The Faulted state of the channel indicates that it cannot be relied on any more. You did not mention what the reason was why the exception was thrown (connectivity, server stopped etc), but as far as WCF is concerned the endpoint is invalid and therefore faulted.
You should recreate the channel and connect to the service again to continue any of your operations. If you use features like Reliable connections then some of the work may be done for you, but if the channel is eventually faulted, the same rules apply.
You will also have to implement your own message queue to re-request messages that were pending when the channel faulted. You cannot rely on the channel to keep and resend the messages.
If I remember correctly, you can avoid the channel faulting if you declare the Fault in the operation contract.
For example:
[ServiceContract]
public interface IService
{
[OperationContract]
[FaultContract(typeof(MyDefinedFault))]
void Operation();
}
As you have already declared MyDefinedFault in the Operation contract if you throw that from the service, the channel is not going to fault (unless of course you are using the System.ServiceModel.Description.ServiceDebugBehavior.IncludeExceptionDetailInFaults=true that may fault the channel anyways).
Where is the MyDefinedFault class.
how to define this class.