0

我们有一个作业服务器来处理从网站提交的作业。网站的程序集被打包并作为作业的一部分提交到作业服务器(包括所有附属资源程序集)。

这些程序集在作业处理开始之前通过: 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;
}
4

1 回答 1

0

这听起来像是一个程序集解析问题。使用 Load(byte[]) 和 LoadFile,您最终没有绑定上下文。总之,要么使用LoadFrom,要么处理AppDomain的AssemblyResolve事件来处理。

请注意,LINQPad 处理 AssemblyResolve 事件以解决由间接引用不同位置的相同 DLL 引起的问题。这样做的一个副作用是,它在绑定可能失败的情况下融合了绑定上下文,从而使原本可能无法正常工作的事情发生。

于 2012-04-25T01:18:23.773 回答