WCF REST Service: InstanceContextMode.PerCall not working - wcf

I have implemented a REST service for WCF. The service offers one function that can be called by many clients and this function takes more than 1 minute to complete. So what I wanted is that for each client, a new object is used, so that many clients can be handled at a time.
My interface looks like this:
[ServiceContract]
public interface ISimulatorControlServices
{
[WebGet]
[OperationContract]
string DoSomething(string xml);
}
And the (test) implementation of it:
[ServiceBehavior(InstanceContextMode = InstanceContextMode.PerCall]
public class SimulatorControlService : SimulatorServiceInterfaces.ISimulatorControlServices
{
public SimulatorControlService()
{
Console.WriteLine("SimulatorControlService started.");
}
public string DoSomething(string xml)
{
System.Threading.Thread.Sleep(2000);
return "blub";
}
}
The problem now is: if I use a client that creates 10 (or whatever number) threads, each of it calling the service, they dont run concurrently. This means, the calls are being handled one after each other. Does anybody have an idea why this happens?
Added: client-side code
Spawning threads:
for (int i = 0; i < 5; i++)
{
Thread thread = new Thread(new ThreadStart(DoSomethingTest));
thread.Start();
}
Method:
private static void DoSomethingTest()
{
try
{
using (ChannelFactory<ISimulatorControlServices> cf = new ChannelFactory<ISimulatorControlServices>(new WebHttpBinding(), "http://localhost:9002/bla/SimulatorControlService"))
{
cf.Endpoint.Behaviors.Add(new WebHttpBehavior());
ISimulatorControlServices channel = cf.CreateChannel();
string s;
int threadID = Thread.CurrentThread.ManagedThreadId;
Console.WriteLine("Thread {0} calling DoSomething()...", threadID);
string testXml = "test";
s = channel.StartPressureMapping(testXml);
Console.WriteLine("Thread {0} finished with reponse: {1}", threadID, s);
}
}
catch (CommunicationException cex)
{
Console.WriteLine("A communication exception occurred: {0}", cex.Message);
}
}
Thanks in advance!

Since the service is controlled by a GUI, the "UseSynchronizationContext" attribute was needed to solve the problem:
[ServiceBehavior(InstanceContextMode = InstanceContextMode.PerCall, ConcurrencyMode=ConcurrencyMode.Multiple, UseSynchronizationContext=false)]

Related

WCF ChannelFactory and channels - caching, reusing, closing and recovery

I have the following planned architecture for my WCF client library:
using ChannelFactory instead of svcutil generated proxies because
I need more control and also I want to keep the client in a separate
assembly and avoid regenerating when my WCF service changes
need to apply a behavior with a message inspector to my WCF
endpoint, so each channel is able to send its
own authentication token
my client library will be used from a MVC front-end, so I'll have to think about possible threading issues
I'm using .NET 4.5 (maybe it has some helpers or new approaches to implement WCF clients in some better way?)
I have read many articles about various separate bits but I'm still confused about how to put it all together the right way. I have the following questions:
as I understand, it is recommended to cache ChannelFactory in a static variable and then get channels out of it, right?
is endpoint behavior specific to the entire ChannelFactory or I can apply my authentication behavior for each channel separately? If the behavior is specific to the entire factory, this means that I cannot keep any state information in my endpoint behavior objects because the same auth token will get reused for every channel, but obviously I want each channel to have its own auth token for the current user. This means, that I'll have to calculate the token inside of my endpoint behavior (I can keep it in HttpContext, and my message inspector behavior will just add it to the outgoing messages).
my client class is disposable (implements IDispose). How do I dispose the channel correctly, knowing that it might be in any possible state (not opened, opened, failed ...)? Do I just dispose it? Do I abort it and then dispose? Do I close it (but it might be not opened yet at all) and then dispose?
what do I do if I get some fault when working with the channel? Is only the channel broken or entire ChannelFactory is broken?
I guess, a line of code speaks more than a thousand words, so here is my idea in code form. I have marked all my questions above with "???" in the code.
public class MyServiceClient : IDisposable
{
// channel factory cache
private static ChannelFactory<IMyService> _factory;
private static object _lock = new object();
private IMyService _client = null;
private bool _isDisposed = false;
/// <summary>
/// Creates a channel for the service
/// </summary>
public MyServiceClient()
{
lock (_lock)
{
if (_factory == null)
{
// ... set up custom bindings here and get some config values
var endpoint = new EndpointAddress(myServiceUrl);
_factory = new ChannelFactory<IMyService>(binding, endpoint);
// ???? do I add my auth behavior for entire ChannelFactory
// or I can apply it for individual channels when I create them?
}
}
_client = _factory.CreateChannel();
}
public string MyMethod()
{
RequireClientInWorkingState();
try
{
return _client.MyMethod();
}
catch
{
RecoverFromChannelFailure();
throw;
}
}
private void RequireClientInWorkingState()
{
if (_isDisposed)
throw new InvalidOperationException("This client was disposed. Create a new one.");
// ??? is it enough to check for CommunicationState.Opened && Created?
if (state != CommunicationState.Created && state != CommunicationState.Opened)
throw new InvalidOperationException("The client channel is not ready to work. Create a new one.");
}
private void RecoverFromChannelFailure()
{
// ??? is it the best way to check if there was a problem with the channel?
if (((IChannel)_client).State != CommunicationState.Opened)
{
// ??? is it safe to call Abort? won't it throw?
((IChannel)_client).Abort();
}
// ??? and what about ChannelFactory?
// will it still be able to create channels or it also might be broken and must be thrown away?
// In that case, how do I clean up ChannelFactory correctly before creating a new one?
}
#region IDisposable
public void Dispose()
{
// ??? is it how to free the channel correctly?
// I've heard, broken channels might throw when closing
// ??? what if it is not opened yet?
// ??? what if it is in fault state?
try
{
((IChannel)_client).Close();
}
catch
{
((IChannel)_client).Abort();
}
((IDisposable)_client).Dispose();
_client = null;
_isDisposed = true;
}
#endregion
}
I guess better late then never... and looks like author has it working, this might help future WCF users.
1) ChannelFactory arranges the channel which includes all behaviors for the channel. Creating the channel via CreateChannel method "activates" the channel. Channel factories can be cached.
2) You shape the channel factory with bindings and behaviors. This shape is shared with everyone who creates this channel. As you noted in your comment you can attach message inspectors but more common case is to use Header to send custom state information to the service. You can attach headers via OperationContext.Current
using (var op = new OperationContextScope((IContextChannel)proxy))
{
var header = new MessageHeader<string>("Some State");
var hout = header.GetUntypedHeader("message", "urn:someNamespace");
OperationContext.Current.OutgoingMessageHeaders.Add(hout);
}
3) This is my general way of disposing the client channel and factory (this method is part of my ProxyBase class)
public virtual void Dispose()
{
CloseChannel();
CloseFactory();
}
protected void CloseChannel()
{
if (((IChannel)_client).State == CommunicationState.Opened)
{
try
{
((IChannel)_client).Close();
}
catch (TimeoutException /* timeout */)
{
// Handle the timeout exception
((IChannel)innerChannel).Abort();
}
catch (CommunicationException /* communicationException */)
{
// Handle the communication exception
((IChannel)_client).Abort();
}
}
}
protected void CloseFactory()
{
if (Factory.State == CommunicationState.Opened)
{
try
{
Factory.Close();
}
catch (TimeoutException /* timeout */)
{
// Handle the timeout exception
Factory.Abort();
}
catch (CommunicationException /* communicationException */)
{
// Handle the communication exception
Factory.Abort();
}
}
}
4) WCF will fault the channel not the factory. You can implement a re-connect logic but that would require that you create and derive your clients from some custom ProxyBase e.g.
protected I Channel
{
get
{
lock (_channelLock)
{
if (! object.Equals(innerChannel, default(I)))
{
ICommunicationObject channelObject = innerChannel as ICommunicationObject;
if ((channelObject.State == CommunicationState.Faulted) || (channelObject.State == CommunicationState.Closed))
{
// Channel is faulted or closing for some reason, attempt to recreate channel
innerChannel = default(I);
}
}
if (object.Equals(innerChannel, default(I)))
{
Debug.Assert(Factory != null);
innerChannel = Factory.CreateChannel();
((ICommunicationObject)innerChannel).Faulted += new EventHandler(Channel_Faulted);
}
}
return innerChannel;
}
}
5) Do not re-use channels. Open, do something, close is the normal usage pattern.
6) Create common proxy base class and derive all your clients from it. This can be helpful, like re-connecting, using pre-invoke/post invoke logic, consuming events from factory (e.g. Faulted, Opening)
7) Create your own CustomChannelFactory this gives you further control how factory behaves e.g. Set default timeouts, enforce various binding settings (MaxMessageSizes) etc.
public static void SetTimeouts(Binding binding, TimeSpan? timeout = null, TimeSpan? debugTimeout = null)
{
if (timeout == null)
{
timeout = new TimeSpan(0, 0, 1, 0);
}
if (debugTimeout == null)
{
debugTimeout = new TimeSpan(0, 0, 10, 0);
}
if (Debugger.IsAttached)
{
binding.ReceiveTimeout = debugTimeout.Value;
binding.SendTimeout = debugTimeout.Value;
}
else
{
binding.ReceiveTimeout = timeout.Value;
binding.SendTimeout = timeout.Value;
}
}

