简体   繁体   中英

Unknown exception when calling a webservice

I have in my system two WCF webservices.

The webservice A calls the webservice B. Most part of the time, it works properly. But sometines, an exception in A is raised when it calls B :

Exception has been thrown by the target of an invocation.

In order to try to know where is the problem, I put a huge Try Catch in the called method in B, from the first instruction to the last. Same problem.

I try then to put customErrors to off and includeExceptionDetailInFaults to true in order to have details from the exception. Same problem.

It's not a timeout problem because requests duration are lower than 1 second.

I checked length of requests, and some good requests are longer than bad requests. The problem is not the size.

I can't reproduce the problem, because it appears only few times.

I think if the problem was on A, exception would have more details than this message.

Maybe the problem is on IIS (both are on the same IIS instance), but A communicate to B via localhost:xxxx/mywebservice.svc, so It's hard to believe it's a communication problem.

EDIT :

There is the InnerException Message :

Cannot access a disposed object. Object name: 'System.ServiceModel.Channels.ServiceChannel'.

The webservice A use a dynamic call for B, using this : http://blogs.msdn.com/b/vipulmodi/archive/2006/11/16/dynamic-programming-with-wcf.aspx Another link here : https://github.com/carlosfigueira/WCFQuickSamples/tree/master/WCFForums/DynamicProxy

Here is my code :

