柳永法的.net技术博客

向更高的人生目标奋斗
posts - 10, comments - 103, trackbacks - 0, articles - 0
  博客园  :: 首页  :: 新随笔  :: 联系 :: 订阅 订阅  :: 管理

历史背景:

  公司有10来个团队项目,每个项目下又有1-4个Site或Service,还有一些Winform、Windows Scheduler等,这样算下来会有近30个项目及相关多个DLL项目,每个项目都可能会用到一些公共的DLL,像:Enterprise Library、NPOI、OpenXML、AspNetPager、Newtonsoft.Json、AppFabric、PanGu等,而这些公共的有些会被再封装,最后项目里可能会引用一个封装过DLL或原DLL,一般DLL间如果有依赖,只要这几个DLL在一起,引用一个封装后的,其它DLL会一并在生成时放入bin下,但有些DLL依赖比较弱(如反射)、或是使用别的什么高深的做法做到没有直接依赖关系、或者Copy DLL时没有将其依赖DLL也一并Copy过来,反正最后是需要那个DLL、但程序却找不着,导致运行时错误。项目一大,这样的错就太难找了,除非做好足够的测试程序,去自动检测。

 解决思路:

  针对以上问题,我们使用TFS管理,每个团队项目都会有一个放DLL的公共区,供这个团队项目下的所有项目引用。如果公用或相关DLL有更新都需要更新各个团队项目下的DLL公共区。但有时因为忙或其它原因,没有及时更新,过后又忘了,而其他人又不知道。这样的问题出现的多了,有些人干脆直接引用所有公共DLL,但这样一来,每次重新生成、发布、打包都得为复制DLL付出时间成本,很不方便。问题反反复复,一次次为此所累后,我受不了了!!!最近不太忙,同事又遇到这样的问题,实在不想搞了,技术高有耐心的调试跟踪一把也能解决。

  但我的观点很简单:如果什么都不做就能解决问题,那就什么都不要做!!! 于是下定决心:不能再让这样的事发生在我身上,也不能让他发生在我们组员身上,因为这样做会让他们把太多的精力花在这些不仅不能产生效益,反而严重影响开发进度的事情上,并且是持续的折磨开发人员,有时会让人产生放弃这个工作的念头。

 解决方案:

   就在有这个想法的一刹那,我想想到了.net Framework,他不就是将公共的DLL全都注册到GAC里,DLL之间的相互依赖也都是从GAC里找,并且相关DLL不在项目里引用时也照样正常工作,非要引用时VS也会出错提示。如果把我们公共DLL都装到GAC,那这一系列问题不都搞定了?Good!!!

  经过一番研究,终于将这些DLL都注册到GAC了,本以为像.net Framework一样,正常工作。但事实并不是这样,首先注册后在VS里的“添加引用”里找不到,得自己定位到DLL目录,那个郁闷呀,.net Framework可以放进去,我这个肯定也能!网上转了一圈,找到方案:除了将DLL注册到GAC后,还需要再将DLL复制到一个目录,并在注册表里为VS做下指引。做完这些后,感觉没问题了,用了一天时间把所有项目的引用都改到GAC引用后,执行TFS里的生成(我们的生成里带了发布的代码),一切OK,看着过往生成记录,现在生成及发布比以前的时间缩短了,兴奋呀。但一测试发现,很多页面都有问题,分析后发现是企业库问题。这时已经影响到别的项目开发了,所又抱怨声很多,甚至之前支持我这个想法的同事也不经意的说起:还是引用本地DLL吧,但他们可曾知道我为了解决这个问题忍受了多久、眼看就要成功了怎么就能这么轻易放弃?同事帮我调了一把实在也搞不明白,下班很久了,都累了,他们也先回去了,但这问题不解决明天还一样影响到别人工作,我决不会这么做的。不吃饭,继续研究,发现确实是EntLib问题,研究过程中同事在回家车上发来短信给了一文章,看了后发现还真可以解决,应用到一个项目上测试没问题后再次发布所有项目。大致走了一遍,ALL OK。爽。

  这次问题解决时间较长,所以产生了写此文章的想法,记录下自己的心路历程,为又后失意时打气。耳边响起了以前常听的一首歌曲《梦想旅程》 :  

人生就像走这一条属于我们自己的路
未知前方有着多少崎岖有着多少迷雾
只要自己坚定信念决不放弃自己的梦
哪怕前方的路有多苦
不管自己理想梦想是否能实现
我对自己说我决不放弃决不认输
属于我们未来就在我们的手中
为了自己梦想人生的路  

