gpt4 book ai didi

wcf - 在哪里捕获 WCF 调用类上的失败连接?

转载 作者:行者123 更新时间:2023-12-04 17:05:49 26 4
gpt4 key购买 nike

我正在尝试编写一个封装 WCF 调用的类(如果重要,客户端是 Silverlight)。这一切都很顺利,但我不确定如何捕获连接失败,就好像服务器不会响应一样。似乎在 ChannelFactory 生成的代码中某处发生了一些工作,但我不确定。也欢迎一般的代码审查。 :)

底线,围绕 channel 的创建,或者 try/catch 中的开始或异步结果委托(delegate)不会捕获失败的连接。我想让那个 catch 运行 ServiceCallError 事件。

public class ServiceCaller : IDisposable
{
private IFeedService _channel;

public ServiceCaller()
{
var elements = new List<BindingElement>();
elements.Add(new BinaryMessageEncodingBindingElement());
elements.Add(new HttpTransportBindingElement());
var binding = new CustomBinding(elements);
var endpointAddress = new EndpointAddress(App.GetRootUrl() + "Feed.svc");
_channel = new ChannelFactory<IFeedService>(binding, endpointAddress).CreateChannel();
}

public void MakeCall(DateTime lastTime, Dictionary<string, string> context)
{
AsyncCallback asyncCallBack = delegate(IAsyncResult result)
{
var items = ((IFeedService)result.AsyncState).EndGet(result);
if (ItemsRetrieved != null)
ItemsRetrieved(this, new ServiceCallerEventArgs(items));
};
_channel.BeginGet(lastTime, context, asyncCallBack, _channel);
}

public event ItemsRetrievedEventHandler ItemsRetrieved;
public event ServiceCallErrorHandler ServiceCallError;

public delegate void ItemsRetrievedEventHandler(object sender, ServiceCallerEventArgs e);

public delegate void ServiceCallErrorHandler(object sender, ServiceCallErrorEventArgs e);

public void Dispose()
{
_channel.Close();
_channel.Dispose();
}
}

这是堆栈跟踪,对于那些好奇的人:
 An AsyncCallback threw an exception.
at System.ServiceModel.AsyncResult.Complete(Boolean completedSynchronously)
at System.ServiceModel.AsyncResult.Complete(Boolean completedSynchronously, Exception exception)
at System.ServiceModel.Channels.HttpChannelFactory.HttpRequestChannel.HttpChannelAsyncRequest.OnGetResponse(IAsyncResult result)
at System.Net.Browser.BrowserHttpWebRequest.<>c__DisplayClassd.<InvokeGetResponseCallback>b__b(Object state2)
at System.Threading._ThreadPoolWaitCallback.WaitCallback_Context(Object state)
at System.Threading.ExecutionContext.Run(ExecutionContext executionContext, ContextCallback callback, Object state)
at System.Threading._ThreadPoolWaitCallback.PerformWaitCallbackInternal(_ThreadPoolWaitCallback tpWaitCallBack)
at System.Threading._ThreadPoolWaitCallback.PerformWaitCallback(Object state)

为此,我在浏览器中启动应用程序,然后从 Visual Studio 中终止 Web 服务器进程。在测试环境中,我通过终止客户端系统的网络连接得到同样的结果。

这是完整异常的 ToString():
System.Exception: An AsyncCallback threw an exception. ---> System.Exception: An AsyncCallback threw an exception. ---> System.ServiceModel.CommunicationException: The remote server returned an error: NotFound. ---> System.Net.WebException: The remote server returned an error: NotFound. ---> System.Net.WebException: The remote server returned an error: NotFound.
at System.Net.Browser.BrowserHttpWebRequest.InternalEndGetResponse(IAsyncResult asyncResult)
at System.Net.Browser.BrowserHttpWebRequest.<>c__DisplayClass5.<EndGetResponse>b__4(Object sendState)
at System.Net.Browser.AsyncHelper.<>c__DisplayClass2.<BeginOnUI>b__0(Object sendState)
--- End of inner exception stack trace ---
at System.Net.Browser.AsyncHelper.BeginOnUI(SendOrPostCallback beginMethod, Object state)
at System.Net.Browser.BrowserHttpWebRequest.EndGetResponse(IAsyncResult asyncResult)
at System.ServiceModel.Channels.HttpChannelFactory.HttpRequestChannel.HttpChannelAsyncRequest.CompleteGetResponse(IAsyncResult result)
--- End of inner exception stack trace ---
at System.ServiceModel.Channels.Remoting.RealProxy.Invoke(Object[] args)
at proxy_2.EndGet(IAsyncResult )
at CoasterBuzz.Feed.Client.ServiceCaller.<MakeCall>b__0(IAsyncResult result)
at System.ServiceModel.AsyncResult.Complete(Boolean completedSynchronously)
--- End of inner exception stack trace ---
at System.ServiceModel.AsyncResult.Complete(Boolean completedSynchronously)
at System.ServiceModel.AsyncResult.Complete(Boolean completedSynchronously, Exception exception)
at System.ServiceModel.Channels.ServiceChannel.SendAsyncResult.CallComplete(Boolean completedSynchronously, Exception exception)
at System.ServiceModel.Channels.ServiceChannel.SendAsyncResult.FinishSend(IAsyncResult result, Boolean completedSynchronously)
at System.ServiceModel.Channels.ServiceChannel.SendAsyncResult.SendCallback(IAsyncResult result)
at System.ServiceModel.AsyncResult.Complete(Boolean completedSynchronously)
--- End of inner exception stack trace ---
at System.ServiceModel.AsyncResult.Complete(Boolean completedSynchronously)
at System.ServiceModel.AsyncResult.Complete(Boolean completedSynchronously, Exception exception)
at System.ServiceModel.Channels.HttpChannelFactory.HttpRequestChannel.HttpChannelAsyncRequest.OnGetResponse(IAsyncResult result)
at System.Net.Browser.BrowserHttpWebRequest.<>c__DisplayClassd.<InvokeGetResponseCallback>b__b(Object state2)
at System.Threading._ThreadPoolWaitCallback.WaitCallback_Context(Object state)
at System.Threading.ExecutionContext.Run(ExecutionContext executionContext, ContextCallback callback, Object state)
at System.Threading._ThreadPoolWaitCallback.PerformWaitCallbackInternal(_ThreadPoolWaitCallback tpWaitCallBack)
at System.Threading._ThreadPoolWaitCallback.PerformWaitCallback(Object state)

