I'm familiar with best practices with creating a WCF client, calling a standard method, then closing or aborting the client when complete but I'm wondering about async methods with clients.
I've got a manager class that has some pass through events for the consuming class to attach to in order to retrieve the results of an async call. For instance:
internal sealed class CommController
{
public event GetClientIdEventHandler ClientIdReceived;
private readonly LocalCommSvcClient _localCommSvcClient = new LocalCommSvcClient();
public CommController()
{
_localCommSvcClient.GetClientIdCompleted += (o, e) => ClientIdReceived(o, e);
}
public void GetClientIdAsync()
{
_localCommSvcClient.GetClientIdAsync();
}
}
But I don't see where the client is getting closed and/or disposed of. I couldn't really find much best practices for closing WCF clients as it pertains to async usages. Where should I put my .Close() and/or .Abort() calls?
You need to Open() a client before you are able to send a message like you do with synchronous clients.
After communication is no longer needed (at least when you have received the response), you should Close() it to free resources.
Details depend on binding and behavior configuration of your service.
See e.g. http://msdn.microsoft.com/en-us/library/system.servicemodel.servicebehaviorattribute.instancecontextmode.aspx
Related
I have created application in .net core 3.1, In which there are one singleton interface and its implementation class, which is receiving the TCP/IP socket message. There is one event handler in the class, which will be invoked once messages received on the socket.
public Class IncomingMessageHandler : IIncomingMessageHandler
{
public event EventHandler<string> OnMessageReceived;
private void InvokeMessageRecived(object sender, string message)
{
this.OnMessageReceived?.Invoke(this, message);
}
}
There is one another service TransactionService class which is having dependency injected for the interface IIncomingMessageHandler and subscribe to OnMessageReceived.
public TransactionService(IIncomingMessageHandler incomingMessageHandler)
{
this.incomingMessageHandler = incomingMessageHandler;
this.incomingMessageHandler.OnMessageReceived += this.IncomingMessageHandler_OnMessageReceived;
}
From this class, I am initiating the transaction and once a transaction started I will receive the messages into IncomingMessageHandler and OnMessageReceived invokes, Messages I am storing into the List for further processing.
Now TransactionService is the Scoped service class and for each API request new object will be created, Now If there are multiple requests are made, for each TransactionService would subscribe to OnMessageReceived and it invokes multiple time because there are multiple objects initiated and override the List of messages.
I can't register TransactionService as singleton due to some other limitations.
Is there any other way through which OnMessageReceived gets invoked only for the specific service object?
I have tried to un-subscribe the OnMessageReceived, but still, this issue will occur for multiple API requests at the same time.
Since you are binding to an event and not unbinding when finished, it causes a bit of a memory leak - the instances of TransactionService live on in other references and can't be GC'd. You should have TransactionService implement IDisposable and unbind it in the Dispose method. That removes the reference from the event in IncomingMessageHandler and you won't have duplicate calls.
Aside: I tried something very similar and I actually found using Reactive Extensions made for a much better pattern overall.
I have a WCF service hosted in IIS:
[WebServiceLogging]
public class ComplaintService : IComplaintService
This service has the WebServiceLogging attribute that does straightforward request/response logging into the database:
public class WebServiceLoggingAttribute : Attribute, IServiceBehavior {
SomeDatabaseConnection connection; // unmanaged resource
... interface implementations
public void ApplyDispatchBehavior(ServiceDescription serviceDescription, System.ServiceModel.ServiceHostBase serviceHostBase) {
IDispatchMessageInspector messageInspector = new WebServiceLogger(connection, _operations);
foreach (ChannelDispatcher dispatcher in serviceHostBase.ChannelDispatchers)
{
foreach (EndpointDispatcher endpointDispatcher in dispatcher.Endpoints)
{
DispatchRuntime dispatchRuntime = endpointDispatcher.DispatchRuntime;
dispatchRuntime.MessageInspectors.Add(messageInspector); // pass the logger into WCF.
}
}
}
}
Logging work is done from the WebServiceLogger, which uses the SomeDatabaseConnection unmanaged resource:
public class WebServiceLogger : IDispatchMessageInspector {
public object AfterReceiveRequest {
... gather Request data.
}
public void BeforeSendReply {
... gather Request data.
... Log using ADO.NET
... Dispose of Command object. No Connection closing!
}
}
I need to close the connection within WebServiceLogger once I'm done with logging. Options I've identified are:
Implement an IDisposable on WebServiceLogging class and do a Dispose() there or
Dispose of SomeDatabaseConnection directly from WebServiceLogger.BeforeSendReply()
My questions here are:
IDispatchMessageInspectors (such as WebServiceLogger) passed into dispatchRuntime.MessageInspectors - I've noticed that this object is not recreated per each request, but rather only once on the first request towards my service. How are such objects disposed of? Does WCF call `Dispose()˙ on them or should I use some other approach here?
Since we're at it, I have a nagging thought that perhaps using unmanaged resources in an Attribute is not such a good idea. Googling for c# attribute dispose didn't yield any results (there is one result on destructor, though). Any critiques on this approach?
Open and close a connection inside the BeforeSendReply method; i.e. make it a local variable (with a using-block, etc.).
Something like this:
public void BeforeSendReply {
... gather Request data.
using (var conn = new SqlConnection(...)) {
... Log using ADO.NET
}
}
The overhead is usually irrelevant (as ADO.NET uses connection pooling and won't really open/close a brand new connection). Second, and most importantly, that way you don't have to think about how your interceptor instance is used/called in a multithreaded (parallel requests) scenario.
That also matches better the unit of work pattern, that would be typically used if you did the same thing in the implementation method of an OperationContract. If you think about it, the interceptor points (AfterReceiveRequest and BeforeSendReply) are really just extensions of such method implementations (kind of AOP).
Our application calls external services like
//in client factory
FooServiceClient client = new FooServiceClient(binding, endpointAddress);
//in application code
client.BarMethod(); //or other methods
Is it possible to track all of these calls (e.g by events or something like that) so that the application can collect the statistics like number of call, response time, etc? Note that my application itself needs to access the values, not only to write to a log file.
What I can think is to create a subclass of VisualStudio-generated FooServiceClient and then add codes like this
override void BarMethod()
{
RaiseStart("BarMethod");
base.BarMethod();
RaiseEnd("BarMethod);
}
and the RaiseStart and RaiseEnd method will raise events that will be listened by my code.
But this seems tedious (because there are a lot of methods to override) and there is a lot of repeated codes, my code needs to change everytime the service contract changes, etc. Is there a simpler way to achieve this, for example by using reflection to create the subclass or by tapping into a built-in method in WCF, if any?
The first thing I would look at is to see if the counters available in your server's Performance Monitor can provide you with the kind of feedback you need. There's built in counters for a variety of metrics for ServiceModel Endpoints, Operations and Services. Here is some more info http://msdn.microsoft.com/en-us/library/ms735098.aspx
You could try building an implementation of IClientMessageInspector, which has a method to be called before the request is sent and when the reply is received. You can inspect the message, make logs etc in these methods.
You provide an implementation of IEndpointBehavior which applies your message inspector, and then add the endpoint behavior to your proxy client instance.
client.Endpoint.Behaviors.Add(new MyEndpointBehavior())
Check out the docs for MessageInspectors and EndpointBehaviors, there are many different ways of applying them (attributes, code, endpoint xml config), I can't remember of the top of my head which apply to which, as there also IServiceBehavior and IContractBehavior. I do know for sure that the endpoint behaviors can be added to the client proxy collection though.
I found a simple way to do it by using dynamic proxy, for example Castle's Dynamic Proxy.
Firstly, use a factory method to generate your client object
IFooClient GetClient()
{
FooClient client = new FooClient(); //or new FooClient(binding, endpointAddress); if you want
ProxyGenerator pg = new ProxyGenerator();
return pg.CreateInterfaceProxyWithTarget<IFoo>(client, new WcfCallInterceptor());
}
And define the interceptor
internal class WcfCallInterceptor : IInterceptor
{
public void Intercept(IInvocation invocation)
{
try
{
RaiseStart(invocation.Method.Name);
invocation.Proceed();
}
finally
{
RaiseEnd(invocation.Method.Name);
}
}
//you can define your implementation for RaiseStart and RaiseEnd
}
I can also change the intercept method as I wish, for example I can add a catch block to call a different handler in case the method throw exception, etc.
What does System.ServiceModel.Clientbase.Open() do? I've never used it but just came across it in some code. Can it throw exceptions? If Close() is not called is it a problem?
If you create a proxy for a WCF service the proxy is effectively ClientBase
Example from my app:
public class DataClient : ClientBase<Classes.IDataService>, Classes.IDataService
{
public DataClient(string connectToHost)
: base(new NetTcpBinding(SecurityMode.Transport)
{
PortSharingEnabled = true,
Security = new NetTcpSecurity()
{
Transport = new TcpTransportSecurity()
{
ClientCredentialType = TcpClientCredentialType.Windows
}
}
},
new EndpointAddress(string.Format("net.tcp://{0}:5555/MyService",connectToHost)))
{ }
#region IDataService Members
public Classes.Folder GetFolder(string entryID)
{
return Channel.GetFolder(entryID);
}
public Classes.IItem GetItem(string entryID)
{
return Channel.GetItem(entryID);
}
#endregion
}
EDIT
Per your request I googled a bit and found this:
Implements ICommunicationObject.Open()
This led to this:
CommunicationException
The ICommunicationObject was unable to
be opened and has entered the Faulted
state.
TimeoutException
The default open timeout elapsed
before the ICommunicationObject was
able to enter the Opened state and has
entered the Faulted state.
Also, per experience and what I've come across on the 'net not closing your clients can cause various forms of strangeness to occur and is thus generally considered "A Bad Thing".
Just found this article:
Best Practice: Always open WCF client proxy explicitly when it is shared
https://blogs.msdn.microsoft.com/wenlong/2007/10/25/best-practice-always-open-wcf-client-proxy-explicitly-when-it-is-shared/
That states in the end:
If you don’t call the “Open” method first, the proxy would be opened internally when the first call is made on the proxy. This is called auto-open.
Why? When the first message is sent through the auto-opened proxy, it will cause the proxy to be opened automatically. You can use .NET Reflector to open the method System.ServiceModel.Channels.ServiceChannel.Call and see the following code:
if (!this.explicitlyOpened)
{
this.EnsureDisplayUI();
this.EnsureOpened(rpc.TimeoutHelper.RemainingTime());
}
When you drill down into EnsureOpened, you will see that it calls CallOnceManager.CallOnce. For non-first calls, you would hit SyncWait.Wait which waits for the first request to complete. This mechanism is to ensure that all requests wait for the proxy to be opened and it also ensures the correct execution order. Thus all requests are serialized into a single execution sequence until all requests are drained out from the queue. This is not a desired behavior in most cases.
To avoid such “serializing” artifact, the best practice is to open the proxy explicitly as above. Once you get to this point, you will be able to share the same proxy object among multiple threads.
I am working on a Silverlight/WCF application and of course have numerous async calls throughout the Silverlight program. I was wondering on how is the best way to handle the creation of the client classes and subscribing. Specifically, if I subscribe to an event in a method, after it returns does it fall out of scope?
internal MyClass
{
public void OnMyButtonClicked()
{
var wcfClient = new WcfClient();
wcfClient.SomeMethodFinished += OnMethodCompleted;
wcfClient.SomeMethodAsync();
}
private void OnMethodCompleted(object sender, EventArgs args)
{
//Do something with the result
//After this method does the subscription to the event
//fall out of scope for garbage collection?
}
}
Will I run into problems if I call the function again and create another subscription?
Thanks in advance to anyone who responds.
You shouldn't let WCF client proxies simply fall out of scope like this. Your code will work but it will also leak resources. WCF clients all implement IDisposable, but this is one case where you can't just use using or Dispose; the Service Proxy Helper can be used for synchronous operations but the cleanup code in there demonstrates how to safely dispose of the client in any context.
When making async operations like this, something needs to be managing the lifetime of that client in a similar fashion. Normally whatever class "owns" the WCF client should implement IDisposable itself, keep a reference to that client in a private field somewhere, and invoke Close/Abort on the client in its disposal method.
Generally, whichever class actually implements the async callback method is going to be the owner, and so that class should be managing the lifetime; therefore, if you really need an "on-demand" client, it may also make sense to perform the cleanup after the callback is finished.
WCF clients are not cheap to create, either, so you should actually try to keep them around as long as possible and not create them ad-hoc like this; think of them as application-wide dependencies.
If you just keep the client instance around, then you don't need to keep subscribing to its events, either; the question effectively goes away.
You won't run into problems. It will generate a new WcfClient instance, and both will call your OnMethodCompleted callback on completion.