WCF的服务的创建行为:使用默认构造函数创建WCF服务对象。如果我们想要在WCF内使用外部对象,最简单的方式就是把外部对象做成全局对象。然而这样的话会增加全局对象的数量,让代码的耦合度增加了。所以,我们需要突破WCF的默认行为。解决的办法是添加自定义的ServiceHost子类。
首先,添加一个IWCFService泛型接口,WCF服务将继承这个接口,从而拥有外部注入泛型属性的能力。
public
interface
IWCFService<TDependency>
{
TDependency Dependency {
get
;
set
; }
}
|
其次,我们需要自定义ServiceHost子类,提供外部注入Dependency的构造函数。
public
class
WCFServiceHost<Service, TDependency> : ServiceHost
where Service : IWCFService<TDependency>,
new
()
{
public
WCFServiceHost(TDependency dependency, Type serviceType,
params
Uri[] baseAddresses)
:
base
(serviceType, baseAddresses)
{
if
(dependency ==
null
) {
throw
new
ArgumentNullException(
"dependency"
);
}
foreach
(var cd
in
ImplementedContracts.Values) {
cd.Behaviors.Add(
new
WCFInstanceProvider<Service, TDependency>(dependency));
}
}
}
|
内部用到了WCFInstanceProvider,意味着,我们必须提供自己的InstanceProvider,实现如下:
public
class
WCFInstanceProvider<Service, TDependency> : IInstanceProvider, IContractBehavior
where Service : IWCFService<TDependency>,
new
()
{
private
readonly
TDependency _dependency;
public
WCFInstanceProvider(TDependency dependency)
{
if
(dependency ==
null
) {
throw
new
ArgumentNullException(
"dependency"
);
}
_dependency = dependency;
}
#region IInstanceProvider Members
public
object
GetInstance(InstanceContext instanceContext, Message message)
{
return
GetInstance(instanceContext);
}
public
object
GetInstance(InstanceContext instanceContext)
{
return
new
Service { Dependency = _dependency };
}
public
void
ReleaseInstance(InstanceContext instanceContext,
object
instance)
{
}
#endregion
#region IContractBehavior Members
public
void
AddBindingParameters(ContractDescription contractDescription, ServiceEndpoint endpoint, BindingParameterCollection bindingParameters)
{
}
public
void
ApplyClientBehavior(ContractDescription contractDescription, ServiceEndpoint endpoint, ClientRuntime clientRuntime)
{
}
public
void
ApplyDispatchBehavior(ContractDescription contractDescription, ServiceEndpoint endpoint, DispatchRuntime dispatchRuntime)
{
dispatchRuntime.InstanceProvider =
this
;
}
public
void
Validate(ContractDescription contractDescription, ServiceEndpoint endpoint)
{
}
#endregion
}
|
这样,我们就差不多完成了自定义ServiceHost的定制,紧接着我们提供一个WCF服务启动关闭的基类,简化WCF服务开启和关闭的行为。
public
abstract
class
WCFServiceBase<IChannel, Channel,TDependency> : IDisposable
where Channel:IWCFService<TDependency>,
new
()
{
private
readonly
System.Threading.AutoResetEvent _waitor =
new
System.Threading.AutoResetEvent(
false
);
private
readonly
object
_locker =
new
object
();
private
bool
_isOpen;
protected
abstract
string
Url {
get
; }
protected
abstract
TDependency Dependency {
get
; }
public
bool
IsOpen
{
get
{
lock
(_locker) {
return
_isOpen;
}
}
private
set
{
lock
(_locker) {
_isOpen = value;
}
}
}
public
void
Open()
{
System.Threading.ThreadPool.QueueUserWorkItem(o => {
var namePipeAddress =
new
Uri(Url);
var serverType =
typeof
(Channel);
using
(var host =
new
WCFServiceHost<Channel,TDependency>(Dependency,serverType, namePipeAddress)) {
var serverInterfaceType =
typeof
(IChannel);
var namePipeBiding =
new
NetNamedPipeBinding();
host.AddServiceEndpoint(serverInterfaceType, namePipeBiding,
""
);
host.Open();
IsOpen =
true
;
OnOpen();
_waitor.WaitOne();
host.Close();
IsOpen =
false
;
}
});
}
public
void
Close()
{
Dispose();
}
protected
virtual
void
OnOpen()
{
}
#region IDisposeable
private
bool
disposed;
~WCFServiceBase()
{
Dispose(
false
);
}
public
void
Dispose()
{
Dispose(
true
);
GC.SuppressFinalize(
this
);
}
private
void
Dispose(
bool
disposing)
{
if
(disposed) {
return
;
}
if
(disposing) {
// 清理托管资源
}
// 清理非托管资源
_waitor.Set();
disposed =
true
;
}
#endregion IDisposeable
}
|
既然,提供了WCFServiceBase,我们当然应该提供一个WCFClientBase,方便WCF客户端代码的编写。
public
abstract
class
WCFClientBase<IChannel>
{
protected
abstract
string
Url {
get
; }
protected
void
Query(Action<IChannel> query, Action<Exception> error =
null
)
{
if
(query ==
null
)
return
;
System.Threading.ThreadPool.QueueUserWorkItem(o => {
try
{
var namePipeBiding =
new
NetNamedPipeBinding();
var namePipeAddress =
new
EndpointAddress(Url);
using
(var client =
new
ChannelFactory<IChannel>(namePipeBiding, namePipeAddress)) {
var updatorChannel = client.CreateChannel();
query(updatorChannel);
}
}
catch
(Exception e) {
if
(error !=
null
) error(e);
}
});
}
protected
void
Query(Action<IChannel> query,Action @
finally
,Action<Exception> error=
null
)
{
if
(query ==
null
)
return
;
System.Threading.ThreadPool.QueueUserWorkItem(o => {
try
{
var namePipeBiding=
new
NetNamedPipeBinding();
var namePipeAddress=
new
EndpointAddress(Url);
using
(var client=
new
ChannelFactory<IChannel>(namePipeBiding,namePipeAddress)){
var updatorChannel=client.CreateChannel();
query(updatorChannel);
}
}
catch
(Exception e){
if
(error!=
null
) error(e);
}
finally
{
if
(@
finally
!=
null
) @
finally
();
}
});
}
protected
void
QuerySync(Action<IChannel> query, Action<Exception> error =
null
)
{
if
(query ==
null
)
return
;
try
{
var namePipeBiding =
new
NetNamedPipeBinding();
var namePipeAddress =
new
EndpointAddress(Url);
using
(var client =
new
ChannelFactory<IChannel>(namePipeBiding, namePipeAddress)) {
var updatorChannel = client.CreateChannel();
query(updatorChannel);
}
}
catch
(Exception e) {
if
(error !=
null
) error(e);
}
}
protected
void
QuerySync(Action<IChannel> query, Action @
finally
, Action<Exception> error =
null
)
{
if
(query ==
null
)
return
;
try
{
var namePipeBiding =
new
NetNamedPipeBinding();
var namePipeAddress =
new
EndpointAddress(Url);
using
(var client =
new
ChannelFactory<IChannel>(namePipeBiding, namePipeAddress)) {
var updatorChannel = client.CreateChannel();
query(updatorChannel);
}
}
catch
(Exception e) {
if
(error !=
null
) error(e);
}
finally
{
if
(@
finally
!=
null
) @
finally
();
}
}
}
|
以上,就是所有基础设施的构建。但是,我们的目标是用上述基础设施代码简化WCF服务和客户代码的开发。我们以提供一个WCF计算服务为例说明如何使用上述基础设施。首先是WCF接口代码:
[ServiceContract(Namespace =
"LambdaClient"
)]
public
interface
ILambdaChannel
{
[OperationContract]
int
Add(
int
i,
int
j);
}
|
很简单,只是一个Add服务API。我们来实现服务端代码:
public
class
LambdaChannel:ILambdaChannel,IWCFService<LambdaProvider>
{
public
int
Add(
int
i,
int
j)
{
return
Dependency.Add(i, j);
}
public
LambdaProvider Dependency {
get
;
set
; }
}
public
class
LambdaProvider
{
public
Func<
int
,
int
,
int
> Add;
}
public
class
LambdaChannelService:WCFServiceBase<ILambdaChannel,LambdaChannel,LambdaProvider>
{
protected
override
string
Url
{
}
protected
override
LambdaProvider Dependency
{
get
{
return
new
LambdaProvider{
Add = (i, j) => i + j
};
}
}
}
class
Program
{
static
void
Main(
string
[] args)
{
var lambdaService =
new
LambdaChannelService();
lambdaService.Open();
Console.WriteLine(
"Lambda计算服务已开启。"
);
Console.Read();
}
}
|
最后,在客户端使用上述WCF计算服务:
public
class
LambdaChannelClient:WCFClientBase<ILambdaChannel>
{
protected
override
string
Url
{
}
public
int
Add(
int
i,
int
j)
{
int
result = 0;
QuerySync(channel => result=channel.Add(i, j));
return
result;
}
}
class
Program
{
static
void
Main(
string
[] args)
{
var lambdaChannelClient =
new
LambdaChannelClient();
var result =lambdaChannelClient.Add(2, 3);
Console.WriteLine(
"{0}+{1}={2}"
,2,3,result);
Console.Read();
}
}
|
实际跑一下,测试下我们的成果。
1、启动服务端。
2、启动客户端。
实验结束,测试完毕。
谢谢阅读。