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 和通道 - 缓存、重用、关闭和恢复 的相关文章

  • 是否可以通过服务类型的实例实例化 WebServiceHost,而无需无参数构造函数?

    我正在尝试创建自托管System ServiceModel Web WebServiceHost NET 4 但是我遇到了构造函数的问题 有以下三种选择 WebServiceHost 一个无参数的构造函数似乎毫无意义 因为无法指定服务的类型
  • Java 工具创建的 WSDL 文件的 WCF 序列化问题

    我的团队的任务是让几个内部开发的 NET 客户端应用程序连接到一些新的 Java Web 服务 Java Web 服务是第三方 供应商提供的 WSDL 文件 我们的团队修改 控制的能力有限 这意味着我们可能有权要求我们的供应商对 WSDL
  • Python 3:如何更改GDAL中的图像数据?

    我有一个 GeoTIFF 图像 其中包含颜色表和带有 8 位表键的单个栅格带 并且使用 LZW 压缩 我加载该图像gdal Open https gdal org python osgeo gdal module html 我还有一个包含
  • WCF 复杂 JSON 输入错误(无法通过 QueryStringConverter 转换)

    我在将复杂 JSON 作为 WCF 服务中的参数工作时遇到问题 在 Visual Studio 2008 SP1 中使用 Microsoft Net 3 5 SP1 签订以下合同 ServiceContract public interfa
  • 通过 IoC 容器实例化 WCF 服务

    是否可以使 WCF 运行时通过 IoC 容器而不是通过其通常的进程来实例化服务 此外 考虑到容器的类型生活方式配置与服务的 InstanceContextBehavior 之间存在潜在冲突 这种方法会是一个糟糕的主意吗 我知道我可能完全问错
  • WCF 数据契约/序列化

    我创建了一个简单的 WCF 应用程序 它公开一个操作 此操作采用复合数据类型作为参数 我没有用 DataContract 属性修饰这个复合数据类型 但这是有效的 我可以在 WSDL 中看到它的架构 现在我的理解是 这个新的自定义类型应该用
  • WCF - 进行多次调用时随机客户端超时

    我有一个WPF客户端通过以下方式请求数据WCF服务托管于IIS 7 服务方法调用存储过程 SQL 2012 using EF检索一些数据 由于需要加载大量数据 因此客户端会多次调用服务方法 以 分解 数据加载并避免大量负载和超时 我们使用生
  • 本地计算机上的服务启动然后停止,某些服务如果没有被其他服务或程序使用则自动停止

    我创建了一个示例 Windows 服务并成功安装了我的服务 但是在要启动服务时 我收到以下错误 本地计算机上的此服务启动然后停止 如果其他服务或程序未使用某些服务 则会自动停止 我的配置文件代码
  • WCF 每个端点有不同的身份验证方法

    我有 WCF 服务 我的服务有 2 个端点 每个端点都有不同的联系人 该服务使用自定义用户名身份验证 在 的 customUserNamePasswordValidatorType 属性中定义 问题是两个端点将使用相同的身份验证方法 无论如
  • 如何添加重试以调用 Web 服务?

    我有一个应用程序调用使用 wsHttpBinding 的 Web 服务 我需要在连接超时等情况下对 Web 服务调用实现某种重试功能 执行此操作的最佳方法是什么 我已经阅读过有关 WS ReliableMessaging 的内容 但这不是
  • ASP.Net Web API 与 WCF,我的项目中应该选择哪一个

    到目前为止 我已经在网络上阅读了很多关于 WCF 和 ASP Net Web API 之间的差异的文章 不幸的是 我无法清楚地知道什么才能达到我的目的 我读过的大多数文章都强调了这两个 Web 服务的设计观点 但我很困惑什么最适合我的项目
  • 将 fetch 与 Content-Type 结合使用时出现 CORS 错误 [重复]

    这个问题在这里已经有答案了 我正在尝试从 FireFox 中的不同域向 REST Web 服务发送 POST 请求 我为此使用 JavaScript 获取 函数 我在 IIS 中托管 REST Web 服务 在我在 JavaScript 中
  • 在(每个)Web API 操作之前执行代码

    我有一个 Web API 接口 我正在尝试适应多租户架构 以前 我们采用 WCF 模式 将参数 客户端 ID 传递给服务 然后服务将其存储起来以供稍后在代码中使用 这意味着客户端 ID 不必是传递给每个调用的第一个参数 我想对 Web AP
  • 测试项目和配置文件

    我的 Visual Studio 2008 解决方案中有这种设置 一个使用库 Lib1 需要 app config 文件中的一些配置条目 的 WCF 服务项目 WCFService 我有一个单元测试项目 MSTest 其中包含与 Lib1
  • 无法从 Windows 7 上的 Windows 服务启动桌面应用程序

    HI 我在 Windows 7 上有 C WCF Windows 服务 以具有管理员权限的用户身份登录 我正在尝试在服务启动后启动桌面应用程序 我发现的所有讨论都是关于 Windows 工作站和桌面 我创建了一个单独的线程 设置线程工作站和
  • 自定义 WCF DataContractSerializer

    是否可以用我自己的序列化程序替换 Windows Communication Foundation 中的 dataContractSerializer 如果可能的话 我怎样才能实现这一目标 是的 您可以提供自己的序列化器实现 默认情况下 W
  • jquery ajax“发布”调用

    我是 jQuery 和 Ajax 的新手 并且在 发布 方面遇到问题 我正在使用 jQuery Ajax post 调用将数据保存到数据库 当我尝试保存数据时 它将 null 传递给我的 C 方法 jQuery 看起来像这样 functio
  • 从一个客户端使用多个 WCF 服务

    我的网络场有 10 台运行 IIS 的服务器 在每台服务器上我都有相同的网站和相同的 WCF 服务 它公开了一些用于读取 删除缓存 会话 应用程序变量和其他内部数据的功能 在其他一些 Web 服务器上 我有一个 管理 Web 应用程序 它是
  • 匿名结构和空结构

    http play golang org p vhaKi5uVmm http play golang org p vhaKi5uVmm package main import fmt var battle make chan string
  • nHibernate + wcf + Isession

    我有一个包含 3 个项目的 C 解决方案 数据 WCF 和 UI 第一个是与数据库对话的类库 它通过第二个项目公开 该项目的类型为 WCF 服务库 原因是它将在第三个项目 称为 UI 的 Asp net 应用程序 作为指向 dll 的简单

随机推荐

  • 在 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 服务更改时重新生成 需要将消息检查器的行为应