WCF - How to delay task for specified amount of time?

I have WCF WebService for Silverlight client.
Let's say client click "Make building".
Service will receive new task, and star counting time, until it's ready to make action (i.e add to database).
Time - how much time task will need to complete (i.e to construct building).
The point is how to delay task for the certain amount of time.
Also, is there a way to stream time from server to client ?
I have setup this:
[OperationContract]
public void GetTime()
{
foreach (IDuplexClient client in _clientDic.Values)
{
client.ShowStatus(DateTime.Now);
}
}
[OperationContract]
public void Login()
{
string clientID = OperationContext.Current.Channel.SessionId;
IDuplexClient client = OperationContext.Current.GetCallbackChannel<IDuplexClient>();
_clientDic.Add(clientID, client);
}
IDuplexClient:
[OperationContract(IsOneWay = true)]
void ShowStatus(DateTime status);
And client side:
_client.LoginAsync();
_client.GetTimeAsync();
_client.ShowStatusReceived += new EventHandler<ShowStatusReceivedEventArgs>(_client_ShowStatusReceived);
void _client_ShowStatusReceived(object sender, ShowStatusReceivedEventArgs e)
{
label1.Content = e.status.ToString();
}
It's working.. For first run. But time doesn't get refreshed, which is not what I want.
As well, after few forced refresh in browser, time stop to show at all.
public partial class MainPage : UserControl
{
Service1Client _client;
int time = 10000;
public MainPage()
{
InitializeComponent();
_client = new Service1Client(new PollingDuplexHttpBinding { DuplexMode = PollingDuplexMode.SingleMessagePerPoll, OpenTimeout = TimeSpan.FromMinutes(10), ReceiveTimeout = TimeSpan.FromMinutes(10) },
new EndpointAddress("http://localhost:44544/Service1.svc"));
_client.LoginAsync();
_client.DoWorkCompleted += new EventHandler<DoWorkCompletedEventArgs>(_client_DoWorkCompleted);
_client.DoWorkAsync();
_client.AddNewTaskAsync("testTaskzor", time);
_client.GetTimeAsync();
//_client.AddNewTaskCompleted += new EventHandler<AddNewTaskCompletedEventArgs>(_client_AddNewTaskCompleted);
_client.ShowStatusReceived += new EventHandler<ShowStatusReceivedEventArgs>(_client_ShowStatusReceived);
}
void _client_ShowStatusReceived(object sender, ShowStatusReceivedEventArgs e)
{
label1.Content = e.status.ToString();
}
void _client_DoWorkCompleted(object sender, DoWorkCompletedEventArgs e)
{
//label1.Content = e.Result;
}
}
That' entire client code.
Although I finally fixed and time is streaming properly to client (it wa surpsingly easy it was enough to enlose foreach with while(true) statment, at least for now).
But on other side. When I close browser, and open it again, nothing show up. As well as after I refresh it, time do not show up at all.
The easiest way would be to implement the delay on the client side. You can't really delay a RESTful service like WCF without breaking the model.

