13

因为monotouch编译为native code,所以它有一些限制,比如不允许动态调用。

但是我在 .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();   

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

4

2 回答 2

20

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

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

下面是我的一个旧服务实现,至少曾经在 MonoTouch 上工作。我将它分成 2 个部分类 - 第一个在所有构建中链接,第二个仅在 iOS 构建中(允许动态生成机制仍然在 Windows 上工作)。
我已将其精简为仅包含 1 个服务调用。

事务服务.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 );
    }
}  

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

    }
}

编辑:我刚刚用最新的 MT (5.2) 测试了这个 - 它不再需要我以前在那里拥有的所有额外的样板,只需 CreateChannel() 覆盖。我已经清理了示例代码以匹配。

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

于 2012-04-07T16:56:01.100 回答
1

我认为您可能会在这里混淆术语 - ChannelFactory通用类型,而不是动态.

根据 MonoTouch 文档,虽然 MonoTouch中的泛型支持存在限制,但ChannelFactory在这里应该没问题。

您是否尝试过使用 ChannelFactory?

于 2012-04-07T13:19:07.117 回答