Web サイトから送信されたジョブを処理するジョブ サーバーがあります。Web サイトのアセンブリはパッケージ化され、ジョブの一部としてジョブ サーバーに送信されます (すべてのサテライト リソース アセンブリを含む)。
これらのアセンブリは、ジョブ処理が開始される前に Assembly.Load( byte[] ) を介してロードされます。
ジョブの処理中に、リソース文字列 (つまり、検証メッセージ) のスナップショットを作成するポイントに到達します。検証ルール/メッセージは時間の経過とともに変化する可能性があり、以前に処理されたジョブ/メッセージを表示するために戻ってきた場合、「最新の」リソース文字列を表示したくないため、単にリソース キーを保存することはできません。表示されるジョブ処理時の値が必要です。また、Web サイトのスレッドが実行されている適切なカルチャでメッセージを表示できるように、サポートされている各カルチャのメッセージのスナップショットが必要です。
メッセージの取得を試行するために、Web サイト アセンブリはサポートされているロケールを指定するため、ジョブ サーバーで次のようにして Web サイト アセンブリの ResourceManager を作成します。
var resourceType = Type.GetType( "BTR.Websites.MadHatter.Clients.ABCCorp.Resources.ClientStrings" );
var rm = resourceType != null ? new ResourceManager( resourceType ) : null;
これは正常に機能し、ResourceManager を取得しますが、XElement validationRule と string[] ロケールが指定されている場合、次のコードは「機能しません」:
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() は、読み込まれた Web サイト アセンブリとサテライト アセンブリの両方を示します。
{ABCCorp.ServiceModel, Version=6.0.4497.18334, Culture=neutral, PublicKeyToken=null} System.Reflection.Assembly {System.Reflection.RuntimeAssembly} {ABCCorp.ServiceModel.resources, Version=6.0.4497.18334, Culture=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();
どんな提案でも大歓迎です。
更新: ジョーからの提案に基づいて、これが最終的なコードです。byte[] コンテンツは、Web サイト アセンブリと、存在する場合はすべてのサテライト リソース アセンブリを含む 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;
}