Вопрос по wcf – Как создать клиентский прокси без svcutil или добавить ссылку на службу в wcf?

12

Как я могу создать клиентский прокси без svcutil.exe или добавить сервисную ссылку в wcf? Я хочу создать клиентский прокси во время компиляции.

Вы знаете контракт заранее? у вас, возможно, есть интерфейс службы в виде кода? Marc Gravell♦
Называй меня сумасшедшим, но зачем тебе ставить награду, а потом не отвечать на вопросы? Я подозреваю, что вы получите больше пользы от SO, если поможете людям помочь вам ... они задают вопросы, потому что это важно для правильного ответа. Marc Gravell♦
Вам нужно создать его во время выполнения, или во время компиляции, или в IDE? Можете ли вы сказать, что вы пытаетесь достичь? В противном случае вы получите ответы, которые не достигнут ваших целей. John Saunders

Ваш Ответ

4   ответа
0

Вот решение, которое я использовал с момента появления wcf: В сборке инфраструктуры:

   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
}

И позвоните на сайт (в сервисном агенте или там, где вы хотите вызвать внешнюю службу из:

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

Учитывая ServiceContract (и контракты данных), определенные в еще одной сборке, здесь просто:

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

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

полный специфики WCF).

Сначала создайте интерфейс, определяющий сервис ([ServiceContract]) с любыми вспомогательными договорами данных в сборке, отдельной от реализации службы.

Ссылка на интерфейс сборки в клиентской сборке.

Затем нужно создать клиентский прокси, дляIMyService:

BasicHttpBinding binding = new BasicHttpBinding();
EndpointAddress endpoint = new EndpointAddress(url);
ChannelFactory<IMyService> chanFac = new ChannelFactory<IMyService>(binding, endpoint);
IMyService clientProxy = chanFac.CreateChannel();
Похоже, решение, которое я использую в одном из моих веб-сервисов. :-)
11

отдельной DLL, вы можете добавить ссылку на эту DLL сервисного контракта и затем сделать что-то вроде:

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

и затем у вас есть программно созданный прокси, который вы теперь можете использовать по своему усмотрению.

@epalm: вы определенно можете хранить объекты привязки и конечной точки и использовать их несколько раз - без проблем.
ЛиChannelFactory нужен новыйBinding возражать каждый раз? Или должно быть хорошо создать адрес привязки и конечной точки один раз и использовать их для созданияChannelFactorys?
7

Vipul Modi имеет библиотеку, которая позволяет вам вызывать сервисы WCF после загрузки их WSDL, и все это во время выполнения.

Библиотека Vipul Modi (последняя версия)

Позволяет вам делать такие вещи:

Create the ProxyFactory specifying the WSDL URI of the service.

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

Browse the endpoints, metadata, contracts etc.

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

Create DynamicProxy to an endpoint by specifying either the endpoint or contract name.

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

//ИЛИ ЖЕ

DynamicProxy proxy = factory.CreateProxy(endpoint);

Invoke operations on the DynamicProxy

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

Close the DynamicProxy

proxy.Close();
Очень круто на самом деле!

Похожие вопросы