65.9K
CodeProject 正在变化。 阅读更多。
Home

Windows Communication Foundation (WCF) 在嵌套 WCF 环境中的调用跳转机制

starIconstarIconstarIconstarIcon
emptyStarIcon
starIcon

4.80/5 (3投票s)

2014年6月30日

CPOL

5分钟阅读

viewsIcon

10583

downloadIcon

71

如何在嵌套 WCF 中实现调用跳转

引言

Windows Communication Foundation (WCF) 提供了一种在网络上托管服务契约的绝佳方式。此外,其内置的自托管和不同协议支持(TCP、HTTP 等)功能使其成为理想的选择。用户可以很好地控制服务及其功能。

WCF 需要三个组件:一个服务器、一个主机和一个客户端。现在,一个简单的调用机制很容易实现。但在当今复杂的业务和软件模型中,很难将每个功能都置于单一阶段。一个系统可能需要进行多次网络调用跳转,服务器可能在内部作为客户端调用另一个服务器,甚至那个另一个服务器也可以作为另一个服务器的客户端。因此,如果每次跳转都通过 WCF 契约,那么在第一阶段之后,调用会遇到技术问题。本文将通过一个小示例来解释这样一个系统,其中包含一些可能遇到的问题以及一个简单的解决方案。

假设:您必须具备 WCF 契约和自托管的基本知识。

问题陈述:当第一个服务器在自托管模型中充当客户端时,对第二个服务器的调用会失败。

背景

首先,让我们理解一个两级架构。假设我们选择通过 BasicHttp 进行自托管。服务器将生成一个配置文件,客户端需要使用该配置文件才能通过主机与服务器进行通信。

假设在服务器端,我们有两个组件:一个是放在“dll”中的服务器端代码。另一个是作为 EXE 的主机,它引用了“dll”,dll 中的每个函数都是客户端可以调用的公开方法。客户端由一个 EXE 和一个由该 EXE 使用的“App.config”文件组成。(此配置需要在运行时绑定连接)。当客户端调用服务器时,服务器“dll”将内部调用另一个自托管的 WCF 服务。为此,服务器需要使用第二个服务器的配置。

WCF 调用跳转

使用代码 - 真实生活示例

让我们从一个例子开始。有一个两级 WCF 架构。一端是客户端,它通过自托管应用程序调用 WCF 函数,反过来,服务器调用另一个 WCF 服务(同样通过自托管应用程序)。客户端应用程序是一个简单的将两个字符串连接起来的应用程序。

客户端应用程序

客户端正在调用一个 WCF 服务来执行任务。客户端代码和契约如下:

private void btnClick_Click(object sender, EventArgs e)
        {
            try
            {
                ContractConcat.ConcatClient obj = new ContractConcat.ConcatClient();
                tbxResult.Text = obj.Concatenate(tbxFirst.Text, tbxSecond.Text);
            }
            catch (Exception ex)
            {
                MessageBox.Show(ex.Message);
            }
        }
   <client>
            <endpoint address="http://127.0.0.1:4040/ServerCode" binding="wsHttpBinding"
                bindingConfiguration="WSHttpBinding_IConcat" contract="ContractConcat.IConcat"
                name="WSHttpBinding_IConcat">
                <identity>
                    <userPrincipalName value="AnantBeriwal-PC\Anant Beriwal" />
                </identity>
            </endpoint>
   </client>

我创建了一个名为 _WCFHost_ 的主机,它托管一个契约。正在托管的契约称为 _IConcat_。主机的 _App.Config_ 具有以下条目,以促进与服务器的正常通信。

<service name="WCFServer.ServerCode">
        <endpoint address="http://127.0.0.1:4040/ServerCode" binding="wsHttpBinding"   contract="WCFServer.IConcat">
        </endpoint>
 </service>

 

如您所见,它具有 _ConcatClient_ 的引用。_ConcatClient_ 通过自托管服务器连接到服务器。服务器契约是一个名为 _WCFServer_ 的项目,其 _ServerCode_ 文件和绑定接口如下:

namespace WCFServer
{
    public class ServerCode : IConcat
    {
        public string Concatenate(string strfirstString, string strSecondString)
        {
            ContractValidity.CheckForValidityClient obj = new ContractValidity.CheckForValidityClient();
            bool ResultFirst = obj.CheckForValidityOfString(strfirstString);
            bool ResultSecond = obj.CheckForValidityOfString(strSecondString);
            if (ResultFirst && ResultSecond)
            {
                return strfirstString + strSecondString;
            }
            else
            {
                return "Not a Valid Input";
            }
        }
    }
}

 

namespace WCFServer
{
    [ServiceContract]
    interface IConcat
    {
        [OperationContract]
        String Concatenate(string strfirstString, string strSecondString);
    }
}