最后给出遇到的问题及解决方案:

 

企业库加入GAC后:Data Access与Validation无法正常工作,可以通过以下配置解决:

<configSections>
<section name="typeRegistrationProvidersConfiguration" type="Microsoft.Practices.EnterpriseLibrary.Common.Configuration.TypeRegistrationProvidersConfigurationSection, Microsoft.Practices.EnterpriseLibrary.Common, Version=5.0.414.0, Culture=neutral, PublicKeyToken=31bf3856ad364e35"/>
</configSections>

<typeRegistrationProvidersConfiguration>
<remove name="Data Access"/>
<add name="Data Access" providerType="Microsoft.Practices.EnterpriseLibrary.Data.Configuration.DatabaseSyntheticConfigSettings, Microsoft.Practices.EnterpriseLibrary.Data, Version=5.0.414.0, Culture=neutral, PublicKeyToken=31bf3856ad364e35"/>

<remove name="Validation"/>
<add name="Validation" providerType="Microsoft.Practices.EnterpriseLibrary.Validation.Configuration.ValidationTypeRegistrationProvider, Microsoft.Practices.EnterpriseLibrary.Validation, Version=5.0.414.0, Culture=neutral, PublicKeyToken=31bf3856ad364e35"/>
</typeRegistrationProvidersConfiguration>

参考地址:http://entlib.codeplex.com/workitem/26903

其它组件加入GAC后网站仍找不到程序集,需要在配置文件里再次声明,如:

<system.web>
<compilation debug="true" targetFramework="4.0">
<assemblies>
<add assembly="AspNetPager, Version=7.3.2.0, Culture=neutral, PublicKeyToken=fb0a0fe055d40fd4, processorArchitecture=MSIL"/>
<add assembly="Microsoft.ReportViewer.WebForms, Version=10.0.0.0, Culture=neutral, PublicKeyToken=B03F5F7F11D50A3A"/>
<add assembly="Microsoft.ReportViewer.Common, Version=10.0.0.0, Culture=neutral, PublicKeyToken=B03F5F7F11D50A3A"/>
<add assembly="Microsoft.Build.Framework, Version=4.0.0.0, Culture=neutral, PublicKeyToken=B03F5F7F11D50A3A"/>
<add assembly="System.Management, Version=4.0.0.0, Culture=neutral, PublicKeyToken=B03F5F7F11D50A3A"/>
</assemblies>
</compilation>
</system.web>

以上两个情况也都可以通过以下方式实现:

