因为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();
// ==&GT;抛出异常:MonoTouch不支持动态代理代码生成。重写此方法或其调用方以返回特定的客户端代理实例
答案 0 :(得分:18)
ChannelFactory<T>
有一个虚拟方法CreateChannel()
。如果没有覆盖它,它将使用动态代码生成,这在MonoTouch上失败。
解决方案是覆盖它并提供自己的编译时实现。
以下是我的一个旧服务实现,至少用于MonoTouch。我将它分成两个部分类 - 第一个在所有构建中链接,第二个仅在iOS构建中(允许动态生成机制仍在Windows上工作)。
我把它剥离了只包含一个服务电话。
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 );
}
}
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:我添加了一个异步方法实现。
答案 1 :(得分:1)
我认为您可能会在这里混淆条款 - ChannelFactory是通用类型,而不是动态。
根据MonoTouch文档,尽管有limitations to the Generics support in MonoTouch,但ChannelFactory 应该在这里没问题。
您是否尝试过使用ChannelFactory?