Monotouch/WCF:如何在没有 svcutil 的情况下使用 wcf 服务
Posted
技术标签:
【中文标题】Monotouch/WCF:如何在没有 svcutil 的情况下使用 wcf 服务【英文标题】:Monotouch/WCF: How to consume the wcf service without svcutil 【发布时间】:2012-04-20 17:26:11 【问题描述】:因为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 不支持动态代理代码生成。重写此方法或其调用者以返回特定的客户端代理实例
【问题讨论】:
这也会影响 WCF 服务的 ClientBaseChannelBase<T>
中使用BeginInvoke()
和EndInvoke()
的集合并完成与Invoke()
相同的操作,但它对我不起作用。我得到空引用异常,我认为是因为运行时无法将 Begin 调用与正确的 End 调用匹配。我尝试了几种不同的方法,但仍然没有乐趣=
@StingyJack 我可以在一分钟前让它工作!我所做的是在 Visual Studio 15.8.1 版本中使用 svcutil 重新生成连接服务参考文件,使用此命令 svcutil /async /tcv:Version35 https://... 然后在同步方法上使用它:var iar = BeginInvoke("YourMethod", _args, null, null); return (string)EndInvoke("YourMethod", Array.Empty
感谢@Ignacio 的提示,我实际上没有任何服务引用或连接的服务(长期以来一直使用 IChannelFactory 来启用类型共享,而不是在每个服务使用者处生成新类型),但是如果这行得通我确信我可以找到我的尝试和生成的代码之间的不同之处。
【参考方案1】:
我认为您可能在这里混淆了术语 - ChannelFactory 是 通用 类型,而不是 动态。
根据 MonoTouch 文档,虽然有 limitations to the Generics support in MonoTouch,但 ChannelFactory 应该在这里没问题。
您是否尝试过使用 ChannelFactory?
【讨论】:
是的,我尝试使用 ChannelFactory ,我已经发布了上面的代码,请参考,谢谢。【参考方案2】:ChannelFactory<T>
有一个虚方法CreateChannel()
。如果这没有被覆盖,它会使用动态代码生成,这在 MonoTouch 上会失败。
解决方案是覆盖它并提供您自己的编译时实现。
下面是我的一个旧服务实现,至少曾经在 MonoTouch 上工作。我将它分成 2 个部分类 - 第一个在所有构建中链接,第二个仅在 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 );
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:我添加了一个异步方法实现。
【讨论】:
这里说它找不到类 ChannelBase。而且我看不到如何将其与异步方法一起使用。谢谢! @cheeesus ChannelBase 在System.ServiceModel.Channels
命名空间内 - 确保您有所需的 using 语句。
@cheeesus 您只需调用BeginInvoke
而不是Invoke
(但仍发送同步样式的方法名称字符串(例如,不要在传入的方法名称的开头添加“Begin”前缀)。我'将编辑答案。
谢谢,做到了。我想知道为什么我一开始那样尝试时它不起作用。
@Jesse 这已经过去了,但从记忆中我想我将它们放在单独的文件中,并且只在 ios 项目中包含了 ios 特定类。或者只使用构建标志和#if。以上是关于Monotouch/WCF:如何在没有 svcutil 的情况下使用 wcf 服务的主要内容,如果未能解决你的问题,请参考以下文章
如何在没有 createSlice 的情况下使用 createThunkAsync
如何在没有没有索引的 url 的情况下调用 codeigniter 控制器功能