<runtime>
<assemblyBinding xmlns="urn:schemas-microsoft-com:asm.v1">
<qualifyAssembly partialName="Microsoft.Practices.EnterpriseLibrary.Caching" fullName="Microsoft.Practices.EnterpriseLibrary.Caching, Version=5.0.414.0, Culture=neutral, PublicKeyToken=31bf3856ad364e35"/>
<qualifyAssembly partialName="Microsoft.Practices.EnterpriseLibrary.Caching.Cryptography" fullName="Microsoft.Practices.EnterpriseLibrary.Caching.Cryptography, Version=5.0.414.0, Culture=neutral, PublicKeyToken=31bf3856ad364e35"/>
<qualifyAssembly partialName="Microsoft.Practices.EnterpriseLibrary.Caching.Database" fullName="Microsoft.Practices.EnterpriseLibrary.Caching.Database, Version=5.0.414.0, Culture=neutral, PublicKeyToken=31bf3856ad364e35"/>
<qualifyAssembly partialName="Microsoft.Practices.EnterpriseLibrary.Common" fullName="Microsoft.Practices.EnterpriseLibrary.Common, Version=5.0.414.0, Culture=neutral, PublicKeyToken=31bf3856ad364e35"/>
<qualifyAssembly partialName="Microsoft.Practices.EnterpriseLibrary.Configuration.Design.HostAdapter" fullName="Microsoft.Practices.EnterpriseLibrary.Configuration.Design.HostAdapter, Version=4.0.0.0, Culture=neutral, PublicKeyToken=31bf3856ad364e35"/>
<qualifyAssembly partialName="Microsoft.Practices.EnterpriseLibrary.Configuration.Design.HostAdapterV5" fullName="Microsoft.Practices.EnterpriseLibrary.Configuration.Design.HostAdapterV5, Version=5.0.414.0, Culture=neutral, PublicKeyToken=31bf3856ad364e35"/>
<qualifyAssembly partialName="Microsoft.Practices.EnterpriseLibrary.Configuration.DesignTime" fullName="Microsoft.Practices.EnterpriseLibrary.Configuration.DesignTime, Version=5.0.414.0, Culture=neutral, PublicKeyToken=31bf3856ad364e35"/>
<qualifyAssembly partialName="Microsoft.Practices.EnterpriseLibrary.Configuration.EnvironmentalOverrides" fullName="Microsoft.Practices.EnterpriseLibrary.Configuration.EnvironmentalOverrides, Version=5.0.414.0, Culture=neutral, PublicKeyToken=31bf3856ad364e35"/>
<qualifyAssembly partialName="Microsoft.Practices.EnterpriseLibrary.Data" fullName="Microsoft.Practices.EnterpriseLibrary.Data, Version=5.0.414.0, Culture=neutral, PublicKeyToken=31bf3856ad364e35"/>
<qualifyAssembly partialName="Microsoft.Practices.EnterpriseLibrary.Data.SqlCe" fullName="Microsoft.Practices.EnterpriseLibrary.Data.SqlCe, Version=5.0.414.0, Culture=neutral, PublicKeyToken=31bf3856ad364e35"/>
<qualifyAssembly partialName="Microsoft.Practices.EnterpriseLibrary.ExceptionHandling" fullName="Microsoft.Practices.EnterpriseLibrary.ExceptionHandling, Version=5.0.414.0, Culture=neutral, PublicKeyToken=31bf3856ad364e35"/>
<qualifyAssembly partialName="Microsoft.Practices.EnterpriseLibrary.ExceptionHandling.Logging" fullName="Microsoft.Practices.EnterpriseLibrary.ExceptionHandling.Logging, Version=5.0.414.0, Culture=neutral, PublicKeyToken=31bf3856ad364e35"/>
<qualifyAssembly partialName="Microsoft.Practices.EnterpriseLibrary.ExceptionHandling.WCF" fullName="Microsoft.Practices.EnterpriseLibrary.ExceptionHandling.WCF, Version=5.0.414.0, Culture=neutral, PublicKeyToken=31bf3856ad364e35"/>
<qualifyAssembly partialName="Microsoft.Practices.EnterpriseLibrary.Logging" fullName="Microsoft.Practices.EnterpriseLibrary.Logging, Version=5.0.414.0, Culture=neutral, PublicKeyToken=31bf3856ad364e35"/>
<qualifyAssembly partialName="Microsoft.Practices.EnterpriseLibrary.Logging.Database" fullName="Microsoft.Practices.EnterpriseLibrary.Logging.Database, Version=5.0.414.0, Culture=neutral, PublicKeyToken=31bf3856ad364e35"/>
<qualifyAssembly partialName="Microsoft.Practices.EnterpriseLibrary.PolicyInjection" fullName="Microsoft.Practices.EnterpriseLibrary.PolicyInjection, Version=5.0.414.0, Culture=neutral, PublicKeyToken=31bf3856ad364e35"/>
<qualifyAssembly partialName="Microsoft.Practices.EnterpriseLibrary.Security" fullName="Microsoft.Practices.EnterpriseLibrary.Security, Version=5.0.414.0, Culture=neutral, PublicKeyToken=31bf3856ad364e35"/>
<qualifyAssembly partialName="Microsoft.Practices.EnterpriseLibrary.Security.AzMan" fullName="Microsoft.Practices.EnterpriseLibrary.Security.AzMan, Version=5.0.414.0, Culture=neutral, PublicKeyToken=31bf3856ad364e35"/>
<qualifyAssembly partialName="Microsoft.Practices.EnterpriseLibrary.Security.Cache.CachingStore" fullName="Microsoft.Practices.EnterpriseLibrary.Security.Cache.CachingStore, Version=5.0.414.0, Culture=neutral, PublicKeyToken=31bf3856ad364e35"/>
<qualifyAssembly partialName="Microsoft.Practices.EnterpriseLibrary.Security.Cryptography" fullName="Microsoft.Practices.EnterpriseLibrary.Security.Cryptography, Version=5.0.414.0, Culture=neutral, PublicKeyToken=31bf3856ad364e35"/>
<qualifyAssembly partialName="Microsoft.Practices.EnterpriseLibrary.Validation" fullName="Microsoft.Practices.EnterpriseLibrary.Validation, Version=5.0.414.0, Culture=neutral, PublicKeyToken=31bf3856ad364e35"/>
<qualifyAssembly partialName="Microsoft.Practices.EnterpriseLibrary.Validation.Integration.AspNet" fullName="Microsoft.Practices.EnterpriseLibrary.Validation.Integration.AspNet, Version=5.0.414.0, Culture=neutral, PublicKeyToken=31bf3856ad364e35"/>
<qualifyAssembly partialName="Microsoft.Practices.EnterpriseLibrary.Validation.Integration.WCF" fullName="Microsoft.Practices.EnterpriseLibrary.Validation.Integration.WCF, Version=5.0.414.0, Culture=neutral, PublicKeyToken=31bf3856ad364e35"/>
<qualifyAssembly partialName="Microsoft.Practices.EnterpriseLibrary.Validation.Integration.WinForms" fullName="Microsoft.Practices.EnterpriseLibrary.Validation.Integration.WinForms, Version=5.0.414.0, Culture=neutral, PublicKeyToken=31bf3856ad364e35"/>
<qualifyAssembly partialName="Microsoft.Practices.EnterpriseLibrary.Validation.Integration.WPF" fullName="Microsoft.Practices.EnterpriseLibrary.Validation.Integration.WPF, Version=5.0.414.0, Culture=neutral, PublicKeyToken=31bf3856ad364e35"/>
<qualifyAssembly partialName="Microsoft.Practices.ServiceLocation" fullName="Microsoft.Practices.ServiceLocation, Version=1.0.0.0, Culture=neutral, PublicKeyToken=31bf3856ad364e35"/>
<qualifyAssembly partialName="Microsoft.Practices.Unity" fullName="Microsoft.Practices.Unity, Version=2.0.414.0, Culture=neutral, PublicKeyToken=31bf3856ad364e35"/>
<qualifyAssembly partialName="Microsoft.Practices.Unity.Configuration" fullName="Microsoft.Practices.Unity.Configuration, Version=2.0.414.0, Culture=neutral, PublicKeyToken=31bf3856ad364e35"/>
<qualifyAssembly partialName="Microsoft.Practices.Unity.Interception" fullName="Microsoft.Practices.Unity.Interception, Version=2.0.414.0, Culture=neutral, PublicKeyToken=31bf3856ad364e35"/>
<qualifyAssembly partialName="Microsoft.Practices.Unity.Interception.Configuration" fullName="Microsoft.Practices.Unity.Interception.Configuration, Version=2.0.414.0, Culture=neutral, PublicKeyToken=31bf3856ad364e35"/>
</assemblyBinding>
</runtime>

