zoukankan      html  css  js  c++  java
  • WebApi 插件式构建方案

    WebApi 插件式构建方案

    公司要推行服务化,不可能都整合在一个解决方案内,因而想到了插件式的构建方案。最终定型选择基于 WebApi 构建服务化,之所以不使用 WCF 是因为不符合 RESTful 风格,并且对 OData 开源查询协议支持不是太好。

    插件化构建的两种思路

    1. 不进行二次开发,直接把编译完成的程序集放到 bin 目录即可。
    2. 针对程序集寻址做扩展,把插件程序集放到 bin 的二级目录。

    在这里,我对两者的优缺点进行一下分析:

    • 第一种方案:如果是临时方案我没有意见,毕竟是过渡用的,业务为重嘛。但是,作为万人敬仰的程序员,你他娘的也太懒了吧!那么多程序集放在一起,万一堆太多堆太久生蛆了肿么办?万一哪家小朋友不听话,把自己埋了肿么办?
    • 第二种方案:嗯,还得开发,而且弄不好还会把项目搞砸!后果很严重,领导很生气!肿么办?无奈 + 无解。。。

    其实不用那么麻烦,用别人开发的一套成熟的东西就好办了。没有?好,坐下来,听我慢慢说。

    WebApi 启动流程简介

    任何基于 Http 的服务端程序,启动管道和请求响应管道指定是跑不了的。

    • 启动管道是服务自我配置的过程:这个时候 XML 配置和一些默认的约定就起作用了,比如 IOC 容器 Unity 启动时会从 unity.config 文件中读取映射配置,WebApi 框架缺省情况下会寻找从 ApiController 继承并且类名称结尾是 Controller 的类作为控制器。
    • 请求响应管道是服务器接到客户端请求后的处理流程:可以想象一下我们公司里的审批流,你要请假了,必须得小组长先批准,然后总监批准,接着人力审核,财务扣钱等等。在这里,一般会首先进行认证,授权和附加信息获取等流程,最后才会交给咱程序员写的逻辑去处理。

    注:对于自承载的服务,也会有一个类似的流程。

    流程一:获取程序集列表

    挂载在 IIS 上时,会从 BuildManager 中获取程序集列表:这个列表是经过 ASP.NET 程序底层优化过的,能够获取所有的程序集信息。自承载时,只是简单粗暴地调用 Assembly 类的静态方法,估计会有一些问题,我没试过,这里不做讨论。考虑到绝大多数人还是使用 IIS 挂载的,说太详细没什么意义,我也没那个精力。

    .Net 4.0 时代,ASP.NET 程序启动时,可以给程序集加上一个 Attribute(PreApplicationStartMethod),可以添加一些启动后不能变更的工作。这里我们要做的工作,就是把那些不在 bin 根目录的程序集加载进去,通过 AddReferencedAssembly 静态方法添加即可。

    注意:

    • 不要加载一个程序集的不同版本,这会对程序的运行产生不可预知的影响。
    • ASP.NET 的某些变量还没初始化,你的某些想法不会成立。

    这里,我在加载了程序集的基础上,又公开了一些模块的元数据信息:

    • 插件的初始配置:插件名称、路径、启动顺序、可用性、插件可见性、数据库连接字符串。
    • 插件运行需要加载的程序集列表。

    这些信息使得我在服务运行后,有了较大的定制空间。比如后面根据模块名称产生模块前缀 RESTful 服务;还有在另外的管理网站,统一管理服务的帮助系统等,源数据都是以其为依据的。

    注:插件初始配置中,可用性决定了这个插件是否加载,这是总开关。

    流程二:IOC 容器初始化

    现代的网站,很难想象如果没有 IOC ,程序的复杂性会提升多少。所以我把 IOC 的初始化提升到最重要的位置。但是考虑到 IOC 容器不同人会有不同的选择,我这里只依照微软 Unity 为蓝本做讲解。至于各个插件的使用上,统一采用 CommonServiceLocator 做 IOC 容器接口。

    这里我解释下为什么使用 CommonServiceLocator 做使用的接口方案:

    • 接口稳定:君不见微软这么多年来,从来没更新过这货吗?
    • 适配器丰富:可以这么说,.Net 世界的 IOC 容器,几乎都有针对的适配器。所以说,不用考虑将来更换 IOC 容器实现时,各个插件的更新问题。这根本就不是事!
    • 公司一直在在用 Unity ,而且还专门做了接口实现,没得选没的说,不解释。

    根据流程一提供的插件路径,约定 Configurationunity.config 为存储接口映射的地方,在程序启动时依据插件启动顺序,逐个加载映射信息。

    这一步完成后,就可以直接通过容器获取接口的实例了,很好的隔离了契约和实现,同时也让我们的程序趋于简单化,不用再用复杂的抽象工厂了。话说使用抽象工厂的配置也不比配置 IOC 容易,还都是私有的配置,一个个实现都不同,新人刚进入环境就是一头雾水。

    流程三:集成加载数据库连接字符串

    每个插件一般都会有自己的数据库访问功能,因为是插件化的方案,所以此时数据库连接字符串就很不好处理:生成后就不用再考虑连接字符串;插件自己放着就好,不用拷贝到指定的地方去。

    很幸运,.Net 提供了一个叫做反射的东西,允许做一些工作后更新到 .Net 框架自带的连接字符串容器中,这样我们就可以在运行时不用管这个叫数据库连接字符串的东东了。唯一注意的一点就是:各个插件提供的数据库连接字符串名称不能有相同的。我相信这不是什么问题!

    注:这个功能的实现依赖于流程一的插件初始配置,需要添加一个连接字符串所在文件的绝对路径的东东,以便于让系统指导从哪里获取这些连接字符串。每个模块都要配置一个,当然不用数据库操作的模块可以忽略。

    流程四:重写的控制器获取工厂

    缺省的控制器获取工厂,只会根据约定产生诸如 {controller}/{action}/{id} 这类的地址,那要我们插件如何是好?万一两家写的地址一样呢?小朋友会不会找不到家了呢?在前面加上 {module} 可好?

    好吧,我们假设方案是可行的,我们注册 {module}/{controller}/{action}/{id} 这样的路由,那就需要能解析这个路由的工厂才行啊,不然我们得不到控制器,谈何执行?

    没什么可说的了,实现接口就好了,参考缺省实现,我们只需要把查找的 Key 加上模块名字就好了。

    流程五:没什么可说的了

    运行你的 WebApi 服务吧,网站不用引用你控制器项目,需要的时候把生成好的程序集放到 IIS 网站下你的目录就好了。这里推荐放在 bin 目录下面,好处是在你更新 bin 下面的文件时,IIS 会重新启动这个网站。

  • 相关阅读:
    js正则表达式中的问号使用技巧总结
    380. Insert Delete GetRandom O(1)
    34. Find First and Last Position of Element in Sorted Array
    162. Find Peak Element
    220. Contains Duplicate III
    269. Alien Dictionary
    18. 4Sum
    15. 3Sum
    224. Basic Calculator
    227. Basic Calculator II
  • 原文地址:https://www.cnblogs.com/lenic/p/4129096.html
Copyright © 2011-2022 走看看