Can you ensure delivery with one-way service methods? - c#

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

Related

When using Channels with SignalR server-to-client streaming, is the server-side Complete guaranteed to be delivered to the client?

I'm doing SignalR server-to-client streaming using System.Threading.Channel with a .NET client. The usage is fairly basic, similar to what is described in the introductory docs.
The hub code is similar to this:
public ChannelReader<byte[]> Retrieve(Guid id, CancellationToken cancellationToken)
{
var channel = Channel.CreateBounded<byte[]>(_limit);
_ = WriteItemsAsync(channel.Writer, id, cancellationToken);
return channel.Reader;
}
private async Task WriteItemsAsync(ChannelWriter<byte[]> writer, Guid id, CancellationToken cancellationToken)
{
Exception localException = null;
try
{
//loop and write to the ChannelWriter until finished
}
catch (Exception ex)
{
localException = ex;
}
finally
{
writer.Complete(localException);
}
}
And client similar to this:
var channel = await hubConnection.StreamAsChannelAsync<byte[]>("Retrieve", _guid, cancellationTokenSource.Token);
while (await channel.WaitToReadAsync())
{
while (channel.TryRead(out var data))
{
//handle data
}
}
When my hub method is done streaming, it calls Complete() on its ChannelWriter. SignalR, presumably, internally sees the Complete call on the corresponding ChannelReader, translates that into an internal SignalR message and delivers that to the client. The client's own ChannelReader is then marked as complete by SignalR and my client code wraps up its own work on the stream.
Is that "completed" notification, from server to client, guaranteed to be delivered? In other cases where the hub is broadcasting non-streaming messages to clients, it generally "fires and forgets", but I've got to assume that calling Complete on the streaming Channel has acknowledged delivery, otherwise the client could be in a state where it is holding a streaming ChannelReader open indefinitely while the server sees the stream as closed.
Less important to the question, but the reason I ask is that I am trying to narrow down just such a scenario where a data flow pipeline that consumes a SignalR streaming interface very occasionally hangs, and it seems that the only point where it is hanging is somewhere in the SignalR client.
I asked the devs over on github: https://github.com/dotnet/aspnetcore/issues/30128.
Here is a quick summary:
"Messages over SignalR are as reliable as TCP. Basically what this means is that either you get the message, or the connection closes. In both cases the channel on the client side will be completed."
And:
"Right it should never hang forever. It'll either send the complete message or disconnect. Either way, a hang would be a bug in the client"

Microsoft service bus - Receive messages from Bus with OnMessage() method

My application has to receive a message every time new message is posted. So I'm using OnMessage() method as mentioned in Microsoft documentation.
When new messages are posted the OnMessage() method does not seem to be working. To resolve this, I've placed the code into a separate task with infinite loop. This seems totally wrong.
public void ReceiveMessageFromSubscription(string topicName, string subscriptioName)
{
Task.Factory.StartNew(() =>
{
while (true)
{
SubscriptionClient Client = SubscriptionClient.CreateFromConnectionString(connectionString, topicName, subscriptionName);
Client.OnMessage((message) =>
{
try
{
var message = brokerMessage.GetBody<MessageDto>();
newMessage.AnnounceNewMessage(message);
message.Complete();
}
catch (Exception ex)
{
message.Abandon();
}
});
}
});
}
Whenever there is a message in Subscription the OnMessage() method has to be called. Can anyone please help me with this.
OnMessage API is an asynchronous process that receives messages in an event-driven message pump. It doesn't stop receiving until you either dispose the client or the code that is running it is terminated. The code above is wrong. You should not instantiate a subscription client in a tight loop and register your callback each time. What you should be doing is creating your client, registering a callback with a desired concurrency, and hold on to that client until you no longer need to receive messages.
Remember, it's a message pump that has to run all the time. Official documentation is a bit dry, perhaps this post will help.
In addition to that, I would strongly recommend not to use the legacy client WindowsAzure.ServiceBus which you're using. Instead, prefer the new Microsoft.Azure.ServiceBus client.

