您的位置:首页 > 移动开发

Apply SOA Design Patterns with WCF (2) WCF Automatic Deployment (自动化部署)

2009-03-25 23:14 537 查看
Original (原创) by Teddy’s Knowledge Base

Content (目录)

(1) WCF Configuration Centralization (WCF配置集中管理)

(2) WCF Automatic Deployment (WCF自动化部署)

(3) WCF Automatic Service Locating (WCF自动化服务定位)

(4) WCF Database Paging & Sorting (WCF数据库分页和排序)

(5) WCF Based ASP.NET DataSouce Control (基于WCF的数据源控件)

(6) 1 + 2 + 3 + 4 + 5 = ?

English Version

摘要

本文提供一种简化在多服务器和服务器群上自动化部署WCF服务的方案。

正文

什么是自动化部署?

自动化部署指自动化地部署一个应用程序到它的运行环境。一般,通过创建批处理脚本来代替手动执行部署过程。对于WCF来说,最好的部署环境是IIS,尤其是包含了WAS的IIS7。最好的IIS上的部署工具是微软即将发布的Web Deployment Tool工具。可以访问其官方网站获得更多详情。

如果使用批处理脚本来自动化部署,那么自动化部署的复杂度就依赖于脚本的复杂度。一个批处理脚本可能包含许多任务,诸如:文件复制、DLL注册、IIS设置、Windows服务设置,甚至更复杂的依赖于其他资源和服务的任务。即使我们用像Web Deployment Tool这样功能强大的部署工具,它也只是能帮你更容易的创建部署脚本,并不会减小实际需要执行的任务的复杂程度。所以说,想要真正简化部署的过程,降低部署成本,我们更应该寻找能够减少或者转移走部署过程中的各种依赖的方法。

配置集中管理对自动化部署的好处

前一章说到了配置集中管理,可能的配置包括服务的元数据、数据库连接字串、应用设置、策略等等。实际上,你很容易就能想象,绝大多数部署过程中可能有的依赖,都和这些配置有关。换句话说,配置管理越集中化,自动化部署也就能变得更简单也更轻巧。

例如。从Dev、QA、Staging到Live环境:

消费和提供服务的元数据因为不同的端点地址、安全和日志策略可能不同。
数据库服务器可能不同,所以,数据库连接字串也可能不同。
任何关联整合的外部资源,诸如:URI,链接,缓存服务器地址等等都可能不同。
如果我们保证大多数配置都能被集中管理,那么在最理想的情况下(实际上,实践中,绝大多数情况下都能达到最理想情况),我们甚至能使得在任意环境部署的文件完全一致,不需要修改。

IIS对简化自动化部署的好处

大多数读者可能已经在IIS里至少部署过最简单的WCF演示程序了,感觉有任何难的吗?想必最可能让人觉得有一点复杂的是元数据(服务行为、端点)的配置。前面讨论过了,如果我们能从应用程序配置文件中移除这个复杂度,你是不是会说他已经足够简单了呢?这是因为IIS还给我们提供了另三个好处:

自动地址绑定。
如果一个WCF服务部署在IIS里,就不需要显式指定服务发布的地址了,因为地址可以通过部署的文件夹和网站的地址和端口计算出来。

自动端口共享。
网站的端口自动地被所有部署在网站中的服务共享。更进一步,在IIS7中,因为IIS7支持诸如TCP这样的更多的接口,部署在IIS7中的服务甚至可以自动共享相同的TCP端口。我们甚至可以在IIS7里让多个不同类型的端点绑定(WSHttp, NetTCP, NetPipedName)指向单一的一个完全相同的服务地址(不包含地址的前缀如’http:’部分)。

