MSMQ: Does MSMQ guarantees sequential message passing? - c#

After load testing, I found some packets are not sequential.
it's a basic WCF service and client is continuously sending the request.

It is possible to have guaranteed (in-order, exactly-once) delivery using netMsmqBinding.
The first thing you need to do is to create your actual MSMQ message queue transactional.
Secondly, you must tell WCF to enlist in the transaction like so:
[OperationBehavior(TransactionScopeRequired = true, TransactionAutoComplete = true)]
public void Handle(Something msg)
{
....
}
Lastly, you need to specify guaranteed behavior of the service by using the exactlyOnce binding paramter:
<netMsmqBinding>
<binding name="netMsmqBinding_IMyServiceInterface"
exactlyOnce="true">
...
</binding>
</netMsmqBinding>
ExactlyOnce tells WCF that we require transactions, that each message will be delivered exactly once and in the order they were sent.

Related

Handle NormalizePoisonException in MSMQ Integration Binding

Good evening,
I have an MSMQ queue that is pushing messages to a WCF service using msmqIntegrationBinding.
The receiveErrorHandling property is set to the default of "Fault".
Occasionally, MSMQ has a hissy fit trying to deserialise a message:
System.ServiceModel.ProtocolException: An error was encountered while deserializing the message. The message cannot be received.
System.Runtime.Serialization.SerializationException: An error occurred while deserializing an MSMQ message's XML body. The message cannot be received. Ensure that the service contract is decorated with appropriate [ServiceKnownType] attributes or the TargetSerializationTypes property is set on the MsmqIntegrationBindingElement.
at System.ServiceModel.Channels.MsmqDecodeHelper.XmlDeserializeForIntegration(MsmqIntegrationChannelListener listener, Stream stream, Int64 lookupId)
at System.ServiceModel.Channels.MsmqDecodeHelper.DeserializeForIntegration(MsmqIntegrationChannelListener listener, Stream bodyStream, MsmqIntegrationMessageProperty property, Int64 lookupId)
The message never reaches the method in the service:
[OperationBehavior(TransactionScopeRequired = true, TransactionAutoComplete = true)]
public void ProcessMessage(MsmqMessage<MyMessage> msg)
{...
The service has this attribute:
[ServiceKnownType(typeof(MyMessage))]
There is a dead letter queue set in the binding:
<msmqIntegrationBinding>
<binding name="MyBinding" serializationFormat="Xml" exactlyOnce="false" deadLetterQueue="Custom" customDeadLetterQueue="msmq.formatname:DIRECT=OS:.\private$\services/deadLetterQueue" useMsmqTracing="true" receiveErrorHandling="Fault">
The message is not processed by the WCF service and is dumped straight into the Journal queue. It is not left in the Messaging queue or moved to the dead letter queue.
I have tried implementing an IErrorHandler as detailed here but it doesn't reach it.
When receiving a message from MSMQ in the traditional way...
MessageQueue msMq = new MessageQueue(_queueName);
msMq.Formatter = new XmlMessageFormatter(new Type[] { typeof(MyMessage) });
Message m = msMq.Receive();
It works if I set the formatter as above. But when despite serializationFormat="Xml" being set in the binding, it still fails to deserialise.
I've missed something for sure. I've Googled everywhere. Any help is greatly appreciated.
Thanks.
After some intense Googling I came across two issues:
1) If you want transactions in MSMQ to work, make sure that whoever setup the queue made it a transactional queue when they created it. (Sigh..)
2) In the IErrorHandler example, I wasn't concentrating with my copying and pasting (Less coffee, more sleep) and put the ApplyDispatchBehavior logic into Validate by mistake, where no ChannelDispatchers exist yet (Extra sigh...).
foreach (ChannelDispatcherBase channelDispatcherBase in serviceHostBase.ChannelDispatchers)
{
ChannelDispatcher channelDispatcher = channelDispatcherBase as ChannelDispatcher;
channelDispatcher.ErrorHandlers.Add(errorHandler);
}
What a kerfluffle!

Can I throw a message fault back to a WCF client from a routing service

