简体   繁体   English

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

[英]Unknown exception when calling a webservice

I have in my system two WCF webservices. 我的系统中有两个WCF Web服务。

The webservice A calls the webservice B. Most part of the time, it works properly. Web服务A调用Web服务B。在大多数情况下,它可以正常工作。 But sometines, an exception in A is raised when it calls B : 但是,有些例程会在A调用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. 为了试图知道问题出在哪里,我从第一个指令到最后一个指令,在B中的被调用方法中放置了一个巨大的Try Catch。 Same problem. 同样的问题。

I try then to put customErrors to off and includeExceptionDetailInFaults to true in order to have details from the exception. 然后,我尝试将customErrors设置为off,将includeExceptionDetailInFaults设置为true,以获取来自异常的详细信息。 Same problem. 同样的问题。

It's not a timeout problem because requests duration are lower than 1 second. 这不是超时问题,因为请求持续时间小于1秒。

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. 我认为,如果问题出在A上,则异常将比此消息包含更多详细信息。

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. 也许问题出在IIS上(两者都在同一个IIS实例上),但是A通过localhost:xxxx / mywebservice.svc与B通信,因此很难相信这是一个通信问题。

EDIT : 编辑:

There is the InnerException Message : 有InnerException消息:

Cannot access a disposed object. 无法访问已处置的对象。 Object name: 'System.ServiceModel.Channels.ServiceChannel'. 对象名称:“ 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 Web服务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

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

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) 在System.RuntimeMethodHandle.InvokeMethodFast(IRuntimeMethodInfo方法,对象目标,Object []参数,签名sig,MethodAttributes方法)处的System.RuntimeMethodHandle._InvokeMethodFast(IRuntimeMethodInfo方法,对象目标,Object []参数,SignatureStruct&sig,MethodAttributes methodAttributes,RuntimeType typeOwner)处,位于System.Reflection.RuntimeMethodInfo.Invoke(对象obj,BindingFlags invokeAttr,活页夹活页夹,Object []参数,CultureInfo文化,布尔型skipVisibilityChecks)位于System.Reflection.RuntimeMethodInfo.Invoke(对象obj,BindingFlags invokeAttr,活页夹活页夹) ,Object []参数,CultureInfo文化)
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) 在WS_Generic.Service.CallWsMethod(String sXmlSettings,字符串sXmlIN, String&sXmlOUT)

There is a complete InnerException : 有完整的InnerException:

Cannot access a disposed object. 无法访问已处置的对象。 Object name: 'System.ServiceModel.Channels.ServiceChannel'. 对象名称:“ 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) 服务器堆栈跟踪:位于System.ServiceModel.Channels.ServiceChannel.Call处System.ServiceModel.Channels.CommunicationObject.ThrowIfDisposedOrNotOpen()处(字符串操作,布尔型单向,ProxyOperationRuntime操作,Object [] ins,Object [] outs,TimeSpan超时) System.ServiceModel.Channels.ServiceChannelProxy.Invoke(IMessage消息)上的System.ServiceModel.Channels.ServiceChannelProxy.InvokeService(IMethodCallMessage methodCall,ProxyOperationRuntime操作)

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) 在[0]处抛出异常:在System.Runtime.Remoting.Proxies.RealProxy.PrivateInvoke(MessageData&msgData,Int32类型)在System.Runtime.Remoting.Proxies.RealProxy.HandleReturnMessage(IMessage reqMsg,IMessage retMsg)在IWsAfsolorization.EmvTr WsAfsolClient.EmvTrxAuthorization(String sXmlIn)处的String sXmlIn)

I did a quick Google with your update and found this post on the asp.net forums. 我对您的更新进行了快速Google搜索,并在asp.net论坛上找到了这篇文章

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(); 在您的代码中,您正在调用proxy.Close();。 which is actually a call to Dispose but you keep the object in your hashtable even though it has been disposed. 这实际上是对Dispose的调用,但是即使对象已被处理,您也将其保留在哈希表中。 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. 然后,选项为1.仅在不再需要时(例如,应用程序关闭或完全在调用代码的上下文中使用短寿命的实例时),才调用close / dispose。 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 根据最新评论编辑#2

The call to Close still destroys the underlying channels. 调用Close仍会破坏底层通道。 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: 您可以通过连续两次调用同一服务,并在第一次调用Close()之后立即调用GC.Collect()来进行测试,如下所示:

....
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

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

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