次の方法で共有


WCF と MSMQ 4.0 の利用


WEB キャスト

このデモの内容

ここでは、MSMQ 4.0 (Microsoft メッセージキュー 4.0) の特徴を簡単に説明し、WCF サービスから MSMQ 4.0 を使用した簡単なサンプルを使って、その特徴を具体的に理解していきます。

デモでご紹介しているソースコード

【コントラクト(C#, IOrder.cs)】

using System;
using System.ServiceModel;
namespace Microsoft.Demo {
    [ServiceContract( SessionMode=SessionMode.Required )]
    public interface IOrders {
        [OperationContract( IsOneWay = true )]
        void OpenPO( string name );
        [OperationContract( IsOneWay = true )]
        void AddLineItem( string item, decimal price, int quantity );
        [OperationContract( IsOneWay = true )]
        void EndPO( int totalItems, decimal totalPrice );
    } // End of interface
} // End of namespace

【サービスの実装 (C#)】

using System;
using System.Windows.Forms;
using System.ServiceModel;
using System.ServiceModel.Channels;
namespace Microsoft.Demo {
    [ServiceBehavior(
        InstanceContextMode = InstanceContextMode.PerSession
    )]
    [DeliveryRequirements(
        QueuedDeliveryRequirements = QueuedDeliveryRequirementsMode.Required
    )]
    class PurchasingService : IOrders {
        //private const int poisonThreshold = 3;
        private string name;
        private int itemCount;
        private decimal totalPrice;
        public PurchasingService() { }
        protected string Name {
            get { return name; }
        }
        [OperationBehavior(
            TransactionScopeRequired = true,
            TransactionAutoComplete = false    /* 自動コミットしない*/
        )]
        public void OpenPO( string name ) {
            ConsoleColor oldColor = Console.ForegroundColor;
            Console.ForegroundColor = ConsoleColor.Yellow;
            Console.WriteLine( "NEW PO: {0}", name );
            Console.ForegroundColor = oldColor;
            this.name = name;
        }
        [OperationBehavior(
            TransactionScopeRequired = true,
            TransactionAutoComplete = false    /* 自動コミットしない*/
        )]
        public void AddLineItem( string item, decimal price, int quantity ) {
            Console.WriteLine( 
                "ITEM: {0} ¥{1:#,##0} x {2} [小計:¥{3:#,##0}]", 
                item, 
                price, 
                quantity, 
                price * quantity 
            );
            itemCount += quantity;
            totalPrice += price * quantity;
        }
        [OperationBehavior(
            TransactionScopeRequired = true,
            TransactionAutoComplete = true    /* 自動コミット*/
        )]
        public virtual void EndPO( int totalItems, decimal totalPrice ) {
            ConsoleColor oldColor;
            bool isValid = ( ( totalPrice == this.totalPrice ) && ( totalItems == itemCount ) );
            Console.WriteLine(
                "TOTAL ITEMS: {0} 合計:¥{1:#,##0} ({2})", 
                totalItems, 
                totalPrice,
                ( isValid ? "Valid" : "Invalid" )
            );
            MsmqMessageProperty msmqMessageProperty =
                OperationContext.Current.IncomingMessageProperties[ MsmqMessageProperty.Name ] as MsmqMessageProperty;
            if ( msmqMessageProperty.AbortCount > 0 || msmqMessageProperty.MoveCount > 0 ) {
                oldColor = Console.ForegroundColor;
                Console.ForegroundColor = ConsoleColor.Magenta;
                Console.WriteLine(
                    "トランザクション(PO: {0}) は{1} 回アボートされています。({2} サイクル目)",  
                    name, 
                    msmqMessageProperty.AbortCount,
                    msmqMessageProperty.MoveCount / 2 
                );
                Console.ForegroundColor = oldColor;
            }
            DialogResult dr =
                MessageBox.Show(
                    string.Format( "トランザクション(PO: {0})をアボートしますか?", name ),
                    "Demo (Transacted Queue - Service Side)",
                    MessageBoxButtons.YesNo,
                    MessageBoxIcon.Question
                );
            if ( dr == DialogResult.Yes ) {
                oldColor = Console.ForegroundColor;
                Console.ForegroundColor = ConsoleColor.Red;
                Console.WriteLine( "トランザクション(PO: {0})はアボートされます。", name );
                Console.ForegroundColor = oldColor;
                throw new Exception( "User aborted the Transaction." );
            }
            else {
                oldColor = Console.ForegroundColor;
                Console.ForegroundColor = ConsoleColor.Cyan;
                Console.WriteLine( "トランザクション(PO: {0})はコミットされました。", name );
                Console.ForegroundColor = oldColor;
            }
        }
    } // End of class
} // End of namespace

【サービスのホスト (C#)】

using System;
using System.Configuration;
using System.Messaging;
using System.ServiceModel;
namespace Microsoft.Demo {
    class Program {
        static void Main( string[] args ) {
            ConsoleColor oldColor;
            string queueName = ConfigurationManager.AppSettings[ "queueName" ];
            oldColor = Console.ForegroundColor;
            Console.ForegroundColor = ConsoleColor.Green;
            Console.WriteLine( "[ENTER]キー押下でキューを作成します。" );
            Console.ForegroundColor = oldColor;
            Console.ReadLine();
            // キューの作成
            if ( !MessageQueue.Exists( queueName ) ) {
                // トランザクショナルなキューを作成
                MessageQueue.Create( queueName, true );
                oldColor = Console.ForegroundColor;
                Console.ForegroundColor = ConsoleColor.Yellow;
                Console.WriteLine( "キュー'{0}' を作成しました。", queueName );
                Console.ForegroundColor = oldColor;
            }
            else {
                oldColor = Console.ForegroundColor;
                Console.ForegroundColor = ConsoleColor.Yellow;
                Console.WriteLine( "キュー'{0}' がすでに存在するため、そのまま使用します。", queueName );
                Console.ForegroundColor = oldColor;
            }
            oldColor = Console.ForegroundColor;
            Console.ForegroundColor = ConsoleColor.Green;
            Console.WriteLine( "[ENTER]キー押下でサービスを開始します。" );
            Console.ForegroundColor = oldColor;
            Console.ReadLine();
            Uri baseUri = new Uri( ConfigurationManager.AppSettings["baseUri"] );
            ServiceHost host =
                new ServiceHost( typeof( PurchasingService ), baseUri );
            host.Open();
            oldColor = Console.ForegroundColor;
            Console.ForegroundColor = ConsoleColor.Green;
            Console.WriteLine( "[ENTER]キー押下で終了します。" );
            Console.ForegroundColor = oldColor;
            Console.ReadLine();
            host.Close();
            // キューの削除
            oldColor = Console.ForegroundColor;
            Console.ForegroundColor = ConsoleColor.Yellow;
            Console.WriteLine( "キュー'{0}' を削除しますか? (Y/N)", queueName );
            Console.ForegroundColor = oldColor;
            ConsoleKeyInfo key = Console.ReadKey( true );
            if ( key.Key == ConsoleKey.Y ) {
                // キューを削除
                oldColor = Console.ForegroundColor;
                Console.ForegroundColor = ConsoleColor.Green;
                Console.WriteLine( "キュー'{0}' を削除しました。", queueName );
                Console.ForegroundColor = oldColor;
                MessageQueue.Delete( queueName );
            }
        }
    } // End of class
} // End of namespace

【サービスの構成 (App.config)】

<?xml version="1.0" encoding="utf-8" ?>
<configuration>
    <system.serviceModel>
        <services>
            <service name="Microsoft.Demo.PurchasingService">
                <endpoint 
                    contract="Microsoft.Demo.IOrders"
                    binding="netMsmqBinding"
                    bindingConfiguration="TxQueueBindingConfig1"
                    address="net.msmq://localhost/private/Demo_TxQueue" 
                />
            </service>
        </services>        
        <bindings>
            <netMsmqBinding>           
        <binding name="TxQueueBindingConfig1" 
          retryCycleDelay="00:00:05"
           receiveRetryCount ="2"
           maxRetryCycles="2" 
           receiveErrorHandling="Move">
          <security mode="None"/>
        </binding>
      </netMsmqBinding>
        </bindings>
    </system.serviceModel>    
    <appSettings>
        <add key="queueName" value=".\private$\Demo_TxQueue" />
        <add key="baseUri" value="https://localhost:9001/"/>
    </appSettings>
</configuration>

【クライアントからの呼び出し (C#)】

using System;
using System.ServiceModel;
using System.Transactions;
using System.Windows.Forms;
namespace Microsoft.Demo {
    class Program {
        static void Main( string[] args ) {
            int txCount = 3;
            ConsoleColor oldColor;
            ChannelFactory<IOrders> factory = 
                new ChannelFactory<IOrders>( "TxQueueClientConfig" );
            for ( int i = 0; i < txCount; i++ ) {
                oldColor = Console.ForegroundColor;
                Console.ForegroundColor = ConsoleColor.Green;
                Console.WriteLine( "[ENTER]キー押下で発注処理を開始します。({0}/{1})", i + 1, txCount );
                Console.ForegroundColor = oldColor;
                Console.ReadLine();
                string title = string.Format( "発注#{0}", i + 1 );
                TransactionScope txs = null;
                try {
                    Console.WriteLine( "トランザクション開始: {0}", title );
                    txs = new TransactionScope();
                    IOrders orders = factory.CreateChannel();
                    orders.OpenPO( title );
                    orders.AddLineItem( "Blue widget", 1500M, i + 2 );
                    orders.AddLineItem( "Red widget", 2000M, i + 2 );
                    orders.EndPO( 4, ( 3500M * ( i + 2 ) ) );
                    ( (IClientChannel) orders ).Close();
                    oldColor = Console.ForegroundColor;
                    Console.ForegroundColor = ConsoleColor.Yellow;
                    Console.WriteLine( "トランザクションをアボートしますか? (Y/N)" );
                    Console.ForegroundColor = oldColor;
                    ConsoleKeyInfo key = Console.ReadKey( true );
                    if ( key.Key == ConsoleKey.Y ) {
                        throw new Exception( "クライアントでトランザクションがアボートされました。" );
                    }
                    txs.Complete();
                    Console.WriteLine( "トランザクション'{0}' はコミットされました。", title );
                }
                catch ( Exception ex ) {
                    oldColor = Console.ForegroundColor;
                    Console.ForegroundColor = ConsoleColor.Red;
                    Console.WriteLine( "エラー: {0}", ex.Message );
                    Console.ForegroundColor = oldColor;
                }
                finally {
                    if ( txs != null ) { txs.Dispose(); }
                }
            }
            oldColor = Console.ForegroundColor;
            Console.ForegroundColor = ConsoleColor.Green;
            Console.WriteLine( "[ENTER]キー押下で終了します。" );
            Console.ForegroundColor = oldColor;
            Console.ReadLine();
        }
    } // End of class
} // End of namespace

【クライアントの構成 (App.config)】

<?xml version="1.0" encoding="utf-8" ?>
<configuration>
    <system.serviceModel>
        <client>
            <endpoint name="TxQueueClientConfig"
                contract="Microsoft.Demo.IOrders"
                binding="netMsmqBinding"
                bindingConfiguration="TxQueueBindingConfig"
                address="net.msmq://localhost/private/Demo_TxQueue"
            />
        </client>
        <bindings>
            <netMsmqBinding>
        <binding name="TxQueueBindingConfig">
          <security mode="None"/>
        </binding>
            </netMsmqBinding>
        </bindings>
    </system.serviceModel>
</configuration>>

ページのトップへ