2013-07-24 3 views
5

Nello scenario in cui un servizio WCF restituisce un DataContract con un membro enum che ha un valore non valido (un int non presente nel tipo Enum) l'eccezione generata sul lato client è The underlying connection was closed: The connection was closed unexpectedly.
Stranamente questa eccezione viene attivata perché DataContractSerializer non può serializzare sul lato server della connessione.Errore in anticipo o lancio chiaro quando un'enumerazione non può essere serializzata

avrei preferito qualcosa di più utile gettato su di me e più importante prima, durante l'esecuzione sul lato server, ma forse un avviso del compilatore ...

WCF Service Contract

[ServiceContract] 
    public interface IDtoService 
    { 
     [OperationContract] 
     MyDto GetData(int value); 
    } 

    public enum Rating 
    { 
     None = 0, 
     NotSet = 1, 
     Somevalue = 34 
    } 

    [DataContract] 
    public class MyDto 
    { 
     Rating _rate; 

     [DataMember] 
     public Rating Rating 
     { 
      get { return _rate; } 
      set 
      { 
       _rate = value; 
      } 
     } 

    } 

Servizio implementazione

public class DtoService : IDtoService 
    { 
     public MyDto GetData(int value) 
     { 
      var dto = new MyDto { Rating = (Rating) 42 }; // not in ENUM! 
      return dto; 
     } 
    } 

client

var cl = new DtoServiceClient.DtoServiceClient(); 
var tada = cl.GetData(1); // connection closed exception 

Per avere l'eccezione effettiva gettato ho dovuto disbale 'consentire solo il mio codice' nel VS2010 opzioni di debug e nelle eccezioni dialogo abilitazione generate per 'linguaggio comune eccezioni di runtime'

Con che le impostazioni l'eccezione importante è:

SerializationException
valore Enum '42' non è valido per il tipo 'WcfService1.Rating' e non può essere serializzato. Assicurarsi che i valori enum necessari sono presenti e sono contrassegnati con attributo EnumMemberAttribute se il tipo ha DataContractAttribute attributo

Questo viene al costo che il debugger diventa molto rumoroso di tutti gli altri tipi di eccezioni generate che per quanto ne so può essere ignorato

Cosa posso provare a lanciare questa eccezione senza il rumore?

C'è qualcosa che posso modificare o aggiungere nella pipeline di WCF?

Una possibile soluzione per riuscire presto con il costo di rilavorazione è l'aggiunta di un'asserzione in più nel setter del membro enum:

Debug.Assert(Enum.IsDefined(typeof(Rating), value),"value is not valid for this enum"); 

Un'alternativa che ho provato era l'aggiunta di un contratto con la speranza un avvertimento potrebbe essere prodotto. Non ho trovato nulla di meglio di una copia di Debug.Assert.

System.Diagnostics.Contracts.Contract.Assert(Enum.IsDefined(typeof(Rating), value)); 

C'è la possibilità di avere il compilatore emettono questo controllo per me o c'è un'alternativa che non sono a conoscenza?
(ho anche provato a compilare con l'check for arithmetic overflow/underflow abilitato senza aspettarsi di essere succeful)

CodeContracts emette un avvertimento, (bisogna enble impliciti obblighi di scrittura Enum) anche se questo non aiuta

il valore effettivo non può essere nell'intervallo definito per questo valore enumerazione

questo comportamento è in VS2010/Net 4.0 contesto.

+0

Mi sembra che il contratto sia il meglio che si possa fare senza tentare di estendere il comportamento di serializzazione WCF (che può diventare fiacco come uno yak). –

+1

@SixtoSaez Dopo aver scavato un po 'di più, sento che il tuo suggerimento è il più pratico ora. Non voglio fare uno yak ... – rene

risposta

3

Si potrebbero fare alcune cose.

Sul lato WCF, utilizzare IncludeExceptionDetailInFaults (utilizzando un attributo ServiceBehavior o app.config). Ciò farà sì che WCF invii eccezioni dettagliate al client. Si noti che questa impostazione è considerata "non sicura" poiché espone le tracce dello stack del server al lato client, quindi è consigliabile utilizzarlo solo durante lo sviluppo. Per la produzione, è necessario utilizzare un gestore errori WCF per registrare tutti gli errori di servizio (o attivare la traccia WCF).

Se si desidera utilizzare Code Contracts per la cattura di questo errore durante fase di compilazione è possibile utilizzare invarianti oggetto:

public class MyDto 
{ 
    public Rating Rating { get; set; } 

    [ContractInvariantMethod] 
    void Invariant() 
    { 
     Contract.Invariant(Enum.IsDefined(typeof(Rating), Rating)); 
    } 
} 

Se si attiva l'analisi statica, si riceverà un messaggio di avviso su questa linea:

new MyDto { Rating = (Rating) 42 }; 
+0

Sembra promettente, ci proverò ... – rene

+0

Trovo la soluzione ContractInvariantMethod una soluzione simile. Grazie per averci dato un'occhiata. – rene

+0

Si noti che questo non è infallibile. Se ottieni l'enum da qualche altra parte, e non una costante di codice, potresti comunque avere un valore non valido (ad esempio, lanciando un int parsed). –