WCF Named pipe message size problems - wcf

I am trying to get working a WCF named pipe communication between two processes on the same computer (on XP), but I am having trouble with "large" messages disappearing. The messages that disappear contain a largish byte array and I have narrowed the failure down to when the array is around 16k in size. Smaller than that and the message gets through. Larger than that and the sender says it went fine but it is never received. I have tried bumping up the buffer sizes on both sender and receiver as per this code for the server:
PipeServer pipeServer = new PipeServer();
ServiceHost serviceHost = new ServiceHost(pipeServer, new Uri[] { new Uri(baseName) });
NetNamedPipeBinding netNamedPipeBinding = new NetNamedPipeBinding();
netNamedPipeBinding.MaxBufferPoolSize = 5000000;
netNamedPipeBinding.MaxBufferSize = 500000;
netNamedPipeBinding.MaxReceivedMessageSize = 500000;
serviceHost.AddServiceEndpoint(typeof(ISSNPipeServer), netNamedPipeBinding, pipeName);
and this code for the client:
_callbacks = new PipeClientCallbacks();
NetNamedPipeBinding netNamedPipeBinding = new NetNamedPipeBinding();
netNamedPipeBinding.MaxBufferPoolSize = 5000000;
netNamedPipeBinding.MaxBufferSize = 500000;
netNamedPipeBinding.MaxReceivedMessageSize = 500000;
_pipeFactory = new DuplexChannelFactory<ISSNPipeServer>(_callbacks,
netNamedPipeBinding,
new EndpointAddress(_targetPipe));
_pipeProxy = _pipeFactory.CreateChannel();
I am eventually looking to transfer arrays in the 60KB size, but this is my first serious WCF experience and I have no idea even where to really start looking.

You can enable WCF tracing on the server to get more information as to what the failure is. Likely, you still need to increase the reader quotas associated with the binding (NetNamedPipeBinding.ReaderQuotas). Check the MaxArrayLength one in particular.

Related

How to increase the timeout values for a WCF service in a dot net core 2.1 project

I am posting this because I was unable to find any place on Stack Overflow that addresses this issue for a .Net-Core project utilizing WCF by adding the service reference through Connected Services.
My issue was that I was facing client side timeouts because of long running operation requests.
So, how does one increase the timeout values for the wcf client objects since .Net-Core no longer uses the web config to store the configuration values for the WCF service references? (Please see my provided answer)
Under Connected Services in Solution Explorer, after adding a WCF service, a few files are generated for that service. You should see a folder with the name you gave the WCF service reference and under that a Getting Started, ConnectedService.json and a Reference.cs file.
To increase any of the client service object's timeout values, open Reference.cs and locate method: GetBindingForEndpoint
Inside this method you should see something like this:
if ((endpointConfiguration == EndpointConfiguration.BasicHttpBinding_IYourService))
{
System.ServiceModel.BasicHttpBinding result = new System.ServiceModel.BasicHttpBinding();
result.MaxBufferSize = int.MaxValue;
result.ReaderQuotas = System.Xml.XmlDictionaryReaderQuotas.Max;
result.MaxReceivedMessageSize = int.MaxValue;
result.AllowCookies = true;
//Here's where you can set the timeout values
result.SendTimeout = new System.TimeSpan(0, 5, 0);
result.ReceiveTimeout = new System.TimeSpan(0, 5, 0);
return result;
}
Just use result. and the timeout you want to increase like SendTimeout, ReceiveTimeout, etc. and set it to a new TimeSpan with the desired timeout value.
I hope this proves to be a useful post to someone.
Answer by Ryan Wilson will work but only until you will try to update service. Reference.cs will be overwritten.
In .NET Core 3.1 you can grammatically modify binding timeouts:
public MemoqTMServiceClass(string api_key)
{
client = new TMServiceClient();
var eab = new EndpointAddressBuilder(client.Endpoint.Address);
eab.Headers.Add(
AddressHeader.CreateAddressHeader("ApiKey", // Header Name
string.Empty, // Namespace
api_key)); // Header Value
client.Endpoint.Address = eab.ToEndpointAddress();
client.Endpoint.Binding.CloseTimeout = new TimeSpan(2, 0, 0);
client.Endpoint.Binding.OpenTimeout = new TimeSpan(2, 0, 0);
client.Endpoint.Binding.ReceiveTimeout = new TimeSpan(0, 10, 0);
client.Endpoint.Binding.SendTimeout = new TimeSpan(0, 10, 0);
}
Just implement the following partial method in the generated proxy class to configure the service endpoint. Place the partial method in your own file to make sure it will not be overwritten.
static partial void ConfigureEndpoint(System.ServiceModel.Description.ServiceEndpoint serviceEndpoint, System.ServiceModel.Description.ClientCredentials clientCredentials);