My company has long used ASPX and windows services through a routing program to manage the connections and allow our datacenters to control where the clients make connections.
Just recently we started using MVC and WCF. Yes in 2015 we are just moving to these things. Anyway they figured out about a month before release they need to route the WCF traffic because of where it sits outside the firewall or in the DMZ.
We will be putting the routing service inside the network and opening a port on a firewall that way all services can communicate protected by the firewall on the routing service.
The only reason I have given all these details is because this sets up the expectations for how our WCF service is configured. We are using certificates for security and message encryption as we must send our messages encrypted. We are also adding a custom header that our router will use to route the messages.
What we have working is our router receives the message, inspects the header, finds if we have an endpoint, forwards the message, gets the response and sends it back to the WCF service. Currently that is all working beautifully. We can even receive the messagefault from the endpoint and send it back to the client.
What I am struggling with is how the router can send a messageFault back to the client when the fault originates in the router. But because my router doesn't know how to encrypt the message this fault is being sent back unencrypted. The faults beings things like "endpoint unreachable" or "no endpoint found". The client receives these faults with the error:
An unsecured or incorrectly secured fault was received from the other party.
See the inner FaultException for the fault code and detail.
With the inner exception being what I defined in my code below.
Dim fe As FaultException = New FaultException(status)
Dim fault As MessageFault = fe.CreateMessageFault()
Dim msg = System.ServiceModel.Channels.Message.CreateMessage(getMessageVersion, fault, getAction)
getMessageVersion will return Soap11 or Soap12 depending on the client
getAction is returning the action from the client request in the header.
Is there a way to configure the clients to accept these faults even though they aren't encrypted? We would like to catch them as Fault Exceptions not as Exceptions to keep our Fault Exception logic together for general Faults.
Any help or insight would be appreciated. Our newer programs are using C# our older ones are still written in VB, so throw whatever .Net code at me you are comfortable with and I'll use it.
Here are the Fault class:
[Serializable]
[System.Xml.Serialization.XmlTypeAttribute(AnonymousType = true, Namespace = "yourNamespace")]
[System.Xml.Serialization.XmlRootAttribute(Namespace = "yourNamespace")]
[System.Runtime.Serialization.DataContractAttribute(Namespace = "yourNamespace")]
public class CustomFault : ISerializable
{
public string Message { get; set; }
}
Here is the interface and operating method referencing the Fault:
[ServiceContract(Namespace = "yourNamespace")]
public interface IService
{
[FaultContractAttribute(
typeof(CustomFault),
Action = "",
Name = "Fault",
Namespace = "yourNamespace")]
[System.ServiceModel.XmlSerializerFormatAttribute(SupportFaults = true)]
[OperationContract]
Response Operation(Request request);
}
And finally how I throw the Fault:
throw new FaultException<CustomFault>
(
new GuiaMedicoFault("Custom Error description"),
new FaultReason("Error description")
);
Maybe some piece of this code can help you or give any ideas.
Using Ricardo's information I was able to narrow down what I was doing. The actual answer to this is entirely up to the Endpoint configuration. It is dependent on your binding.
We didn't have to change any thing in the router, but we had to change the client it looks like this.
serviceClient.Endpoint.Binding = getWSHttpBinding();
Then it should be
private CustomBinding getWSHttpBinding()
{
WSHttpBinding binding = new WSHttpBinding();
binding.Security.Mode = SecurityMode.Message;
binding.Security.Message.EstablishSecurityContext = false;
binding.Security.Message.NegotiateServiceCredential = false;
binding.Security.Message.ClientCredentialType = MessageCredentialType.Certificate;
binding.MaxReceivedMessageSize = (1024 * 1024 * 10);
BindingElementCollection elements = binding.CreateBindingElements();
elements.Find<SecurityBindingElement>().EnableUnsecuredResponse = true;
return new CustomBinding(elements);
}
this link has further information if you see this problem. https://support.microsoft.com/en-us/kb/971493
We will probably just handle this as an exception rather than a fault.

Catch-22 prevents streamed TCP WCF service securable by WIF; ruining my Christmas, mental health

