Pergunta sobre wcf – Como criar proxy cliente sem svcutil ou adicionar referência de serviço no wcf?

12

Como posso criar um proxy de cliente sem svcutil.exe ou adicionar referência de serviço no wcf? Eu quero criar um proxy cliente em tempo de compilação.

Você precisa criá-lo em tempo de execução, ou em tempo de compilação ou no IDE? Você pode dizer o que está tentando realizar? Caso contrário, você obterá respostas que não atingirão seus objetivos. John Saunders
Me chame de louco, mas por que você faria uma recompensa e depois não responderia a perguntas? Eu suspeito que você obterá mais do SO se ajudar as pessoas a ajudá-lo ... elas estão fazendo perguntas porque é importante dar uma resposta apropriada. Marc Gravell
Você conhece o contrato antecipadamente? Ou seja, você talvez tenha a interface de serviço como código? Marc Gravell

Sua resposta

4   a resposta
5

o de especificações do WCF).

Primeiro crie a interface que define o serviço ([ServiceContract]) com quaisquer contratos de dados de suporte em uma montagem separada da implementação do serviço.

Referencie o conjunto da interface na montagem do cliente.

Então precisa criar um proxy cliente, paraIMyService:

BasicHttpBinding binding = new BasicHttpBinding();
EndpointAddress endpoint = new EndpointAddress(url);
ChannelFactory<IMyService> chanFac = new ChannelFactory<IMyService>(binding, endpoint);
IMyService clientProxy = chanFac.CreateChannel();
Soa como uma solução que eu uso em um dos meus serviços da web. :-) Wim ten Brink
7

O Vipul Modi tem uma biblioteca que permite chamar os serviços do WCF depois de baixar o WSDL, tudo em tempo de execução.

Biblioteca de Vipul Modi (versão mais recente)

Permite que você faça esse tipo de coisa:

Crie o ProxyFactory especificando o URI do WSDL do serviço.

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

Navegue pelos endpoints, metadados, contratos etc.

factory.Endpointsfábrica.Metadatafactory.Contractsfábrica.

Crie DynamicProxy para um nó de extremidade especificando o nó de extremidade ou o nome do contrato.

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

//OU

DynamicProxy proxy = factory.CreateProxy(endpoint);

Chamar operações no DynamicProxy

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

Feche o DynamicProxy

proxy.Close();
Muito legal mesmo! grenade
0

Em uma montagem de infraestrutura:

   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 chame o site (no agente de serviço ou onde quer que você queira chamar o serviço externo de:

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

Dado o ServiceContract (e datacontracts) definido em outra montagem, aqui simplesmente:

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

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

uma DLL separada, poderá adicionar uma referência a essa DLL de contrato de serviço e, em seguida, fazer 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();

e então você tem seu proxy programaticamente criado, que agora você pode usar como quiser.

OChannelFactory precisa de um novoBinding objeto de cada vez? Ou deve ser bom criar um link de vinculação e endpoint uma vez e usá-los para criarChannelFactorys? epalm
@epalm: você pode definitivamente manter os objetos binding e endpoint ao redor e usá-los várias vezes - sem problemas. marc_s

Perguntas relacionadas