WCF streaming SQLFileStream by Message Contract

In my WCF service, I try to load a File from MS SQL table which has a FileStream column and I try to pass it as a stream back
responseMsg.DocSqlFileStream = new MemoryStream();
try
{
using (FileStreamDBEntities dbEntity = new FileStreamDBEntities())
{
...
using (TransactionScope x = new TransactionScope())
{
string sqlCmdStr = "SELECT dcraDocFile.PathName() AS InternalPath, GET_FILESTREAM_TRANSACTION_CONTEXT() AS TransactionContext FROM dcraDocument WHERE dcraDocFileID={0}";
var docFileStreamInfo = dbEntity.Database.SqlQuery<DocFileStreamPath>(sqlCmdStr, new object[] { docEntity.dcraDocFileID.ToString() }).First();
SqlFileStream sqlFS = new SqlFileStream(docFileStreamInfo.InternalPath, docFileStreamInfo.TransactionContext, FileAccess.Read);
sqlFS.CopyTo(responseMsg.DocSqlFileStream);
if( responseMsg.DocSqlFileStream.Length > 0 )
responseMsg.DocSqlFileStream.Position = 0;
x.Complete();
}
}
...
I'm wondering whats the best way to pass the SQLFileStream back through a message contract back to take advantage of streaming. Currently I copied the SQLFilEStream to a memory stream because I got an error message in WCF trace which says: Type 'System.Data.SqlTypes.SqlFileStream' cannot be serialized.
In WebApi there is such thing as PushStreamContent it allows delegating all transaction stuff to async lambda, don't know if there is something similar in WCF, but the following approach may be helpful:
http://weblogs.asp.net/andresv/archive/2012/12/12/asynchronous-streaming-in-asp-net-webapi.aspx
You can't stream an SQLFileStream back to the client because it can only be read within the SQL transaction. I think your solution with the MemoryStream is a good way of dealing with the problem.
I had a similar problem and was worried about the large object heap when using a new Memory Stream every time. I came up with the idea of using a temporary file on the disk instead of a memory stream. We are using this solution in several project now and it works really well.
See here for the example code:
https://stackoverflow.com/a/11307324/173711

How to send canvas image large size from silverlight to WCF service

I have a large size byte[] formed from silverlight Canvas using following code
var img = new WriteableBitmap(cnvControlHolder, null);
var outStream = new MemoryStream();
EncodeJpeg(img, outStream);
Now I want to send this to WCF service to form image from this byte array & save it as an image on server side so that I can consume it in SSRS. My problem is as the byte[] is big I get the classic Method not found from WCF service.
I read in few links that WCF streaming would be one option, but could not find any sample on the net. My service method is like this:
public bool Upload(Stream image)
{
FileStream fileStream = null;
BinaryWriter writer = null;
var filePath = HttpContext.Current.Server.MapPath(".") + #"\" +
ConfigurationManager.AppSettings["PictureUploadDirectory"] + #"\Diagram.jpeg";// +image.ImageName;
if (image!=null)
{
//return ByteArrayToFile(filePath, image.Imagestream);
fileStream = File.Open(filePath, FileMode.Create);
writer = new BinaryWriter(fileStream);
writer.Write("Diagram.jpeg");
}
return false;
}
and client call is this :
var img = new WriteableBitmap(canvas1, null);
var outStream = new MemoryStream();
EncodeJpeg(img, outStream); //custom library to compress into jpeg
var client = new Service1Client();
client.UploadCompleted += new EventHandler<UploadCompletedEventArgs>(client_UploadCompleted);
client.UploadAsync(outStream.ToArray());
Can somebody suggest some sample or any other solution to fix my issue.
I recently implemented a very similar solution in Silverlight. The solution involves:
Dividing the large byte[] into n chunks of size that can be sent via a web service call
Making a web call to the service, registering a file upload request for n chunks, and requesting a guid from the service.
Making n web calls to the service and uploading each chunk, supplying the guid and the ordinal of the chunk (the chunks may arrive out of sequence).
Once the server receives all n chunks, it combines the chunks and writes the data into a file.
I hope this can help to get you started.

WCF namedpipe callback timeout exception

I am using WCF for sending and getting data to and from 2 different win form applications running in the same machine. I am using namedpipe and duplexchannel. My client side implementation is shown below.
InstanceContext myContext = new InstanceContext(this);
NetNamedPipeBinding nb = new NetNamedPipeBinding();
nb.MaxBufferPoolSize = 5000000;
nb.MaxBufferSize = 500000;
nb.MaxReceivedMessageSize = 500000;
nb.ReceiveTimeout = TimeSpan.FromMinutes(5);
DuplexChannelFactory<IService> myProxy = new DuplexChannelFactory<IService>(myContext, nb, new EndPointAddress("net.pipe://localhost/MyService"));
IService myServiceClient = myProxy.CreateChannel();
And Server side implementation is shown below:
NetNamedPipeBinding np = new NetNamedPipeBinding();
np.MaxBufferPoolSize = 5000000;
np.MaxBufferSize = 500000;
np.MaxReceivedMessageSize = 500000;
host.AddServiceEndpoint(typeof(IService), np, "net.pipe://localhost/MyService");
host.OpenTimeout = TimeSpan.FromMinutes(5);
host.CloseTimeout = TimeSpan.FromMinutes(5);
host.Open();
I can pass about 100 object collection (ObservableCollection<Customer>) from 1 application through callback to other app. But if I make it 1000 or greater objects, the following Timeout Exception error occurs.
The write to the pipe did not complete
within the allotted timeout of
00:00:00. The time allotted to this
operation may have been a portion of a
longer timeout.
What is the fault in my code ? Please help me to overcome this issue.
Thanks in advance...
Looks like this question was also asked and answered here:
http://social.msdn.microsoft.com/Forums/eu/wcf/thread/38926593-8ea6-481d-8c43-072b73292f6a

Hold TcpClient Connection with WCF

Hallo
I need a Tcp connection to a server alive in backgrond and applications will send data with this connection.I searched around and found WCF singleton is apporiate for this task
here is a code snippet that i use below
my question is that the good way and any problem can be with this?
string hostAddress = string.Empty;
try
{
srvHost = new ServiceHost(typeof(ControllerClass));
NetTcpBinding netTcpBinding = new NetTcpBinding(SecurityMode.None);
netTcpBinding.Security.Message.ClientCredentialType = MessageCredentialType.None;
netTcpBinding.Security.Transport.ProtectionLevel = System.Net.Security.ProtectionLevel.None;
netTcpBinding.Security.Transport.ClientCredentialType = TcpClientCredentialType.None;
srvHost.AddServiceEndpoint(typeof(IControllerContract), netTcpBinding, hostAddress);
srvHost.Credentials.WindowsAuthentication.AllowAnonymousLogons = true;
ServiceThrottlingBehavior serviceThrottlingBehavior = new ServiceThrottlingBehavior();
serviceThrottlingBehavior.MaxConcurrentCalls = 1000;
serviceThrottlingBehavior.MaxConcurrentInstances = 1000;
serviceThrottlingBehavior.MaxConcurrentSessions = 1000;
srvHost.Description.Behaviors.Add(serviceThrottlingBehavior);
srvHost.Open();
}
catch (System.TimeoutException timeoutEx)
{
Thread.Sleep(1000);
ReOpenHostConnection();//initialize again Controller Class
}
catch (Exception ex)
{
Trace.WriteLine(string.Format("cannot start Service Ex:{0}", ex.ToString()), TraceEventType.Error.ToString());
}
//Controller Class Initialize Code Snippet
TcpClient iTcpClient = new TcpClient();
iTcpClient.Connect(serverIP, serverPort);
networkStream = iTcpClient.GetStream();
aSychDataByte = new byte[iTcpClient.ReceiveBufferSize];
networkStream.BeginRead(aSychDataByte, 0, incommTcpClient.ReceiveBufferSize, ReadAsych, null);
Why do you combine TcpClient with WCF? If you need low level Tcp communication build client and server based on low level Tcp classes. If you need service and you don't bother with message formats use WCF.
For your problem. You don't need singleton. You just need the connection to be opened. For this you need to create WCF proxy instance (open channel) on the client and call the service. It will create connection to service instance wich will live until you close the client proxy, until your service host stops working or until timeout (10 minutes of client inactivity by default).