可变排队通信

可变示例示例演示如何通过消息队列 (MSMQ) 传输来执行可变排队通信。 此示例使用 NetMsmqBinding。 此例中的服务是自承载控制台应用程序,通过它可以观察服务接收排队消息。

注意

本主题的最后介绍了此示例的设置过程和生成说明。

在排队通信中,客户端使用队列与服务进行通信。 更确切地说,客户端向队列发送消息。 服务从队列接收消息。 因此不必同时运行服务和客户端便可使用队列进行通信。

发送没有保证的消息时,MSMQ 仅尽量传递消息,这不同于“一次性”保证。具有“一次性”保证时,MSMQ 可确保消息被送达,如果无法送达消息,则会向您发出通知。

在某些情况下,当及时送达比丢失消息更重要时,您可能想要通过某个队列发送没有保证的可变消息。 队列管理器崩溃时可变消息不存在。 因此,如果队列管理器崩溃,用于存储可变消息的非事务性队列可以存在,但消息本身则无法存在,因为消息未存储在磁盘中。

注意

不能使用 MSMQ 在某个事务范围内发送没有保证的可变消息。 还必须创建非事务性队列以发送可变消息。

此示例中的服务协定是定义最适合与队列一起使用的单向服务的 IStockTicker

[ServiceContract(Namespace = "http://Microsoft.ServiceModel.Samples")]
public interface IStockTicker
{
    [OperationContract(IsOneWay = true)]
    void StockTick(string symbol, float price);
}

服务操作显示股票代号符号和价格,如下面的示例代码所示:

public class StockTickerService : IStockTicker
{
    public void StockTick(string symbol, float price)
    {
        Console.WriteLine("Stock Tick {0}:{1} ", symbol, price);
     }
     …
}

服务是自承载服务。 使用 MSMQ 传输时,必须提前创建所使用的队列。 可以手动或通过代码完成此操作。 在此示例中,该服务包含代码,以检查队列是否存在并在必要时创建队列。 从配置文件中读取队列名称。 ServiceModel 元数据实用工具 (Svcutil.exe) 使用基址生成服务代理。

// Host the service within this EXE console application.
public static void Main()
{
    // Get MSMQ queue name from app settings in configuration.
    string queueName = ConfigurationManager.AppSettings["queueName"];

    // Create the transacted MSMQ queue if necessary.
    if (!MessageQueue.Exists(queueName))
        MessageQueue.Create(queueName);

    // Create a ServiceHost for the StockTickerService type.
    using (ServiceHost serviceHost = new ServiceHost(typeof(StockTickerService)))
    {
        // Open the ServiceHost to create listeners and start listening for messages.
        serviceHost.Open();

        // The service can now be accessed.
        Console.WriteLine("The service is ready.");
        Console.WriteLine("Press <ENTER> to terminate service.");
        Console.WriteLine();
        Console.ReadLine();

        // Close the ServiceHost to shutdown the service.
        serviceHost.Close();
    }
}

MSMQ 队列名是在配置文件的 appSettings 节中指定的。 服务终结点是在配置文件的 system.serviceModel 节中定义的,它指定了 netMsmqBinding 绑定。

注意

队列名称对本地计算机使用圆点 (.),并在使用 System.Messaging 创建队列时在其路径中使用反斜杠分隔符。 Windows Communication Foundation (WCF) 终结点地址指定一个 net.msmq: 方案,使用“localhost”来表示本地计算机,并在其路径中使用正斜杠。

消息的保证和持久性或可变性也在配置中指定。

<appSettings>
  <!-- use appSetting to configure MSMQ queue name -->
  <add key="queueName" value=".\private$\ServiceModelSamplesVolatile" />
</appSettings>

<system.serviceModel>
  <services>
    <service name="Microsoft.ServiceModel.Samples.StockTickerService"
             behaviorConfiguration="CalculatorServiceBehavior">
    ...
      <!-- Define NetMsmqEndpoint -->
      <endpoint address="net.msmq://localhost/private/ServiceModelSamplesVolatile"
                binding="netMsmqBinding"
                bindingConfiguration="volatileBinding"
                contract="Microsoft.ServiceModel.Samples.IStockTicker" />
    ...
    </service>
  </services>

  <bindings>
    <netMsmqBinding>
      <binding name="volatileBinding"
             durable="false"
           exactlyOnce="false"/>
    </netMsmqBinding>
  </bindings>
  ...