Timeout exception - c# ( wcf )

While I'm executing the server method asynchronously, getting this Timeout exception continuously.
"Additional information:
This request operation sent to http://schemas.microsoft.com/2005/12/ServiceModel/Addressing/Anonymous
did not receive a reply within the configured timeout (00:01:00).
The time allotted to this operation may have been a portion of a longer timeout.
This may be because the service is still processing the operation or
because the service was unable to send a reply message.
Please consider increasing the operation timeout
(by casting the channel/proxy to IContextChannel and setting the OperationTimeout property)
and ensure that the service is able to connect to the client."
Could someone mention how to increasing the operation timeout
by casting the channel/proxy to IContextChannel and setting the OperationTimeout property ?
This is my existing binding (with client) code.
DuplexChannelFactory<IPortal> datafactory;
NetTcpBinding tcpBinding = new NetTcpBinding();
String sURL = "net.tcp://localhost:8002/MyPortal";
tcpBinding.MaxReceivedMessageSize = System.Int32.MaxValue;
tcpBinding.ReaderQuotas.MaxArrayLength = System.Int32.MaxValue;
datafactory = new DuplexChannelFactory<IPortal>(this,tcpBinding, sURL);
Portal = datafactory.CreateChannel();
If you follow the link in the error (schemas.microsoft.com etc etc) it serves up:
Theresource you are looking for has been removed, had its name
changed, or is temporarily unavailable.
Why are you looking up MS? It sounds like you've got some config data wrong somewhere. If you search your source for that url, what do you find? Does it look sensible?

ClientBase EndPoint Binding SendTimeout ReceiveTimeout: how to change while debugging

I'm developing a solution with a WCF service and a client that uses the service. Sometimes I'm debugging the service, sometime the client, and sometimes both.
During debugging I get a TimeoutException with additional information
Additional information: The request channel timed out while waiting for a reply after 00:00:59.9950000. Increase the timeout value passed to the call to Request or increase the SendTimeout value on the Binding. The time allotted to this operation may have been a portion of a longer timeout.
The reason if of course that my server is waiting at a breakpoint instead of answering the question.
During debugging I want longer timeouts, preferably without creating a new configuration for my service client, because if other values of this configuration would change, the changer would have to remember that a special configuration for debugging was created.
I think it is something like:
private IMyServiceInterface CreateServiceChannel()
{
var myServiceClient = new MyServiceClient(); // reads from configuration file
if (Debugger.IsAttached)
{
// Increase timeouts to enable slow debugging
...
}
return (IMyServiceInterface)myServiceClient;
}
According to MSDN Binding.SendTimeout Property is used for something else:
SendTimeout gets or sets the interval of time provided for a write operation to complete before the transport raises an exception.
Therefore I'd rather not change this value if not needed.
Is SendTimeout really the best timeout to increase, or is there something like a TransactionTimeout, the timeout between my question and the receipt of the answer?
How to change the timeout programmatically
The article All WCF timouts explained states that indeed there is something like a transaction timeout: IContextChannel.OperationTimeout
The operation timeout covers the whole service call (sending the request, processing it and receiving a reply). In other words, it defines the maximum time a service call is active from a client’s point of view. If not set, WCF initializes the operation timeout with the configured send timeout.
This explains why the TimeoutException that is thrown advises to change the send timeout.
However, it is possible to change the operation timeout without changing the send timeout:
var myServiceClient = new MyServiceClient(); // reads from configuration file
if (Debugger.IsAttached)
{ // Increase timeouts to enable slow debugging:
IContextChannel contextChannel = (IContextChannel)myServiceClient.InnerChannel;
// InnerChannel is of type IClientChannel, which implements IContextChannel
// set the operation timeout to a long value, for example 3 minutes:
contextChannel.OperationTimeout = TimeSpan.FromMinutes(3);
}
return (IMyInterface)myService;

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