自动的服务宿主管理。
在其他的WCF服务宿主环境,诸如命令行程序或Windows服务程序中,必须要写额外的代码来管理ServiceHost类的实例的生命周期;而在IIS中,我么们可以简单的写一个.svc文件,IIS通过.NET Framework提供的ServiceHostFactory类可以自动为你管理ServiceHost实例的生命周期。尽管.NET Framework提供的ServiceHostFact的默认实现只能从应用程序配置文件读取WCF服务的元数据配置,我们可以写一个自定义的ServiceHostFactory类,从其他地方,例如我们提到过的集中化的配置中心读取元数据配置。下面的代码是一个从集中化的Store读取元数据配置的自定义的ServiceHostFactory实现片断:

public class WcfServiceHostFactory : ServiceHostFactory
{
//…

protected override ServiceHost CreateServiceHost(Type serviceType, Uri[] baseAddresses)
{
var serviceContracts = WcfServiceHelper.GetServiceContracts(serviceType);

var host = new ServiceHost(serviceType, BuildBaseAddresses(serviceContracts));
foreach (var serviceContract in serviceContracts)
{
var endpoints = EndpointStore.GetServerEndpoints(serviceContract);
if (endpoints.Count == 0)
return host;

foreach (var endpoint in endpoints)
{
var address = WcfServiceHelper.BuildAddress(endpoint);
if (address == default(Uri)) continue;

var binding = WcfServiceHelper.BuildBinding(serviceContract, endpoint);

if (binding == null) continue;

if (!IsBehaviorConfigured<ServiceMetadataBehavior>(host))
{
var smb = new ServiceMetadataBehavior();
host.Description.Behaviors.Add(smb);
}

if (endpoint.MexBindingEnabled)
{
host.AddServiceEndpoint(typeof (IMetadataExchange), new CustomBinding(binding), "mex");
}

if (!IsBehaviorConfigured<ServiceThrottlingBehavior>(host))
{
var serviceThrottle = new ServiceThrottlingBehavior();
if (endpoint.MaxConcurrentCalls.HasValue)
serviceThrottle.MaxConcurrentCalls = endpoint.MaxConcurrentCalls.Value;
if (endpoint.MaxConcurrentInstances.HasValue)
serviceThrottle.MaxConcurrentInstances = endpoint.MaxConcurrentInstances.Value;
if (endpoint.MaxConcurrentSessions.HasValue)
serviceThrottle.MaxConcurrentSessions = endpoint.MaxConcurrentSessions.Value;
host.Description.Behaviors.Add(serviceThrottle);
}

if (!IsBehaviorConfigured<ServiceDebugBehavior>(host) && endpoint.IncludeExceptionDetailInFaults.HasValue && endpoint.IncludeExceptionDetailInFaults.Value)
{
var serviceDebug = new ServiceDebugBehavior
{
IncludeExceptionDetailInFaults =
endpoint.IncludeExceptionDetailInFaults.Value
};
host.Description.Behaviors.Add(serviceDebug);
}

host.AddServiceEndpoint(serviceContract, binding, address);
}
}

return host;
}

}

提示

一般,在.svc文件中指定的Type是服务的实现类的类型,ServiceHostFactory的CreateHostHost方法会将这个类型作为参数传给ServiceHost类的构造函数。但是,也可以只在.svc文件里指定服务的接口类型,然后通过使用诸如Unity和Castle这样的IoC容器,在你的自定义ServiceHostFactory的实现中,先从服务接口类型获取服务的实现类型,然后再传给ServiceHost的构造函数。
在自定义的ServiceHostFactory实现中,要小心捕获创建ServiceHost的过程中的错误并记录日志,因为任何在ServiceHost的创建过程中抛出的的异常的详细信息都不会反映给服务的客户端。客户端永远不会知道是为什么,只会收到一个连接被拒绝的消息。不过我们还是可以像调试其他Web应用程序一样,用VS2008的远程调试工具来调试自定义的ServiceHostFactory的。

参考

(1) SOA Design Pattern Catalog: http://www.soapatterns.org/

//我是结尾符,待续…
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: 
相关文章推荐