WCF ChannelFactory 和通道 - 缓存、重用、关闭和恢复

2023-12-29

我为我的 WCF 客户端库规划了以下架构:

  • 使用 ChannelFactory 而不是 svcutil 生成代理,因为 我需要更多的控制权,而且我想让客户处于单独的状态 程序集并避免在我的 WCF 服务更改时重新生成
  • 需要将消息检查器的行为应用到我的 WCF 端点,因此每个通道都能够发送其 自己的身份验证令牌
  • 我的客户端库将从 MVC 前端使用,因此我必须考虑可能的线程问题
  • 我正在使用 .NET 4.5(也许它有一些帮助程序或新方法以更好的方式实现 WCF 客户端?)

我读过很多关于各种不同部分的文章,但我仍然对如何以正确的方式将它们组合在一起感到困惑。我有以下问题:

  1. 据我了解,建议将 ChannelFactory 缓存在静态变量中,然后从中获取通道,对吧?
  2. 端点行为是特定于整个 ChannelFactory 的还是我可以单独为每个通道应用我的身份验证行为?如果该行为特定于整个工厂,这意味着我无法在端点行为对象中保留任何状态信息,因为每个通道都会重复使用相同的身份验证令牌,但显然我希望每个通道都有自己的身份验证令牌当前用户。这意味着,我必须计算端点行为内部的令牌(我可以将其保留在 HttpContext 中,而我的消息检查器行为只会将其添加到传出消息中)。
  3. 我的客户端类是一次性的(实现 IDispose)。我如何正确处理通道,知道它可能处于任何可能的状态(未打开、打开、失败......)?我只需处理掉它吗?我要中止它然后处置吗?我是否要关闭它(但它可能根本还没有打开)然后丢弃?
  4. 如果我在使用频道时遇到问题该怎么办?是只有通道坏了还是整个ChannelFactory坏了?

我想,一行代码胜过一千个单词,所以这是我的代码形式的想法。我在上面所有的问题都标有“???”在代码中。

public class MyServiceClient : IDisposable
{
    // channel factory cache
    private static ChannelFactory<IMyService> _factory;
    private static object _lock = new object();

    private IMyService _client = null;
    private bool _isDisposed = false;

     /// <summary>
    /// Creates a channel for the service
    /// </summary>
    public MyServiceClient()
    {
        lock (_lock)
        {
            if (_factory == null)
            {
                // ... set up custom bindings here and get some config values

                var endpoint = new EndpointAddress(myServiceUrl);
                _factory = new ChannelFactory<IMyService>(binding, endpoint);

                // ???? do I add my auth behavior for entire ChannelFactory 
                // or I can apply it for individual channels when I create them?
            }
        }

        _client = _factory.CreateChannel();
    }

    public string MyMethod()
    {
        RequireClientInWorkingState();
        try
        {
            return _client.MyMethod();
        }
        catch
        {
            RecoverFromChannelFailure();
            throw;
        }
    }

    private void RequireClientInWorkingState()
    {
        if (_isDisposed)
            throw new InvalidOperationException("This client was disposed. Create a new one.");

        // ??? is it enough to check for CommunicationState.Opened && Created?
        if (state != CommunicationState.Created && state != CommunicationState.Opened)
            throw new InvalidOperationException("The client channel is not ready to work. Create a new one.");
    }

    private void RecoverFromChannelFailure()
    {
        // ??? is it the best way to check if there was a problem with the channel?
        if (((IChannel)_client).State != CommunicationState.Opened)
        {
            // ??? is it safe to call Abort? won't it throw?
            ((IChannel)_client).Abort();
        }

        // ??? and what about ChannelFactory? 
        // will it still be able to create channels or it also might be broken and must be thrown away? 
        // In that case, how do I clean up ChannelFactory correctly before creating a new one?
    }

    #region IDisposable

    public void Dispose()
    {    
        // ??? is it how to free the channel correctly?
        // I've heard, broken channels might throw when closing 
        // ??? what if it is not opened yet?
        // ??? what if it is in fault state?
        try
        {
            ((IChannel)_client).Close();
        }
        catch
        {
           ((IChannel)_client).Abort();              
        }

        ((IDisposable)_client).Dispose();

        _client = null;
        _isDisposed = true;
    }

