自定义WCF的配置文件
WCF的承载既可以通过编码实现,也能够通过配置实现.而且使用配置,更有利于日后的维护和扩展。我们经常会碰到这样的一个场景:需要把WCF的配置信息放在一个单独的文件中,这种情况经常出现在需要为自己开发的服务配置,需要采用独立的配置文件,而不是只能放到app.config/web.config中。.NET提供了一种机制是通过ConfigSource。例如在asp.net的在站点的默认 Web.Config 文件中使用:
<appSettings configSource="customAppSetting.config"/>
然后新建 customAppSetting.Config 文件:
<?xml version="1.0" encoding="utf-8"?>
<appSettings>
<add key="IsDev" value="True"/>
</appSettings>
在网站运行时,如果修改 Web.Config 文件会引起站点的重启,而修改 My.Config 文件则不会,同时也提高了配置文件的可读性。
然而WCF的配置上configSource是无效的,那么WCF如何自定义配置文件?
WCF的ServiceHost和ChannelFactory<T>分别提供了服务端和客户端的可扩展解决方案。下面针对这两个对象分别说明如何自定义服务端和客户端的配置文件。
1、服务端自定义配置文件:在ServiceHost的父类ServiceHostBase中,有一个和配置文件的加载密切相关的方法,它为:
protected virtual void ApplyConfiguration();
这个方法用于将应用程序配置文件中<system.serviceModel>节点下的配置信息,转换成WCF的具体服务设置。那么重写这个方法,代码如下:
/// <summary>
/// override ApplyConfiguration to load config from custom file
/// </summary>
protected override void ApplyConfiguration()
{
//get custom config file name by our rule: config file name = ServiceType.Name
var myConfigFileName = this.Description.ServiceType.FullName;
//get config file path
string dir = System.AppDomain.CurrentDomain.SetupInformation.ApplicationBase;
string myConfigFilePath = System.IO.Path.Combine(dir, myConfigFileName + ".config");
if (!System.IO.File.Exists(myConfigFilePath))
{
base.ApplyConfiguration();
return;
}
var configFileMap = new System.Configuration.ExeConfigurationFileMap();
configFileMap.ExeConfigFilename = myConfigFilePath;
var config = System.Configuration.ConfigurationManager.OpenMappedExeConfiguration(configFileMap, ConfigurationUserLevel.None);
var serviceModel = System.ServiceModel.Configuration.ServiceModelSectionGroup.GetSectionGroup(config);
if (serviceModel == null)
{
base.ApplyConfiguration();
return;
}
foreach (ServiceElement serviceElement in serviceModel.Services.Services)
{
if (serviceElement.Name == this.Description.ServiceType.FullName)
{
LoadConfigurationSection(serviceElement);
return;
}
}
throw new Exception("there is no service element match the description!");
}
}
}
2、WCF的客户端自定义配置文件,WCF可以通过两种方式构建代理,ClientBase<T>和ChannelFactory<T>,ClientBase最终也是通过ChannelFactory<T>来构建Channel的
ChannelFactory<T>有两个方法为自定义配置文件提供解决方案:
protected virtual void ApplyConfiguration(string configurationName);
protected abstract ServiceEndpoint CreateDescription();
ApplyConfiguration
方法和ServiceHost的ApplyConfiguration
方法的功能类似,但是有一点不同的是需要和CreateDescription交互。其实ApplyConfiguration并不是客户端代理这里所要关注的地方,我们只需要关注CreateDescription就可以了。
ChannelFactory<T>的方法CreateDescription实现上是从默认配置文件(缺省AppDomain的配置文件),所以我们通过重写这个方法就可以实现从外部文件加载配置。
/// <summary>
/// Loads the serviceEndpoint description from the specified configuration file
/// </summary>
/// <returns></returns>
protected override ServiceEndpoint CreateDescription()
{
ServiceEndpoint serviceEndpoint = base.CreateDescription();
ExeConfigurationFileMap map = new ExeConfigurationFileMap();
map.ExeConfigFilename = this.configurationPath;
Configuration config = ConfigurationManager.OpenMappedExeConfiguration(map, ConfigurationUserLevel.None);
ServiceModelSectionGroup group = ServiceModelSectionGroup.GetSectionGroup(config);
ChannelEndpointElement selectedEndpoint = null;
foreach (ChannelEndpointElement endpoint in group.Client.Endpoints)
{
if (endpoint.Contract == serviceEndpoint.Contract.ConfigurationName)
{
selectedEndpoint = endpoint;
break;
}
}
if (selectedEndpoint != null)
{
if (serviceEndpoint.Binding == null)
{
serviceEndpoint.Binding = CreateBinding(selectedEndpoint.Binding, group);
}
if (serviceEndpoint.Address == null)
{
serviceEndpoint.Address = new EndpointAddress(selectedEndpoint.Address, GetIdentity(selectedEndpoint.Identity), selectedEndpoint.Headers.Headers);
}
if (serviceEndpoint.Behaviors.Count == 0 && selectedEndpoint.BehaviorConfiguration != null)
{
AddBehaviors(selectedEndpoint.BehaviorConfiguration, serviceEndpoint, group);
}
serviceEndpoint.Name = selectedEndpoint.Contract;
}
return serviceEndpoint;
}
具体的实现可以参看例子代码,这个例子WCF sdk的例子ICalculator。代码下载CustomChannel.zip
- 01.SVN介绍与安装
- 由sqlplus中的一个小细节所做的折腾(r5笔记第11天)
- 浅析多线程的对象锁和Class锁
- 使用strace诊断奇怪的sqlplus登录问题(r5笔记第29天)
- 读书笔记 之《Thinking in Java》(对象、集合、异常)
- 深度解析dba_segments和sys.seg$中的细节差异(上) (r5笔记第27天)
- 【大牛经验】26种语言输出HelloWord
- 深度解析dba_segments和sys.seg$中的细节差异(下) (r5笔记第28天)
- Linux命令(面试+工作版)
- 纠结的paste格式问题(未解决) (r5笔记第26天)
- 由MySQL中的falcon存储引擎引申的八卦杂谈(r5笔记第23天)
- 12.观察者/状态模式
- 数据补丁中需要注意的几个问题(r5笔记第21天)
- 简单对比MySQL和Oracle中的一个sql解析细节 (r5笔记第40天)
- JavaScript 教程
- JavaScript 编辑工具
- JavaScript 与HTML
- JavaScript 与Java
- JavaScript 数据结构
- JavaScript 基本数据类型
- JavaScript 特殊数据类型
- JavaScript 运算符
- JavaScript typeof 运算符
- JavaScript 表达式
- JavaScript 类型转换
- JavaScript 基本语法
- JavaScript 注释
- Javascript 基本处理流程
- Javascript 选择结构
- Javascript if 语句
- Javascript if 语句的嵌套
- Javascript switch 语句
- Javascript 循环结构
- Javascript 循环结构实例
- Javascript 跳转语句
- Javascript 控制语句总结
- Javascript 函数介绍
- Javascript 函数的定义
- Javascript 函数调用
- Javascript 几种特殊的函数
- JavaScript 内置函数简介
- Javascript eval() 函数
- Javascript isFinite() 函数
- Javascript isNaN() 函数
- parseInt() 与 parseFloat()
- escape() 与 unescape()
- Javascript 字符串介绍
- Javascript length属性
- javascript 字符串函数
- Javascript 日期对象简介
- Javascript 日期对象用途
- Date 对象属性和方法
- Javascript 数组是什么
- Javascript 创建数组
- Javascript 数组赋值与取值
- Javascript 数组属性和方法
- 用 Docker swarm 快速部署分布式图数据库 Nebula Graph 集群
- Labelhub 基于腾讯云 Serverless 技术为人工智能企业提供数据与模型解决方案
- 手把手教你使用 Prometheus 监控 JVM
- 基于云开发 CloudBase 搭建在线视频会议应用
- 手搓一个分布式大气监测系统(六)云端能力更新、说明及源码放出
- maybe incorrect parameters such as bit_rate, rate, width or height
- vue 怎么将Checkbox 多选框选中的值提交
- vue-element怎么给select下拉框赋值?
- 小程序生成二维码海报的组件-wxa-plugin-canvas
- kbone 是什么?这可能是最好的小程序开源框架
- jQuery根据填写的input的数值导出excel表格
- 解决多种版本python冲突问题
- 探索 App Clips
- ES索引模糊查询
- Dubbo定时任务时间轮(Time Wheel)算法详解