I have an application which is written in silverlight 3.0. It uses RIA services to communicate between the client and server.
My question doesn't seem to be answered very well on the web. The client communicates to the server using RIA services, which uses WCF behind the scenes. If the communication takes more than 60 seconds it times out with this message,
'Load operation failed for query 'ApplyUpgrade'. The HTTP requrest to 'http://localhost:52403/ClientBin/DatabaseUpgradeTool-Web-UpgradePackageDomainService.svc/binary' has exceeded the allotted timeout. The time allotted to this operation may have been a portion of a longer timeout.'
My server is performing a database upgrade, so it is valid for it to take more than 60 seconds. Probably double or triple that.
I tried settings like this in the web.config,
<services>
<service name="DatabaseUpgradeTool.Web.UpgradePackageDomainService">
<endpoint address="" binding="wsHttpBinding" contract="DatabaseUpgradeTool.Web.UpgradePackageDomainService"></endpoint>
<endpoint address="/soap" binding="basicHttpBinding" contract="DatabaseUpgradeTool.Web.UpgradePackageDomainService"></endpoint>
<endpoint address="/binary" binding="customBinding" bindingConfiguration="BinaryHttpBinding" contract="DatabaseUpgradeTool.Web.UpgradePackageDomainService"></endpoint>
</service>
</services>
<bindings>
<customBinding>
<binding name="BinaryHttpBinding"
receiveTimeout="00:00:10"
sendTimeout="00:00:10"
openTimeout="00:00:10"
closeTimeout="00:00:10">
<binaryMessageEncoding />
<httpTransport keepAliveEnabled="true"/>
</binding>
</customBinding>
</bindings>
Still no joy. Any ideas as to what is wrong with what I have tried above? I would expect the above to cause it to timeout within 10 seconds, not 60.
Thanks.
Not sure if this will help, I haven't tried it with time outs configurations, but it might point you in the right direction:
http://blogs.objectsharp.com/CS/blogs/dan/archive/2010/04/13/maxitemsinobjectgraph-wcf-ria-services-exception.aspx
I faced the same problem, I posted the answer to this question here: Silverlight 4 WCF RIA Service Timeout Problem
Here is the answer:
I'll explain my context and I wish it will work for my. I'm sure about that.
First of all to call RIA services, and using some domain context, in my example:
EmployeeDomainContext context = new EmployeeDomainContext();
InvokeOperation<bool> invokeOperation = context.GenerateTMEAccessByEmployee(1, 'Bob');
invokeOperation.Completed += (s, x) =>
{....};
Nothing new until here. And with this I was facing every time that same timeout exception after 1 minute. I spend quite a lot of time trying to face how to change the timeout definition, I tried all possible changes in Web.config and nothing. The solution was:
Create a CustomEmployeeDomainContext, that is a partial class localizated in the same path of the generated code and this class use the hook method OnCreate to change the behavior of created domain context. In this class you should wrote:
public partial class EmployeeDomainContext : DomainContext
{
partial void OnCreated()
{
PropertyInfo channelFactoryProperty = this.DomainClient.GetType().GetProperty("ChannelFactory");
if (channelFactoryProperty == null)
{
throw new InvalidOperationException(
"There is no 'ChannelFactory' property on the DomainClient.");
}
ChannelFactory factory = (ChannelFactory)channelFactoryProperty.GetValue(this.DomainClient, null);
factory.Endpoint.Binding.SendTimeout = new TimeSpan(0, 10, 0);
}
}
I looking forward for you feedback.
Related
I built a WCF service library and hosted it through a host application. Then I constructed a client application, but it seems that the address of the service host is hard coded in the client program. What if the host changes its address? Is it possible to write the client application so that the address of the host can be entered by the client at run time?
Yes, it's possible, if you write the WCF client proxy by hand, instead of generating it automatically with Visual Studio adding a service reference.
Let's start from this example (https://learn.microsoft.com/it-it/dotnet/framework/wcf/feature-details/how-to-use-the-channelfactory), just to understand how ChannelFactory works, and then modify it a little bit, adding the following function.
private ChannelFactory<IMath> _myChannelFactory;
// ...
private IMath GetChannel(string endpointConfigurationName, string endpointAddress)
{
if (_myChannelFactory == null)
{
this.DebugLog("Channel factory is null, creating new one");
if (String.IsNullOrEmpty(endpointAddress))
{
_myChannelFactory = new ChannelFactory<IMath>(endpointConfigurationName);
}
else
{
_myChannelFactory = new ChannelFactory<IMath>(endpointConfigurationName, new EndpointAddress(endpointAddress));
}
}
return _myChannelFactory.CreateChannel();
}
You can define the default server IP in the client App.config file
<system.serviceModel>
<!-- ... -->
<client>
<endpoint address="net.tcp://192.168.10.55:81/math/" binding="netTcpBinding"
bindingConfiguration="NetTcpBinding_IMath"
contract="MyNamespace.IMath" name="NetTcpBinding_IMath" />
</client>
</system.serviceModel>
In this way, when GetChannel("NetTcpBinding_IMath", "net.tcp://127.0.0.1:81/math") is called, it picks up the endpoint configuration from App.config file, replacing the default address (192.168.10.55) with the new one (127.0.0.1).
Some more documentation about ChannelFactory: https://learn.microsoft.com/en-us/dotnet/api/system.servicemodel.channelfactory-1.createchannel?view=netframework-4.8
I have one app (UWP - Win10) and a Windows service.
The service is running in background, and they were both developed in C#. "callAsync" is the method on the service. I am using await to call it on the client.
var obj = await callAsync(10);
The problem is:
If this call takes less than 1min40s (100 seconds), then everything works ok. But if it takes more than 1min40s, then an exception will occur "TaskCanceledException: A task was canceled".
I have search SO and the web but still could not find any indication on how to resolve this "timeout" issue. I have added all the "open/close/receive/send" timeout flags on both app and service app.config, although the exception that is thrown in that case is different.
If I try with a simple delay in the client:
await Task.delay(200000);
it works properly.
This service was added through VS2015 "Add Service Reference". I have also "attached" to the server and the server keeps running and prints in the console before and after logs (to confirm that everything is ok).
What am I missing? What configuration and where do I need to change so that the task can run for more than 1 minute and 40 seconds?
CODE:
Example of Server Pseudo-Code:
Interface File:
[ServiceContract(Namespace="http://.....")]
interface ICom {
[OperationContract]
int call(int val);
}
Service.cs
public ServiceHost serviceHost = null;
public BlaBlaWindowsService()
{
ServiceName = "BlaBlaWindowsService";
}
public static void Main()
{
ServiceBase.Run(new BlaBlaWindowsService());
}
protected override void OnStart(string[] args)
{
if (serviceHost != null)
{
serviceHost.Close();
}
serviceHost = new ServiceHost(typeof(BlaBlaService));
serviceHost.Open();
}
protected override void OnStop()
{
if (serviceHost != null)
{
serviceHost.Close();
serviceHost = null;
}
}
}
[RunInstaller(true)]
public class ProjectInstaller : Installer
{
private ServiceProcessInstaller process;
private ServiceInstaller service;
public ProjectInstaller()
{
process = new ServiceProcessInstaller();
process.Account = ServiceAccount.LocalSystem;
service = new ServiceInstaller();
service.ServiceName = "BlaBlaWindowsService";
Installers.Add(process);
Installers.Add(service);
}
}
BlaBlaService.cs
class TPAService : ITPAComunication {
public int call(int val) {
System.Threading.Thread.Sleep(200000)
return 0;
}
}
App.config file:
<?xml version="1.0" encoding="utf-8" ?>
<configuration>
<system.serviceModel>
<bindings>
<binding name="ServiceTimeout" closeTimeout="00:10:00" receiveTimeout="00:10:00" openTimeout="00:10:00" sendTimeout="00:10:00"/>
</bindings>
<services>
<service name="BlaBla.Service.Service"
behaviorConfiguration="ServiceBehavior">
<host>
<baseAddresses>
<add baseAddress="http://localhost:8000/BlaBla/service"/>
</baseAddresses>
</host>
<endpoint address=""
binding="basicHttpBinding"
bindingConfiguration="ServiceTimeout"
contract="BlaBla.Service.ICom" />
<endpoint address="mex"
binding="mexHttpBinding"
contract="IMetadataExchange" />
</service>
</services>
<behaviors>
<serviceBehaviors>
<behavior name="ServiceBehavior">
<serviceMetadata httpGetEnabled="true"/>
<serviceDebug includeExceptionDetailInFaults="False"/>
</behavior>
</serviceBehaviors>
</behaviors>
</system.serviceModel>
</configuration>
Example of App pseudo-code:
System.ServiceModel.EndpointAddress epa = new System.ServiceModel.EndpointAddress("http://localhost:8000/blabla/service");
System.ServiceModel.BasicHttpBinding bhb = new System.ServiceModel.BasicHttpBinding();
Timespan t = new TimeSpan(0, 10, 0);
bhb.SendTimeout = t; bhb.ReceiveTimeout =t; bhb.OpenTimeout = t; bhb.CloseTimeout = t;
Blabla.ComunicationClient com = new Blabla.ComunicationClient(bhb, epa);
var obj = await com.callAsync(int val);
return obj;
UPDATE #1
This situation only happens in UWP. I have created a similar WinForms project and everything works as expected. This means that it is probably something related to UWP.
After several tries, manipulating different config files, I have not found a solution regarding how to remove the timeout limitation of 100 seconds. To solve this specific problem, I implemented a counter-measure.
What I have found during my tries was:
If the project is in WinForms, everything works as expected. This means, this 100-second-limit, is an UWP "Feature";
If you reduce the SendTimeout to less than 100 seconds, it will throw a TimeoutException with the corresponding timer;
This is not exclusive to the Windows Service. It also happens when comunicating with a SOAP Webservice implementation;
This seems to happen only if you are doing a task the requires "external communication" with a service reference. If you have a "internal" task that takes more than 100 seconds, it works as expected (eg. await Task.delay(250000)).
How I solved this?
After chatting at C# SO channel, #Squiggle suggested a polling approach and that is what I implemented and tested successfully.
These are the steps I took:
I updated the existing service request (call(int val)) to accept a another argument, a Guid, so I could identify which request I wanted to do the "polling";
I created an additional request at the service to InquireAboutCurrentRequest that accepted also accepted a GUID parameter, and returned an int;
I updated the Service Reference at the UWP app with the new request;
I called "await call(val,guid)" with a try catch. I did this because 90% of these calls return in less than 30 seconds*;
In the catch I added an "If" that checked if the exception was a CancelTask, and if was I call "await InquireAboutCurrentRequest(guid)";
This method, at the windows service, keeps checking if the other operation has ended and sleeps every X seconds. Since the total time of the first call can only be at most 2 minutes, I only need to wait 20 seconds;
After that I will deal with the result accordingly, but at least this time I know I have "waited 2 minutes" for the response.
There are other possible solutions such as sockets, which I have not tried, that could work.
* If all the requests take more than 100 seconds, I suggest using the polling approach from the beginning of the requests, instead of waiting for the try/catch.
I'm not sure exactly - but may be better use Task.WhenAll instead of await ?
I have added a WCF service reference to Silverlight application and here's what the binding from web.config that I have looks like
<bindings>
<wsDualHttpBinding>
<binding name="wsDualHttpBinding">
<security mode="None" />
</binding>
</wsDualHttpBinding>
<pollingDuplexHttpBinding>
<binding name="multipleMessagesPerPollPollingDuplexHttpBinding"
duplexMode="MultipleMessagesPerPoll" />
</pollingDuplexHttpBinding>
</bindings>
And I have this snippet to create a service client instance
var serviceClient = new DuplexCallerIdServiceClient(
new PollingDuplexHttpBinding(PollingDuplexMode.MultipleMessagesPerPoll),
new EndpointAddress("http://localhost:51445/Service/MyService.svc"));
My concern is that why do I have to provide an absolute url in code. I have a winforms application that uses the same service and I can just do new DuplexCallerIdServiceClient() to create a service client instance which seems ideal. Is there any way I can work around it. I cannot change the binding settings.
Thanks
You do not have to hardcode the service URL. Replace the hard coded string that either is passed in as an argument or makes a function call (or gets some object's property) to populate the constructor with a valid service URL.
Here's one way among many:
var serviceClient = new DuplexCallerIdServiceClient(
new PollingDuplexHttpBinding(PollingDuplexMode.MultipleMessagesPerPoll),
new EndpointAddress(Info.Instance.ServiceURL));
Where Info is a singleton object, Instance gets the singleton's instance and ServiceUrl is a string property that comes from... wherever. Database, config file, hard coded to start etc...
P.S. Careful with the Singleton pattern, but as config info entities they can be very useful.
In WCF 4.0, How can I commit 3 different service operation as a single Transaction? (Commit in SOA)
I have 3 different WCF service like below, Each service method invokes DB operation
service1.CreateEmployee();
service2.SendSetupRequestForEmployee();
service3.GiveOfficePermissionToEmployee();
Even if one operation fails entire thing should be rolled back...any help appreciated.
The short answer: Make your service calls under a TransactionScope, and make sure the calls themselves are set up to run under transactions.
TLDR read this article here.
Basically, you need to decorate your Operation Contract method as such:
[TransactionFlow(TransactionFlowOption.Allowed)]
void MyWcfServiceCall() {...}
and the service method call itself with:
[OperationBehavior(TransactionScopeRequired = true)]
void MyWcfServiceCall() {...}
and call under a TransactionScope
using (TransactionScope tx = new TransactionScope(TransactionScopeOption.RequiresNew)) {
myServiceClient.MyWcfServiceCall();
myOtherServiceClient.MyOtherWcfServiceCall();
tx.Complete();
}
in your config file for the bindings, set transactionFlow to true:
<bindings>
<wsHttpBinding>
<binding name="MyServiceBinding" transactionFlow="true" ... />
</wsHttpBinding>
</bindings>
This exception is consistently thrown on a SOAP Request which takes almost three minutes to receive and is 2.25 megs in size.
When scouring the web I find all sorts of posts which all seem to be about setting headers on the Request, some want me to not send the "Expect:" header, some want me to send the "Keep-Alive:" header, but irregardless of the headers I send I still get this pesky error. I don't believe that setting any headers is my answer, because I can recreate the exact same request using "curl" and a response does eventually come back with no problems what-so-ever.
My <httpRuntime maxRequestLength="409600" executionTimeout="900"/>.
I feel as if I'm running out of options. If anyone can provide any assistance I would be most grateful. A few other things to note would be that the server I'm Requesting data from is out of my hands, also these requests are over https and other requests with smaller responses work flawlessly.
Thanks
You tagged the post as .NET35, so are you using WCF?
If so, here is an example of the App.config we use for large data sets:
<system.serviceModel>
<bindings>
<basicHttpBinding>
<binding name="BasicHttpBinding" maxBufferSize="2147483647" maxReceivedMessageSize="2147483647">
<readerQuotas maxDepth="32" maxStringContentLength="8388608" maxArrayLength="16384" maxBytesPerRead="4096" maxNameTableCharCount="16384" />
</binding>
</basicHttpBinding>
</bindings>
<client>
<endpoint address="http://localhost:1602/EndPoint.svc" binding="basicHttpBinding" bindingConfiguration="BasicHttpBinding" contract="IEndPointContract" name="EndPoint" behaviorConfiguration="EndpointBehaviour" />
</client>
<behaviors>
<endpointBehaviors>
<behavior name="EndpointBehaviour">
<dataContractSerializer maxItemsInObjectGraph="2147483647" />
</behavior>
</endpointBehaviors>
</behaviors>
</system.serviceModel>
I hope it's not too late for answering this question.
Try adding the following attribute on the definition of your contract interface: [ServiceKnownType(typeof(ReturnClass))]
For more generic solution that allows returning polymorphic classes please refer to this post:
http://www.goeleven.com/blog/entryDetail.aspx?entry=45
If you are using dbml instead of edmx you will get this( The underlying connection was closed: The connection was closed unexpectedly.) as dbml will not return serialisable data it needs datacontract so go to properties of dbml file and change the Serialization mode to unidirectional.
Have you tried the sugestion of this Blog Post? The problem will most probably lie in the TCP/HTTP stack implementation of .NET .
i got this error because my datatransfereobjects refered to each other in an recursive manner.
For example:
Customer-> (has) -> Rating
Rating-> (belong to) -> Customer
so you have to remove cycles.
[DataContract]
public class Rating
{
private Customer _customer;
//[DataMember] // <- EITHER HERE
public Customer Customer
{
get { return _customer; }
set { _customer = value; }
}
}
[DataContract]
public class Customer
{
private long _customerID;
[DataMember]
public long CustomerID
{
get { return _customerID; }
set { _customerID = value; }
}
[DataMember] // <- OR HERE
public Rating Rating
{
get { return _rating; }
set { _rating = value; }
}
}
Tried several ways to get rid of this error message until I found this solution:
http://kiranpatils.wordpress.com/2008/09/22/the-underlying-connection-was-closed-the-connection-was-closed-unexpectedly-while-returning-data-table-from-wcf-service/
You may change your List<> to DataSet. I suspect DataSet can handle much amount of data than the List<>.
Hope it helps.
I've got the same issue, and after deep investigations I found this article:
Merrick Chaffer's Blog
It was all related to setting the "dataContractSerializer" for both client and server.
Hope this to be helpful.
I have added another field, but didn't have a set on the property.
That was my solution for the same error.
[DataMember]
public bool HasValue
{
get { return true; }
set { }//adding this line made the solution.
}
This is a generic error raised if there is an internal error.
Try adding tracing here: http://msdn.microsoft.com/en-us/library/ms732023(v=vs.110).aspx
You will see the full log then.
For WCF with EF, just add the following code in the context class.
base.Configuration.ProxyCreationEnabled = false;