使用Fody时,CS-SCRIPT动态代码无法找到程序集
FODY会将相关的程序集处理成资源文件,CS_SCRIPT强制要求引用的程序集必须是文件
public override IEvaluator ReferenceAssembly(Assembly assembly)
{
if (assembly != null)//this check is needed when trying to load partial name assemblies that result in null
{
if (assembly.Location.IsEmpty())
throw new Exception(
$"Current version of CodeDom evaluator (csc.exe) doesn't support referencing assemblies " +
"which are not loaded from the file location.");
var asmFile = assembly.Location;
if (referencedAssemblies.FirstOrDefault(x => asmFile.SamePathAs(x)) == null)
referencedAssemblies.Add(asmFile);
}
return this;
}
@@#
解决办法:
- 动态代码涉及到的命名空间放在一个公共的程序集中,最好是接口描述,FODY生成的时候,将这个程序集排除在外
- 上述方法没办法做到发布为单一文件,毕竟使用FODY就是为了只生成一个文件,可强行在代码中在编译动态代码前,释放该文件。(缺点:该程序集名称固定在了代码中)
//fody时无法加载程序集,释放到临时文件使用(不在当前目录下,防止释放后不能删除,下次程序启动时优先从文件加载此程序集)
string protocolDll = FileHelper.GetAbsolutePath(Path.Combine("scripts", "Protocol.dll"));
AssemblyUtil.ExtractFodyDll(protocolDll, "protocol.dll");
//添加临时目录为程序集搜索目录
CSScript.GlobalSettings.AddSearchDir(Path.GetDirectoryName(protocolDll));
//动态执行代码获取所有数据
CSScript.EvaluatorConfig.Engine = EvaluatorEngine.CodeDom;
// // CSScript.EvaluatorConfig.Engine = EvaluatorEngine.Roslyn;
//该方法与FODY冲突,FODY会导致无法找到引用
script = CSScript.Evaluator.ReferenceDomainAssemblies(DomainAssemblies.AllStaticNonGAC);
script.ReferenceAssembly(Path.GetFileName(protocolDll));//添加释放出的程序集
public static void ExtractFodyDll(string fileName, string dllName)
{
System.Reflection.Assembly Asmb = System.Reflection.Assembly.GetCallingAssembly();
if (!System.IO.Directory.Exists(System.IO.Path.GetDirectoryName(fileName)))
System.IO.Directory.CreateDirectory(System.IO.Path.GetDirectoryName(fileName));
string strName = "costura." + dllName;
using (System.IO.Stream ManifestStream = Asmb.GetManifestResourceStream(strName))
{
if (strName.EndsWith(".compressed"))
{
using (DeflateStream source = new DeflateStream(ManifestStream, CompressionMode.Decompress))
using (FileStream output = new FileStream(fileName, FileMode.Create))
source.CopyTo(output);
}
else
{
byte[] StreamData = new byte[ManifestStream.Length];
ManifestStream.Read(StreamData, 0, (int)ManifestStream.Length);
System.IO.File.WriteAllBytes(fileName, StreamData);
}
}
}
@@#