這篇文章,通過一個簡單的WCF交互,講解一下WF4.0中一組重要活動:Messaging,它包括:Receive、ReceiveAndSendReply、Send、 SendAndReceiveReply。這裡將詳細講解ReceiveAndSendReply和SendAndReceiveReply兩個活動的配置以及使用,以及它與普通的WCF的區別 。
如果你了解WCF,你一定知道WCF可以縮略為ABC。A :Address (服務在哪裡?),B: Binding (怎麼才能訪問服務?),C: Contract (提供了哪些服務?)。既然同樣也是WCF服務,WF4.0中WCF服務同樣也存在ABC的概念。我將一步一步通過實現WF中的wcf服務的 ABC來實現這個Demo,請你注意它與普通的WCF的區別。
首先,我們定義一下用於數據交換的實體。
定義Request消息ReservationRequest
代碼
1 [MessageContract(IsWrapped = false)]
2 public class ReservationRequest
3 {
4 private String _ISBN;
5 private String _Title;
6 private String _Author;
7 private Guid _RequestID;
8 private Branch _Requester;
9 private Guid _InstanceID;
10
11 #region Constructors
12 public ReservationRequest()
13 {
14 }
15
16 public ReservationRequest(String title, String author, String isbn,
17 Branch requestor)
18 {
19 _Title = title;
20 _Author = author;
21 _ISBN = isbn;
22 _Requester = requestor;
23 _RequestID = Guid.NewGuid();
24 }
25
26 public ReservationRequest(String title, String author, String isbn,
27 Branch requestor, Guid id)
28 {
29 _Title = title;
30 _Author = author;
31 _ISBN = isbn;
32 _Requester = requestor;
33 _RequestID = id;
34 }
35 #endregion Constructors
36
37 #region Public Properties
38 [MessageBodyMember]
39 public String Title
40 {
41 get { return _Title; }
42 set { _Title = value; }
43 }
44
45 [MessageBodyMember]
46 public String ISBN
47 {
48 get { return _ISBN; }
49 set { _ISBN = value; }
50 }
51
52 [MessageBodyMember]
53 public String Author
54 {
55 get { return _Author; }
56 set { _Author = value; }
57 }
58
59 [MessageBodyMember]
60 public Guid RequestID
61 {
62 get { return _RequestID; }
63 set { _RequestID = value; }
64 }
65
66 [MessageBodyMember]
67 public Branch Requester
68 {
69 get { return _Requester; }
70 set { _Requester = value; }
71 }
72
73 [MessageBodyMember]
74 public Guid InstanceID
75 {
76 get { return _InstanceID; }
77 set { _InstanceID = value; }
78 }
79 #endregion Public Properties
80 }
定義Response消息ReservationResponse:
代碼
1 [MessageContract(IsWrapped = false)]
2 public class ReservationResponse
3 {
4 private bool _Reserved;
5 private Branch _Provider;
6 private Guid _RequestID;
7
8 #region Constructors
9 public ReservationResponse()
10 {
11 }
12
13 public ReservationResponse(ReservationRequest request, bool reserved,
14 Branch provider)
15 {
16 _RequestID = request.RequestID;
17 _Reserved = reserved;
18 _Provider = provider;
19 }
20 #endregion Constructors
21
22 #region Public Properties
23 [MessageBodyMember]
24 public bool Reserved
25 {
26 get { return _Reserved; }
27 set { _Reserved = value; }
28 }
29
30 [MessageBodyMember]
31 public Branch Provider
32 {
33 get { return _Provider; }
34 set { _Provider = value; }
35 }
36
37 [MessageBodyMember]
38 public Guid RequestID
39 {
40 get { return _RequestID; }
41 set { _RequestID = value; }
42 }
43 #endregion Public Properties
44 }
服務端的實現
一、C(Contract )
定義這個服務具體提供了哪些服務:
1 [ServiceContract]
2 public interface ILibraryReservation
3 {
4 [OperationContract]
5 void RequestBook(ReservationRequest request);
6
7 [OperationContract]
8 void RespondToRequest(ReservationResponse response);
9 }
這裡定義了兩個方法:RequestBook、RespondToRequest。在普通的WCF中,一般做法是:通過一個類繼承這個接口。在類中實現wcf的具 體內容。而在WF4.0中,這裡我將使用Messaging中的活動:ReceiveAndSendReply。
1、新建一個控制台應用程序WF3Demo:
注意:這裡創建的是Console Application。而不是WorkflowConsoleApplication。
2、添加下面這些引用:
System.Activities.dll
System.ServiceModel.dll
System.ServiceModel.Activities.dll
3、創建一個自定義活動CreateResponse,它用於創建返回給客戶端的ReservationResponse對象,代碼如下:
1 //這種是一個自定義的活動,用於創建一個ReservationResponse對象
2 public sealed class CreateResponse : CodeActivity
3 {
4 public InArgument<ReservationRequest> Request { get; set; }
5 public InArgument<bool> Reserved { get; set; }
6 public OutArgument<ReservationResponse> Response { get; set; }
7
8 protected override void Execute(CodeActivityContext context)
9 {
10 // 打開配 置文件
11 Configuration config = ConfigurationManager
12 .OpenExeConfiguration(ConfigurationUserLevel.None);
13 AppSettingsSection app =
14 (AppSettingsSection)config.GetSection("appSettings");
15
16 // 創建ReservationResponse對象
17 ReservationResponse r = new ReservationResponse
18 (
19 Request.Get(context),
20 Reserved.Get(context),
21 new Branch
22 {
23 BranchName = app.Settings["Branch Name"].Value,
24 BranchID = new Guid (app.Settings["ID"].Value),
25 Address = app.Settings ["Address"].Value
26 }
27 );
28 // 將Response保存到OutArgument
29 Response.Set(context, r);
30 }
31 }
5、添加一個名字為ProcessRequest工作流,在其中拖放一個ReceiveAndSendReply。
在ProcessRequest添加如下變量:
設置Receive活動:
OperationName:RequestBook
Content: 設置Message data為request、設置Message type為ReservationRequest
ServiceContractName:ILibraryReservation
ILibraryReservation:true
設置SendReply
Content: 設置Message data為response、設置Message type 為ReservationResponse,如下圖:
6、為了更好的诠釋服務,在Receive活動和SendReply活動之間加入如下圖活動,詳細見代碼。
這樣我們定義好了 Contract
二、B(Binding)和A(Address )
C實現之後,Binding和Address就簡單了。這裡Binding使用BasicHttpBinding,使用如下代碼實現B和A:
1 WorkflowService service = new WorkflowService
2 {
3 Name = "LibraryReservation",
4 Body = new ProcessRequest(),
5 Endpoints =
6 {
7 new Endpoint
8 {
9 ServiceContractName="ILibraryReservation",
10 AddressUri = new Uri("http://localhost:" + adr +
11 "/LibraryReservation"),
12 Binding = new BasicHttpBinding (),
13 }
14 }
15 };
16
17 System.ServiceModel.Activities.WorkflowServiceHost wsh =
18 new System.ServiceModel.Activities.WorkflowServiceHost(service);
19
20 wsh.Open();
至此,WF4中的wcf服務就這樣簡單的配置好了。
客戶端調用:
對於調用一般的WCF,可以通過添加service引用或者通過命令自動生成調用wcf的代碼。這與WF4.0不同,這裡我使用 SendAndReceiveReply活動來調用WCF服務。
1、首先自定義一個活動CreateRequest,用於創建一個提交wcf服務ReservationRequest對象。
1 public sealed class CreateRequest : CodeActivity
2 {
3 public InArgument<string> Title { get; set; }
4 public InArgument<string> Author { get; set; }
5 public InArgument<string> ISBN { get; set; }
6 public OutArgument<ReservationRequest> Request { get; set; }
7 public OutArgument<string> RequestAddress { get; set; }
8
9 protected override void Execute(CodeActivityContext context)
10 {
11 // 打開配置文件,得到請求的地址
12 Configuration config = ConfigurationManager
13 .OpenExeConfiguration (ConfigurationUserLevel.None);
14 AppSettingsSection app =
15 (AppSettingsSection)config.GetSection("appSettings");
16
17 // 使用輸入參數創建一個 ReservationRequest對象
18 ReservationRequest r = new ReservationRequest
19 (
20 Title.Get(context),
21 Author.Get(context),
22 ISBN.Get(context),
23 new Branch
24 {
25 BranchName = app.Settings["Branch Name"].Value,
26 BranchID = new Guid(app.Settings["ID"].Value),
27 Address = app.Settings["Address"].Value
28 }
29 );
30
31 //將request保存到OutArgument中
32 Request.Set (context, r);
33
34 // 將address保存到OutArgument
35 RequestAddress.Set(context, app.Settings["Request Address"].Value);
36 }
37 }
2、添加一個名字為SendRequest的工作流,在其中拖放一個SendAndReceiveReply活動,以及一個CreateRequest活動,將CreateRequest 活動拖放到Send前面。
3、在ProcessRequest添加如下變量:
在ProcessRequest添加如下參數:
4、設置Send:
OperationName:RequestBook
Content: 設置Message data為request、設置Message type為ReservationRequest
ServiceContractName:ILibraryReservation
Endpoint:Endpoint
Endpoint.Binding:BasicHttpBinding
EndpointAddress:New Uri("http://localhost/:" + requestAddress + "/LibraryReservation")
5、設置ReceiveReplyForSend
將ReceiveReplyForSend的Content的Message data設為response,將ReceiveReplyForSend的Content的Message type設為 ReservationResponse
6、為了便於觀察,添加幾個WriteLine用於輸出,如下圖,詳見代碼:
這樣設置好了客戶端。
使用wcf服務:
我們只需啟動ProcessRequest這個工作流來調用wcf服務:
1 IDictionary<string, object> input = new Dictionary<string, object>
2 {
3 { "Title" , "Gone with the Wind" },
4 { "Author", "Margaret Mitchell" },
5 { "ISBN", "9781416548898" }
6 };
7
8 IDictionary<string, object> output =
9 WorkflowInvoker.Invoke(new SendRequest(), input);
10 ReservationResponse resp = (ReservationResponse)output["Response"];
運行程序:
啟動WCF服務。等待客戶端的調用,如下圖:
輸入回車,啟動客戶端的工作流,來調用WCF服務,輸入結果如下:
整個運行的過程
如下圖:
總結:
這篇文章講述了在WF4.0中使用WCF服務。WF中的WCF與普通的WCF,在原理上是一致的,但是在形式上區別很大。WF4.0中提供了一組活動 ,這樣比直接使用WCF更加簡單和直觀。
本文配套源碼