2009-05-07 5 views

risposta

10

È necessario inviare Eccezioni. Le eccezioni sono mappate in HRESULTS dal Framework e HRESULT sono il modo standard per restituire errori ai client COM, quindi questa è la strada da percorrere.

Ogni tipo di eccezione ha una proprietà HResult. Quando il codice gestito richiamato da un client COM genera un'eccezione, il runtime passa HResult al client COM. Se si desidera utilizzare codici HRESULT specifici dell'applicazione, è possibile creare i propri tipi di eccezioni personalizzati e impostare la proprietà Exception.HResult.

Un punto da notare è che le informazioni sullo stack di chiamata andranno perse quando un'eccezione viene lanciata a un client COM. Può quindi essere una buona idea registrare le eccezioni prima di propagare al client COM.

Una tecnica che a volte utilizzo è la seguente: implementare esplicitamente un'interfaccia ComVisible per i client COM che registra e rilancia le eccezioni. I client COM utilizzano l'interfaccia ComVisible che registra le eccezioni prima di propagarle. I client .NET utilizzano la classe concreta e sono tenuti a predisporre i propri arrangiamenti per la gestione delle eccezioni. È un po 'prolisso scrivere ma può essere utile quando successivamente si risolvono i problemi.

Un altro vantaggio di questo approccio è che è possibile avere un'API adattata alle restrizioni di COM per i client COM e un'API più standard per i client .NET standard. Ad esempio, i client COM sono limitati al passaggio di matrici per riferimento, mentre il passaggio per riferimento è scoraggiato per i client .NET.

Esempio:

[ 
ComVisible(true), 
GuidAttribute("..."), 
Description("...") 
] 
public interface IMyComVisibleClass 
{ 
    // Text from the Description attribute will be exported to the COM type library. 

    [Description("...")] 
    MyResult MyMethod(...); 

    [Description("...")] 
    MyOtherResult MyArrayMethod([In] ref int[] ids,...); 
} 
... 
[ 
ComVisible(true), 
GuidAttribute("..."), 
ProgId("..."), 
ClassInterface(ClassInterfaceType.None), 
Description("...") 
] 
public class MyComVisibleClass : IMyComVisibleClass 
{ 
    public MyResult MyMethod(...) 
    { 
     ... implementation without exception handling ... 
    } 

    public MyOtherResult MyArrayMethod(int[] ids,...) 
    { 
     ... input parameter does not use ref keyword for .NET clients ... 
     ... implementation without exception handling ... 
    } 

    MyResult IMyComVisibleClass.MyMethod(...) 
    { 
     // intended for COM clients only 
     try 
     { 
      return this.MyMethod(...); 
     } 
     catch(Exception ex) 
     { 
      ... log exception ... 
      throw; // Optionally wrap in a custom exception type 
     } 
    } 

    MyOtherResult IMyComVisibleClass.MyArrayMethod(ref int[] ids, ...) 
    { 
     // intended for COM clients only 
     try 
     { 
      // Array is passed without ref keyword 
      return this.MyArrayMethod(ids, ...); 
     } 
     catch(Exception ex) 
     { 
      ... log exception ... 
      throw; // Optionally wrap in a custom exception type 
     } 
    } 

} 
1

penso che dipende da come l'applicazione legacy reagirà. Se comprende i valori restituiti dall'errore, allora segui questo approccio. In caso contrario, dovrai generare eccezioni e sperare che le gestisca in modo appropriato.

Inoltre, se si tratta di un riferimento errato (riferimento null per esempio) o di altri errori critici, invierò sempre un'eccezione. Tuttavia, si dovrebbero evitare eccezioni per cose che il consumatore non può controllare in anticipo (ad esempio una ricerca che appare vuota non dovrebbe generare eccezioni).

3

Se l'applicazione COM supporta le interfacce IErrorInfo durante la chiamata al servizio C# e si tratta di un progetto interamente interno, è probabile che il lancio di eccezioni sia la soluzione migliore in quanto cattura la maggior parte delle informazioni. Tuttavia, COM si è tradizionalmente basata sui risultati delle risorse umane per comunicare i risultati dello stato e potrebbe essere migliore se il servizio deve essere pubblicato su altre fonti.

MODIFICA: Mi piace la risposta di Joe meglio.

+0

eccezioni sono mappati HRESULTS, quindi questo è l'approccio migliore. Vedi la mia risposta qui sotto. – Joe

1

Il miglior giudice se si desidera utilizzare eccezioni o valori restituiti sarebbe TU. Le "eccezioni di lancio" superano "i valori di ritorno" in diversi modi. MA in alcuni casi i valori di ritorno sarebbero sufficienti.

3

Sono d'accordo con gli altri che questa non è una risposta "sì o no" senza conoscere intimamente il tuo progetto.

Essa dipenderà da una serie di fattori quali:

  • di sicurezza (cioè quello che dovrebbe il vostro cliente sapere sulla vostra eccezione)
  • efficienza (cioè è il tempo di elaborazione critica)
  • manutenibilità (per esempio, si può alterare l'eredità codice C++ per analizzare le vostre condizioni di eccezione)

Here's a good blog post that discusses a number of subtle points about exception processing.

L'autore raccomanda uno di due approcci:

O:

  • restituiscono un documento di errore.

o:

  • registrare tutte le informazioni sull'eccezione sul server.
  • Creare una nuova eccezione che fa riferimento alle informazioni registrate .
  • Invia la nuova eccezione a il client per l'elaborazione lato client e segnalazione.

Personalmente, penso che dovresti evitare di accoppiare strettamente il tuo servizio C# con l'applicazione C++. In altre parole, scrivi il tuo servizio C# in modo che possa essere teoricamente utilizzato da qualsiasi consumatore. Allo stesso modo, il codice C++ dovrebbe essere scritto in modo che non si basi sui meccanismi interni del servizio C#, quindi le modifiche o le aggiunte alle eccezioni (o ai codici di errore) non infrangono il consumatore.