このデモの内容
ここでは、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>>
ページのトップへ
WEB キャスト