2009-07-06 24 views
12

Come si crea un proxy client senza svcutil.exe o aggiungere riferimento al servizio in WCF? Voglio creare un proxy client in fase di compilazione.Come creare un proxy client senza svcutil o aggiungere riferimenti di servizio in wcf?

+2

Hai bisogno di crearlo in fase di runtime, in fase di compilazione o in IDE? Puoi dire cosa stai cercando di realizzare? Altrimenti riceverai risposte che non raggiungeranno i tuoi obiettivi. –

+1

Conosci il contratto in anticipo? cioè hai forse l'interfaccia di servizio come codice? –

+3

Chiamami pazzo, ma perché dovresti piazzare una taglia e poi non rispondere alle domande? Ho il sospetto che tu possa ottenere di più da SO se aiuti le persone ad aiutarti ... stanno facendo domande perché è importante dare una risposta appropriata. –

risposta

10

Se si ha accesso al contratto di servizio (l'interfaccia IService) in una DLL separata, è possibile aggiungere un riferimento a quella DLL contratto di servizio e quindi fare qualcosa di simile:

NetTcpBinding binding = new NetTcpBinding(); 
EndpointAddress address = new EndpointAddress("net.tcp://localhost:9000/YourService") 

ChannelFactory<IService> factory = new ChannelFactory<IService>(binding, address); 
IService proxy = factory.CreateChannel(); 

e poi avete la vostra proxy creato a livello di codice, che ora puoi utilizzare come desideri.

+0

Il 'ChannelFactory' ha bisogno di un nuovo oggetto' Binding' ogni volta? O dovrebbe essere bene creare una volta l'indirizzo di binding e di endpoint e usarli per creare 'ChannelFactory's? – epalm

+0

@epalm: puoi sicuramente mantenere gli oggetti di bind e endpoint e utilizzarli più volte, nessun problema. –

5

Non è necessario codificare generare (o usare un file di configurazione completa di specifiche WCF).

Innanzitutto creare l'interfaccia definizione del servizio ([ServiceContract]) con eventuali sostegno contratti dati in un assieme separati dalla implementazione del servizio.

di riferimento il gruppo di interfaccia nell'assemblea client.

quindi necessario creare un proxy client, per IMyService:

BasicHttpBinding binding = new BasicHttpBinding(); 
EndpointAddress endpoint = new EndpointAddress(url); 
ChannelFactory<IMyService> chanFac = new ChannelFactory<IMyService>(binding, endpoint); 
IMyService clientProxy = chanFac.CreateChannel(); 
+1

Sembra una soluzione che utilizzo in uno dei miei servizi web. :-) –

7

questo potrebbe non essere quello che stai cercando, ma è piuttosto interessante.

Vipul Modi ha una libreria che consente di chiamare i servizi WCF dopo aver scaricato la loro WSDL, tutte in fase di esecuzione.

Vipul Modi's library (latest version)

ti permette di fare questo genere di cose:

Creare il ProxyFactory specificando il WSDL URI del servizio.

DynamicProxyFactory factory = new DynamicProxyFactory("http://localhost:8080/WcfSamples/DynamicProxy?wsdl"); 

visualizza le endpoint, metadati, contratti ecc

  • factory.Endpoints
  • factory.Metadata
  • factory.Contracts
  • factory.Bindings
.210

Creare DynamicProxy a un endpoint specificando sia l'endpoint o nome del contratto.

DynamicProxy proxy = factory.CreateProxy("ISimpleCalculator"); 

// O

DynamicProxy proxy = factory.CreateProxy(endpoint); 

operazioni Invoke sulla DynamicProxy

double result = (double)proxy.CallMethod("Add", 1d ,2d); 

Chiudere il DynamicProxy

proxy.Close(); 
+0

Davvero fantastico! – grenade

0

Ecco la soluzione ho utilizzato dal WCF è stato introdotto: In un'assemblea infrastrutture:

internal class PerCallDisposeRealProxy<T> : RealProxy where T : class 
{ 
    private readonly Binding _binding; 
    private readonly EndpointAddress _endpointAddress; 

    private static string EndpointName 
    { 
     get 
     { 
      string endpointName = typeof(T).Name; 
      if (endpointName.StartsWith("I")) 
      { 
       endpointName = endpointName.Substring(1); 
      } 
      return endpointName; 
     } 
    } 

    internal PerCallDisposeRealProxy() 
     : base(typeof(T)) 
    {    
    } 

    internal PerCallDisposeRealProxy(Binding binding, EndpointAddress endpointAddress) 
     : base(typeof(T)) 
    { 
     if (binding == null) 
      throw new ArgumentNullException("binding"); 
     if (endpointAddress == null) 
      throw new ArgumentNullException("endpointAddress"); 

     _binding = binding; 
     _endpointAddress = endpointAddress; 
    } 

