2009-07-06 17 views
12

¿Cómo puedo crear un proxy de cliente sin svcutil.exe o agregar una referencia de servicio en wcf? Quiero crear un proxy de cliente en tiempo de compilación.¿Cómo crear proxy de cliente sin svcutil o agregar referencia de servicio en wcf?

+2

¿Necesita crearlo en tiempo de ejecución, o en tiempo de compilación, o en el IDE? ¿Puedes decir lo que estás tratando de lograr? De lo contrario, obtendrás respuestas que no cumplirán tus objetivos. –

+1

¿Conoces el contrato por adelantado? es decir, ¿tiene quizás la interfaz del servicio como código? –

+3

Llámame loco, pero ¿por qué colocarías una recompensa y luego no respondiste a las preguntas? Sospecho que sacará más provecho de SO si ayuda a las personas a que lo ayuden ... hacen preguntas porque es importante dar una respuesta adecuada. –

Respuesta

10

Si tiene acceso al contrato de servicios (la interfaz IService) en una DLL independiente, puede agregar una referencia a la DLL de contrato de servicio y luego hacer algo como:

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

y luego tienes tu Proxy creado programáticamente, que ahora puede usar como lo desee.

+0

¿El 'ChannelFactory' necesita un nuevo objeto' Binding' cada vez? ¿O debería estar bien crear una dirección de encuadernación y punto final una vez, y usarlos para crear 'ChannelFactory's? – epalm

+0

@epalm: definitivamente puede mantener los objetos de enlace y punto final alrededor y usarlos varias veces, no hay problema. –

5

No necesita generar código (o usar un archivo de configuración lleno de detalles de WCF).

Primero cree la interfaz que define el servicio ([ServiceContract]) con cualquier contrato de datos de soporte en un conjunto separado de la implementación del servicio.

Haga referencia al conjunto de interfaz en el conjunto del cliente.

continuación, tendrá que crear un proxy de cliente, por IMyService:

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

Suena como una solución que uso en uno de mis servicios web. :-) –

7

esto podría no ser lo que usted está buscando, pero es bastante interesante.

Vipul Modi tiene una biblioteca que le permite llamar a los servicios WCF después de descargar su WSDL, todo en tiempo de ejecución.

Vipul Modi's library (latest version)

le permite hacer este tipo de cosas:

Cree el ProxyFactory especificando el URI WSDL del servicio.

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

Examinar los puntos finales, metadatos, contratos, etc.

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

Cree DynamicProxy en un punto final especificando el nombre del punto final o .

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

// o

DynamicProxy proxy = factory.CreateProxy(endpoint); 

operaciones Invoke en la DynamicProxy

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

Cierre la DynamicProxy

proxy.Close(); 
+0

¡Muy bien! – grenade

0

Aquí está la solución que he estado usando desde WCF se introdujo: En una asamblea infraestructura:

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 
} 

Y llamada sitio (en el agente de servicio o dondequiera que usted desee llamar el servicio externo de:

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

Dada la ServiceContract (y DataContracts) definida en otro asssembly, aquí simplemente:

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

    [OperationContract] 
    string DecimalToRoman(Decimal @decimal); 
} 
Cuestiones relacionadas