WCF服务属性注入基础设施
WCF服务属性注入基础设施
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、启动客户端。

实验结束,测试完毕。
谢谢阅读。
WCF服务属性注入基础设施的更多相关文章
- 使用NetTcpBinding,WCF服务未能被激活
我的WCF采用的是NetTcpBinding,使用时就会报错,换成BasicHttpBinding,就一切正常 The requested service, 'net.tcp://wcf.xxxxx. ...
- autofac 注入普通服务和WCF服务
using Autofac;using Autofac.Builder;using Autofac.Core; //实现Autofac扩展 public static AutofacRegisterW ...
- WCF服务中,[DataMember]属性标记的属性一定要有set访问器
WCF服务中,如果实体类中,包含有[DataMember]属性标记时,该属性一定要有set访问器.当系统必须调用到[DataMember]标记的属性时,如果该属性没有set访问器,则会出错.
- net core天马行空系列: 一个接口多个实现类,利用mixin技术通过自定义服务名,实现精准属性注入
系列目录 1.net core天马行空系列:原生DI+AOP实现spring boot注解式编程 2.net core天马行空系列: 泛型仓储和声明式事物实现最优雅的crud操作 哈哈哈哈,大家好,我 ...
- Entity Framework 6 Recipes 2nd Edition(9-7)译->在WCF服务中序列化代理
9-7. 在WCF服务中序列化代理 问题 从一个查询里返回一个动态代理对象,想要把它序列为一个POCO(Plain-Old CLR Objects)对象. 实现基于POCO实体对象, 在运行时,EF会 ...
- WCF服务编程 读书笔记——第1章 WCF基础(1)
第1章 WCF基础 本章主要介绍WCF的基本概念.构建模块以及WCF体系架构,以指导读者构建一个简单的WCF服务.从本章的内容中,我们可以了解到WCF的基本术语,包括地址(Address).绑定(Bi ...
- 翻译:使用 CoreWCF 升级 WCF 服务到 .NET 6
翻译:使用 CoreWCF 升级 WCF 服务到 .NET 6 原文地址:https://devblogs.microsoft.com/dotnet/upgrading-a-wcf-service-t ...
- Autofac - 属性注入
属性注入不同于通过构造函数方式传入参数. 这里是通过注入的方式, 在类创建完毕之后, 资源释放之前, 给属性赋值. 这里, 我重新弄一些类来演示这一篇吧. public class ClassA { ...
- WCF学习之旅—WCF服务部署到IIS7.5(九)
上接 WCF学习之旅—WCF寄宿前的准备(八) 四.WCF服务部署到IIS7.5 我们把WCF寄宿在IIS之上,在IIS中宿主一个服务的主要优点是在发生客户端请求时宿主进程会被自动启动,并且你可以 ...
随机推荐
- canvas绘制贝塞尔曲线
原文:canvas绘制贝塞尔曲线 1.绘制二次方贝塞尔曲线 quadraticCurveTo(cp1x,cp1y,x,y); 其中参数cp1x和cp1y是控制点的坐标,x和y是终点坐标 数学公式表示如 ...
- InstallShield集成安装MSDE2000最小版本(一) fishout特许授权发布
原文:InstallShield集成安装MSDE2000最小版本(一) fishout特许授权发布 原帖地址:http://blog.csdn.net/fishout/archive/2009/10/ ...
- PDF解决方案(2)--文件转PDF
相关专题链接: PDF解决方案(1)--文件上传 PDF解决方案(2)--文件转PDF PDF解决方案(3)--PDF转SWF PDF解决方案(4)--在线浏览 前言:上一篇中讲到的文件上传,文件上传 ...
- ECharts图表系统 特性总览
最近在玩ECharts,感觉真心不错,在这里把官方的资料收集收集,给大家推荐一下下~ Architecture ECharts (Enterprise Charts 商业产品图表库) 提供商业产品常用 ...
- 手机发送短信JS验证
function tj() { var phone = jQuery('#phone').val(); var code = jQuery('#verificationcode').val(); va ...
- Linux Shell脚本入门--awk命令详解
简单使用: awk :对于文件中一行行的独处来执行操作 . awk -F :'{print $1,$4}' :使用‘:’来分割这一行,把这一行的第一第四个域打印出来 . 详细介绍: AWK命令介绍 ...
- 远程连接mysql速度慢的解决方法
最近在公司内部连mysql速度非常慢,一直还以为公司的网络有问题,后经查发现出现这种问题的主要原因是mysql默认开启了DNS的反向解析功能,连接时反向解析计算机名称时耗时严重,导致连接超慢.解决方法 ...
- sql 进制转换,支持93内的进制相互转换
功能:实现在SQL内进制的互相转换,支持从2 - 93进制内的转换,若需要支持其他字符,可以自定义@ym变量实现扩充 -- ====================================== ...
- 【值得收藏】Mathematica数值计算工具的学习资料汇编【可免费下载】
Mathematica学习教程 Mathematica是一款科学计算软件,很好地结合了数值和符号计算引擎.图形系统.编程语言.文本系统.和与其他应用程序的高级连接.Mathematica与Matlab ...
- 【推荐】30个Matlab视频教程合集(含GUI视频教程)下载
自己收集别人网盘上存的资源,分享一下[点击文件名可得到下载地址] Matlab 7.8 基础视频教程 实例1 数据传递和多窗口编程_avi.zip 205.11 MB Matlab ...