在上篇博文.Net core 程序Nuget包独立存放(一)中介绍了运行环境中,如何实现将nuget库存放,还有一个问题没有解决:如何将nuget包从publish的程序集中分离。本文就介绍下如何解决这个问题:
首先,我们直接将dll放在additionalProbingPaths的时候,会发现会出现找不到dll的现象。研究下Nuget的缓存包,发现它是这样的一个格式的路径:
newtonsoft.json\13.0.1\lib\netstandard2.0\Newtonsoft.Json.dll
基本上是由package version path三部分组成。那如何获取这三部分内容呢,研究一下publish的文件就会发现它们是存储在deps.json文件中。
"targets": {
"Newtonsoft.Json/13.0.1": {
"runtime": {
"lib/netstandard2.0/Newtonsoft.Json.dll": {
"assemblyVersion": "13.0.0.0",
}
}
}
有了这些内容后,我们已经可以将所有dll放在additionalProbingPaths中了。但这有点做过头了,我们仅仅只需要将nuget程序包放进去而已。项目生成的dll还是需要和exe放在一起的。
因此,我们还需要知道另外一部分信息:哪些是nuget程序包引入的dll,哪些是项目生成的dll。这些也可以从deps.json中找到。
"libraries": {
"Newtonsoft.Json/13.0.1": {
"type": "package",
"serviceable": true,
}
}
根据type是package的则是nuget程序包。
有了上述基础后,我们就可以写一个程序实现Nuget程序独立存放了。一个简单的示例如下。
1 static void Main(string[] args) 2 { 3 var content = File.ReadAllText(@".\demo.deps.json"); 4 5 var targetLibPath = "libs"; // 需要预先设置runtimeconfig.json "additionalProbingPaths": ["libs"], 6 7 var root = JsonConvert.DeserializeObject(content) as JObject; 8 9 10 var npkgs = root["libraries"] 11 .Children<JProperty>() 12 .Where(i => i.Value["type"]?.Value<string>() == "package") 13 .Select(i => i.Name) 14 .ToHashSet(); 15 16 var libs = root.SelectTokens(@"targets.*.*.runtime") 17 .Cast<JObject>() 18 .Select(token => 19 { 20 var packageToken = token.Parent.Parent.Parent as JProperty; 21 var package = packageToken.Name; 22 23 var dlls = token.Properties().Select(i => i.Name).ToArray(); 24 25 return new { name = package, dlls }; 26 }) 27 .ToArray(); 28 29 30 var packages = libs.Where(i => npkgs.Contains(i.name)) 31 .ToArray(); 32 33 var projects = libs.Except(packages).ToArray(); 34 35 foreach (var p in packages) 36 { 37 //存在一个包下多个dll的情况 38 foreach (var dllPath in p.dlls) 39 { 40 var file = Path.GetFileName(dllPath); 41 if (!File.Exists(file)) 42 { 43 continue; 44 } 45 46 var fullPath = Path.Combine(targetLibPath, p.name, dllPath); 47 Directory.CreateDirectory(Path.GetDirectoryName(fullPath)); 48 File.Move(file, fullPath); 49 } 50 } 51 }