调用Web服务时出现未知异常

时间:2015-01-30 15:17:04

标签: c# .net wcf dynamic-proxy

我的系统中有两个WCF网络服务。

Web服务A调用Web服务B.大部分时间,它都能正常工作。但是,在调用B:

时,会引发A中的异常
  

调用目标抛出了异常。

为了试着知道问题出在哪里,我在B中的被调用方法中放了一个巨大的Try Catch,从第一条指令到最后一条指令。同样的问题。

然后我尝试将customErrors设置为off并将includeExceptionDetailInFaults设置为true,以便从异常中获取详细信息。同样的问题。

这不是超时问题,因为请求持续时间低于1秒。

我检查了请求的长度,一些好的请求比不好的请求长。问题不在于规模。

我无法重现这个问题,因为它只出现了几次。

我认为如果问题出现在A上,则异常会比此消息有更多详细信息。

问题可能在IIS上(两者都在同一个IIS实例上),但A通过localhost:xxxx / mywebservice.svc与B通信,所以很难相信这是一个通信问题。

编辑:

有InnerException消息:

  

无法访问已处置的对象。对象名称:   'System.ServiceModel.Channels.ServiceChannel'。

网络服务A使用动态调用B,使用:http://blogs.msdn.com/b/vipulmodi/archive/2006/11/16/dynamic-programming-with-wcf.aspx 另一个链接:https://github.com/carlosfigueira/WCFQuickSamples/tree/master/WCFForums/DynamicProxy

这是我的代码:

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

和FactoryTest课程:

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;
        }
    }
}

有一个完整的例外:

  

调用目标抛出了异常。在   System.RuntimeMethodHandle._InvokeMethodFast(IRuntimeMethodInfo   方法,对象目标,Object []参数,SignatureStruct& SIG,   MethodAttributes methodAttributes,RuntimeType typeOwner)at   System.RuntimeMethodHandle.InvokeMethodFast(IRuntimeMethodInfo方法,   Object target,Object []参数,Signature sig,MethodAttributes   methodAttributes,RuntimeType typeOwner)at   System.Reflection.RuntimeMethodInfo.Invoke(Object obj,BindingFlags   invokeAttr,Binder binder,Object []参数,CultureInfo文化,   布尔值skipVisibilityChecks)at   System.Reflection.RuntimeMethodInfo.Invoke(Object obj,BindingFlags   invokeAttr,Binder binder,Object []参数,CultureInfo文化)
  在System.RuntimeType.InvokeMember(String name,BindingFlags   bindingFlags,Binder binder,Object target,Object [] providedArgs,   ParameterModifier []修饰符,CultureInfo文化,String []   在WS_Generic.Service.CallWsMethod(String。)中的namedParams   sXmlSettings,String sXmlIN,String& sXmlOUT)

有一个完整的InnerException:

  

无法访问已处置的对象。对象名称:   'System.ServiceModel.Channels.ServiceChannel'。

     

服务器堆栈跟踪:at   System.ServiceModel.Channels.CommunicationObject.ThrowIfDisposedOrNotOpen()   在System.ServiceModel.Channels.ServiceChannel.Call(String action,   Boolean oneway,ProxyOperationRuntime操作,Object [] ins,   对象[]出局,TimeSpan超时)at   System.ServiceModel.Channels.ServiceChannelProxy.InvokeService(IMethodCallMessage   methodCall,ProxyOperationRuntime operation)at   System.ServiceModel.Channels.ServiceChannelProxy.Invoke(即时聊天   消息)

     

在[0]处重新抛出异常:at   System.Runtime.Remoting.Proxies.RealProxy.HandleReturnMessage(即时聊天   reqMsg,IMessage retMsg)at   System.Runtime.Remoting.Proxies.RealProxy.PrivateInvoke(MessageData&安培;   IWsAfsol.EmvTrxAuthorization(String sXmlIn)中的msgData,Int32类型)   在WsAfsolClient.EmvTrxAuthorization(String sXmlIn)

1 个答案:

答案 0 :(得分:0)

我在您的更新中快速使用了Google,并在asp.net论坛上找到了this post

我猜测(不知道你的代码是什么样的)你有一个共享的连接/服务,你打开它然后在代码中需要时调用。

选项(再次,猜测这里没有看到代码)

  1. 在拨打电话之前检查服务的状态,看看它是否已准备好/能够被呼叫。如果它已关闭,请创建一个新实例。销毁/创建的共享资源的问题是,除非您使其线程安全,否则该进程不是线程安全的。
  2. (我将采取的方式)始终创建一个新实例并在每次调用时关闭它,让底层框架处理连接池。服务连接只在使用它的方法中具有范围。
  3. 根据您的最新修改进行修改:

    在您的代码中,您正在调用proxy.Close();这实际上是对Dispose的调用,但是你将对象保留在哈希表中,即使它已经被处理掉了。您对同一对象/服务的第二次调用(无论何时发生)将触发您的异常。然后选项是1.只在不再需要时调用close / dispose,例如当应用程序关闭或完全在调用代码的上下文中使用短期实例时,即。为每个调用创建,使用,销毁和忘记,并且不要将实例保留在哈希表中(您可以将其转换为构建器以为每个请求提供新实例)。

    根据最新评论编辑#2

    对Close的调用仍然会破坏底层频道。您可以通过连续两次调用相同的服务并在第一次调用Close()之后立即调用GC.Collect()来测试这个:

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

    这是一种可以重构代码的方法。

    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