# 跟我一起學WCF(10)——WCF中事務處理
## 一、引言
好久沒更新,總感覺自己欠了什么一樣的,所以今天迫不及待地來更新了,因為后面還有好幾個系列準備些,還有很多東西需要學習總結的。今天就來介紹下WCF對事務的支持。
## 二、WCF事務詳解
## 2.1 事務概念與屬性
首先,大家在學習數據庫的時候就已經接觸到事務這個概念了。所謂事務,它是一個操作序列,這些操作要么都執行,要么都不執行,它是一個不可分割的工作單元。例如,銀行轉賬功能,這個功能涉及兩個邏輯操作
1. 從一個賬戶A中扣錢
2. 另一個賬戶B增加對應的錢。
現實生活中,這兩個操作需要要么都執行,要么都不執行。所以在實現轉賬功能時,這兩個操作就可以作為一個事務來進行提交,這樣才能夠保證轉賬功能的正確執行。
上面通過銀行轉賬的例子來解釋了事務的概念了,也可以說非常容易理解。然后在數據庫的相關書籍里面都會介紹事務的特性。一個邏輯工作單元要成為事務,必須滿足四個特性,這四個特性包括原子性、一致性、隔離性和持久性。這四個特性也簡稱為ACID(ACID是四個特性英文單詞首字母的縮寫)。
* 原子性。此屬性可確保特定事務下完成的所有更新都已提交并保持持久,或所有這些更新都已中止并回滾到其先前狀態。
* 一致性。此屬性可保證某一事務下所做的更改表示從一種一致狀態轉換到另一種一致狀態。例如,將錢從支票帳戶轉移到存款帳戶的事務并不改變整個銀行帳戶中的錢的總額。
* 隔離。此屬性可防止事務遵循屬于其他并發事務的未提交的更改。隔離在確保一種事務不能對另一事務的執行產生意外的影響的同時,還提供一個抽象的并發。
* 持久性。這意味著一旦提交對托管資源(如數據庫記錄)的更新,即使出現失敗這些更新也會保持持久。
## 2.2 事務協議
WCF支持分布式事務,也就是說WCF中的事務可以跨越服務邊界、進程、機器和網絡,在多個客戶端和服務之間存在。即WCF中事務可以被傳播的。既然WCF支持事務,則自然就有對應傳輸事務信息的相關協議。所以也就有了事務協議。
WCF使用不同的事務協議來控制事務的執行范圍,事務協議是為了實現分布式環境中事務的傳播。WCF支持以下三種事務協議:
1. 輕量級協議(Lightweight Protocol):該協議僅用于管理本地環境中的事務,即處于同一應用程序域中的事務。它無法跨越應用程序域的邊界傳播事務,則更不用說跨越進程和機器邊界了。所以Lightweight Protocol只適用于某個服務的內部或外部。但相對于其他協議來說,輕量級協議的性能是最好的,這應該是顯然的,不能跨越進程和機器邊界,則就不存在網絡傳輸。
2. OleTx協議:該協議用于跨應用程序域、進程和機器邊界傳播事務。協議采用遠程過程調用(RPC),并采用Windows專用的二進制格式。但該協議無法穿越防火墻或與非Windows方協作。所以OleTx協議多用于Windows體系下的內網環境(即Intranet環境)。
3. WS-Atomic(WS原子性,WSAT)事務協議:該協議與OleTx協議類似,同樣允許事務穿越應用程序域、進程和機器邊界傳播事務。但不同于OleTx協議的是,WSAT協議基于一種行業標準,它使用HTTP協議,并編碼形式為文本格式,因而可以穿越防火墻。雖然可以在內網中使用WSAT協議,但它主要還是用于Internet環境。
因為輕量級協議不能跨越服務邊界傳播事務,所有沒有綁定支持輕量級協議。WCF預定義的綁定中實現了標準的WS-Atomic 協議和Microsoft專有的OleTx協議,我們可以通過編程或配置文件來設置事務協議。具體設置方法如下所示:
```
1 <bindings>
2 <netTcpBinding>
3 <!--通過transactionProtocol屬性來設置事務協議-->
4 <binding name="transactionTCP" transactionFlow="true" transactionProtocol="WSAtomicTransactionOctober2004"/>
5 </netTcpBinding>
6 </bindings>
7 // 通過編程設置
8 NetTcpBinding tcpBinding = new NetTcpBinding();
9 // 注意: 事務協議的配置只有在事務傳播的情況下才有意義
10 tcpBinding.TransactionFlow = true;
11 tcpBinding.TransactionProtocol = TransactionProtocol.WSAtomicTransactionOctober2004;
```
這里需要注意,事務協議的配置只有在允許事務傳播的情況下才有意義。并且NetTcpBinding和NetNamedPipeBinding都提供了TransactionProtocol屬性。由于TCP和IPC綁定只能在內網使用,將它們設置為WSAT協議并無實際意義,對于WS綁定(如WSHttpBinding、WSDualHttpBinding和WSFederationHttpBinding)并沒有TransactionProtocol屬性,它們設計的目的在于當涉及多個使用WAST協議的事務管理器時,能夠跨越Internet。但如果只有一個事務協調器,OleTx協議將是默認的協議,不必也不能為它配置一個特殊的協議。
## 2.3 事務管理器
分布式事務的實現要依靠第三方事務管理器來實現。它負責管理一個個事務的執行情況,最后根據全部事務的執行結果,決定提交或回滾整個事務。WCF提供了三個不同的事務管理器,它們分別是輕量級事務管理器(LTM)、核心事務管理器(KTM)和分布式事務協調器(DTC)。WCF根據平臺使用的公共,應用程序的事務執行的任務、調用的服務以及所消耗的資源分配合適的事務管理器。通過自動地分配事務管理器,WCF將事務管理從服務代碼和用到的事務協議中解耦出來,開發者不必為事務管理器而苦惱。下面分別介紹下這三種事務管理器。
* LTM:它只管理本地事務,即在一個單獨應用程序域內的事務。LTM只能管理在一個單獨服務內的事務,該服務不能將事務傳遞給其他服務。LTM在所有的事務管理器中,性能最好。
* KTM:與LTM一樣,KTM管理的事務只能引入一個服務,并且該服務不得向其他服務傳播事務。
* DTC:DTC可以管理跨越任意執行邊界的事務,從本地跨越所有的邊界,如進程、機器或站點的邊界。DTC既可以使用OleTx協議,也可以使用WSAT協議。DTC與WCF緊密的集成一起,它是每個運行WCF的機器上默認可用的系統服務,DTC可以創建新的事務、跨機器傳播事務,手機之一管理器的投票并通知資源管理器進行回滾或提交。
## 2.4 服務支持的4種事務模式
事務使用哪個事務由綁定的事務流屬性([TransactionFlow](http://msdn.microsoft.com/zh-cn/library/system.servicemodel.nettcpbinding.transactionflow(v=vs.110).aspx)屬性)、操作契約中的事務流選項([TransactionFlowOption](http://msdn.microsoft.com/zh-cn/library/system.servicemodel.transactionflowoption(v=vs.110).aspx)) 以及操作行為特性中的事務范圍屬性([TransactionScopeRequired](http://msdn.microsoft.com/zh-cn/library/system.servicemodel.operationbehaviorattribute.transactionscoperequired(v=vs.110).aspx))共同決定。TransactionFlow屬性有2個值,true 或false,TransactionFlowOption有三個值,NotAllowed、Allowed和Mandatory,TransactionScopeRequired有兩個值,true或false。所以一共有12種(2*3*2)可能的配置設置。在這些配置設置中,有4種不滿足要求的,例如在綁定中設置TransactionFlow屬性為false,卻設置TransactionFlowOption為Mandatory。下圖列出了剩下的8種情況:

上圖中的8中排列組合實際最終只產生了四種事務傳播模式,這4種傳播模式為:Client/Service、Client、Service和None。上圖黑體字指出各種模式推薦的配置設置。在設計應用程序時,每種模式都有它自己的適用場景。對于除None模式的其他三種模式的推薦配置詳細介紹如下所示:
* Client/Service:最常見的一種事務模型,通常由客戶端或服務本身啟用一個事務。設置步驟:
(1) 選擇一個支持事務的Binding,設置 TransactionFlow = true。 (2) 設置 TransactionFlow(TransactionFlowOption.Allowed)。 (3) 設置 OperationBehavior(TransactionScopeRequired=true)。
* Client:強制服務必須參與事務,而且必須是客戶端啟用事務。設置步驟:
(1) 選擇一個支持事務的Binding,設置 TransactionFlow = true。 (2) 設置 TransactionFlow(TransactionFlowOption.Mandatory)。 (3) 設置 OperationBehavior(TransactionScopeRequired=true)。
* Service:服務必須啟用一個根事務,且不參與任何外部事務。設置步驟:
(1) 選擇任何一種Binding,設置 TransactionFlow = false(默認)。 (2) 設置 TransactionFlow(TransactionFlowOption.NotAllowed)。 (3) 設置 OperationBehavior(TransactionScopeRequired=true)。
## 三、WCF事務服務的實現
上面內容對WCF中事務進行了一個詳細的介紹,下面具體通過一個實例來說明WCF中如何實現對事務的支持。首先還是按照前面博文中介紹的步驟來實現該實例。
第一步:創建WCF契約和契約的實現,具體的實現代碼如下所示:
```
namespace WCFContractAndService
{
// 服務契約
[ServiceContract(SessionMode= SessionMode.Required)]
//[ServiceBehavior(ReleaseServiceInstanceOnTransactionComplete = false)]
public interface IOrderService
{
// 操作契約
[OperationContract]
// 控制客戶端的事務是否傳播到服務
// TransactionFlow的值會包含在服務發布的元數據上
[TransactionFlow(TransactionFlowOption.NotAllowed)]
List<Customer> GetCustomers();
[OperationContract]
[TransactionFlow(TransactionFlowOption.NotAllowed)]
List<Product> GetProducts();
[OperationContract]
[TransactionFlow(TransactionFlowOption.Mandatory)]
string PlaceOrder(Order order);
[OperationContract]
[TransactionFlow(TransactionFlowOption.Mandatory)]
string AdjustInventory(int productId, int quantity);
[OperationContract]
[TransactionFlow(TransactionFlowOption.Mandatory)]
string AdjustBalance(int customerId, decimal amount);
}
[DataContract]
public class Customer
{
[DataMember]
public int CustomerId { get; set; }
[DataMember]
public string CompanyName { get; set; }
[DataMember]
public decimal Balance { get; set; }
}
[DataContract]
public class Product
{
[DataMember]
public int ProductId { get; set; }
[DataMember]
public string ProductName { get; set; }
[DataMember]
public decimal Price { get; set; }
[DataMember]
public int OnHand { get; set; }
}
[DataContract]
public class Order
{
[DataMember]
public int CustomerId { get; set; }
[DataMember]
public int ProductId { get; set; }
[DataMember]
public decimal Price { get; set; }
[DataMember]
public int Quantity { get; set; }
[DataMember]
public decimal Amount { get; set; }
}
}
namespace WCFContractAndService
{
// 服務實現
[ServiceBehavior(
TransactionIsolationLevel = IsolationLevel.Serializable,
TransactionTimeout= "00:00:30",
InstanceContextMode = InstanceContextMode.PerSession,
TransactionAutoCompleteOnSessionClose = true)]
public class OrderService :IOrderService
{
private List<Customer> customers = null;
private List<Product> products = null;
private int orderId = 0;
private string conString = Properties.Settings.Default.TransactionsConnectionString;
public List<Customer> GetCustomers()
{
customers = new List<Customer>();
using (var cnn = new SqlConnection(conString))
{
using (var cmd = new SqlCommand("SELECT * " + "FROM Customers ORDER BY CustomerId", cnn))
{
cnn.Open();
using (SqlDataReader CustomersReader = cmd.ExecuteReader())
{
while (CustomersReader.Read())
{
var customer = new Customer();
customer.CustomerId = CustomersReader.GetInt32(0);
customer.CompanyName = CustomersReader.GetString(1);
customer.Balance = CustomersReader.GetDecimal(2);
customers.Add(customer);
}
}
}
}
return customers;
}
public List<Product> GetProducts()
{
products = new List<Product>();
using (var cnn = new SqlConnection(conString))
{
using (var cmd = new SqlCommand(
"SELECT * " +
"FROM Products ORDER BY ProductId", cnn))
{
cnn.Open();
using (SqlDataReader productsReader =
cmd.ExecuteReader())
{
while (productsReader.Read())
{
var product = new Product();
product.ProductId = productsReader.GetInt32(0);
product.ProductName = productsReader.GetString(1);
product.Price = productsReader.GetDecimal(2);
product.OnHand = productsReader.GetInt16(3);
products.Add(product);
}
}
}
}
return products;
}
// 設置服務的環境事務
// 使用Client模式,即使用客戶端的事務
[OperationBehavior(TransactionScopeRequired =true, TransactionAutoComplete = false)]
public string PlaceOrder(Order order)
{
using (var conn = new SqlConnection(conString))
{
var cmd = new SqlCommand(
"Insert Orders (CustomerId, ProductId, " +
"Quantity, Price, Amount) " + "Values( " +
"@customerId, @productId, @quantity, " +
"@price, @amount)", conn);
cmd.Parameters.Add(new SqlParameter(
"@customerId", order.CustomerId));
cmd.Parameters.Add(new SqlParameter(
"@productid", order.ProductId));
cmd.Parameters.Add(new SqlParameter(
"@price", order.Price));
cmd.Parameters.Add(new SqlParameter(
"@quantity", order.Quantity));
cmd.Parameters.Add(new SqlParameter(
"@amount", order.Amount));
try
{
conn.Open();
if (cmd.ExecuteNonQuery() <= 0)
{
return "The order was not placed";
}
cmd = new SqlCommand(
"Select Max(OrderId) From Orders " +
"Where CustomerId = @customerId", conn);
cmd.Parameters.Add(new SqlParameter(
"@customerId", order.CustomerId));
using (SqlDataReader reader = cmd.ExecuteReader())
{
while (reader.Read())
{
orderId = Convert.ToInt32(reader[0].ToString());
}
}
return string.Format("Order {0} was placed", orderId);
}
catch (Exception ex)
{
throw new FaultException(ex.Message);
}
}
}
// 使用Client模式,即使用客戶端的事務
[OperationBehavior(TransactionScopeRequired = true, TransactionAutoComplete = false)]
public string AdjustInventory(int productId, int quantity)
{
using (var conn = new SqlConnection(conString))
{
var cmd = new SqlCommand(
"Update Products Set OnHand = " +
"OnHand - @quantity " +
"Where ProductId = @productId", conn);
cmd.Parameters.Add(new SqlParameter(
"@quantity", quantity));
cmd.Parameters.Add(new SqlParameter(
"@productid", productId));
try
{
conn.Open();
if (cmd.ExecuteNonQuery() <= 0)
{
return "The inventory was not updated";
}
else
{
return "The inventory was updated";
}
}
catch (Exception ex)
{
throw new FaultException(ex.Message);
}
}
}
// 使用Client模式,即使用客戶端的事務
[OperationBehavior(TransactionScopeRequired = true, TransactionAutoComplete = false)]
public string AdjustBalance(int customerId, decimal amount)
{
using (var conn = new SqlConnection(conString))
{
var cmd = new SqlCommand(
"Update Customers Set Balance = " +
"Balance - @amount " +
"Where CustomerId = @customerId", conn);
cmd.Parameters.Add(new SqlParameter(
"@amount", amount));
cmd.Parameters.Add(new SqlParameter(
"@customerId", customerId));
try
{
conn.Open();
if (cmd.ExecuteNonQuery() <= 0)
{
return "The balance was not updated";
}
else
{
return "The balance was updated";
}
}
catch (Exception ex)
{
throw new FaultException(ex.Message);
}
}
}
}
}
```
上面的服務契約和服務實現與傳統的實現沒什么區別。這里使用IIS來宿主WCF服務。
第二步:宿主的實現。創建一個空的Web的項目,并添加WCF服務文件,具體內容如下所示:
對應的Web.config的內容如下所示:
```
<configuration>
<system.web>
<compilation debug="true" targetFramework="4.5" />
<httpRuntime targetFramework="4.5" />
</system.web>
<system.serviceModel>
<behaviors>
<serviceBehaviors>
<behavior name="OrderServiceBehavior">
<serviceMetadata httpGetEnabled="true" httpsGetEnabled="true" />
<serviceDebug includeExceptionDetailInFaults="false" />
</behavior>
</serviceBehaviors>
</behaviors>
<bindings>
<wsHttpBinding>
<!--通過設置transactionFlow屬性為true來使綁定支持事務傳播;對于wsHttpBinding契約事務傳播-->
<binding name="wsHttpBinding" transactionFlow="true">
<!--啟用消息可靠性選項-->
<!--<reliableSession enabled="true"/>-->
</binding>
</wsHttpBinding>
</bindings>
<services>
<service name="WCFContractAndService.OrderService" behaviorConfiguration="OrderServiceBehavior">
<endpoint address="" binding="wsHttpBinding" bindingConfiguration="wsHttpBinding" contract="WCFContractAndService.IOrderService"/>
</service>
</services>
<serviceHostingEnvironment aspNetCompatibilityEnabled="true"
multipleSiteBindingsEnabled="true" />
</system.serviceModel>
</configuration>
```
這里采用了wsHttpBinding綁定,并設置其transactionFlow屬性為true使其支持事務傳播。接下來看看客戶端的實現。
第三步:WCF客戶端的實現,通過添加服務引用的方式來生成代理類。這里的客戶端是WinForm程序。
```
1 public partial class Form1 : Form
2 {
3 public Form1()
4 {
5 InitializeComponent();
6 }
7
8 private Customer customer = null;
9 private List<Customer> customers = null;
10 private Product product = null;
11 private List<Product> products = null;
12 private OrderServiceClient proxy = null;
13 private Order order = null;
14 private string result = String.Empty;
15
16 private void Form1_Load(object sender, EventArgs e)
17 {
18 proxy = new OrderServiceClient("WSHttpBinding_IOrderService");
19 GetCustomersAndProducts();
20 }
21
22 private void GetCustomersAndProducts()
23 {
24 customers = proxy.GetCustomers().ToList<Customer>();
25 customerBindingSource.DataSource = customers;
26
27 products = proxy.GetProducts().ToList<Product>();
28 productBindingSource.DataSource = products;
29 }
30
31 private void placeOrderButton_Click(object sender, EventArgs e)
32 {
33 customer = (Customer)this.customerBindingSource.Current;
34 product = (Product)this.productBindingSource.Current;
35 Int32 quantity = Convert.ToInt32(quantityTextBox.Text);
36
37 order = new Order();
38 order.CustomerId = customer.CustomerId;
39 order.ProductId = product.ProductId;
40 order.Price = product.Price;
41 order.Quantity = quantity;
42 order.Amount = order.Price * Convert.ToDecimal(order.Quantity);
43
44 // 事務處理
45 using (var tranScope = new TransactionScope())
46 {
47 proxy = new OrderServiceClient("WSHttpBinding_IOrderService");
48 {
49 try
50 {
51 result = proxy.PlaceOrder(order);
52 MessageBox.Show(result);
53
54 result = proxy.AdjustInventory(product.ProductId, quantity);
55 MessageBox.Show(result);
56
57 result = proxy.AdjustBalance(customer.CustomerId,
58 Convert.ToDecimal(quantity) * order.Price);
59 MessageBox.Show(result);
60
61 proxy.Close();
62 tranScope.Complete(); // Cmmmit transaction
63 }
64 catch (FaultException faultEx)
65 {
66 MessageBox.Show(faultEx.Message +
67 "\n\nThe order was not placed");
68
69 }
70 catch (ProtocolException protocolEx)
71 {
72 MessageBox.Show(protocolEx.Message +
73 "\n\nThe order was not placed");
74 }
75 }
76 }
77
78 // 成功提交后強制刷新界面
79 quantityTextBox.Clear();
80 try
81 {
82 proxy = new OrderServiceClient("WSHttpBinding_IOrderService");
83 GetCustomersAndProducts();
84 }
85 catch (FaultException faultEx)
86 {
87 MessageBox.Show(faultEx.Message);
88 }
89 }
90 }
```
從上面代碼可以看出,WCF事務的實現是利用[TransactionScope](http://msdn.microsoft.com/zh-cn/library/system.transactions.transactionscope(v=vs.110).aspx)事務類來完成的。下面讓我們看看程序的運行結果。在運行程序之前,我們必須運行SQL腳本來創建程序中的使用的數據庫,具體的腳本如下所示:
```
1 USE [TransactionsDemo]
2 GO
3 /****** Object: Table [dbo].[Customers] Script Date: 01/15/2009 08:14:25 ******/
4 SET ANSI_NULLS ON
5 GO
6 SET QUOTED_IDENTIFIER ON
7 GO
8 CREATE TABLE [dbo].[Customers](
9 [CustomerId] [int] IDENTITY(1,1) NOT NULL,
10 [Name] [nvarchar](20) NOT NULL,
11 [Balance] [smallmoney] NOT NULL, check(Balance >= 0),
12 CONSTRAINT [PK_Customers] PRIMARY KEY CLUSTERED
13 (
14 [CustomerId] ASC
15 )WITH (PAD_INDEX = OFF, STATISTICS_NORECOMPUTE = OFF, IGNORE_DUP_KEY = OFF, ALLOW_ROW_LOCKS = ON, ALLOW_PAGE_LOCKS = ON) ON [PRIMARY]
16 ) ON [PRIMARY]
17 GO
18 /****** Object: Table [dbo].[Products] Script Date: 01/15/2009 08:14:25 ******/
19 SET ANSI_NULLS ON
20 GO
21 SET QUOTED_IDENTIFIER ON
22 GO
23 CREATE TABLE [dbo].[Products](
24 [ProductId] [int] IDENTITY(1,1) NOT NULL,
25 [Name] [nvarchar](20) NOT NULL,
26 [Price] [smallmoney] NOT NULL,
27 [OnHand] [smallint] NOT NULL, check(OnHand >= 0),
28 CONSTRAINT [PK_Products] PRIMARY KEY CLUSTERED
29 (
30 [ProductId] ASC
31 )WITH (PAD_INDEX = OFF, STATISTICS_NORECOMPUTE = OFF, IGNORE_DUP_KEY = OFF, ALLOW_ROW_LOCKS = ON, ALLOW_PAGE_LOCKS = ON) ON [PRIMARY]
32 ) ON [PRIMARY]
33 GO
34 /****** Object: Table [dbo].[Orders] Script Date: 01/15/2009 08:14:25 ******/
35 SET ANSI_NULLS ON
36 GO
37 SET QUOTED_IDENTIFIER ON
38 GO
39 CREATE TABLE [dbo].[Orders](
40 [OrderId] [int] IDENTITY(1,1) NOT NULL,
41 [CustomerId] [int] NOT NULL,
42 [ProductId] [int] NOT NULL,
43 [Quantity] [smallint] NOT NULL,
44 [Price] [smallmoney] NOT NULL,
45 [Amount] [smallmoney] NOT NULL,
46 CONSTRAINT [PK_Orders] PRIMARY KEY CLUSTERED
47 (
48 [OrderId] ASC
49 )WITH (PAD_INDEX = OFF, STATISTICS_NORECOMPUTE = OFF, IGNORE_DUP_KEY = OFF, ALLOW_ROW_LOCKS = ON, ALLOW_PAGE_LOCKS = ON) ON [PRIMARY]
50 ) ON [PRIMARY]
51 GO
52 INSERT Customers (Name, Balance) VALUES ('Contoso', 10000)
53 INSERT Customers (Name, Balance) VALUES ('Northwind', 25000)
54 INSERT Customers (Name, Balance) VALUES ('Litware', 50000)
55 INSERT Products (Name, Price, OnHand) VALUES ('Wood', 100, 1000)
56 INSERT Products (Name, Price, OnHand) VALUES ('Wallboard', 200, 2500)
57 INSERT Products (Name, Price, OnHand) VALUES ('Pipe', 500, 5000)
58 GO
```
生成程序使用的數據庫之后,按F5運行WCF客戶端程序,并在出現的界面中購買Wood材料100,運行結果如下圖所示:

單擊Place order按鈕后,即執行下訂單操作,如果訂單成功后,將會更新產品的庫存和用戶的余額,你將看到如下圖所示的運行結果:

## 四、小結
到這里,關于WCF中事務的介紹就結束了。WCF支持四種事務模式,Client/Service、Client、Service和None,對于每種模式都有其不同的配置。一般盡量使用Client/Service或Client事務模式。WCF事務的實現借助于已有的System.Transaction實現本地事務的編程,而分布式事務則借助MSDTC分布式事務協調機制來實現。WCF提供了支持事務傳播的綁定協議包括:wsHttpBinding、WSDualHttpBinding、WSFederationBinding、NetTcpBinding和NetNamedPipeBinding,最后兩個綁定允許選擇WS-AT協議或OleTx協議,而其他綁定都使用標準的WS-AT協議。在一一篇博文將分享WCF對消息隊列的支持。
本文所有源代碼:[WCFTransaction.zip](http://files.cnblogs.com/zhili/WCFTransaction.zip)
- C# 基礎知識系列
- C# 基礎知識系列 專題一:深入解析委托——C#中為什么要引入委托
- C# 基礎知識系列 專題二:委托的本質論
- C# 基礎知識系列 專題三:如何用委托包裝多個方法——委托鏈
- C# 基礎知識系列 專題四:事件揭秘
- C# 基礎知識系列 專題五:當點擊按鈕時觸發Click事件背后發生的事情
- C# 基礎知識系列 專題六:泛型基礎篇——為什么引入泛型
- C# 基礎知識系列 專題七: 泛型深入理解(一)
- C# 基礎知識系列 專題八: 深入理解泛型(二)
- C# 基礎知識系列 專題九: 深入理解泛型可變性
- C#基礎知識系列 專題十:全面解析可空類型
- C# 基礎知識系列 專題十一:匿名方法解析
- C#基礎知識系列 專題十二:迭代器
- C#基礎知識 專題十三:全面解析對象集合初始化器、匿名類型和隱式類型
- C# 基礎知識系列 專題十四:深入理解Lambda表達式
- C# 基礎知識系列 專題十五:全面解析擴展方法
- C# 基礎知識系列 專題十六:Linq介紹
- C#基礎知識系列 專題十七:深入理解動態類型
- 你必須知道的異步編程 C# 5.0 新特性——Async和Await使異步編程更簡單
- 全面解析C#中參數傳遞
- C#基礎知識系列 全面解析C#中靜態與非靜態
- C# 基礎知識系列 C#中易混淆的知識點
- C#進階系列
- C#進階系列 專題一:深入解析深拷貝和淺拷貝
- C#進階系列 專題二:你知道Dictionary查找速度為什么快嗎?
- C# 開發技巧系列
- C# 開發技巧系列 使用C#操作Word和Excel程序
- C# 開發技巧系列 使用C#操作幻燈片
- C# 開發技巧系列 如何動態設置屏幕分辨率
- C# 開發技巧系列 C#如何實現圖片查看器
- C# 開發技巧 如何防止程序多次運行
- C# 開發技巧 實現屬于自己的截圖工具
- C# 開發技巧 如何使不符合要求的元素等于離它最近的一個元素
- C# 線程處理系列
- C# 線程處理系列 專題一:線程基礎
- C# 線程處理系列 專題二:線程池中的工作者線程
- C# 線程處理系列 專題三:線程池中的I/O線程
- C# 線程處理系列 專題四:線程同步
- C# 線程處理系列 專題五:線程同步——事件構造
- C# 線程處理系列 專題六:線程同步——信號量和互斥體
- C# 多線程處理系列專題七——對多線程的補充
- C#網絡編程系列
- C# 網絡編程系列 專題一:網絡協議簡介
- C# 網絡編程系列 專題二:HTTP協議詳解
- C# 網絡編程系列 專題三:自定義Web服務器
- C# 網絡編程系列 專題四:自定義Web瀏覽器
- C# 網絡編程系列 專題五:TCP編程
- C# 網絡編程系列 專題六:UDP編程
- C# 網絡編程系列 專題七:UDP編程補充——UDP廣播程序的實現
- C# 網絡編程系列 專題八:P2P編程
- C# 網絡編程系列 專題九:實現類似QQ的即時通信程序
- C# 網絡編程系列 專題十:實現簡單的郵件收發器
- C# 網絡編程系列 專題十一:實現一個基于FTP協議的程序——文件上傳下載器
- C# 網絡編程系列 專題十二:實現一個簡單的FTP服務器
- C# 互操作性入門系列
- C# 互操作性入門系列(一):C#中互操作性介紹
- C# 互操作性入門系列(二):使用平臺調用調用Win32 函數
- C# 互操作性入門系列(三):平臺調用中的數據封送處理
- C# 互操作性入門系列(四):在C# 中調用COM組件
- CLR
- 談談: String 和StringBuilder區別和選擇
- 談談:程序集加載和反射
- 利用反射獲得委托和事件以及創建委托實例和添加事件處理程序
- 談談:.Net中的序列化和反序列化
- C#設計模式
- UML類圖符號 各種關系說明以及舉例
- C#設計模式(1)——單例模式
- C#設計模式(2)——簡單工廠模式
- C#設計模式(3)——工廠方法模式
- C#設計模式(4)——抽象工廠模式
- C#設計模式(5)——建造者模式(Builder Pattern)
- C#設計模式(6)——原型模式(Prototype Pattern)
- C#設計模式(7)——適配器模式(Adapter Pattern)
- C#設計模式(8)——橋接模式(Bridge Pattern)
- C#設計模式(9)——裝飾者模式(Decorator Pattern)
- C#設計模式(10)——組合模式(Composite Pattern)
- C#設計模式(11)——外觀模式(Facade Pattern)
- C#設計模式(12)——享元模式(Flyweight Pattern)
- C#設計模式(13)——代理模式(Proxy Pattern)
- C#設計模式(14)——模板方法模式(Template Method)
- C#設計模式(15)——命令模式(Command Pattern)
- C#設計模式(16)——迭代器模式(Iterator Pattern)
- C#設計模式(17)——觀察者模式(Observer Pattern)
- C#設計模式(18)——中介者模式(Mediator Pattern)
- C#設計模式(19)——狀態者模式(State Pattern)
- C#設計模式(20)——策略者模式(Stragety Pattern)
- C#設計模式(21)——責任鏈模式
- C#設計模式(22)——訪問者模式(Vistor Pattern)
- C#設計模式(23)——備忘錄模式(Memento Pattern)
- C#設計模式總結
- WPF快速入門系列
- WPF快速入門系列(1)——WPF布局概覽
- WPF快速入門系列(2)——深入解析依賴屬性
- WPF快速入門系列(3)——深入解析WPF事件機制
- WPF快速入門系列(4)——深入解析WPF綁定
- WPF快速入門系列(5)——深入解析WPF命令
- WPF快速入門系列(6)——WPF資源和樣式
- WPF快速入門系列(7)——深入解析WPF模板
- WPF快速入門系列(8)——MVVM快速入門
- WPF快速入門系列(9)——WPF任務管理工具實現
- ASP.NET 開發
- ASP.NET 開發必備知識點(1):如何讓Asp.net網站運行在自定義的Web服務器上
- ASP.NET 開發必備知識點(2):那些年追過的ASP.NET權限管理
- ASP.NET中實現回調
- 跟我一起學WCF
- 跟我一起學WCF(1)——MSMQ消息隊列
- 跟我一起學WCF(2)——利用.NET Remoting技術開發分布式應用
- 跟我一起學WCF(3)——利用Web Services開發分布式應用
- 跟我一起學WCF(3)——利用Web Services開發分布式應用
- 跟我一起學WCF(4)——第一個WCF程序
- 跟我一起學WCF(5)——深入解析服務契約 上篇
- 跟我一起學WCF(6)——深入解析服務契約 下篇
- 跟我一起學WCF(7)——WCF數據契約與序列化詳解
- 跟我一起學WCF(8)——WCF中Session、實例管理詳解
- 跟我一起學WCF(9)——WCF回調操作的實現
- 跟我一起學WCF(10)——WCF中事務處理
- 跟我一起學WCF(11)——WCF中隊列服務詳解
- 跟我一起學WCF(12)——WCF中Rest服務入門
- 跟我一起學WCF(13)——WCF系列總結
- .NET領域驅動設計實戰系列
- .NET領域驅動設計實戰系列 專題一:前期準備之EF CodeFirst
- .NET領域驅動設計實戰系列 專題二:結合領域驅動設計的面向服務架構來搭建網上書店
- .NET領域驅動設計實戰系列 專題三:前期準備之規約模式(Specification Pattern)
- .NET領域驅動設計實戰系列 專題四:前期準備之工作單元模式(Unit Of Work)
- .NET領域驅動設計實戰系列 專題五:網上書店規約模式、工作單元模式的引入以及購物車的實現
- .NET領域驅動設計實戰系列 專題六:DDD實踐案例:網上書店訂單功能的實現
- .NET領域驅動設計實戰系列 專題七:DDD實踐案例:引入事件驅動與中間件機制來實現后臺管理功能
- .NET領域驅動設計實戰系列 專題八:DDD案例:網上書店分布式消息隊列和分布式緩存的實現
- .NET領域驅動設計實戰系列 專題九:DDD案例:網上書店AOP和站點地圖的實現
- .NET領域驅動設計實戰系列 專題十:DDD擴展內容:全面剖析CQRS模式實現
- .NET領域驅動設計實戰系列 專題十一:.NET 領域驅動設計實戰系列總結