【问题标题】:WCF Common Parameters ClientMessageInspector, DispatchMessageInspector or alternative?WCF 常用参数 ClientMessageInspector、DispatchMessageInspector 还是替代方案?
【发布时间】:2023-11-10 16:43:01
【问题描述】:

我仅将 WCF 用于数据服务(即应用程序内部并且非常精简,没有会话状态等),以保持我们的 Web 应用程序可扩展。

我们需要为当前一直传入的每个服务调用提供一些通用属性。每次调用都只有一个请求对象并不理想,因为除了这些常见属性之外,其余的都非常多样化,并且在开发过程中变化非常频繁。

目前我正在考虑使用自定义标头和 clientmessageinspector 来设置值。 对于这种情况,这是最简单的推荐方法还是有更好的方法?

更多细节..

下面的红点是我不确定正确方法(或如何去做)的地方。

发送的内容

发送的数据是一组简单的 id(3 或 4 个用于 userid、clientid 等) - 所有这些 id 都会影响安全性和性能(在某些情况下,它决定了要转到哪个数据库)。

我们还将对其进行扩展,使其拥有更复杂的权限 - Windows 工作人员不需要。

调用者可以是来自会话对象的 Web 应用程序,也可以是手动填充这些对象的 Windows 服务工作者。

当前的想法

理想情况下,调用者工作流上的 getinstance 将使用会话对象自动填充这些属性,或者使用 Windows 服务调用(不同的构造函数?)手动填充这些属性。

然后,我们将确保这些参数始终可用,无需任何思考,也无需在整个代码中不断引用,以在调用它的每个函数上构造合约。我们目前有很多服务调用(由于应用程序的规模/复杂性,而不是由于糟糕的工程:)),因此随着复杂权限的扩展,以自我记录的方式执行规则变得有点困难。

从概念上讲,会话是您在应用程序中处理此问题的地方,但服务实际上只是一个数据访问层(具有视图映射、分页和来自存储库调用的最后调用安全性),因此我们不需要它某种重复或复杂性,只是要包含在查询中的关键身份和权限字段。

问题

这感觉很像我们应该在调用的标头上做的事情,因为我们总是需要这些字段,但我有点不确定 set 和 get 应该位于端点和客户端接口的生命周期中的哪个位置.我也很高兴我错了。

【问题讨论】:

  • 您似乎正在考虑的称为规范模型消息方案soapatterns.org/patterns/canonical_schema,是一种强大的方法。
  • 嗨 Martin,这是下面@Slugster 建议的模式,但我们真的不希望每次调用都带有合约的抽象层。我们的大多数请求都需要简单的参数,因为我们的服务是内部的,我们不需要版本控制等。参数更加自我记录,除非执行复杂的搜索样式操作,在这种情况下我们使用合同。

标签: c# asp.net wcf soa wcf-4


【解决方案1】:

根据我使用消息检查器的经验,最初设置和配置可能非常棘手,并且在我的研究中没有涵盖所有内容的网站,我不得不从几个不同的地方挑选 sn-ps 并将它们拼凑在一起。

您需要质疑您在标题中添加的内容。是被调用的方法需要使用的信息吗?如果是这样,那么将它放在标题中是错误的选择,因为每个方法都需要将信息解析出来。

最适合这种情况的信息是自定义身份验证和/或与 WCF 调用相关的用户特定元数据。在我的情况下,我有一个由自动化服务发起的 WCF 调用,该调用被中继到进一步的 WCF 端点,这是使用消息检查器的理想场景,因为我能够将元数据添加到中继点的标头以供后续使用终点。

如果您只是想打包每个调用共有的一些数据,那么我将包括创建一个具有适当属性的基本数据对象,然后将其扩展为更专业的调用(端点可以确保该公共数据要么存在,要么假设一些默认值(如果不存在)。对于每个端点所需的公共数据,使用消息检查器是多余的,并且可能不可行。

【讨论】:

  • 所以每次调用都需要解析数据,这有点笨拙对吧?我对通用数据合约的问题是我们有数百个调用,我不想要数百个消息合约或带有冗余字段的合约。我们的 wcf 层实际上是一种数据访问形式,因此精简且易于阅读是必不可少的。我曾希望“就在那里”拥有属性,并且服务调用具有“额外”属性。
  • 让我不确定的另一件事是,我们正在谈论的数据是非常用户元数据。我希望在“getinstance”点由工作流层(调用服务)填充这些数据,所以它有点设置和忘记。使用通用合约时,仍需要在每次调用时填充它。我也有 Windows 服务和调用它们的网站,因此可以通过更改 getinstance 调用来解决稍微不同的问题。
  • @Gats 有多少用户特定的数据可以静态存储在数据库中(所以不需要每次调用都传递——你只需要传递一个标识符)?很简单,如果 endpoint 将要处理信息,它可以放在标题中。如果被调用的方法要处理它,那么它属于合同数据对象(因此我的评论是将它们放在所有其他数据对象派生的基础对象中)。
  • 但是对您来说更好的答案可能是在服务器上启用会话状态 - 您初始调用“登录”并创建会话,然后可以将常用内容保留在会话中服务器直到会话结束?这样就不需要消息检查器,也不需要将其作为每次调用的一部分。
  • 您是否考虑过使用 OperationContext.IncommingMessagePropreties。您可以定义自己的消息属性,并与 serviceModel 层的特定请求绑定。这些比标头更快,并且不影响线路格式,并且这些在 MessageInspector 和管道中的其他层可用。
【解决方案2】:

这可能是一种较旧的方法,但您可以轻松地从System.Runtime.Remoting.Messaging 中利用CallContext。客户端可以使用IClientMessageInspector 的实现来设置操作调用的调用上下文,并在服务器上使用IMessageInspector 的实现来从CallContext 中检索共享数据。

【讨论】:

    【解决方案3】:

    我应用了类似的架构;基本上每个客户端调用都需要携带一些关于选择哪个数据库的信息,一个标识符等。在服务器端,这些参数会自动处理并存储在字典中。

    我创建了一个通用代理类来包装客户端代理,以便为每个服务调用添加相关的标头。每个需要调用服务的开发人员都在他们的调用中使用了这个通用代理类。

    在服务端,我实现了DispatchMessageInspector 作为端点行为,其中数据从请求标头中提取并存储在字典中。字典在 OperationContext (IExtension<OperationContext>) 的扩展中初始化,并且在请求处理期间可用。

    注意服务的实例上下文模式为PerCall

    【讨论】:

    最近更新 更多