We have some weird behavior with WCF bindings configured in configuration files.
We do service calls that may be long-running so we need a send-/operation-timeout longer than the default 1 minute.
Our WCF configuration reflects that, setting sendTimeout to 10 minutes.
But if the service call exceeds 1 minute there is an error message saying the operation timed out after 1 minute at the one-minute mark.
Debugging this we check whether the configuration is correct, like this (here the service call made is shorter than 1 minute for the purpose of debugging):
public class MyWcfClient : ClientBase<IMyWcf>, IMyWcf
{
public ResultType MyMethod()
{
var originalBinding = base.Endpoint.Binding;
var result = this.Channel.MyMethod();
var changedBinding = base.Endpoint.Binding;
return result;
}
}
Here originalBinding will contain the configured settings (sendTimeout = 10 minutes, etc.). But after the call, checking the changedBinding variable, there are other values in the binding, among others the sendTimeout is 1 minute
and it seems the latter one is the one used by the service-call considering the timeout response when making a long-running call. The type of the binding has changed as well from NetTcpBinding to CustomBinding.
Now changing the code slightly, to:
public class MyWcfClient : ClientBase<IMyWcf>, IMyWcf
{
public void MyMethod()
{
var originalBinding = base.Endpoint.Binding;
var sendTimeout = ((IContextChannel)base.Channel).OperationTimeout;
var changedBinding = base.Endpoint.Binding;
}
}
Here we get the same behavior when it comes to the binding values as before. The variable sendTimeout gets value 1 minute, so again it seems the changed binding value is the one honored.
A third example, setting OperationTimeout explicitly before making the service call the set value is honored.
public class MyWcfClient : ClientBase<IMyWcf>, IMyWcf
{
public ResultType MyMethod()
{
((IContextChannel)base.Channel).OperationTimeout = TimeSpan.FromMinutes(10);
var result = this.Channel.MyMethod();
return result;
}
}
Here when making a long-running service-call (though less than 10 minutes) there is no timeout.
So it works setting timeout explicitly in code but we would like to do it all in configuration files.
The binding looks similar to this (same on server and client side):
<binding name="NetTcpBinding"
sendTimeout="00:10:00"
receiveTimeout="00:10:00"
openTimeout="00:10:00"
closeTimeout="00:10:00"
transactionFlow="false"
portSharingEnabled="true"
maxReceivedMessageSize="2147483647"
maxBufferPoolSize="2147483647"
maxBufferSize="2147483647" >
...
</binding>
Any ideas on the explanation for this? What can we do for the configuration to be honored?
Turns out this is a bug in the telemetryClient Wcf-extension. Without it the binding is kept and the timeout works.
https://github.com/Microsoft/ApplicationInsights-SDK-Labs/issues/124
Related
My FooData.svc.cs file looks like this: (Take note of the undeclared object CurrentDataSource.)
public class FooData : DataService<FooEntities>
{
public static void InitializeService(DataServiceConfiguration config)
{
// init code
}
[WebGet]
public IQueryable<someStoredProcedure_Result> someStoredProcedure(int param1, int param2)
{
return CurrentDataSource.someStoredProcedure(param1, param2).AsQueryable();
}
}
My Authorizer.cs file looks like this:
public class Authorizer : System.ServiceModel.ServiceAuthorizationManager
{
protected override bool CheckAccessCore(OperationContext operationContext)
{
if (base.CheckAccessCore(operationContext))
{
if (IsAuthorized())
return true;
else
return false;
}
else
return false;
}
private bool IsAuthorized(OperationContext operationContext)
{
// some code here that gets the authentication headers,
// etc from the operationContext
// *********
// now, how do I properly access the Entity Framework to connect
// to the db and check the credentials since I don't have access
// to CurrentDataSource here
}
}
Applicable section from Web.config, for good measure:
<system.serviceModel>
<behaviors>
<serviceBehaviors>
<behavior>
<serviceAuthorization serviceAuthorizationManagerType="MyNamespace.Authorizer, MyAssemblyName" />
</behavior>
</serviceBehaviors>
</behaviors>
</system.serviceModel>
So my question has to do with where you see all the asterisks in the code in Authorizer.cs. What is the recommended way to connect to the Entity Framework from within the ServiceAuthorizationManager since I don't have access to CurrentDataSource there? Do I just establish a separate "connection"? e.g.
using (var db = new MyNamespace.MyEntityFrameworkDBContext())
{
// linq query, stored proc, etc using the db object
}
To clarify, the above code works just fine. I'm just wondering if it's the correct way. By the way, this is a Visual Studio 2012 WCF Data Services project with .NET 4.5 and Entity Framework 5.
I think you answered your own question. If you are concerned with the creation of DbContext for each IsAuthorized - then unless you are calling this functions hundreds of times during 1 request you should be fine. As mentioned here,here or here recreation of EF context is not only inexpensive operation but also recommended.
EDIT:
Please note that DataService constructor is called after IsAuthorized, therefore independent instance of DbContext is the most likely the way to go.
I have an simple Pub/Sub service built on WCF. the interface of server side looks like below:
[ServiceBehavior(UseSynchronizationContext = false, InstanceContextMode = InstanceContextMode.Single, ConcurrencyMode = ConcurrencyMode.Multiple)]
public class RDFService : IRDFService
{
public Guid Register(string ric)
public void Unregister(Guid guid)
}
Client side call back interface:
[CallbackBehavior(ConcurrencyMode = ConcurrencyMode.Multiple)]
internal class ServiceCallback : IRDFCallBack
{
// [OperationContract(IsOneWay = true)]
public void UpdateSignal(Guid guid, string ric, MarketFeedData data, MarketDataMessageType type)
}
Client side is an Win form project.
The handling logic is as below:
If client receives an UpdateSignal request, withing the handling method, client will make an call to unregister it self.
Usually, both UpdateSignal and Unreg methods takes almost no time. But when an influx(8-10) of UpdateSignal requests are sent to client concurrently, there's a significant delay between 1-3 seconds. I opened trace and found that the time are held on the Unregister service method call:
As in the picture, there's an 2 seconds delay between activity 3 and 4. What can be the cause? Thanks.
I have a WCF service which has one method returning a stream.
[ServiceContract]
public interface IService1
{
[OperationContract]
MyMessage Test();
}
Now, MyMessage is defined like this:
[MessageContract]
public class MyMessage
{
public MyMessage(string file)
{
this.Stream = File.OpenRead(file);
this.Length = Stream.Length;
}
[MessageHeader]
public long Length;
[MessageBodyMember]
public Stream Stream;
}
Peachy.
The service has a streamed response, using basicHttpBinding. This is the binding configuration:
<basicHttpBinding>
<binding name="BasicStreaming"
maxReceivedMessageSize="67108864" maxBufferSize="65536" transferMode="StreamedResponse" />
</basicHttpBinding>
Now this is where things start to get interesting. When calling this service, the last byte is lost if i read the stream in a particular way. Here is the code illustrating the two different approaches:
Service1Client client = new Service1Client();
//this way the last byte is lost
Stream stream1;
var length = client.Test(out stream1);
var buffer1 = new byte[length];
stream1.Read(buffer1, 0, (int)length);
File.WriteAllBytes("test1.txt", buffer1);
stream1.Close();
//here i receive all bytes
Stream stream2;
length = client.Test(out stream2);
var buffer2 = new byte[length];
int c = 0, b;
while ((b = stream2.ReadByte()) != -1)
{
buffer2[c++] = (byte)b;
}
File.WriteAllBytes("test2.txt", buffer2);
stream2.Close();
I am sure I'm missing something, but can anyone point out to me exactly why this is happening? The biggest problem is that in another service, whichever way i read the stream, i lose the last byte, but maybe by identifying the problem here I can solve that one too.
Technical details:
IIS 7.0
.NET 3.5
Basic HTTP Binding
Streamed response mode
Note: I have uploaded the project isolating the problem, so anyone can try it out: mediafire
I don't have an exact answer as to why this works (my brain isn't fully engaged at the moment), however this DOES work:
var buffer1 = new byte[length+2];
stream1.Read(buffer1, 0, buffer1.Length);
(and, yes, you end up with a buffer that's too large. It's just a starting point for further thinking)
In testing I found +1 isn't large enough, but +2 is.
Why passing a count of (length + 1)? It should be length, otherwise you are attempting to read one more byte than what is available.
I'm using WCF in communication between a server and client (both written in C#).
In release-mode, the timouts should be set to ~20 seconds, but in debug mode I want to set them to a higher value so that I can debug/step in my code without the timeout occurring.
I know that I can change the timeouts by modifying the app.config file. However, I've got two different bindings and 4 time out values in each so I would have to change in several places, and its easy to forget.
To solve this, I would like to have a small #if DEBUG-section in my code which programmatically changes the timeout values to 1 hour.
I tried to use the following code to do this:
Configuration configuration =
ConfigurationManager.OpenExeConfiguration(ConfigurationUserLevel.None);
ServiceModelSectionGroup serviceModel =
ServiceModelSectionGroup.GetSectionGroup(configuration);
BindingsSection bindings = serviceModel.Bindings;
foreach (var configuredBinding in bindings.WSHttpBinding.ConfiguredBindings)
{
configuredBinding.CloseTimeout = new TimeSpan(0, 30, 0);
configuredBinding.OpenTimeout = new TimeSpan(0, 30, 0);
but the *Timeout properties are readonly so I get a compilation error.
I'm not fond of the idea of creating bindings from scratch programmatically. If I change some of the attributes in the app.config, I have to remember to do the same change in the code to make sure that the debug-behavior is similar to the release-behavior (except for the timeouts..)
How to handle this?
You could do the following:
create the binding and the endpoint in code
set the timeouts on the binding instance
then create your client proxy using those two elements
Something like:
BasicHttpBinding myBinding = new BasicHttpBinding("ConfigName");
myBinding.CloseTimeout = .......
myBinding.OpenTimeout = .......
myBinding.ReceiveTimeout = .......
myBinding.SendTimeout = .......
EndpointAddress myEndpoint = new EndpointAddress("http://server:8181/yourservice");
YourServiceClient proxy = new YourServiceClient(myBinding, myEndpoint);
That way, you can leverage the basic config when describing binding timeouts and yet you can tweak the settings you want and create your client proxy from it.
You can create a second binding in the web.config and set a longer sendTimeout.
if (debug)
{
proxy = new MyClient("WSHttpBinding_MyLocal");
}
else
{
proxy = new MyClient("WSHttpBinding_MyDev");
}
<wsHttpBinding>
<binding name="WSHttpBinding_MyLocal" closeTimeout="00:01:00"
openTimeout="00:01:00" receiveTimeout="00:10:00" sendTimeout="00:20:00"
...
How can I implement one way WCF operations?
I just tried using IsOneWay attribute as:
[OperationContract(IsOneWay=true)]
void MethodName(string param1, int param2)
Is there any other change I need to make or any specific change in app.config?
FYI, my WCF service implements netTcpBinding, though I think that shouldn't make any difference.
As shown, your code looks ok. There should be no problem with doing one-way calls with netTcpBinding.
If you're interested, chapter 5 in Juval Lowy's awesome Programming WCF Services 2nd Edition contains a good bit of information about one-way services.
From what you've shown, so far though I don't see anything wrong. Please give us some more details.
We had a problem with one-way calls not returning immediately using the NetTcpBinding. This blog post identifies the problem and provides a solution.
http://blogs.msdn.com/b/distributedservices/archive/2009/02/12/client-proxy-close-method-call-does-not-finish-immediately-in-one-way-wcf-calls.aspx
From the article:
Problem: Clients calling a one-way method in WCF Service and then close method on proxy does not return until the call is actually finished or call times out. Ever wonder why this happens?
Cause: When you specify “One-Way” on your interface, the underlying channel operation is still two-way since the one way binding element is not in the channel stack. Thus, the close operation gets blocked until the one way operation completes.
This is by design and the development team is working to change it in future versions of .Net framework.
...
Solution (Work around):
Layer the OneWayBindingElement on top of netTcpBinding as shown in the below code. This way, close call on proxy will return immediately and eventually the one-way call will return in fire and forget fashion.
[ServiceContract]
public interface IService1
{
[OperationContract(IsOneWay = true)]
void SetData(int value);
}
public class Service1 : IService1
{
public void SetData(int value)
{
//Application specific code
}
}
Service Host code:
Form1ServiceHost = new ServiceHost(this, new Uri("net.tcp://localhost:8091/WindowsFormApp/Form1/"), new Uri("http://localhost:8090/WindowsFormApp/Form1/"));
Binding binding = new NetTcpBinding();
BindingElementCollection oldBindingElements = binding.CreateBindingElements();
BindingElementCollection bindingElements = new BindingElementCollection();
bindingElements.Add(new OneWayBindingElement());
foreach (BindingElement bindingElement in oldBindingElements)
{
bindingElements.Add(bindingElement);
}
binding = new CustomBinding(bindingElements);
Form1ServiceHost.AddServiceEndpoint("WCFServiceLibrary.IService1", binding, "");
Form1ServiceHost.Open();
Client Code:
Binding binding = new NetTcpBinding();
BindingElementCollection oldBindingElements = binding.CreateBindingElements();
BindingElementCollection bindingElements = new BindingElementCollection();
bindingElements.Add(new OneWayBindingElement());
foreach (BindingElement bindingElement in oldBindingElements)
{
bindingElements.Add(bindingElement);
}
binding = new CustomBinding(bindingElements);
Service1Client client = new Service1Client(binding, new EndpointAddress("net.tcp://localhost:8091/WindowsFormApp/Form1/"));
client.SetData(10);
Console.WriteLine("set data");
Console.WriteLine("Now closing the channel,Before close, current time is {0}", DateTime.Now.ToString() + " " + DateTime.Now.Millisecond.ToString());
client.Close();
Console.WriteLine("Now closing the channel,After close, current time is {0}", DateTime.Now.ToString() + " " + DateTime.Now.Millisecond.ToString());`