Duplex WCF + Static Collection of COM objects

I am trying to build a WCF service that exposes the functionality of a particular COM object that I do not have the original source for. I am using duplex binding so that each client has their own instance as there are events tied to each particular instance which are delivered through a callback (IAgent). It appears there is a deadlock or something because after the first action, my service blocks at my second action's lock. I have tried implementing these custom STA attribute and operation behaviors (http://devlicio.us/blogs/scott_seely/archive/2009/07/17/calling-an-sta-com-object-from-a-wcf-operation.aspx) but my OperationContext.Current is always null. Any advice is much appreciated.
Service
Collection:
private static Dictionary<IAgent, COMAgent> agents = new Dictionary<IAgent, COMAgent>();
First action:
public void Login(LoginRequest request)
{
IAgent agent = OperationContext.Current.GetCallbackChannel<IAgent>();
lock (agents)
{
if (agents.ContainsKey(agent))
throw new FaultException("You are already logged in.");
else
{
ICOMClass startup = new ICOMClass();
string server = ConfigurationManager.AppSettings["Server"];
int port = Convert.ToInt32(ConfigurationManager.AppSettings["Port"]);
bool success = startup.Logon(server, port, request.Username, request.Password);
if (!success)
throw new FaultException<COMFault>(new COMFault { ErrorText = "Could not log in." });
COMAgent comAgent = new COMAgent { Connection = startup };
comAgent.SomeEvent += new EventHandler<COMEventArgs>(comAgent_COMEvent);
agents.Add(agent, comAgent);
}
}
}
Second Action:
public void Logoff()
{
IAgent agent = OperationContext.Current.GetCallbackChannel<IAgent>();
lock (agents)
{
COMAgent comAgent = agents[agent];
try
{
bool success = comAgent.Connection.Logoff();
if (!success)
throw new FaultException<COMFault>(new COMFault { ErrorText = "Could not log off." });
agents.Remove(agent);
}
catch (Exception exc)
{
throw new FaultException(exc.Message);
}
}
}
Take a look at this very similar post: http://www.netfxharmonics.com/2009/07/Accessing-WPF-Generated-Images-Via-WCF
You have to use an OperationContextScope to have access to the current OperationContext from the newly generated thread:
System.Threading.Thread thread = new System.Threading.Thread(new System.Threading.ThreadStart(delegate
{
using (System.ServiceModel.OperationContextScope scope = new System.ServiceModel.OperationContextScope(context))
{
result = InnerOperationInvoker.Invoke(instance, inputs, out staOutputs);
}
}));

