2015-04-06 17 views
8

Sto utilizzando le chiamate asincrone WCF nel mio progetto e sto utilizzando i metodi asincroni lato client. Ho uno scenario come qui sotto -Come generare un'eccezione dalla richiamata in WCF Async utilizzando IAsyncResult

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

Quindi, come mostrato nel codice sopra frammento di esso non genera l'eccezione dal livello di business a livello web come verrà soppressa qui a livello di business stesso.

Ho controllato alcuni dei blog e dei siti che suggeriscono di andare in asincrono e attendo l'approccio, dato che ho il framework .NET 4.0 e sto vedendo l'opzione "Genera operazioni basate su" disabilitata. Quindi, se ci sono opzioni che usano "IAsyncResult" (inizio & End in client) per favore fammi sapere. Se ci sono altri approcci anche benvenuti.

Gentilmente qualcuno mi aiuti.

Grazie.

+0

controllare il collegamento potrebbe essere utile http://blogs.msdn.com/b/nikos/archive/2011/03/14/how-to-implement-iasyncresult-in-another-way.aspx#comments – reapen

+0

Are stai dicendo che il tuo blocco 'catch' non cattura alcuna eccezione? Se un'eccezione non gestita viene lanciata nel codice lato server, il tuo blocco 'catch' qui sopra dovrebbe prendere una' FaultException' di default. –

+0

Quindi vuoi fare un'eccezione al chiamante quando chiama "GetGeneralNews"? – usr

risposta

0

Comunque ho risolto questo utilizzando TPL (Task Parallel Library).

La ragione per cui ho riscontrato problemi nell'approccio precedente è che i miei nuovi thread non saranno in grado di riconoscere il thread principale, da quale layer è stato chiamato il metodo.Quindi usando TPL ho fatto il mio thread principale aspettare che gli altri thread facciano il lavoro e tornare indietro e poi basarmi sulla risposta per lanciare l'eccezione.

Spero che aiuti.

0

1) Se il codice del client WCF è già stato generato con i metodi asincrono ("Begin ..."/"End ..."), allora è possibile utilizzare l'API delle attività di TPL per lavorare con WCF (ContinueWith ecc.) Tramite Task.Factory.FromAsync (example) - ottimo per gestire i metodi/API legacy IAsyncResult ("Begin ..."/"End ...") (per quanto semplice, puoi vedere l'origine con reflector);

2) Il codice client generato dallo strumento non è un buon approccio - invece è possibile scrivere il proprio proxy client universale con supporto sincrono (non solo usando il thread in background). Here è un buon esempio di come iniziare, è necessario eseguire il wrapping dei metodi "Begin ..."/"End ..." con i metodi basati su attività (utilizzare lo stesso Task.Factory.FromAsync) e utilizzare le strutture di espressione per eliminare il metodo di servizio basato su stringhe chiama (non posso condividere la mia fonte di classe).

Oppure è possibile utilizzare soluzioni esistenti come this.

3) Non dimenticare di ConfigureAwait.

Edit:

Non è necessario generare le operazioni basate su attività, è sufficiente per generare il codice client WCF con metodi di funzionamento di servizio asincrona ("Begin ..."/"End ..."). Oppure puoi anche avere solo un contratto WCF sincrono! (vedi link). TPL disponibile in .NET 4 (senza zucchero sintattico asincrono/atteso - che è la funzione del linguaggio CSharp 5.0). Usalo (ContinueWith invece attendi + WhenAny, WhenAll). L'ho usato anche in 3.5 tramite Microsoft Reactive Extensions v1.0.2856.0. AFAIK Reactive Extensions era la versione iniziale che era inclusa in BCL. ParallelExtensionsExtras potrebbe anche essere utile

+0

Come già detto "Genera operazioni basate sulle attività" sarà disponibile solo nella versione 4.5 di .NET. Quindi non ho questa opzione qui. –

+0

Non è necessario. Vedi la risposta modificata. Leggi attentamente. – SalientBrain

+0

Si prega di prendere in considerazione l'aggiunta di commenti quando si esegue il downvot. – SalientBrain

2

Ecco un'app di esempio che mostra che WCF non ingoia l'eccezione. Se non si riceve l'eccezione, deve essere ingerita dal codice lato server.

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" 
     ); 

    } 
} 

}

Ecco l'output di questo programma:

ready 
Got the exception: Please catch this 
Problemi correlati