I have 2 WCF services that are both installed locally on the same Windows Service. The 2 WCF services make calls to the same database and use Net TCP Binding.
Side Note: I made 2 services instead of 1 because the service had too many methods and as a result, the XML file was too large and I couldn't add the service reference to the consumer app. Also, it's more readable this way.
On the client app, I've added a service reference to both WCF services. To use the services, I extended the CommunicationObject so it has a "Using()" method: see the code below.
Communication Object Extension for .Using() Method
public static class CommunicationObjectExtensions
{
public static void Using<T>(this T client, Action<T> work)
where T : ICommunicationObject
{
try
{
// make sure client is open
//client.Open(); // didn't work
work(client);
}
catch (CommunicationException e)
{
client.Abort();
throw;
}
catch (TimeoutException e)
{
client.Abort();
throw;
}
catch (Exception e)
{
client.Abort();
throw;
}
finally
{
client.Close();
}
}
}
Service Calls
new ServiceClientA().Using(client =>
{
var someObjectA = client.GetSomeObjectA();
});
new ServiceClientB().Using(client =>
{
var someObjectB = client.GetSomeObjectB();
});
I get the "The socket connection has been disposed" error when ServiceClientB's method actually has data to return (versus an empty list) and returns (I'm able to debug and go through the entire service call).
I don't run into this problem when using the other WCF services that point to different databases.
Anyone have any ideas what's going on?
Update
Ok turns out it only happens with the method I'm calling (client.GetSomeObjectB()). The object it's returning is causing errors. Apparently this is because the object is too big, but it shouldn't be a problem (since I'm only returning 1 small object).
Related
I have a web application that serves users through connections to other third party web services.
I am not sure about the safe/efficient way to create those web service clients in my application.
As of .NET 4.5, I can use client code generated through svcutil and cache channel factories per service by setting the static CacheSetting property.
Example from MSDN site:
class Program
{
static void Main(string[] args)
{
ClientBase<ITest>.CacheSettings = CacheSettings.AlwaysOn;
foreach (string msg in messages)
{
using (TestClient proxy = new TestClient (new BasicHttpBinding(), new EndpointAddress(address)))
{
// ...
proxy.Test(msg);
// ...
}
}
}
}
// Generated by SvcUtil.exe
public partial class TestClient : System.ServiceModel.ClientBase, ITest { }
As a result there is no need to custom implement that functionality as well mentioned in :
creating WCF ChannelFactory<T>
https://philmunro.wordpress.com/2012/02/15/creating-a-wcf-service-proxy-with-channelfactory/
Also MSDN states that we should not use the C# "using" statement to automatically clean up resources when using a typed client and handle it with try/catch.
Example from MSDN site:
try
{
...
double result = client.Add(value1, value2);
...
client.Close();
}
catch (TimeoutException exception)
{
Console.WriteLine("Got {0}", exception.GetType());
client.Abort();
}
catch (CommunicationException exception)
{
Console.WriteLine("Got {0}", exception.GetType());
client.Abort();
}
1) Is the above way of calling a service safe to follow? Do I miss something? Or it's better to handle factory creation manually?
2) Am I going to have any problems with faulty states (both factory/channel)?
3) I need to create a new client for each service call right?
I have a WCF web service that accesses a WCF windows service on a different machine. The windows service does all the data accessing and passes the results to the web service. I have read several articles about disposing the service client for a WCF service correctly, but I'm not sure what the best way is to do this in a web service. (If this helps, the web service is PerCall not PerSession)
This is all I'm doing right now:
Public Class Service1
Implements IService1
Private p_oWindowsService As DataService.Service1Client
Public Sub New()
p_oWindowsService = New DataService.Service1Client
End Sub
Public Function GetData(ByVal value As Integer) As String Implements IService1.GetData
Return p_oWindowsService.GetData(value)
End Function
Public Function GetDataUsingDataContract(ByVal composite As CompositeType) As CompositeType Implements IService1.GetDataUsingDataContract
If composite Is Nothing Then
Throw New ArgumentNullException("composite")
End If
If composite.BoolValue Then
composite.StringValue &= "Suffix"
End If
Return composite
End Function
I'm not disposing the service client at all right now, from what I've read this is a major issue. The workaround I'm looking at is something like this inside the GetData function:
Public Function GetData(ByVal value As Integer) As String Implements IService1.GetData
Using oWindowsService As New DataService.Service1Client
Return oWindowsService.GetData(value)
End Using
End Function
Based off What is the best workaround for the WCF client `using` block issue?, I know I shouldn't actually depend on the using block. But should I be creating and disposing a service client in every function? That's my real question.
Thank you.
Yes do not use dispose. Do it like this:
var client = new ...;
try {
// Do work
// Everything went well so close the client
client.Close();
}
catch( Exception ex ) {
// Something went wrong so call abort
client.Abort();
// Other logging code
}
if( client.State != System.ServiceModel.CommunicationState.Closed ) {
client.Close();
}
Calling Close() on client notifies the service instance that it is no longer in use and may be collected by GC (subject to service instance management).
You may wonder why Abort in the catch block? The reason is:
Given the WCF binding use transport sessions, the client after a fault would not even be able to close it (if there was no transport layer session then the client could use or close the proxy, but this is not recommended as the configuration of sessions could change). So after a fault has happened the only safe operation is to abort a proxy.
See this for more on Abort vs Close.
EDIT
In your comments you asked:
Do you recommend creating and closing a service client like this within every function the web service calls the windows service?
No I don't think that is necessary. Let's see you are calling the WCF service from a web application (ASP MVC), then you would do something like this in the Dispose method of the controller since ClientBase<TChannel> implements ICommunicationObject:
protected override void Dispose(bool disposing) {
base.Dispose( disposing );
ServiceHelper.DisposeService( ( this._whateverServiceClient as ICommunicationObject ) );
}
And here is the ServiceHelper class that you can use from anywhere:
public static class ServiceHelper {
/// <summary>
/// Disposes the given service.
/// </summary>
/// <param name="service">The service.</param>
public static void DisposeService(ICommunicationObject service) {
if( service != null ) {
bool abort = true;
try {
if( service.State == CommunicationState.Opened || service.State == CommunicationState.Opening ) {
service.Close();
abort = false;
}
}
finally {
// Determine if we need to Abort the communication object.
if( abort )
service.Abort();
}
}
}
}
The idea would be the same if you were calling it from another client.
You don't need to explicitly dispose the client, how ever if you truly must, this is one way of properly closing & disposing your client:
// use client
try
{
((IClientChannel)client).Close();
}
catch
{
((IClientChannel)client).Abort();
}
finally
{
((IDisposable)client).Dispose();
}
How can i catch the exception that occurs when starting a windows service. I am unable to get the exception here in my below code even though i am throwing exception in the Onstart() method of the service.
public class InterOpIntegrationWinService : ServiceBase
{
protected override void OnStart(string[] args)
{
throw new InvalidOperationException(message);
}
}
Calling thread code
try
{
using (ServiceController controller = new ServiceController())
{
controller.ServiceName = objServiceConfig.ServiceName;
controller.Start();
System.Windows.Forms.Application.DoEvents();
//controller.WaitForStatus(ServiceControllerStatus.Running, new TimeSpan(0, 0, 15));
//controller.WaitForStatus(ServiceControllerStatus.Running);
//if (!string.IsNullOrEmpty(LogUtilities.ServiceOnStartException))
//{
// MessageBox.Show("Error with starting service : " + LogUtilities.ServiceOnStartException);
// LogUtilities.ServiceOnStartException = string.Empty;
//}
}
}
catch (System.InvalidOperationException InvOpExcep)
{
DisplayError(InvOpExcep.Message);
LogUtilities.DisplayMessage("Failed to start service. " + LogUtilities.ServiceOnStartException, InvOpExcep);
LogUtilities.ServiceOnStartException = string.Empty;
}
catch (Exception ex)
{
DisplayError(ex.Message);
LogUtilities.DisplayMessage("Failed to start service. " + LogUtilities.ServiceOnStartException, ex);
LogUtilities.ServiceOnStartException = string.Empty;
}
i check for application license in the onstart() method and throws a licensing error if it fails. i want this to shared to my calling thread so i could show the message in a DialogBox. Any ideas of how to do this if i cannot handle the exceptions in my calling process.
Separate your service into (at least) two components - a component that deals with IPC in some form (e.g. Remoting, WCF endpoint, REST service, etc) and (one or more) components that do its actual job.
If the licensing check fails, don't start the other components - but do still start the component that offers IPC. After starting your service (which should now always at least start), you forms-based application can connect to the service and (through whatever means you want) determine that the service is currently refusing to provide any functionality due to a failed licensing check.
I have two self hosted services running on the same network. The first is sampling an excel sheet (or other sources, but for the moment this is the one I'm using to test) and sending updates to a subscribed client.
The second connects as a client to instances of the first client, optionally evaluates some formula on these inputs and the broadcasts the originals or the results as updates to a subscribed client in the same manner as the first. All of this is happening over a tcp binding.
My problem is occuring when the second service attempts to subscribe to two of the first service's feeds at once, as it would do if a new calculation is using two or more for the first time. I keep getting TimeoutExceptions which appear to be occuring when the second feed is subscribed to. I put a breakpoint in the called method on the first server and stepping through it, it is able to fully complete and return true back up the call stack, which indicates that the problem might be some annoying intricacy of WCF
The first service is running on port 8081 and this is the method that gets called:
public virtual bool Subscribe(int fid)
{
try
{
if (fid > -1 && _fieldNames.LeftContains(fid))
{
String sessionID = OperationContext.Current.SessionId;
Action<Object, IUpdate> toSub = MakeSend(OperationContext.Current.GetCallbackChannel<ISubClient>(), sessionID);//Make a callback to the client's callback method to send the updates
if (!_callbackList.ContainsKey(fid))
_callbackList.Add(fid, new Dictionary<String, Action<Object, IUpdate>>());
_callbackList[fid][sessionID] = toSub;//add the callback method to the list of callback methods to call when this feed is updated
String field = GetItem(fid);//get the current stored value of that field
CheckChanged(fid, field);//add or update field, usually returns a bool if the value has changed but also updates the last value reference, used here to ensure there is a value to send
FireOne(toSub, this, MakeUpdate(fid, field));//sends an update so the subscribing service will have a first value
return true;
}
return false;
}
catch (Exception e)
{
Log(e);//report any errors before returning a failure
return false;
}
}
The second service is running on port 8082 and is failing in this method:
public int AddCalculation(string name, string input)
{
try
{
Calculation calc;
try
{
calc = new Calculation(_fieldNames, input, name);//Perform slow creation before locking - better wasted one thread than several blocked ones
}
catch (FormatException e)
{
throw Fault.MakeCalculationFault(e.Message);
}
lock (_calculations)
{
int id = nextID();
foreach (int fid in calc.Dependencies)
{
if (!_calculations.ContainsKey(fid))
{
lock (_fieldTracker)
{
DataRow row = _fieldTracker.Rows.Find(fid);
int uses = (int)(row[Uses]) + 1;//update uses of that feed
try
{
if (uses == 1){//if this is the first use of this field
SubServiceClient service = _services[(int)row[ServiceID]];//get the stored connection (as client) to that service
service.Subscribe((int)row[ServiceField]);//Failing here, but only on second call and not if subscribed to each seperately
}
}
catch (TimeoutException e)
{
Log(e);
throw Fault.MakeOperationFault(FaultType.NoItemFound, "Service could not be found");//can't be caught, if this timed out then outer connection timed out
}
_fieldTracker.Rows.Find(fid)[Uses] = uses;
}
}
}
return id;
}
}
catch (FormatException f)
{
Log(f.Message);
throw Fault.MakeOperationFault(FaultType.InvalidInput, f.Message);
}
}
The ports these are on could change but are never shared. The tcp binding used is set up in code with these settings:
_tcpbinding = new NetTcpBinding();
_tcpbinding.PortSharingEnabled = false;
_tcpbinding.Security.Mode = SecurityMode.None;
This is in a common library to ensure they both have the same set up, which is also a reason why it is declared in code.
I have already tried altering the Service Throttling Behavior for more concurrent calls but that didn't work. It's commented out for now since it didn't work but for reference here's what I tried:
ServiceThrottlingBehavior stb = new ServiceThrottlingBehavior
{
MaxConcurrentCalls = 400,
MaxConcurrentSessions = 400,
MaxConcurrentInstances = 400
};
host.Description.Behaviors.RemoveAll<ServiceThrottlingBehavior>();
host.Description.Behaviors.Add(stb);
Has anyone had similar issues of methods working correctly but still timing out when sending back to the caller?
This was a difficult problem and from everything I could tell, it is an intricacy of WCF. It cannot handle one connection being reused very quickly in a loop.
It seems to lock up the socket connection, though trying to add GC.Collect() didn't free up whatever resources it was contesting.
In the end the only way I found to work was to create another connection to the same endpoint for each concurrent request and perform them on separate threads. Might not be the cleanest way but it was all that worked.
Something that might come in handy is that I used the svc trace viewer to monitor the WCF calls to try and track the problem, I found out how to use it from this article: http://www.codeproject.com/Articles/17258/Debugging-WCF-Apps
I'm new in WCF, just learning it so far. But I was wondering how to close a WCF client connection from the client side (if it is needed at all? I think so).
I have an interface called
[ServiceContract]
ICalculatorService { blabla... }
The question is on the client side.
So far, I used the following format:
EndpointAddress epAddress = new EndpointAddress("http://localhost:8090/CalculatorService");
ICalculatorService calculatorProxy = ChannelFactory<ICalculatorService>.CreateChannel(new WSHttpBinding(), epAddress);
and now I can:
Result numeralResult = calculatorProxy.AddNumbers(4, 5);
and I got the result and I was happy.
Every single (for example) Button pressing caused the mentioned code to run once.
My question is: is the efficient?
Now I'm thinking of putting this into a separate class, for example:
class CalculatorProxy
{
static EndpointAddress epAddress = new EndpointAddress("http://localhost:8090/CalculatorService");
public static ChannelFactory<ICalculatorService> GetCalculatorProxy()
{
}
public void Dispose() { ... }
}
... and use it like:
using (ICalculatorService calculatorClient = CalculatorProxy.GetCalculatorProxy())
{
calculatorClient.AddNumbers(4, 4);
}
which one would be more efficient?
UPDATE:
Thank you all for your answers.
I finally ended up with this class:
class CalculatorServiceClient : ClientBase<ICalculatorService>, IDisposable
{
static EndpointAddress epAddress = new EndpointAddress("http://localhost:8090/CalculatorService");
ICalculatorService myCalculatorProxy;
public CalculatorServiceClient()
: base(new WSHttpBinding(), epAddress)
{
myCalculatorProxy = ChannelFactory.CreateChannel();
}
public static CalculatorServiceClient GetNewInstance()
{
return new CalculatorServiceClient();
}
public Result AddNumbers(int aIn, int bIn)
{
return myCalculatorProxy.AddNumbers(aIn, bIn);
}
public void Dispose()
{
try
{
Close();
}
catch (CommunicationObjectFaultedException ex)
{
throw new DBCommunicationException("CalculatorServiceClient is in the Faulted state.", ex);
}
catch (Exception ex)
{
throw new DBCommunicationException("Communication is unsuccessful between the CalculatorServiceClient and the CalculatorService.", ex);
}
}
}
And use it in this way:
try
{
using (CalculatorServiceClient calculatorClient = CalculatorServiceClient.GetNewInstance())
{
Result aResult = calculatorClient.AddNUmbers(tbA.Text, tbB.Text);
}
}
catch (DBCommunicationException ex)
{
MessageBox.Show("Service is shut down.");
}
My question is: is this efficient?
You should just close the client when each operation you have done is completed and you don't need anymore to make other calls.
When your work is finished, just close the client using the Close method:
calculatorProxy.Close();
About the Close() method, the MSDN documentation states:
This method causes a CommunicationObject to gracefully transition from
any state, other than the Closed state, into the Closed state. The
Close method allows any unfinished work to be completed before
returning. For example, finish sending any buffered messages.
About your approach, I think the second one is fine and more efficient, because you're also implementing the Dispose pattern and release the used resources (this depends on the resources you're using). Just add the Close() method when the work is finished:
calculatorClient.AddNumbers(4, 4);
calculatorProxy.Close();
Remember also that there's no performance issue creating and closing continuously the WCF clients. This is just a normal habitude.
using (var client = new CalculatorServiceClient())
{
client.SomeMethod();
}
The CalculatorServiceClient object will be available once you add a Service Reference to your Calculator WebService to your client project.
you can call the close method of your proxy class.
like
calculatorProxy.Close();
Alternatively you call the abort method on your service proxy class in case of exception.
try
{
calculatorProxy.SomeMethod();
calculatorProxy.Close();
}
catch
{
calculatorProxy.Abort();
}
Refer to this link for further details
I think you would find it better to put all of that in a class. Establishing an instance of the class can construct the connection and close/dispose when the time comes. Until then, you have an open and active channel to make calls to.