How to create client proxy without svcutil or add service reference in wcf?

How can I create a client proxy without svcutil.exe or add service reference in wcf?
I want to create a client proxy at compile time.
If you have access to the service contract (the IService interface) in a separate DLL, you can add a reference to that service contract DLL and then do something like:
NetTcpBinding binding = new NetTcpBinding();
EndpointAddress address = new EndpointAddress("net.tcp://localhost:9000/YourService")
ChannelFactory<IService> factory = new ChannelFactory<IService>(binding, address);
IService proxy = factory.CreateChannel();
and then you have your programmatically created proxy, which you can now use as you wish.
This might not be what you are looking for, but it's pretty interesting.
Vipul Modi has a library that allows you to call WCF services after downloading their WSDL, all at runtime.
Vipul Modi's library (latest version)
Allows you to do this kind of thing:
Create the ProxyFactory specifying the WSDL URI of the service.
DynamicProxyFactory factory = new DynamicProxyFactory("http://localhost:8080/WcfSamples/DynamicProxy?wsdl");
Browse the endpoints, metadata, contracts etc.
factory.Endpoints
factory.Metadata
factory.Contracts
factory.Bindings
Create DynamicProxy to an endpoint by specifying either the endpoint or
contract name.
DynamicProxy proxy = factory.CreateProxy("ISimpleCalculator");
//OR
DynamicProxy proxy = factory.CreateProxy(endpoint);
Invoke operations on the DynamicProxy
double result = (double)proxy.CallMethod("Add", 1d ,2d);
Close the DynamicProxy
proxy.Close();
You don't need to code generate (or use a configuration file full of WCF specifics).
First create the interface defining the service ([ServiceContract]) with any supporting data contracts in an assembly separate from the service implementation.
Reference the interface assembly in the client assembly.
Then need to create a client proxy, for IMyService:
BasicHttpBinding binding = new BasicHttpBinding();
EndpointAddress endpoint = new EndpointAddress(url);
ChannelFactory<IMyService> chanFac = new ChannelFactory<IMyService>(binding, endpoint);
IMyService clientProxy = chanFac.CreateChannel();
Here is the solution I have been using since wcf was introduced:
In an infrastructure assembly:
internal class PerCallDisposeRealProxy<T> : RealProxy where T : class
{
private readonly Binding _binding;
private readonly EndpointAddress _endpointAddress;
private static string EndpointName
{
get
{
string endpointName = typeof(T).Name;
if (endpointName.StartsWith("I"))
{
endpointName = endpointName.Substring(1);
}
return endpointName;
}
}
internal PerCallDisposeRealProxy()
: base(typeof(T))
{
}
internal PerCallDisposeRealProxy(Binding binding, EndpointAddress endpointAddress)
: base(typeof(T))
{
if (binding == null)
throw new ArgumentNullException("binding");
if (endpointAddress == null)
throw new ArgumentNullException("endpointAddress");
_binding = binding;
_endpointAddress = endpointAddress;
}
private ChannelFactory<T> CreateChannel()
{
if (_binding != null && _endpointAddress != null)
return new ChannelFactory<T>(_binding, _endpointAddress);
else
return new ChannelFactory<T>(EndpointName);
}
[DebuggerStepThrough]
public override IMessage Invoke(IMessage message)
{
if (message == null) throw new ArgumentNullException("message");
//Extract method info
var methodCall = message as IMethodCallMessage;
Debug.Assert(methodCall != null);
MethodInfo methodInfo = methodCall.MethodBase as MethodInfo;
Debug.Assert(methodInfo != null);
T channel = null;
ChannelFactory<T> channelFactory = null;
try
{
//setup channel
try
{
channelFactory = CreateChannel();
}
catch (InvalidOperationException ex)
{
throw new ApplicationException(string.Format("Invalid endpoint configuration, make sure there is a servicemodel endpoint defined in configuration with the name {0}", EndpointName), ex);
}
channelFactory.Open();
channel = channelFactory.CreateChannel();
object result = methodInfo.Invoke(channel, methodCall.InArgs);
return new ReturnMessage(result, null, 0, methodCall.LogicalCallContext, methodCall);
}
catch (FaultException faultException)
{
string msg = "FaultException: " + faultException.Message;
MessageFault fault = faultException.CreateMessageFault();
if (fault.HasDetail)
{
System.Xml.XmlReader reader = fault.GetReaderAtDetailContents();
if (reader.Name == "ExceptionDetail")
{
ExceptionDetail detail = fault.GetDetail<ExceptionDetail>();
msg += "\n\nStack Trace: " + detail.StackTrace;
}
}
return new ReturnMessage(faultException, methodCall);
}
catch (TargetInvocationException targetInvocationException)
{
return targetInvocationException.InnerException != null ? new ReturnMessage(targetInvocationException.InnerException, methodCall) : new ReturnMessage(targetInvocationException, methodCall);
}
catch (Exception exception)
{
return new ReturnMessage(exception, methodCall);
}
finally
{
if (channel as IClientChannel != null)
{
try
{
(channel as IClientChannel).Close(TimeSpan.FromSeconds(5));
}
catch
{
try
{
(channel as IClientChannel).Abort();
}
catch
{
}
}
try
{
(channel as IClientChannel).Dispose();
}
catch
{
}
}
try
{
((IDisposable)channelFactory).Dispose();
}
catch
{
}
}
}
}
public static class ClientProxyFactory
{
public static T CreateProxy<T>() where T : class
{
return CreateProxy<T>(ProxyType.PerCallChannel);
}
public static T CreateProxy<T>(ProxyType proxyType) where T : class
{
return CreateProxy<T>(proxyType, null, null);
}
public static T CreateProxy<T>(ProxyType proxyType, Binding binding, EndpointAddress endpointAddress) where T : class
{
switch (proxyType)
{
case ProxyType.PerCallChannel:
PerCallDisposeRealProxy<T> proxy = null;
proxy = binding == null && endpointAddress == null ? new PerCallDisposeRealProxy<T>() : new PerCallDisposeRealProxy<T>(binding, endpointAddress);
Debug.Assert(proxy != null);
object transparentProxy = proxy.GetTransparentProxy();
Debug.Assert(transparentProxy != null);
Debug.Assert(transparentProxy is T);
return transparentProxy as T;
default:
throw new NotImplementedException("Did not implement proxytype:" + proxyType);
}
}
}
public enum ProxyType
{
/// <summary>
/// PerCall indicates a proxy that will create a channel pr. proxy method call and dispose of it before returning.
/// </summary>
PerCallChannel
}
And call site (in the service agent or whereever you want to call the external service from:
INumeralConverterService proxy = ClientProxyFactory.CreateProxy<INumeralConverterService>();
string result = proxy.DecimalToRoman(i);
Given the ServiceContract (and datacontracts) defined in yet another asssembly, here simply:
[ServiceContract]
public interface INumeralConverterService
{
[OperationContract]
Decimal RomanToDecimal(string roman);
[OperationContract]
string DecimalToRoman(Decimal #decimal);
}

service.close() vs. service.abort() - WCF example

In one of the WCF tutorials, I saw the following sample code:
Dim service as ...(a WCF service )
try
..
service.close()
catch ex as Exception()
...
service.abort()
end try
Is this the correct way to ensure that resources (i.e. connections) are released even under error conditions?
See Indisposable: WCF Gotcha #1*, where he comes up with a convenient wrapper method:
public delegate void UseServiceDelegate<T>(T proxy);
public static class Service<T>
{
public static ChannelFactory<T> _channelFactory = new ChannelFactory<T>("");
public static void Use(UseServiceDelegate<T> codeBlock)
{
var proxy = (IClientChannel)_channelFactory.CreateChannel();
var success = false;
try
{
codeBlock((T)proxy);
proxy.Close();
success = true;
}
finally
{
if (!success)
{
proxy.Abort();
}
}
}
}
Usage:
Service<IOrderService>.Use(
orderService =>
{
orderService.PlaceOrder(request);
});
* Link removed as it appears to be malicious.
I've had good luck with this model:
Dim service As New MyService()
Dim closed As Boolean = False
Try
service.Open()
If Not service.State = ServiceModel.CommunicationState.Opened Then
''Handle a not-opened state here
End If
service.MyMethod()
service.Close()
closed = true
Catch ex As Exception
''Handle errors here
Finally
If Not closed Then
service.Abort()
End If
End Try
service = Nothing
You've got the general idea correct. I've used the following extension method to keep the lines of repetitive code to a minimum.
public static class ICommunicationObjectExtensions
{
public static void SafelyCloseConnection(this ICommunicationObject objectToClose)
{
bool success = false;
try
{
objectToClose.Close();
success = true;
}
finally
{
if (!success)
{
objectToClose.Abort();
}
}
}
}
Example of code using this extension method:
HelloWorldServiceClient client = new HelloWorldServiceClient();
HelloWorldDataContract dc = new HelloWorldDataContract();
try
{
client.Open();
dc = client.SayHello();
} // Add catch blocks here for anything you want to handle.
finally
{
client.SafelyCloseConnection();
}
Of course this is C#, but I think that should still be of help.
If you use a client side cache, you might consider using Expression Trees (see http://thegrenade.blogspot.com/2009/07/using-expression-trees-for-more-elegant.html):
private static TEntity GetItem<TProxy, TEntity, TIdentity>(Expression<Func<TProxy, TIdentity, TEntity>> expression, TProxy proxy, TIdentity id)
where TEntity : class
where TProxy : ICommunicationObject
{
TEntity item = Cache.GetItem<TEntity, TIdentity>(id);
if (item == null)
{
try
{
var originalDelegate = expression.Compile();
item = originalDelegate.Invoke(proxy, id);
}
finally
{
try{ proxy.Close(); }
finally { proxy.Abort(); }
}
Cache.AddItem<TEntity, TIdentity>(item);
}
return item;
}
Usage:
Product p = GetItem((client, identifier) => client.GetProduct(identifier), new CatalogServiceClient(), 123);