注册到GAC后,在VS的添加引用里看不到、及DLL的注释没了,解决方法是:

将这些DLL及相应的XML说明文档再放到一个位置,然后在注册表添加指引来解决。

如:目前都放在:C:\WINDOWS\Common.Reference.Assemblies\,按目录分隔各功能,

注册表里写法如下,每一个都会定位到对应的功能目录(只有一级目录的DLL会显示在VS的添加引用里):

Windows Registry Editor Version 5.00

[HKEY_LOCAL_MACHINE\SOFTWARE\Microsoft\.NETFramework\v4.0.30319\AssemblyFoldersEx\Common.Reference.Assemblies.AppFabric]
@="C:\\WINDOWS\\Common.Reference.Assemblies\\AppFabric"

[HKEY_LOCAL_MACHINE\SOFTWARE\Microsoft\.NETFramework\v4.0.30319\AssemblyFoldersEx\Common.Reference.Assemblies.AspNetPager]
@="C:\\WINDOWS\\Common.Reference.Assemblies\\AspNetPager"

[HKEY_LOCAL_MACHINE\SOFTWARE\Microsoft\.NETFramework\v4.0.30319\AssemblyFoldersEx\Common.Reference.Assemblies.EntLib]
@="C:\\WINDOWS\\Common.Reference.Assemblies\\EntLib"

[HKEY_LOCAL_MACHINE\SOFTWARE\Microsoft\.NETFramework\v4.0.30319\AssemblyFoldersEx\Common.Reference.Assemblies.Json]
@="C:\\WINDOWS\\Common.Reference.Assemblies\\Json"

[HKEY_LOCAL_MACHINE\SOFTWARE\Microsoft\.NETFramework\v4.0.30319\AssemblyFoldersEx\Common.Reference.Assemblies.NPOI]
@="C:\\WINDOWS\\Common.Reference.Assemblies\\Office"

 

首发地址:.net环境,将DLL程序集加入GAC后的一系列问题汇总 http://www.yongfa365.com/Item/Custom-DLL-To-GAC.html