Frage an wcf – Wie erstelle ich einen Client-Proxy ohne svcutil oder füge eine Dienstreferenz in wcf hinzu?

12

Wie kann ich einen Client-Proxy ohne svcutil.exe erstellen oder eine Dienstreferenz in wcf hinzufügen? Ich möchte beim Kompilieren einen Client-Proxy erstellen.

Kennen Sie den Vertrag im Voraus? Haben Sie vielleicht die Service-Schnittstelle als Code? Marc Gravell
Müssen Sie es zur Laufzeit, zur Kompilierungszeit oder in der IDE erstellen? Können Sie sagen, was Sie erreichen wollen? Andernfalls erhalten Sie Antworten, die Ihre Ziele nicht erreichen. John Saunders
Nenn mich verrückt, aber warum würdest du ein Kopfgeld setzen und dann nicht auf Fragen antworten? Ich vermute, Sie werden mehr aus SO herausholen, wenn Sie den Leuten helfen, Ihnen zu helfen ... sie stellen Fragen, weil es wichtig ist, eine angemessene Antwort zu geben. Marc Gravell

Deine Antwort

4   die antwort
7

wonach Sie suchen, aber es ist ziemlich interessant.

Vipul Modi verfügt über eine Bibliothek, mit der Sie WCF-Dienste nach dem Herunterladen ihrer WSDL zur Laufzeit aufrufen können.

Vipul Modi's Bibliothek (neueste Version)

Ermöglicht Ihnen Folgendes:

Erstellen Sie die ProxyFactory, und geben Sie den WSDL-URI des Dienstes an.

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

Durchsuchen Sie die Endpunkte, Metadaten, Verträge usw.

fabrik.Endpunktefactory.Metadatafabrik.VerträgeFabrik.Bindungen

Erstellen Sie DynamicProxy für einen Endpunkt, indem Sie entweder den Endpunkt- oder den Vertragsnamen angeben.

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

//ODER

DynamicProxy proxy = factory.CreateProxy(endpoint);

Rufen Sie Operationen auf dem DynamicProxy auf

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

Schließen Sie den DynamicProxy

proxy.Close();
Sehr cool in der Tat! grenade
0

In einer Infrastruktur-Assembly:

   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
}

Und rufen Sie die Site an (im Serviceagenten oder wo immer Sie den externen Service anrufen möchten von:

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

In Anbetracht des ServiceContract (und der Datenkontrakte), die in einer weiteren Assembly definiert wurden, hier einfach:

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

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

ervice-Schnittstelle) haben, können Sie einen Verweis auf diese Servicevertrag-DLL hinzufügen und dann folgendermaßen vorgehen:

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

und dann haben Sie Ihren programmgesteuert erstellten Proxy, den Sie nun wie gewünscht verwenden können.

Tut dasChannelFactory brauche eine neueBinding Objekt jedes Mal? Oder sollte es in Ordnung sein, die Bindungs- und Endpunktadresse einmal zu erstellen und zum Erstellen zu verwendenChannelFactorys? epalm
@epalm: Sie können die Bindungs- und Endpunktobjekte definitiv behalten und mehrfach verwenden - kein Problem. marc_s
5

Sie müssen keinen Code generieren (oder eine Konfigurationsdatei mit WCF-Details verwenden).

Erstellen Sie zuerst die Schnittstelle, die den Service definiert ([ServiceContract]) mit allen unterstützenden Datenverträgen in einer von der Service-Implementierung getrennten Assembly.

Verweisen Sie auf die Schnittstellenassembly in der Clientassembly.

Dann müssen Sie einen Client-Proxy erstellen, zIMyService:

BasicHttpBinding binding = new BasicHttpBinding();
EndpointAddress endpoint = new EndpointAddress(url);
ChannelFactory<IMyService> chanFac = new ChannelFactory<IMyService>(binding, endpoint);
IMyService clientProxy = chanFac.CreateChannel();
Klingt nach einer Lösung, die ich zufällig in einem meiner Webdienste verwende. :-) Wim ten Brink

Verwandte Fragen