这篇文章,通过一个简单的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更加简单和直观。
欢迎加入博客园WF4.0技术交流群:51262864
下载1:XMAL工作流代码
下载2:CS工作流代码下载
作者:朱祁林
出处:http://zhuqil.cnblogs.com
本文版权归作者和博客园共有,欢迎转载,但未经作者同意必须保留此段声明,且在文章页面明显位置给出原文连接,否则保留追究法律责任的权利。