简体   繁体   English

如何使用IAsyncResult从WCF异步中的回调引发异常

[英]How to throw an exception from callback in WCF Async using IAsyncResult

I am using WCF Async calls in my project and i am using Client side asynchronous methods. 我在项目中使用WCF异步调用,并且在使用客户端异步方法。 I have a scenario like below - 我有一个类似下面的情况-

  //Code in Business Layer and this method is called from Web layer 
    private void GetGeneralNews()
    {
        client.BeginGetGeneralNewsFeed(GeneralNewsCallback, null);
    }

    //Call Back Method
    private static void GeneralNewsCallback(IAsyncResult asyncResult)
    {
       string response = string.Empty;

       try
       {
          response = client.EndGetGeneralNewsFeed(asyncResult);
       }
       catch(Exception ex)
       {
          throw ex; // Here is the problem. It does not throw the exception to the web layer instead it will suppress the   error.
       }
    }

So as shown in the above code snippet it does not throw the exception from business layer to web layer as it will be suppressed here in business layer itself. 因此,如上面的代码片段所示,它不会在业务层到Web层之间引发异常,因为它将在业务层本身中被抑制。

I checked in some of the blogs and sites they are suggesting to go for async and await approach, as i have .NET 4.0 framework and i am seeing " Generate task-based Operations " option disabled. 我检查了一些建议使用异步和等待方法的博客和网站,因为我具有.NET 4.0框架,并且看到“ 生成基于任务的操作 ”选项已禁用。 So if there are any options using "IAsyncResult" (Begin & End in client side) please let me know. 因此,如果有任何使用“ IAsyncResult”的选项(在客户端开始和结束),请告诉我。 If there are any other approaches also welcome. 如果还有其他方法也欢迎。

Kindly someone help me. 请有人帮助我。

Thanks. 谢谢。

Here is a sample app which shows that WCF doesn't swallow the exception. 这是一个示例应用程序,它显示WCF不会吞下该异常。 If you don't receive the exception, it must be swallowed by your server side code. 如果没有收到该异常,则必须由服务器端代码将其吞没。

using System;
using System.ServiceModel;
using System.ServiceModel.Description;
using WcfQ.QServiceReference;

namespace WcfQ
{
[ServiceBehavior(IncludeExceptionDetailInFaults = true)]
public class QService : IQService
{
    public void Foo()
    {
        throw new ApplicationException("Please catch this");
    }
}

[ServiceContract]
public interface IQService
{
    [OperationContract]
    void Foo();
}

class Program
{
    static private QServiceClient client;

    static void Main(string[] args)
    {
        ServiceHost host = new ServiceHost(typeof(QService), new Uri("http://localhost:20001/q"));
        AddWsdlSupport(host);
        host.AddServiceEndpoint(typeof (IQService), new WSHttpBinding(SecurityMode.None), "");
        host.Open();

        client = new QServiceClient();
        client.BeginFoo(FooCallback, null);
        Console.WriteLine("ready");
        Console.ReadKey();
    }

    private static void FooCallback(IAsyncResult asyncResult)
    {
        try
        {
            client.EndFoo(asyncResult);
        }
        catch (Exception ex)
        {
            Console.WriteLine("Got the exception: " + ex.Message);
        }
    }

    static void AddWsdlSupport(ServiceHost svcHost)
    {
        ServiceMetadataBehavior smb = svcHost.Description.Behaviors.Find<ServiceMetadataBehavior>();
        // If not, add one
        if (smb == null)
            smb = new ServiceMetadataBehavior();
        smb.HttpGetEnabled = true;
        smb.MetadataExporter.PolicyVersion = PolicyVersion.Policy15;
        svcHost.Description.Behaviors.Add(smb);
        // Add MEX endpoint
        svcHost.AddServiceEndpoint(
          ServiceMetadataBehavior.MexContractName,
          MetadataExchangeBindings.CreateMexHttpBinding(),
          "mex"
        );

    }
}

} }

Here is the output of this program: 这是该程序的输出:

ready 
Got the exception: Please catch this

1) If you have already generated WCF client code with async ("Begin..."/"End...") methods - than you can use TPL's task API to work with WCF (ContinueWith etc.) via Task.Factory.FromAsync ( example ) - good for dealing with legacy IAsyncResult ("Begin..."/"End...") methods/APIs (simple though, you can see source with reflector); 1)如果您已经使用异步(“ Begin ...” /“ End ...”)方法生成了WCF客户端代码-那么您可以通过Task.Factory使用TPL的任务API与WCF(ContinueWith等)一起使用。 FromAsync( 示例 )-适用于处理旧版IAsyncResult(“ Begin ...” /“ End ...”)方法/ API(尽管简单,您可以看到带有反射器的源代码);

2) Tool-generated client code is not good approach - instead you can write your own universal client-proxy with true-async support (not just using background thread). 2)工具生成的客户端代码不是一个好方法-相反,您可以编写自己的具有true-async支持的通用client-proxy(而不仅仅是使用后台线程)。 Here is good example how to start, you need wrap "Begin..."/"End..." methods with task based methods (use same Task.Factory.FromAsync) and use expression trees to get rid string based service method calls (I can't share my class source). 是一个很好的示例,如何开始,您需要将“ Begin ...” /“ End ...”方法与基于任务的方法包装在一起(使用相同的Task.Factory.FromAsync),并使用表达式树来获取基于字符串的服务方法调用(我不能分享我的课程资料)。

Or you can use existing solutions like this . 或者,您可以使用像这样的现有解决方案。

3) Don't forget about ConfigureAwait . 3)不要忘记ConfigureAwait

Edit: 编辑:

You don't have to generate task-based operations, it's enough to generate WCF client code with async service operation methods ("Begin..."/"End..."). 您不必生成基于任务的操作,只需使用异步服务操作方法(“ Begin ...” /“ End ...”)即可生成WCF客户端代码。 Or you can even have only synchronous WCF contract! 或者,您甚至只能拥有同步WCF合同! (see links). (请参阅链接)。 TPL available in .NET 4 (without async/await syntactic sugar - which is CSharp 5.0 language feature). .NET 4中提供了TPL(没有异步/等待语法糖-这是CSharp 5.0语言功能)。 Use it (ContinueWith instead await + WhenAny, WhenAll). 使用它(ContinueWith代替await + WhenAny,WhenAll)。 I used it even in 3.5 via Microsoft Reactive Extensions v1.0.2856.0. 我什至在3.5中通过Microsoft Reactive Extensions v1.0.2856.0使用了它。 AFAIK Reactive Extensions was the initial version which than was included in BCL. AFAIK Reactive Extensions是初始版本,该版本已包含在BCL中。 ParallelExtensionsExtras may be useful as well ParallelExtensionsExtras也可能有用

Anyway i solved this by using TPL (Task Parallel Library). 无论如何,我通过使用TPL(任务并行库)解决了这个问题。

Reason i was getting problems in the above approach is my new threads will not be able to recognize the main thread, from which layer the method has been called. 我在上述方法中遇到问题的原因是我的新线程将无法识别主线程,从哪个层调用了该方法。 So using TPL i made my main thread wait till my other threads do the job and come back and then based on the response throw the exception. 因此,使用TPL,我让我的主线程等待,直到我的其他线程完成工作,然后再返回,然后根据响应抛出异常。

Hope it helps. 希望能帮助到你。

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

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