DynamicProxy proxy = null;
[...]
proxy = FactoryTest.getProxy(sServiceWsdl, sContract);
[...]
try {
   sXmlOUT = (String)proxy.CallMethod(sMethod, sXmlIN);
   proxy.Close();
catch (Exception e)
{
   // Here appears the exception
}
[...]

And FactoryTest class :

public sealed class FactoryTest
{
    private static object syncRoot = new Object();
    private static Hashtable hashFactory = new Hashtable();

    public static DynamicProxy getProxy(String sServiceWsdl, String sContract)
    {
        if (hashFactory[sServiceWsdl] == null || ((ProxyTest)hashFactory[sServiceWsdl]).getTimeFromCreation().TotalSeconds > 60 * 60 * 6)
        {
            lock (syncRoot)
            {
                if (hashFactory[sServiceWsdl] == null || ((ProxyTest)hashFactory[sServiceWsdl]).getTimeFromCreation().TotalSeconds > 60 * 60 * 6)
                {
                    hashFactory.Add(sServiceWsdl, new ProxyTest(sServiceWsdl, sContract));
                }
            }
        }

        return ((ProxyTest)hashFactory[sServiceWsdl]).getProxy();
    }

    public static bool isProxyExists(String sServiceWsdl, String sContract)
    {
        lock (syncRoot)
        {
            return hashFactory[sServiceWsdl] == null ? false : true;
        }
    }
}

There is a complete Exception :

Exception has been thrown by the target of an invocation. at System.RuntimeMethodHandle._InvokeMethodFast(IRuntimeMethodInfo method, Object target, Object[] arguments, SignatureStruct& sig, MethodAttributes methodAttributes, RuntimeType typeOwner) at System.RuntimeMethodHandle.InvokeMethodFast(IRuntimeMethodInfo method, Object target, Object[] arguments, Signature sig, MethodAttributes methodAttributes, RuntimeType typeOwner) at System.Reflection.RuntimeMethodInfo.Invoke(Object obj, BindingFlags invokeAttr, Binder binder, Object[] parameters, CultureInfo culture, Boolean skipVisibilityChecks) at System.Reflection.RuntimeMethodInfo.Invoke(Object obj, BindingFlags invokeAttr, Binder binder, Object[] parameters, CultureInfo culture)
at System.RuntimeType.InvokeMember(String name, BindingFlags bindingFlags, Binder binder, Object target, Object[] providedArgs, ParameterModifier[] modifiers, CultureInfo culture, String[] namedParams) at WS_Generic.Service.CallWsMethod(String sXmlSettings, String sXmlIN, String& sXmlOUT)

There is a complete InnerException :

Cannot access a disposed object. Object name: 'System.ServiceModel.Channels.ServiceChannel'.

Server stack trace: at System.ServiceModel.Channels.CommunicationObject.ThrowIfDisposedOrNotOpen() at System.ServiceModel.Channels.ServiceChannel.Call(String action, Boolean oneway, ProxyOperationRuntime operation, Object[] ins, Object[] outs, TimeSpan timeout) at System.ServiceModel.Channels.ServiceChannelProxy.InvokeService(IMethodCallMessage methodCall, ProxyOperationRuntime operation) at System.ServiceModel.Channels.ServiceChannelProxy.Invoke(IMessage message)

Exception rethrown at [0]: at System.Runtime.Remoting.Proxies.RealProxy.HandleReturnMessage(IMessage reqMsg, IMessage retMsg) at System.Runtime.Remoting.Proxies.RealProxy.PrivateInvoke(MessageData& msgData, Int32 type) at IWsAfsol.EmvTrxAuthorization(String sXmlIn) at WsAfsolClient.EmvTrxAuthorization(String sXmlIn)

I did a quick Google with your update and found this post on the asp.net forums.

I am guessing (without knowing what your code looks like) that you have a shared connection/service that you leave open and then call whenever you need it in your code.

Options (again, guessing here without seeing code)

  1. Check the state of the service before making a call to see if it is ready/able to be called. If it is closed create a new instance. The problem with shared resources that are destroyed/created is that the process is not thread safe unless you make it thread safe.
  2. (the way I would take it) Always create a new instance and close it with every call and let the underlying framework handle the connection pooling. The service connection would have scope only inside the method that is consuming it.

Edit based on your latest edit:

In your code you are calling proxy.Close(); which is actually a call to Dispose but you keep the object in your hashtable even though it has been disposed. Your second call to the same object/service (whenever that occurs) will then trigger your exception. Options are then 1. only call close/dispose when it is no longer needed like when application shuts down or use short lived instances entirely in the context of the calling code ie. create, use, destroy and forget for each call and do not persist the instance in your hashlist (you could turn it into a builder to serve a new instance for each request).

Edit #2 based on latest comment

The call to Close still destroys the underlying channels. You could test this by calling the same service 2 times in a row and by calling GC.Collect() immediately after your 1st call to Close() like this:

....
sXmlOUT = (String)proxy.CallMethod(sMethod, sXmlIN);
proxy.Close();
GC.Collect();
var sXmlOUT2 = (String)proxy.CallMethod(sMethod, sXmlIN); // should trigger your exception
...

Here is a way you could refactor your code.

public class SomeClass
{
FactoryTest factory; // instantiate this somewhere like constructor

public void someMethod()
{
[...]
var proxy = factory.getProxy(sServiceWsdl, sContract);
[...]
try {
   sXmlOUT = (String)proxy.CallMethod(sMethod, sXmlIN);
   //  proxy.Close(); - do not close connection
catch (Exception e)
{
   // Here appears the exception
}
}// end method
}// end class

// optionally if you want the same instance to server other callers
// you can turn this into a Singleton pattern and return a shared 
// static instance of FactoryTest via a static method. Do not forget to 
// dispose of the singleton at the end of your application
public sealed class FactoryTest : IDisposable
{
    private object syncRoot = new Object();
    private Hashtable hashFactory = new Hashtable();

    public DynamicProxy getProxy(String sServiceWsdl, String sContract)
    {
        if (hashFactory[sServiceWsdl] == null || ((ProxyTest)hashFactory[sServiceWsdl]).getTimeFromCreation().TotalSeconds > 60 * 60 * 6)
        {
            lock (syncRoot)
            {
                if (hashFactory[sServiceWsdl] == null || ((ProxyTest)hashFactory[sServiceWsdl]).getTimeFromCreation().TotalSeconds > 60 * 60 * 6)
                {
                    hashFactory.Add(sServiceWsdl, new ProxyTest(sServiceWsdl, sContract));
                }
            }
        }

        return ((ProxyTest)hashFactory[sServiceWsdl]).getProxy();
    }

    public bool isProxyExists(String sServiceWsdl, String sContract)
    {
        lock (syncRoot)
        {
            return hashFactory[sServiceWsdl] == null ? false : true;
        }
    }

public void Dispose()
{
// implement IDisposable
// dispose of everything hashFactory using Close() or Dispose()
}

} // end class

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM