2012-04-07 30 views
9

Diventa monotouch compilato al codice nativo, quindi ha alcune limitazioni come invocazione dinamica non consentita.Monotouch/WCF: Come consumare il servizio wcf senza svcutil

Ma ho molta classe in .net, che uso la dinamica ChannelFactory per invocare il servizio wcf: new ChannelFactory (myBinding, myEndpoint); Ora in monotouch dovrei usare slsvcutil per generare la classe proxy wcf, ma lo slsvcutil genera un sacco di codice extra non necessario (enorme), e rende i consumatori difficili da testare, a causa dell'elevato accoppiamento con l'infrastruttura WCF attraverso la classe ClientBase.

Esiste una soluzione migliore ad eccezione di ChannelFactory? Preferisco scrivere il codice manualmente, avere più controllo su come vengono invocati i servizi come ChannelFactory.

==========

 ChannelFactory<IMyContract> factory = new ChannelFactory<IMyContract>(binding, endpointAddress); 
     return factory.CreateChannel(); 

// ==> E 'un'eccezione tiro: MonoTouch non supporta la generazione di codice di proxy dinamico. Ignorare questo metodo o la sua chiamante per tornare client specifico esempio di proxy

risposta

13

ChannelFactory<T> ha un metodo virtuale CreateChannel(). Se non viene sovrascritto, utilizza la generazione del codice dinamico, che non riesce su MonoTouch.

La soluzione è sovrascriverla e fornire la propria implementazione in fase di compilazione.

Di seguito è una mia vecchia implementazione del servizio che almeno ha funzionato su MonoTouch. L'ho diviso in 2 classi parziali: il primo è stato collegato in tutte le build, il secondo solo nelle build iOS (consentendo al meccanismo di generazione dinamica di funzionare ancora su Windows).
L'ho rimosso per contenere solo 1 chiamata di servizio.

TransactionService.cs:

public partial class TransactionService : ClientBase<IConsumerService>, IConsumerService 
{ 

    public TransactionService() 
    { 
    } 

    public TransactionService(string endpointConfigurationName) : 
     base(endpointConfigurationName) 
    { 
    } 

    public TransactionService(string endpointConfigurationName, string remoteAddress) : 
     base(endpointConfigurationName, remoteAddress) 
    { 
    } 

    public TransactionService(string endpointConfigurationName, EndpointAddress remoteAddress) : 
     base(endpointConfigurationName, remoteAddress) 
    { 
    } 

    public TransactionService(Binding binding, EndpointAddress remoteAddress) : 
     base(binding, remoteAddress) 
    { 
    } 

    public AccountBalanceResponse GetAccountBalance(AccountBalanceQuery query) 
    { 
     return Channel.GetAccountBalance(query); 
    } 
} 

TransactionService.iOS.cs: ConsumerServiceClientChannel che esegue le chiamate tramite riflessione)

public partial class TransactionService 
{ 
    protected override IConsumerService CreateChannel() 
    { 
     return new ConsumerServiceClientChannel(this); 
    } 

    private class ConsumerServiceClientChannel : ChannelBase<IConsumerService>, IConsumerService 
    { 

     public ConsumerServiceClientChannel(System.ServiceModel.ClientBase<IConsumerService> client) : 
      base(client) 
     { 
     } 

     // Sync version 
     public AccountBalanceResponse GetAccountBalance(AccountBalanceQuery query) 
     { 
      object[] _args = new object[1]; 
      _args[0] = query; 
      return (AccountBalanceResponse)base.Invoke("GetAccountBalance", _args); 
     } 

     // Async version 
     public IAsyncResult BeginGetAccountBalance(AccountBalanceQuery query, AsyncCallback callback, object asyncState) 
     { 
      object[] _args = new object[1]; 
      _args[0] = query; 
      return (IAsyncResult)base.BeginInvoke("GetAccountBalance", _args, callback, asyncState); 
     } 


     public AccountBalanceResponse EndGetAccountBalance(IAsyncResult asyncResult) 
     { 
      object[] _args = new object[0]; 
      return (AccountBalanceResponse)base.EndInvoke("GetAccountBalance", _args, asyncResult); 
     } 

    } 
} 

EDIT: Ho appena provato questo con l'ultima MT (5.2) - Non ha più bisogno di tutto quel piatto di caldaia extra che avevo lì prima, solo l'override di CreateChannel(). Ho ripulito il codice di esempio per abbinarlo.

EDIT2: ho aggiunto un'implementazione del metodo asincrono.

+0

grazie per la condivisione, ci provo ora. – BlueSky

+0

La tua soluzione ha successo, grazie. – BlueSky

+0

Qui dice che non riesce a trovare la classe ChannelBase. E non vedo come posso usarlo con metodi asincroni. Grazie! – cheeesus

0

Penso che potrebbe essere confusi termini qui - ChannelFactory è un tipo generica, non un dinamica.

Secondo la documentazione di MonoTouch, anche se c'è limitations to the Generics support in MonoTouch, ChannelFactory dovrebbe essere ok qui.

Hai provato a utilizzare ChannelFactory?

+0

Sì, ho provato ad utilizzare ChannelFactory, ho inserito il codice sopra, pls ref, grazie. – BlueSky

Problemi correlati