Monotouch/WCF:如何在没有svcutil的情况下使用wcf服务

Blu*_*Sky 12 wcf xamarin.ios

因为monotouch编译为本机代码,所以它有一些限制,例如不允许动态调用.

但我在.net中有很多类,我使用ChannelFactory动态来调用wcf服务:new ChannelFactory(myBinding,myEndpoint); 现在在monotouch中我应该使用slsvcutil来生成wcf代理类,但是slsvcutil会生成大量不必要的额外代码(巨大的),并且由于通过ClientBase类与WCF基础结构的高度耦合,使得消费者难以进行单元测试.

除了ChannelFactory之外还有更好的解决方案吗?我宁愿手动编写代码,也可以更好地控制如何调用服务,例如ChannelFactory.

==========

        ChannelFactory<IMyContract> factory = new ChannelFactory<IMyContract>(binding, endpointAddress);
        return factory.CreateChannel();   
Run Code Online (Sandbox Code Playgroud)

// ==>它抛出异常:MonoTouch不支持动态代理代码生成.重写此方法或其调用方以返回特定的客户端代理实例

Tys*_*son 18

ChannelFactory<T>有一个虚方法CreateChannel().如果没有覆盖它,它将使用动态代码生成,这在MonoTouch上失败.

解决方案是覆盖它并提供您自己的编译时实现.

下面是我的一个旧服务实现,至少用于MonoTouch.我将它分成两个部分类 - 第一个在所有构建中链接,第二个仅在iOS构建中(允许动态生成机制仍在Windows上工作).
我把它剥离了只包含1个服务电话.

TransactionService.cs:

public partial class TransactionService : ClientBase<IConsumerService>, IConsumerService
{

    public TransactionService()
    {
    }

    public TransactionService(string endpointConfigurationName) : 
        base(endpointConfigurationName)
    {
    }

    public TransactionService(string endpointConfigurationName, string remoteAddress) : 
        base(endpointConfigurationName, remoteAddress)
    {
    }

    public TransactionService(string endpointConfigurationName, EndpointAddress remoteAddress) : 
        base(endpointConfigurationName, remoteAddress)
    {
    }

    public TransactionService(Binding binding, EndpointAddress remoteAddress) : 
        base(binding, remoteAddress)
    {
    }

    public AccountBalanceResponse GetAccountBalance( AccountBalanceQuery query )
    {
        return Channel.GetAccountBalance( query );
    }
}  
Run Code Online (Sandbox Code Playgroud)

TransactionService.iOS.cs: ConsumerServiceClientChannel通过反射执行调用)

public partial class TransactionService
{
    protected override IConsumerService CreateChannel()
    {
        return new ConsumerServiceClientChannel(this);
    }

    private class ConsumerServiceClientChannel : ChannelBase<IConsumerService>, IConsumerService
    {

        public ConsumerServiceClientChannel(System.ServiceModel.ClientBase<IConsumerService> client) :
            base(client)
        {
        }

        // Sync version
        public AccountBalanceResponse GetAccountBalance(AccountBalanceQuery query)
        {
            object[] _args = new object[1];
            _args[0] = query;
            return (AccountBalanceResponse)base.Invoke("GetAccountBalance", _args);
        }

        // Async version
        public IAsyncResult BeginGetAccountBalance(AccountBalanceQuery query, AsyncCallback callback, object asyncState )
        {
            object[] _args = new object[1];
            _args[0] = query;
            return (IAsyncResult)base.BeginInvoke("GetAccountBalance", _args, callback, asyncState );
        }


        public AccountBalanceResponse EndGetAccountBalance(IAsyncResult asyncResult)
        {
            object[] _args = new object[0];
            return (AccountBalanceResponse)base.EndInvoke("GetAccountBalance", _args, asyncResult);
        }

    }
}
Run Code Online (Sandbox Code Playgroud)

编辑:我刚用最新的MT(5.2)对它进行了测试 - 它不再需要我之前所有的额外锅炉板,只需要CreateChannel()覆盖.我已经清理了示例代码以匹配.

EDIT2:我添加了一个异步方法实现.