I have a requirement to secure a streamed WCF net.tcp service endpoint using WIF. It should authenticate incoming calls against our token server. The service is streamed because it is designed to transfer large amounts of data n stuff.
This appears to be impossible. And if I can't get around the catch, my Christmas will be ruined and I'll drink myself to death in a gutter while merry shoppers step over my slowly cooling body. Totes serious, you guys.
Why is this impossible? Here's the Catch-22.
On the client, I need to create a channel with the GenericXmlSecurityToken I get from our token server. No problemo.
// people around here hate the Framework Design Guidelines.
var token = Authentication.Current._Token;
var service = base.ChannelFactory.CreateChannelWithIssuedToken(token);
return service.Derp();
Did I say "no problemo"? Problemo. In fact, NullReferenceException style problemo.
"Bro, " I asked the Framework, "do you even null check?" The Framework was silent, so I disassembled and found that
((IChannel)(object)tChannel).
GetProperty<ChannelParameterCollection>().
Add(federatedClientCredentialsParameter);
was the source of the exception, and that the GetProperty call was returning null. So, WTF? Turns out that if I turn on Message security and set the client credential type to IssuedToken then this property now exists in the ClientFactory (protip: There is no "SetProperty" equivalent in IChannel, the bastard).
<binding name="OMGWTFLOL22" transferMode="Streamed" >
<security mode="Message">
<message clientCredentialType="IssuedToken"/>
</security>
</binding>
Sweet. No more NREs. However, now my client is faulted at birth (still love him, tho). Digging through WCF diagnostics (protip: make your worst enemies do this after crushing them and driving them before you but right before enjoying the lamentations of their women and children), I see it's because of a security mismatch between the server and client.
The requested upgrade is not supported by 'net.tcp://localhost:49627/MyService'. This could be due to mismatched bindings (for example security enabled on the client and not on the server).
Checking the host's diags (again: crush, drive, read logs, enjoy lamentations), I see this is true
Protocol Type application/ssl-tls was sent to a service that does not support that type of upgrade.
"Well, self," I says, "I'll just turn on Message security on the host!" And I do. If you want to know what it looks like, it's an exact copy of the client config. Look up.
Result: Kaboom.
The binding ('NetTcpBinding','http://tempuri.org/') supports streaming which cannot be configured together with message level security. Consider choosing a different transfer mode or choosing the transport level security.
So, my host cannot be both streamed and secured via tokens. Catch-22.
tl;dr: How can I secure a streamed net.tcp WCF endpoint using WIF???
WCF has gotchas in a few areas with streaming (I'm looking at you, MTOM1) due to a fundamental issue in how it fails to perform preauthentication the way most people would think that should work (it only affects subsequent requests for that channel, not the first request) Ok, so this is not exactly your issue but please follow along as I will get to yours at the end. Normally the HTTP challenge works like this:
client hits server anonymously
server says, sorry, 401, I need authentication
client hits server with authentication token
server accepts.
Now, if you ever try to enable MTOM streaming on an WCF endpoint on the server, it will not complain. But, when you configure it on the client proxy (as you should, they must match bindings) it will explode in a fiery death. The reason for this is that the above sequence of events that WCF is trying to prevent is this:
client streams 100MB file to server anonymously in a single POST
server says sorry, 401, I need authentication
client again streams 100MB file to server with an authentication header
server accepts.
Notice that you just sent 200MB to the server when you only needed to send 100MB. Well, this is the problem. The answer is to send the authentication on the first attempt but this is not possible in WCF without writing a custom behaviour. Anyway, I digress.
Your Problem
First up, let me tell you that what you're trying is impossible2. Now, in order for you to stop spinning your wheels, let me tell you why:
It strikes me that you are now wandering in a similar class of problem. If you enable message level security, the client must load the entire stream of data into memory before it can actually close out the message with the usual hash function and xml signature required by ws-security. If it has to read the entire stream to sign the single message (which is not really a message, but it's a single continuous stream) then you can see the problem here. WCF will have to stream it once "locally" to compute the message security, then stream it again to send it to the server. This is clearly a silly thing, so WCF does not permit message level security for streaming data.
So, the simple answer here is that you should send the token either as a parameter to the initial web service, or as a SOAP header and use a custom behaviour to validate it. You cannot use WS-Security to do this. Frankly, this is not just a WCF issue - I cannot see how it could practically work for any other stacks.
Solving the MTOM Problem
This is just for an example how I solved my MTOM streaming issue for basic authentication, so perhaps you could take the guts of this and implement something similar for your issue. The crux of it is that in order to enable your custom message inspector, you have to disable all notion of security on the client proxy (it remains enabled on the server,) apart from transport level (SSL):
this._contentService.Endpoint.Behaviors.Add(
new BasicAuthenticationBehavior(
username: this.Settings.HttpUser,
password: this.Settings.HttpPass));
var binding = (BasicHttpBinding)this._contentService.Endpoint.Binding;
binding.Security.Mode = BasicHttpSecurityMode.Transport; // SSL only
binding.Security.Transport.ClientCredentialType =
HttpClientCredentialType.None; // Do not provide
Note that I have turned off transport security here because I will be providing that myself using a message inspector and custom behaviour:
internal class BasicAuthenticationBehavior : IEndpointBehavior
{
private readonly string _username;
private readonly string _password;
public BasicAuthenticationBehavior(string username, string password)
{
this._username = username;
this._password = password;
}
public void AddBindingParameters(ServiceEndpoint endpoint,
BindingParameterCollection bindingParameters) { }
public void ApplyClientBehavior(ServiceEndpoint endpoint,
ClientRuntime clientRuntime)
{
var inspector = new BasicAuthenticationInspector(
this._username, this._password);
clientRuntime.MessageInspectors.Add(inspector);
}
public void ApplyDispatchBehavior(ServiceEndpoint endpoint,
EndpointDispatcher endpointDispatcher) { }
public void Validate(ServiceEndpoint endpoint) { }
}
internal class BasicAuthenticationInspector : IClientMessageInspector
{
private readonly string _username;
private readonly string _password;
public BasicAuthenticationInspector(string username, string password)
{
this._username = username;
this._password = password;
}
public void AfterReceiveReply(ref Message reply,
object correlationState) { }
public object BeforeSendRequest(ref Message request,
IClientChannel channel)
{
// we add the headers manually rather than using credentials
// due to proxying issues, and with the 101-continue http verb
var authInfo = Convert.ToBase64String(
Encoding.Default.GetBytes(this._username + ":" + this._password));
var messageProperty = new HttpRequestMessageProperty();
messageProperty.Headers.Add("Authorization", "Basic " + authInfo);
request.Properties[HttpRequestMessageProperty.Name] = messageProperty;
return null;
}
}
So, this example is for anyone who is suffering with the MTOM issue, but also as a skeleton for you to implement something similar to authenticate your token generated by the primary WIF-secured token service.
Hope this helps.
(1) Large Data and Streaming
(2) Message Security in WCF (see "disadvantages.")

Can you ensure delivery with one-way service methods?

Say I have a proxy that sends a message to a WCF server:
NetNamedPipeBinding b = new NetNamedPipeBinding(NetNamedPipeSecurityMode.None);
b.MaxConnections = 1000000;
EndpointAddress address = new EndpointAddress(#"net.pipe://sendmessage");
channelFactory = new ChannelFactory<ISendMessage>(b, address);
proxy = channelFactory.CreateChannel();
proxy.SendMessage("Hello, world.");
Say the SendMessage function has a one-way OperationContract:
[OperationContract(IsOneWay=true)]
void SendMessage(string message);
Does running the line of code, proxy.SendMessage("Hello, world."); guarantee delivery of the message to the server? If not by default, is there a way to guarantee delivery? Say my application crashes, and it crashes right after proxy.SendMessage("Hello, world."); runs, will the message have made it to the server assuming no network glitches?
One-way operation ensures that your request is queued on service side. The main difference from request-reply operation is that client unblocks immediately after the server got the message without waiting for operation dispatching. Therefore, there is no way to know operation result, exceptions thrown or even the fact that operation was invoked.
You can read details here
http://msdn.microsoft.com/en-us/magazine/cc163537.aspx#S1

How to broadcast (push) a message send by one client, to all clients through a server using WCF NetHttpBinding (WebSockets)?

In .NET 4.5 a new WCF binding- NetHttpBinding- has been introduced which uses WebSocket protocol as it's underlying transport. Which implies that this enables a true push from server. Now, I have been able to make some sort of push using A callback contract like this:
[ServiceBehavior(ConcurrencyMode = ConcurrencyMode.Multiple)]
public class WebSocketSampleService : IDuplexContract
{
public string SayHelloDuplex()
{
//push to the current caller
OperationContext.Current.
GetCallbackChannel<IDuplexCallbackContract>().
SayingHello("Hello from WebSockets");
//answer the current caller in the regular http way
return "Hello";
}
}
[ServiceContract(CallbackContract=typeof(IDuplexCallbackContract))]
public interface IDuplexContract
{
[OperationContract]
string SayHelloDuplex(string name);
}
[ServiceContract]
public interface IDuplexCallbackContract
{
[OperationContract]
void SayingHello(string message);
}
What I would like to do though, is to broadcast the message to all clients when a single client calls the method SayHelloDuplex(). Is there a way to access the callback channels of all clients? Or should I record the callback channels of all the clients for later use in some other method (E.g. Connect())? Perhaps I'm tackling this problem in the wrong way?
Any help will be appreciated. Thanks
Callback channel is unique per client, so there is no way to access the callback channel of all clients.
Instead you should save the callback channel for each client in a list or even better in a dictionary so you can target specific client.
Then when you want to broadcast a message to all clients just go over the list.

Categories