    #endregion
}

我想晚总比不晚好……而且看起来作者已经成功了,这可能会对未来的 WCF 用户有所帮助。

1)ChannelFactory对通道进行排列,其中包括通道的所有行为。通过 CreateChannel 方法创建通道会“激活”通道。通道工厂可以被缓存。

2) 您通过绑定和行为来塑造通道工厂。此形状与创建此频道的每个人共享。正如您在评论中指出的,您可以附加消息检查器,但更常见的情况是使用标头将自定义状态信息发送到服务。您可以通过OperationContext.Current附加标头

using (var op = new OperationContextScope((IContextChannel)proxy))
{
    var header = new MessageHeader<string>("Some State");
    var hout = header.GetUntypedHeader("message", "urn:someNamespace");
    OperationContext.Current.OutgoingMessageHeaders.Add(hout);
}

3)这是我处理客户端通道和工厂的一般方法(此方法是我的 ProxyBase 类的一部分)

public virtual void Dispose()
{
    CloseChannel();
    CloseFactory();
}

protected void CloseChannel()
{
    if (((IChannel)_client).State == CommunicationState.Opened)
    {
        try
        {
            ((IChannel)_client).Close();
        }
        catch (TimeoutException /* timeout */)
        {
            // Handle the timeout exception
            ((IChannel)innerChannel).Abort();
        }
        catch (CommunicationException /* communicationException */)
        {
            // Handle the communication exception
            ((IChannel)_client).Abort();
        }
    }
}

protected void CloseFactory()
{
    if (Factory.State == CommunicationState.Opened)
    {
        try
        {
            Factory.Close();
        }
        catch (TimeoutException /* timeout */)
        {
            // Handle the timeout exception
            Factory.Abort();
        }
        catch (CommunicationException /* communicationException */)
        {
            // Handle the communication exception
            Factory.Abort();
        }
    }
}

4)WCF将故障通道而不是工厂。您可以实现重新连接逻辑,但这需要您从某些自定义 ProxyBase 创建并派生客户端,例如

protected I Channel
{
    get
    {
        lock (_channelLock)
        {
            if (! object.Equals(innerChannel, default(I)))
            {
                ICommunicationObject channelObject = innerChannel as ICommunicationObject;
                if ((channelObject.State == CommunicationState.Faulted) || (channelObject.State == CommunicationState.Closed))
                {
                    // Channel is faulted or closing for some reason, attempt to recreate channel
                    innerChannel = default(I);
                }
            }

            if (object.Equals(innerChannel, default(I)))
            {
                Debug.Assert(Factory != null);
                innerChannel = Factory.CreateChannel();
                ((ICommunicationObject)innerChannel).Faulted += new EventHandler(Channel_Faulted);
            }
        }

        return innerChannel;
    }
}

5) 不要重复使用通道。打开、做某事、关闭是正常的使用模式。

6) 创建公共代理基类并从中派生所有客户端。这可能会很有帮助,例如重新连接、使用调用前/调用后逻辑、使用工厂中的事件(例如故障、打开)

7) 创建您自己的 CustomChannelFactory 这使您可以进一步控制工厂的行为方式,例如设置默认超时、强制执行各种绑定设置(MaxMessageSizes)等。

public static void SetTimeouts(Binding binding, TimeSpan? timeout = null, TimeSpan? debugTimeout = null)
        {
            if (timeout == null)
            {
                timeout = new TimeSpan(0, 0, 1, 0);
            }
            if (debugTimeout == null)
            {
                debugTimeout = new TimeSpan(0, 0, 10, 0);
            }
            if (Debugger.IsAttached)
            {
                binding.ReceiveTimeout = debugTimeout.Value;
                binding.SendTimeout = debugTimeout.Value;
            }
            else
            {
                binding.ReceiveTimeout = timeout.Value;
                binding.SendTimeout = timeout.Value;
            }
        }