    private ChannelFactory<T> CreateChannel() 
    { 
     if (_binding != null && _endpointAddress != null) 
      return new ChannelFactory<T>(_binding, _endpointAddress); 
     else 
      return new ChannelFactory<T>(EndpointName); 
    } 

    [DebuggerStepThrough] 
    public override IMessage Invoke(IMessage message) 
    { 
     if (message == null) throw new ArgumentNullException("message"); 

     //Extract method info 
     var methodCall = message as IMethodCallMessage; 
     Debug.Assert(methodCall != null); 
     MethodInfo methodInfo = methodCall.MethodBase as MethodInfo; 
     Debug.Assert(methodInfo != null); 

     T channel = null; 
     ChannelFactory<T> channelFactory = null; 
     try 
     { 
      //setup channel 
      try 
      { 
       channelFactory = CreateChannel(); 
      } 
      catch (InvalidOperationException ex) 
      { 
       throw new ApplicationException(string.Format("Invalid endpoint configuration, make sure there is a servicemodel endpoint defined in configuration with the name {0}", EndpointName), ex); 
      } 
      channelFactory.Open(); 
      channel = channelFactory.CreateChannel(); 

      object result = methodInfo.Invoke(channel, methodCall.InArgs); 
      return new ReturnMessage(result, null, 0, methodCall.LogicalCallContext, methodCall); 
     } 
     catch (FaultException faultException) 
     { 
      string msg = "FaultException: " + faultException.Message; 
      MessageFault fault = faultException.CreateMessageFault(); 
      if (fault.HasDetail) 
      { 
       System.Xml.XmlReader reader = fault.GetReaderAtDetailContents(); 
       if (reader.Name == "ExceptionDetail") 
       { 
        ExceptionDetail detail = fault.GetDetail<ExceptionDetail>(); 
        msg += "\n\nStack Trace: " + detail.StackTrace; 
       } 
      } 
      return new ReturnMessage(faultException, methodCall); 
     } 
     catch (TargetInvocationException targetInvocationException) 
     { 
      return targetInvocationException.InnerException != null ? new ReturnMessage(targetInvocationException.InnerException, methodCall) : new ReturnMessage(targetInvocationException, methodCall); 
     } 
     catch (Exception exception) 
     { 
      return new ReturnMessage(exception, methodCall); 
     } 
     finally 
     { 
      if (channel as IClientChannel != null) 
      { 
       try 
       { 
        (channel as IClientChannel).Close(TimeSpan.FromSeconds(5)); 
       } 
       catch 
       { 
        try 
        { 
         (channel as IClientChannel).Abort(); 
        } 
        catch 
        { 
        } 
       } 
       try 
       { 
        (channel as IClientChannel).Dispose(); 
       } 
       catch 
       { 
       } 
      } 

      try 
      { 
       ((IDisposable)channelFactory).Dispose(); 
      } 
      catch 
      { 
      } 
     } 
    } 
} 

    public static class ClientProxyFactory 
{ 
    public static T CreateProxy<T>() where T : class 
    { 
     return CreateProxy<T>(ProxyType.PerCallChannel); 
    } 

    public static T CreateProxy<T>(ProxyType proxyType) where T : class 
    { 
     return CreateProxy<T>(proxyType, null, null); 
    } 

    public static T CreateProxy<T>(ProxyType proxyType, Binding binding, EndpointAddress endpointAddress) where T : class 
    { 
     switch (proxyType) 
     { 
      case ProxyType.PerCallChannel: 
       PerCallDisposeRealProxy<T> proxy = null; 
       proxy = binding == null && endpointAddress == null ? new PerCallDisposeRealProxy<T>() : new PerCallDisposeRealProxy<T>(binding, endpointAddress); 
       Debug.Assert(proxy != null); 
       object transparentProxy = proxy.GetTransparentProxy(); 
       Debug.Assert(transparentProxy != null); 
       Debug.Assert(transparentProxy is T); 
       return transparentProxy as T; 
      default: 
       throw new NotImplementedException("Did not implement proxytype:" + proxyType); 
     } 
    } 
} 

    public enum ProxyType 
{ 
    /// <summary> 
    /// PerCall indicates a proxy that will create a channel pr. proxy method call and dispose of it before returning. 
    /// </summary> 
    PerCallChannel 
} 

e call sito (nella agente di servizio o dovunque si desidera chiamare il servizio esterno da:

INumeralConverterService proxy = ClientProxyFactory.CreateProxy<INumeralConverterService>(); 
string result = proxy.DecimalToRoman(i); 

Data la ServiceContract (e datacontracts) definita in un altro asssembly, qui semplicemente:

[ServiceContract] 
public interface INumeralConverterService 
{ 
    [OperationContract] 
    Decimal RomanToDecimal(string roman); 

    [OperationContract] 
    string DecimalToRoman(Decimal @decimal); 
} 
Problemi correlati