Pregunta sobre wcf – ¿Cómo crear un proxy de cliente sin svcutil o agregar una referencia de servicio en wcf?

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.

¿Necesita crearlo en tiempo de ejecución, en tiempo de compilación o en el IDE? ¿Puedes decir lo que estás tratando de lograr? De lo contrario, obtendrá respuestas que no lograrán sus objetivos. John Saunders
Llámame loco, pero ¿por qué colocar una recompensa y luego no responder a las preguntas? Sospecho que obtendrá más de SO si ayuda a las personas a ayudarlo ... están haciendo preguntas porque es importante para dar una respuesta adecuada. Marc Gravell
¿Conoces el contrato con antelación? es decir, tal vez tienes la interfaz de servicio como código? Marc Gravell

Tu respuesta

4   la respuesta
0

Aquí está la solución que he estado usando desde que se introdujo wcf: En un ensamblaje de 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 llame al sitio (en el agente de servicio o donde quiera que desee llamar al servicio externo desde:

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

Dado el ServiceContract (y los registros de datos) definidos en otro montaje, aquí simplemente:

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

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

No necesita generar código (o usar un archivo de configuración con todas las especificaciones de WCF).

Primero crea la interfaz definiendo el servicio ([ServiceContract]) con cualquier contrato de datos de soporte en un montaje separado de la implementación del servicio.

Consulte el conjunto de la interfaz en el conjunto del cliente.

Luego necesita crear un proxy de cliente, paraIMyService:

BasicHttpBinding binding = new BasicHttpBinding();
EndpointAddress endpoint = new EndpointAddress(url);
ChannelFactory<IMyService> chanFac = new ChannelFactory<IMyService>(binding, endpoint);
IMyService clientProxy = chanFac.CreateChannel();
Suena como una solución que utilizo en uno de mis servicios web. :-) Wim ten Brink
11

Si tiene acceso al contrato de servicio (la interfaz IService) en una DLL separada, puede agregar una referencia a esa 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 mediante programación, que ahora puedes usar como desees.

Hace elChannelFactory necesita un nuevoBinding objeto cada vez? O debería estar bien para crear el enlace y la dirección del punto final una vez, y usarlos para crearChannelFactorys? epalm
@epalm: definitivamente puede mantener los objetos de enlace y punto final y usarlos varias veces, no hay problema. marc_s
7

Puede que esto no sea lo que estás buscando, pero es bastante interesante.

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

La biblioteca de Vipul Modi (última versión)

Te permite hacer este tipo de cosas:

Cree el ProxyFactory especificando el URI de WSDL del servicio.

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

Examine los puntos finales, metadatos, contratos, etc.

fábrica.puntosfábrica.Metadatafábrica.contratosfábrica. Encuadernaciones

Cree DynamicProxy a un punto final especificando el nombre del punto final o del contrato.

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

//O

DynamicProxy proxy = factory.CreateProxy(endpoint);

Invocar operaciones en el DynamicProxy

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

Cierra el DynamicProxy

proxy.Close();
Muy bien hecho! grenade

Preguntas relacionadas