有的时候你可能会碰到.NET程序在发布机上不能启动的问题,.NET程序告诉你有的Assembly不能加载,你想看看.NET程序到底依赖于哪些Assembly的话,可以试一下下面的程序(注意:你只能在可以执行这个.NET程序的机器上运行下面的程序):
1. using System; 2. using System.Collections.Generic; 3. using System.Linq; 4. using System.Text; 5. using System.Reflection; 6. using System.IO; 7. using System.Diagnostics; 8. 9. namespace ListDependents 10. { 11. class Program 12. { 13. private const string HOST_ASSEMBLY_NAME = "han"; 14. 15. public static void Main(string[] args) 16. { 17. if (args.Length != 1) 18. { 19. Console.WriteLine("Usage: ListDependents <assembly path>"); 20. return; 21. } 22. 23. ListDependentsByAppDomain(args[0]); 24. } 25. 26. /// <summary> 27. /// Use AppDomain.Load to load assemblies 28. /// 29. /// This approach has its benefit,you can apply assembly app.config file to load 30. /// the dependented assembly,please read 31. /// </summary> 32. /// <param name="p"></param> 33. private static void ListDependentsByAppDomain(string path) 34. { 35. if (string.IsNullOrEmpty(path)) 36. throw new ArgumentNullException("path"); 37. 38. AppDomainSetup setup = new AppDomainSetup(); 39. 40. string assemblyPath = Path.GetFullPath(path); 41. // setup.ApplicationBase = Path.GetDirectoryName(assemblyPath); 42. setup.ApplicationName = Path.GetFileNameWithoutExtension(path); 43. // Try to get assembly's app.config file 44. string configPath = assemblyPath + ".config"; 45. if (File.Exists(configPath)) 46. setup.ConfigurationFile = configPath; 47. 48. AppDomain workingDomain = AppDomain.CreateDomain("ListDep",null,setup); 49. workingDomain.SetData(HOST_ASSEMBLY_NAME,typeof(Program).Assembly.GetName().Name); 50. 51. Trace.WriteLine("Start working domain"); 52. string extension = Path.GetExtension(assemblyPath); 53. try 54. { 55. if (extension == ".exe") 56. workingDomain.ExecuteAssembly(assemblyPath); 57. else 58. workingDomain.Load(assemblyPath); 59. } 60. catch (Exception ex) 61. { 62. Trace.TraceWarning(string.Format("Failed to load {0} with exception {1}", 63. assemblyPath,ex.Message)); 64. } 65. 66. workingDomain.DomainUnload += new EventHandler(CollectDependents); 67. Trace.WriteLine("Unload working domain"); 68. AppDomain.Unload(workingDomain); 69. } 70. 71. private static void CollectDependents(object sender,EventArgs e) 72. { 73. string hostAssemblyName = (string)AppDomain.CurrentDomain.GetData(HOST_ASSEMBLY_NAME); 74. Assembly[] assemblies = AppDomain.CurrentDomain.GetAssemblies(); 75. 76. using (StreamWriter writer = new StreamWriter(@"dependents.txt",false)) 77. { 78. writer.WriteLine("digraph AssemblyDependence"); 79. writer.WriteLine("{"); 80. 81. foreach (Assembly assembly in assemblies) 82. { 83. AssemblyName name = assembly.GetName(); 84. if (name.Name == hostAssemblyName) 85. continue; 86. 87. string regName = name.Name.Replace(".","_"); 88. writer.WriteLine("/t{0} [label = /"{1}/",style=filled,fillcolor=orange,fontsize=8,fontcolor=white,fontname=Impact]", 89. regName,regName); 90. } 91. 92. writer.WriteLine(); 93. 94. foreach (Assembly assembly in assemblies) 95. { 96. AssemblyName[] depdents = assembly.GetReferencedAssemblies(); 97. AssemblyName name = assembly.GetName(); 98. if (name.Name == hostAssemblyName) 99. continue; 100. 101. foreach (AssemblyName depdentName in depdents) 102. { 103. writer.WriteLine("/t{0} -> {1} [fontsize=8,fontcolor=blue]", 104. name.Name.Replace(".","_"),depdentName.Name.Replace(".","_")); 105. } 106. } 107. writer.WriteLine("}"); 108. } 109. } 110. } 111. } 112. |
这个程序的原理是,当.NET加载.NET程序以后,.NET自己会解决.NET程序Assembly之间依赖的问题,而且.NET会自己维护Assembly之间的依赖关系。因此我们只要将其打印出来,并且配上Graphivz程序生成一个依赖图就可以一目了然.NET之间的依赖关系了。