</system.serviceModel>

由于该示例通过使用非事务性队列来发送排队消息,因此无法将经过事务处理的消息发送到队列。

// Create a client.
Random r = new Random(137);

StockTickerClient client = new StockTickerClient();

float price = 43.23F;
for (int i = 0; i < 10; i++)
{
    float increment = 0.01f * (r.Next(10));
    client.StockTick("zzz" + i, price + increment);
}

//Closing the client gracefully cleans up resources.
client.Close();

运行示例时,客户端和服务活动将显示在服务和客户端控制台窗口中。 您可以看到服务从客户端接收消息。 在每个控制台窗口中按 Enter 可以关闭服务和客户端。 请注意:由于正在使用队列,因此不必同时启动和运行客户端和服务。 可以先运行客户端,再将其关闭,然后启动服务,这样服务仍然会收到客户端的消息。

The service is ready.
Press <ENTER> to terminate service.

Stock Tick zzz0:43.25
Stock Tick zzz1:43.23
Stock Tick zzz2:43.28
Stock Tick zzz3:43.3
Stock Tick zzz4:43.23
Stock Tick zzz5:43.25
Stock Tick zzz6:43.25
Stock Tick zzz7:43.24
Stock Tick zzz8:43.32
Stock Tick zzz9:43.3

设置、生成和运行示例

  1. 请确保已执行 Windows Communication Foundation 示例的一次性安装过程

  2. 若要生成 C# 或 Visual Basic .NET 版本的解决方案,请按照 Building the Windows Communication Foundation Samples中的说明进行操作。

  3. 要使用单机配置或跨计算机配置来运行示例,请按照运行 Windows Communication Foundation 示例中的说明进行操作。

默认情况下使用 NetMsmqBinding 启用传输安全。 MSMQ 传输安全有两个相关的属性,即 MsmqAuthenticationModeMsmqProtectionLevel.。默认情况下,身份验证模式设置为 Windows,保护级别设置为 Sign。 为了使 MSMQ 提供身份验证和签名功能,MSMQ 必须是域的一部分,并且必须安装 MSMQ 的 Active Directory 集成选项。 如果在不满足这些条件的计算机上运行此示例,将会收到错误。

在加入到工作组或在没有 Active Directory 集成的计算机上运行示例

  1. 如果计算机不是域成员或尚未安装 Active Directory 集成,请将身份验证模式和保护级别设置为 None 以关闭传输安全性,如下面的示例配置代码所示:

    <system.serviceModel>
        <services>
          <service name="Microsoft.ServiceModel.Samples.StockTickerService"
                   behaviorConfiguration="StockTickerServiceBehavior">
            <host>
              <baseAddresses>
                <add baseAddress="http://localhost:8000/ServiceModelSamples/service"/>
              </baseAddresses>
            </host>
    
            <!-- Define NetMsmqEndpoint -->
            <endpoint address="net.msmq://localhost/private/ServiceModelSamplesVolatile"
                      binding="netMsmqBinding"
                      bindingConfiguration="volatileBinding"
                      contract="Microsoft.ServiceModel.Samples.IStockTicker" />
            <!-- the mex endpoint is exposed at http://localhost:8000/ServiceModelSamples/service/mex -->
            <endpoint address="mex"
                      binding="mexHttpBinding"
                      contract="IMetadataExchange" />
    
          </service>
        </services>
    
        <bindings>
          <netMsmqBinding>
            <binding name="volatileBinding"
                  durable="false"
                  exactlyOnce="false">
              <security mode="None" />
            </binding>
          </netMsmqBinding>
        </bindings>
    
        <behaviors>
          <serviceBehaviors>
            <behavior name="StockTickerServiceBehavior">
              <serviceMetadata httpGetEnabled="True"/>
            </behavior>
          </serviceBehaviors>
        </behaviors>
    
      </system.serviceModel>
    
  2. 确保在运行示例前更改服务器和客户端上的配置。

    注意

    security mode 设置为 None 等效于将 MsmqAuthenticationModeMsmqProtectionLevelMessage 安全设置为 None