我们有一个作业服务器来处理从网站提交的作业。网站的程序集被打包并作为作业的一部分提交到作业服务器(包括所有附属资源程序集)。
这些程序集在作业处理开始之前通过: Assembly.Load( byte[] ) 加载。
在作业处理过程中,我们需要对资源字符串(即验证消息)进行快照。请注意,简单地存储资源密钥不是一个选项,因为验证规则/消息可能会随着时间而改变,如果他们回来查看以前处理的作业/消息,我不希望显示“最新”资源字符串。我需要显示作业处理时的值。而且我需要每个支持的文化信息的快照,以便我可以在网站线程正在运行的适当文化中显示信息。
为了尝试检索消息,网站程序集指定支持哪些语言环境,因此在作业服务器上,我执行以下操作来创建网站程序集的 ResourceManager:
var resourceType = Type.GetType( "BTR.Websites.MadHatter.Clients.ABCCorp.Resources.ClientStrings" );
var rm = resourceType != null ? new ResourceManager( resourceType ) : null;
这很好用,我得到了一个 ResourceManager,但是,给定一个 XElement 验证规则和一个字符串 [] 语言环境,以下代码“不起作用”:
validationRule.Add(
from l in locales
let message = rm.GetString( p.Value.ToString(), new CultureInfo( l ) )
select new XAttribute( string.Format( "Message.{0}", l ), message ) );
本质上,无论我传入什么 CultureInfo,我都会收到默认(en-US)文化的消息。
AppDomain.CurrentDomain.GetAssemblies() 显示加载的网站程序集和附属程序集:
{ABCCorp.ServiceModel,版本=6.0.4497.18334,文化=中性,PublicKeyToken=null} System.Reflection.Assembly {System.Reflection.RuntimeAssembly} {ABCCorp.ServiceModel.resources,版本=6.0.4497.18334,文化=fr-FR, PublicKeyToken=null} System.Reflection.Assembly {System.Reflection.RuntimeAssembly}
但是,如果我在监视窗口中尝试以下操作(与上面的代码相同),我会得到 en-US 版本:
rm.GetString("ResourceKey", new CultureInfo("fr-FR"))
最后,大概我们都熟悉 LINQPad :) 以下脚本“有效”。我没有对 ABCCorp 的 ServiceModel.dll 或卫星 dll 的任何引用。
Assembly.LoadFile( @"C:\BTR\Source\ABCCorp.ServiceModel.dll" );
Assembly.LoadFile( @"C:\BTR\Source\fr-FR\ABCCorp.ServiceModel.resources.dll" );
AppDomain.CurrentDomain.GetAssemblies().Dump();
var resourceType = Type.GetType( "BTR.Websites.MadHatter.Clients.ABCCorp.Resources.ClientStrings, ABCCorp.ServiceModel" ).Dump();
var rm = resourceType != null ? new ResourceManager( resourceType ) : null;
rm.GetString( "FlatMemberInformationBasicInformation_DateDeathProof", new CultureInfo( "fr-FR" ) ).Dump();
任何建议将不胜感激。
更新: 根据 Joe 的建议,这是我们最终得到的代码。byte[] 内容是一个 zip 文件,其中包含网站程序集和所有卫星资源程序集(如果存在)。
private Assembly LoadPackagedAssembly( byte[] content )
{
var loaded = new Dictionary<string, Assembly>();
AppDomain.CurrentDomain.AssemblyResolve += delegate( object sender, ResolveEventArgs args )
{
return loaded.ContainsKey( args.Name )
? loaded[ args.Name ]
: null;
};
Assembly mainAssembly = null;
using ( var stream = new MemoryStream( content ) )
{
using ( var zip = new ZipInputStream( stream ) )
{
ZipEntry entry;
while ( ( entry = zip.GetNextEntry() ) != null )
{
using ( var buffer = new MemoryStream() )
{
Streams.CopyStream( zip, buffer );
var assembly = Assembly.Load( buffer.ToArray() );
loaded[ assembly.FullName ] = assembly;
if ( mainAssembly == null ) mainAssembly = assembly;
}
}
}
}
return mainAssembly;
}