顺便说一句,我能捕获这一点的唯一方法是在 SL 客户端中使用应用程序级别的 UnhandledException 事件。

最佳答案

杰夫,我不能完全确定你是如何模拟连接失败的。我假设“好像服务器不会响应”意味着您正在寻找某种超时错误。您可能正在通过在服务器端使用 Thread.Sleep() 强制您的服务调用缓慢响应来模拟无响应的服务器。对?足够近?

我有一个类似的项目,所以我对此进行了测试,并且能够成功捕获超时和其他异常。我想您可能没有看到这些异常,因为您的自定义绑定(bind)有一个很长的默认超时时间,而且您可能没有等待足够长的时间。

解释一下,WCF 超时由绑定(bind)配置控制。查看您的代码,您正在创建自己的自定义绑定(bind),如下所示:

var elements = new List<BindingElement>();
elements.Add(new BinaryMessageEncodingBindingElement());
elements.Add(new HttpTransportBindingElement());
var binding = new CustomBinding(elements);

如果您在此处设置断点并检查您创建的自定义绑定(bind),您将看到它有一分钟 SendTimeout默认情况下。我怀疑您要么等待的时间不够长,要么没有将服务的模拟超时设置得足够长,因此您无法捕获超时异常。

下面是一些代码更改来演示。首先,设置绑定(bind)的超时时间:
var binding = new CustomBinding(elements);
//Set the timeout to something reasonable for your service
//This will fail very quickly
binding.SendTimeout = TimeSpan.FromSeconds(1);

最后,要捕获异常并引发正确的事件,您可以按如下方式更新您的 AsyncCallback 委托(delegate)。调用 EndGet() 时会引发异常。
AsyncCallback asyncCallBack = delegate(IAsyncResult result)
{
IFeedService service = ((IFeedService)result.AsyncState);
try
{
var items = service.EndGet(result);
ItemsRetrieved(this, EventArgs.Empty);
}
catch (System.TimeoutException ex)
{
//Handles timeout
ServiceCallError(this, EventArgs.Empty);
}
catch (System.ServiceModel.CommunicationException ex)
{
//Handles a number of failures:
// Lack of cross-domain policy on target site
// Exception thrown by a service
ServiceCallError(this, EventArgs.Empty);
}
catch (System.Exception ex)
{
//Handles any other errors here
ServiceCallError(this, EventArgs.Empty);
}
};

就一般代码审查而言,我建议您避免对绑定(bind)配置进行硬编码。您可以改为在 ServiceReferences.ClientConfig 文件中声明您的端点配置(包括合理的超时),并使用如下端点名称新建您的 channel 工厂:
new ChannelFactory<IFeedService>("feedServiceEndpoint");

随着时间的推移,这应该会使应用程序更易于维护。

我希望这有帮助。

杰瑞

更新:

杰夫,

请查看此代码和其中的注释,以获取对这里发生的事情的更多解释。 MakeCall() 方法正在创建一个传递给 BeginGet() 方法的函数(委托(delegate))。该函数稍后在服务响应时执行。

请进行建议的更改并在以“AsyncCallback asyncCallback”和“var items”开头的行处设置断点。您将看到调试器的第一次传递只是声明了在服务响应时要执行的代码(函数/委托(delegate)),而第二次传递是该响应的实际处理,从委托(delegate)声明的内部开始。这意味着在处理服务调用的响应时,外部 try/catch 将不在范围内。
public void MakeCall(DateTime lastTime, Dictionary<string, string> context)
{
try
{
AsyncCallback asyncCallBack = delegate(IAsyncResult result)
{
try
{
var items = ((IFeedService)result.AsyncState).EndGet(result);
if (ItemsRetrieved != null)
ItemsRetrieved(this, new ServiceCallerEventArgs(items));
}
catch (Exception ex)
{
//This will catch errors from the service call
}
};
_channel.BeginGet(lastTime, context, asyncCallBack, _channel);
}
catch(Exception ex)
{
//This will not catch an error coming back from the service. It will
//catch only errors in the act of calling the service asynchronously.

//The communication with the service and response is handled on a different
//thread, so this try/catch will be out of scope when that executes.

//So, at this point in the execution, you have declared a delegate
//(actually an anonymous delegate the compiler will turn into a hidden class)
//which describes some code that will be executed when the service responds.

//You can see this in action by setting a breakpoint just inside the delegate
//at the line starting with "var items". It will not be hit until the service
// responds (or doesn't respond in a timeout situation).
}
}

杰瑞

关于wcf - 在哪里捕获 WCF 调用类上的失败连接?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/1204534/

26 4 0
Copyright 2021 - 2024 cfsdn All Rights Reserved 蜀ICP备2022000587号
广告合作:1813099741@qq.com 6ren.com