本文内容由网友自发贡献,版权归原作者所有,本站不承担相应法律责任。如您发现有涉嫌抄袭侵权的内容,请联系:hwhale#tublm.com(使用前将#替换为@)

WCF ChannelFactory 和通道 - 缓存、重用、关闭和恢复 的相关文章

  • 我要恢复我的记忆!我怎样才能真正处理一个控件?

    我正在制作一个应用程序 它创建大量的窗口控件 按钮和标签等 它们都是通过函数动态生成的 我遇到的问题是 当我删除控件并处置它们时 它们不会从内存中删除 void loadALoadOfStuff while tabControlToClea
  • 双工服务的实例、会话和并发

    我有一个要求 服务应该每秒向客户端发送一条消息 该服务只能有一个客户端 我创建了一个双工服务 现在对该服务的实例 并发性和会话感到困惑 双工服务是否始终需要会话 会话模式 必需 InstanceContextMode 是否应始终为 PerS
  • 需要 WCF 的完整 DI 示例

    有人有完整且有效的 WCF DI 示例吗 Every http www eggheadcafe com tutorials aspnet b428fb65 08b4 45c8 97cd 47ee1a1eaf41 composing wcf
  • 实体框架POCO与WCF软件设计问题

    我将在我的应用程序中使用实体框架和 WCF 正如我所看到的 建议的做法是将 POCO 与实体框架结合使用 并使用 POCO 类作为 DataContracts 如果我没记错的话 这实际上就是 POCO 和属性的用途 但是 我被要求对 Ent
  • WCF服务库项目找不到对其他项目的引用

    我的解决方案中有两个项目 MyApp Domain 和 MyApp WebService MyApp WebService 是一个 WCF 服务库 我想使用 MyApp Domain 中的一些实用函数 因此 在 MyApp WebServi
  • 当一个控制台应用程序已在运行时,如何在 Visual Studio 中启动第二个控制台应用程序

    我正在研究 WCF 书中的一些示例 单个解决方案中有一个主机项目和客户端项目 两者都是控制台应用程序 主机是启动应用程序 但客户端应用程序似乎没有像书中所说的那样打开控制台 书上说 当主机运行时 运行客户端 运行 按钮已被禁用 因为它已经在
  • WCF 错误:相对端点地址

    嗯 对 WCF 还很陌生 我想我有点搞砸了 这就是我到目前为止所做的 我在 IIS 中托管了我的 WCF 服务 首先是合同 using System using System Collections Generic using System
  • WCF 服务绑定采用默认值而不是自定义值

    我已经构建了一个 APi 它是一个 WCF 服务 在服务的 web config 中 我指定了一个自定义 bindong 如下所示
  • WCF:如何诊断故障通道?

    我正在为我的实验室进行一项更改 希望能够帮助诊断我们所看到的一些奇怪的通道故障现象 有一个测试应用程序使用 DuplexChannelFactory 连接到几个 Windows 服务 并且由于某种原因 该测试应用程序上的通道似乎出现了很多故
  • ASP.NET Identity 2.0解密Owin cookie

    我正在应用多租户的服务器端应用程序中工作 在这个服务器端我有一个后台 ASP NET MVC 和后端 WCF 我想解密身份 cookie 以便我可以检查它是否有效并使用它在 WCF 服务中进行身份验证 更具体地说 我真的想知道 ASP NE
  • 没有 ASP.NET/IIS 的 .NET Web 服务?

    我正在实现一个需要公开 Web 服务接口的服务器组件 但应用程序不需要它在 IIS 上与 ASP NET 一起运行 有没有一种直接的方法可以在不使用 ASP NET IIS 的情况下在 NET 中实现 Web 服务 我使用的是 NET 3
  • 使用 NSubstitute 模拟动作

    Web 服务的代理需要进行单元测试 而无需 显然 访问 Web 服务 这就是我想要绝育的方法 public void Invoke Action
  • 通过 https 负载均衡器的 WCF http 服务

    我有一个可以通过 http 端点访问的 WCF Web 服务 现在 该服务应通过 https 与负载均衡器一起发布 客户端是通过 svcutil exe 在 Net 中创建的 但 Java 客户端也需要 WSDL 我的理解是 Web 服务在
  • WCF 未在 IIS 6.0 下运行

    尝试让我的 WCF 服务在 IIS 6 下运行 我已经创建了 svc and aspnet isapi dll映射根据 http msdn microsoft com en us library ms752241 aspx http msd
  • 错误:在 Visual Studio 2013 中找不到类型或命名空间名称“ApplicationUser”

    我正在学习 RESTful WCF 服务 教程 但是当我构建我的应用程序时 我收到此错误 找不到类型或命名空间名称 ApplicationUser 您是否缺少 using 指令或程序集引用 c users basma documents v
  • WCF RIA 服务 - 加载多个实体

    我正在寻找一种模式来解决以下问题 我认为这很常见 我正在使用 WCF RIA 服务在初始加载时将多个实体返回给客户端 我希望两个实体异步加载 以免锁定 UI 并且我想利用 RIA 服务来执行此操作 我的解决方案如下 似乎有效 这种方法会遇到
  • 如何从c#中的窗口服务获取登录用户和机器名?

    如何在c 中从窗口服务获取登录用户 交互式用户 和机器名 当我尝试使用环境和其他类来登录用户名时 它只从窗口服务返回 NT AUTHORITY SYSTEM 该服务在 SYSTEM 帐户下执行 因此您在Environment班级 机器名称应
  • SVCUtil“更新服务参考”等效命令参数

    我想使用 SVCUtil 更新 Visual Studio 2010 解决方案中的服务引用 因为该解决方案有多个项目 并且一一刷新引用并不好 我想知道您的观点 因为我必须确保执行与 Visual Studio 2010 执行的命令完全相同的
  • 将复杂对象传递到 WCF Rest 服务

    我有一个接受复杂对象的操作合约 并且我通过 jQuery 调用该操作 如何使用 jQuery 传递像这样的复杂类型对象 以下是操作签名 public Resolution CreateNewResolution Resolution New
  • TransactionFlow(TransactionFlowOption.Mandatory) 操作行为(TransactionScopeRequired = true

    我正在尝试了解 WCF 事务 但对一个概念感到困惑 行为上有什么不同 TransactionFlow TransactionFlowOption Mandatory and OperationBehavior TransactionScop

随机推荐

  • 在 R 中对整齐数据同时执行多个 t.test

    我有一个如下所示的数据集 id samediff factor value 1 S give 3 1 S impact 4 2 S give 2 2 S impact 5 3 D give 1 3 D impact 4 4 D give 3
  • 如何向 Kivy For Android 添加模块?

    我在 Android 设备上安装了 Kivy 但 help modules 显示未安装 PIL 模块 我怎样才能添加它 编辑 我的意思是 我安装了 kivy launcher 并编写了一个小型测试应用程序 它可以工作 现在 如果我的应用程序
  • 当我单击 li 标签时,它会获取数据值,但是当我插入它时,它具有空值

    单击时我得到 li 标签数据值 现在我需要使用插入回数据库的值 但它在我的数据库中显示空值 但我使用 console log 它显示了价值 如何获取值并插入数据库 mymoviemanagement php movie 的值为 null i
  • 如何在 PHP 中设置 cookie 然后重定向?

    进行一些处理后 我想为用户输入设置一个 cookie 值 然后将它们重定向到新页面 但是 cookie 尚未设置 如果我注释掉重定向 则 cookie 设置成功 我认为这是某种标题问题 对于这种情况 最好的解决方法是什么 if form s
  • 不同大小类别的不同表视图单元格行高?

    如何更改此 UITableViewController 自定义类以动态更改表视图单元格的高度 我为 iPad 和 iPhone 尺寸类别指定了不同的字体大小 这是之前与 rdelmar 讨论的延续 import CREWFoodWaterL
  • 计算POST内容长度

    如何计算内容长度 例如 POST Upload HTTP 1 1 Host test lan User Agent Shockwave Flash Connection Keep Alive Cache Control no cache A
  • 操作栏抽屉切换自定义图标

    我正在尝试使用操作栏抽屉切换 但我希望它显示的不仅仅是菜单图标 我希望它在自定义菜单图标的右上角显示通知计数 但我仍然希望操作栏抽屉式开关在需要时显示后退箭头 因此 我首先尝试查看是否可以在操作栏抽屉切换上显示自定义布局 包含菜单图标的图像
  • Guid.NewGuid() VS Random.Next() 的随机字符串生成器

    我和我的同事正在讨论使用哪种方法来自动生成用户 ID 和帖子 ID 以在数据库中进行识别 一个选项使用 Random 的单个实例 并采用一些有用的参数 以便它可以重用于各种字符串生成情况 即从 4 位数字 pin 到 20 位字母数字 id
  • 如何使用JPA或HQL动态排序多对多关系?

    我有一个这样的映射 ManyToMany cascade CascadeType PERSIST JoinTable name product product catalog joinColumns JoinColumn name prod
  • 访问 Android 上先前安装创建的文件 - 范围存储 Android 11

    我正在使用 LibGDX 开发一个带有预设管理器的音乐应用程序 该管理器使用 LibGDX 的 FileHandle 来管理文件和目录 在我更新到 Android 11 API 30 之前 此功能一直运行良好 现在由于 Android 新的
  • Ruby OptionParser:隐藏命令选项的帮助文本

    Ruby OptionParser 将根据此描述自动为您生成帮助屏幕 http ruby about com od advancedruby a optionparser htm 有没有办法删除命令选项的帮助文本 我可以使用隐藏命令 而是使
  • 访问 Ruby 中受保护的方法

    我正在尝试在 Ruby 中为自己使用访问修饰符 我有 class Person def initialize first name last name age first name first name last name last nam
  • 全球之前一切都是开玩笑?

    我需要使用 React 测试库和 Jest 在测试中模拟不同的窗口大小 目前我必须拥有这个beforeAll在每个测试文件中 import matchMediaPolyfill from mq polyfill beforeAll gt m
  • 数据表行选择不起作用

    我有一个数据表
  • 在 JQueryMobile 中使用 autoInitializePage 的示例

    我正在寻找一个简单的示例 展示如何使用 JQueryMobile 呈现已在客户端动态组装的页面 mobile autoInitialize 曾经在几个版本前工作过 现在我们有 mobile autoInitializePage 但我似乎无法
  • jQuery UI - 按钮集按钮并不总是在第一次单击时起作用

    我正在使用 jQuery UI 按钮集 基于一些单选按钮 一切都工作得很好 除了有时当您单击其中一个按钮时什么也没有发生 就像您根本没有单击过它一样 我认为这可能是我的实现的问题 所以我去了演示站点 http jqueryui com de
  • 从 ec2 到 s3 的大文件

    我有一个 27GB 的文件 正在尝试将其从 AWS Linux EC2 移动到 S3 我尝试过 S3put 命令和 S3cmd put 命令 两者都使用测试文件 两者都不适用于大文件 没有给出错误 命令立即返回 但没有任何反应 s3cmd
  • Swift:按顺序多个异步请求。如何等待上一个请求完成?

    作为我的应用程序中身份验证过程的一部分 用户可以使用他们的 Facebook 帐户登录 我正在使用 Facebook iOS SDK 来处理此过程 身份验证完成后 我向 Facebook 图形 api 发出请求以获取用户个人资料数据 这是第
  • 如何更改Android Studio终端背景颜色

    Android Studio is so powerful tool and very convenient to use I super like its Darcula Theme But the problem is all wind
  • WCF ChannelFactory 和通道 - 缓存、重用、关闭和恢复

    我为我的 WCF 客户端库规划了以下架构 使用 ChannelFactory 而不是 svcutil 生成代理 因为 我需要更多的控制权 而且我想让客户处于单独的状态 程序集并避免在我的 WCF 服务更改时重新生成 需要将消息检查器的行为应