如果您仔细查看代码部分,您会发现此服务器代码正在调用 _IValidity_ WCF 服务,因此当客户端调用 Concatenate 时,实际上有两次跳转。第二个服务器称为 _WCFHopServer_,它公开了一个名为 _IValidity_ 的契约。代码示例如下:

namespace WCFHopServer
{
    public class HopServerCode : ICheckForValidity
    {
        public bool CheckForValidityOfString(string strString)
        {
            for (int i = 0; i < strString.Length; i++)
            {
                if (char.IsLetter(strString[i]))
                {
                    continue;
                }
                else
                {
                    return false;
                }
            }
            return true;
        }
    }
}

 

namespace WCFHopServer
{
    [ServiceContract]
    interface ICheckForValidity
    {
        [OperationContract]
        bool CheckForValidityOfString(string strString);
    }
}

其相应的宿主将具有这样的条目以促进通信。(实际上,我使用了同一个 EXE 来公开这两个服务,因为它们都在同一台机器上。但这无论如何都不会影响跳转机制。)

 <service name="WCFHopServer.HopServerCode">
        <endpoint address="http://127.0.0.1:4040/HopServerCode" binding="wsHttpBinding" contract="WCFHopServer.ICheckForValidity">
        </endpoint>
</service>

最终架构如下:

WCF 调用跳转

现在我们将运行应用程序。首先,将运行主机。当主机启动时,它将托管这两个服务契约(这是为了方便展示;这两个契约可以分开托管)。

WCFHost

现在,当点击“_Concatenate_”按钮时,您期望什么?它应该能正常工作,还是我们遗漏了什么?等等,出现了一个错误。

原因很简单。_WCFServer_ 没有 _WCFHopServer_ 配置。为什么?因为我们从未提供过。实际上,它并不像看起来那么简单。如果您仔细观察,_WCFServer_ 已经有了一个配置。那就是 _IConcat_ 的配置,由 _WCFHost_ 提供(一个“dll”本身没有任何配置,父 EXE 为其提供)。由于 _WCFHost_ 托管 _IConcat_ 服务,它有一个 app.config,它会传递给 _WCFServer_。现在 _WCFSever_ 如何使用 _WCFHopServer_ 的服务配置?

有三种方法可以做到这一点。

  1. 将其硬编码到 _WCFServer_ 代码中。绑定类可以为您做到这一点。但这是不理想的。为了方便起见,您可以将所有配置放在另一个文件中,自己读取值,然后初始化绑定类。但代码是额外的开销。
  2. 其次,如果您不想编写太多代码,ConfigurationManager 类将为您完成大部分工作(读取和管理 app.config,特别是读取配置文件本身的节点)。但您仍然需要自己编写绑定代码并自己调用服务器。另外,维护另一个 app.config 会很麻烦。
  3. 您可以走第三条路,这也是本文的主题。我们不需要添加任何代码,将所有内容留给配置文件。我们将使用这种技术。

问题在于主机无法提供关于第二个服务器配置的任何信息。但我们可以修改 app.config 来做到这一点。为了分类,在 App.config 中,有两种类型的契约。

  1. <Services> 定义服务器端契约
  2. <Client> 定义客户端契约

我们可以将这两个部分保留在同一个配置文件中。让我们看看我们需要的客户端部分。它是一个 <Client> 标签,其中包含 _IValidity_ 契约的详细信息。

<client>
      <endpoint address="http://127.0.0.1:4040/HopServerCode" binding="wsHttpBinding"
          contract="ContractValidity.ICheckForValidity">
      </endpoint>
    </client>

将此标签添加到 _WCFHost_ 的 App.Config 中。现在,根据配置文件,_WCFHost_ 同时作为客户端和服务器运行。最终配置如下:

<configuration>
  <system.web>
    <compilation debug="true" />
  </system.web>
  <system.serviceModel>
    <services>
      <service name="WCFServer.ServerCode">
        <endpoint address="http://127.0.0.1:4040/ServerCode" binding="wsHttpBinding" contract="WCFServer.IConcat">
        </endpoint>
      </service>
      <service name="WCFHopServer.HopServerCode">
        <endpoint address="http://127.0.0.1:4040/HopServerCode" binding="wsHttpBinding" contract="WCFHopServer.ICheckForValidity">
        </endpoint>
      </service>
    </services>
    <client>
      <endpoint address="http://127.0.0.1:4040/HopServerCode" binding="wsHttpBinding"
          contract="ContractValidity.ICheckForValidity">
      </endpoint>
    </client>
    </system.serviceModel>
</configuration>

我们利用了 EXE 的基本属性,即它会为 dll 的底层提供配置。现在 dll 正在寻找一个客户端契约,但它收到了一个服务器契约。因此问题仍然存在。有了新的 _WCFHost_ 及其配置,客户端将不会抛出任何异常,并将显示结果。

最终结果

就这样,各位。我希望这是一种有用、简单且节省时间的解决方案。

sample code can be downloaded from here- SampleCode.zip

© . All rights reserved.