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 服务的 ClientBase 客户端。 “MonoTouch 不支持动态代理代码生成。覆盖此方法或其调用者以返回特定的客户端代理实例”。 尝试覆盖 ChannelBase 如@Tyson 的回答所描述的那样不起作用@ 987654322@ 方法仅适用于某些目标框架,不属于 netstandard2.0。我们剩下一个 Begin/EndInvoke(),它只抛出 Null ref ex。 嗨@StingyJack!是的!这就是发生在我身上的事情,我没有可用的调用。那么,我必须做些什么才能将 Xamarin.Forms 中的 ios 中的 WCF 与 .Net 标准 2.0 连接起来? @Ignacio - 我还不知道。您应该能够在ChannelBase&lt;T&gt; 中使用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(), iar);. 感谢@Ignacio 的提示,我实际上没有任何服务引用或连接的服务(长期以来一直使用 IChannelFactory 来启用类型共享,而不是在每个服务使用者处生成新类型),但是如果这行得通我确信我可以找到我的尝试和生成的代码之间的不同之处。 【参考方案1】:

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

根据 MonoTouch 文档,虽然有 limitations to the Generics support in MonoTouch,但 ChannelFactory 应该在这里没问题。

您是否尝试过使用 ChannelFactory?

【讨论】:

是的,我尝试使用 ChannelFactory ,我已经发布了上面的代码,请参考,谢谢。【参考方案2】:

ChannelFactory&lt;T&gt; 有一个虚方法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 控制器功能

如何在没有 UITableViewController 的情况下结束 UIRefreshControl

如何在没有 GPU 的情况下运行 tensorflow?

如何在没有'id'列的MySql中获取最后插入的记录?