Derleme yüklerini çözme
.NET, derleme yükleme üzerinde daha fazla denetim gerektiren uygulamalar için olayı sağlar AppDomain.AssemblyResolve . Uygulamanız bu olayı işleyerek normal yoklama yollarının dışından bir derlemeyi yük bağlamı içine yükleyebilir, yüklenecek birkaç derleme sürümünü seçebilir, dinamik bir derleme yayınlayabilir ve döndürebilir vb. Bu konu, olayı işlemeye AssemblyResolve yönelik rehberlik sağlar.
Not
Derleme yüklerini yalnızca yansıma bağlamında çözümlemek için bunun yerine olayını kullanın AppDomain.ReflectionOnlyAssemblyResolve .
AssemblyResolve olayı nasıl çalışır?
Olay için bir işleyici kaydettiğinizde AssemblyResolve , çalışma zamanı ada göre bir derlemeye bağlanamadığında işleyici çağrılır. Örneğin, kullanıcı kodundan aşağıdaki yöntemleri çağırmak AssemblyResolve olayın tetik edilmesine neden olabilir:
İlk AppDomain.Load bağımsız değişkeni yüklenecek derlemenin görünen adını temsil eden bir dize (yani özelliği tarafından Assembly.FullName döndürülen dize) olan bir yöntem aşırı yüklemesi veya Assembly.Load yöntem aşırı yüklemesi.
İlk AppDomain.Load bağımsız değişkeni yüklenecek derlemeyi tanımlayan bir nesne olan yöntem AssemblyName aşırı yüklemesi veya Assembly.Load yöntem aşırı yüklemesi.
Yöntem Assembly.LoadWithPartialName aşırı yüklemesi.
Başka bir AppDomain.CreateInstance uygulama etki alanında bir nesne örneği oluşturan bir veya AppDomain.CreateInstanceAndUnwrap yöntemi aşırı yüklemesi.
Olay işleyicisi ne yapar?
Olay işleyicisi AssemblyResolve , özelliğinde ResolveEventArgs.Name yüklenecek derlemenin görünen adını alır. İşleyici derleme adını tanımıyorsa (C#), (Visual Basic) Nothing
veya nullptr
(Visual C++) döndürür null
.
İşleyici derleme adını tanırsa, isteği karşılayan bir derlemeyi yükleyip döndürebilir. Aşağıdaki listede bazı örnek senaryolar açıklanmaktadır.
İşleyici derlemenin bir sürümünün konumunu biliyorsa, veya Assembly.LoadFile yöntemini kullanarak derlemeyi Assembly.LoadFrom yükleyebilir ve başarılı olursa yüklenen derlemeyi döndürebilir.
İşleyicinin bayt dizileri olarak depolanan bir derleme veritabanına erişimi varsa, bayt dizisi alan yöntem aşırı yüklemelerinden Assembly.Load birini kullanarak bayt dizisini yükleyebilir.
İşleyici dinamik bir derleme oluşturabilir ve döndürebilir.
Not
İşleyici, derlemeyi yük bağlamı içine, yük bağlamı içine veya bağlam olmadan yüklemelidir. İşleyici, veya yöntemini kullanarak Assembly.ReflectionOnlyLoad derlemeyi yalnızca yansıma bağlamı içine Assembly.ReflectionOnlyLoadFrom yüklerse, olayı tetikleyen AssemblyResolve yük girişimi başarısız olur.
Uygun bir derleme döndürmek olay işleyicisinin sorumluluğundadır. İşleyici, özellik değerini AssemblyName(String) oluşturucuya geçirerek istenen derlemenin ResolveEventArgs.Name görünen adını ayrıştırabilir. .NET Framework 4'le başlayarak işleyici, geçerli isteğin ResolveEventArgs.RequestingAssembly başka bir derlemenin bağımlılığı olup olmadığını belirlemek için özelliğini kullanabilir. Bu bilgiler, bağımlılığı karşılayan bir derlemenin tanımlanmasına yardımcı olabilir.
Olay işleyicisi, derlemenin istenen sürümden farklı bir sürümünü döndürebilir.
Çoğu durumda, işleyici tarafından döndürülen derleme, işleyicinin yüklediği bağlamdan bağımsız olarak yük bağlamında görünür. Örneğin, işleyici bir derlemeyi Assembly.LoadFrom yükten bağlama yüklemek için yöntemini kullanıyorsa, işleyici onu döndürdüğünde derleme yük bağlamında görünür. Ancak, aşağıdaki durumda işleyici onu döndürdüğünde derleme bağlam olmadan görünür:
İşleyici bağlam olmadan bir derleme yükler.
ResolveEventArgs.RequestingAssembly Özelliği null değil.
İstekte bulunan derleme (yani özelliği tarafından ResolveEventArgs.RequestingAssembly döndürülen derleme) bağlam olmadan yüklendi.
Bağlamlar hakkında bilgi için bkz Assembly.LoadFrom(String) . yöntem aşırı yüklemesi.
Aynı derlemenin birden çok sürümü aynı uygulama etki alanına yüklenebilir. Tür atama sorunlarına neden olabileceği için bu uygulama önerilmez. Bkz. Derleme yükleme için en iyi yöntemler.
Olay işleyicisinin yapmaması gerekenler
Olayı işlemeye yönelik AssemblyResolve birincil kural, tanımadığınız bir derlemeyi döndürmeyi denememektir. İşleyiciyi yazarken, olayın tetiklenmesine neden olabilecek derlemeleri bilmeniz gerekir. İşleyiciniz diğer derlemeler için null döndürmelidir.
Önemli
.NET Framework 4'le başlayarak, AssemblyResolve olay uydu derlemeleri için tetiklenir. İşleyici tüm derleme yük isteklerini çözümlemeye çalışırsa, bu değişiklik .NET Framework'ün önceki bir sürümü için yazılmış bir olay işleyicisini etkiler. Tanımadıkları derlemeleri yoksayan olay işleyicileri bu değişiklikten etkilenmez: döndürürler null
ve normal geri dönüş mekanizmaları izlenir.
Bir derlemeyi yüklerken, olay işleyicisi AppDomain.Load olayın özyinelemeli olarak yükseltilmesine neden AssemblyResolve olabilecek veya Assembly.Load yöntemi aşırı yüklemelerinden hiçbirini kullanmamalıdır, çünkü bu bir yığın taşmasına neden olabilir. (Bu konunun önceki bölümlerinde sağlanan listeye bakın.) Tüm olay işleyicileri döndürülene kadar özel durum oluşturmadığından yük isteği için özel durum işleme sağlasanız bile bu durum oluşur. Bu nedenle, aşağıdaki kod bulunamazsa MyAssembly
yığın taşmasıyla sonuçlanır:
using System;
using System.Reflection;
class BadExample
{
static void Main()
{
AppDomain ad = AppDomain.CreateDomain("Test");
ad.AssemblyResolve += MyHandler;
try
{
object obj = ad.CreateInstanceAndUnwrap(
"MyAssembly, version=1.2.3.4, culture=neutral, publicKeyToken=null",
"MyType");
}
catch (Exception ex)
{
Console.WriteLine(ex.Message);
}
}
static Assembly MyHandler(object source, ResolveEventArgs e)
{
Console.WriteLine("Resolving {0}", e.Name);
// DO NOT DO THIS: This causes a StackOverflowException
return Assembly.Load(e.Name);
}
}
/* This example produces output similar to the following:
Resolving MyAssembly, Version=1.2.3.4, Culture=neutral, PublicKeyToken=null
Resolving MyAssembly, Version=1.2.3.4, Culture=neutral, PublicKeyToken=null
...
Resolving MyAssembly, Version=1.2.3.4, Culture=neutral, PublicKeyToken=null
Resolving MyAssembly, Version=1.2.3.4, Culture=neutral, PublicKeyToken=null
Process is terminated due to StackOverflowException.
*/
Imports System.Reflection
Class BadExample
Shared Sub Main()
Dim ad As AppDomain = AppDomain.CreateDomain("Test")
AddHandler ad.AssemblyResolve, AddressOf MyHandler
Try
Dim obj As object = ad.CreateInstanceAndUnwrap(
"MyAssembly, version=1.2.3.4, culture=neutral, publicKeyToken=null",
"MyType")
Catch ex As Exception
Console.WriteLine(ex.Message)
End Try
End Sub
Shared Function MyHandler(ByVal source As Object, _
ByVal e As ResolveEventArgs) As Assembly
Console.WriteLine("Resolving {0}", e.Name)
// DO NOT DO THIS: This causes a StackOverflowException
Return Assembly.Load(e.Name)
End Function
End Class
' This example produces output similar to the following:
'
'Resolving MyAssembly, Version=1.2.3.4, Culture=neutral, PublicKeyToken=null
'Resolving MyAssembly, Version=1.2.3.4, Culture=neutral, PublicKeyToken=null
'...
'Resolving MyAssembly, Version=1.2.3.4, Culture=neutral, PublicKeyToken=null
'Resolving MyAssembly, Version=1.2.3.4, Culture=neutral, PublicKeyToken=null
'
'Process is terminated due to StackOverflowException.
using namespace System;
using namespace System::Reflection;
ref class Example
{
internal:
static Assembly^ MyHandler(Object^ source, ResolveEventArgs^ e)
{
Console::WriteLine("Resolving {0}", e->Name);
// DO NOT DO THIS: This causes a StackOverflowException
return Assembly::Load(e->Name);
}
};
void main()
{
AppDomain^ ad = AppDomain::CreateDomain("Test");
ad->AssemblyResolve += gcnew ResolveEventHandler(&Example::MyHandler);
try
{
Object^ obj = ad->CreateInstanceAndUnwrap(
"MyAssembly, version=1.2.3.4, culture=neutral, publicKeyToken=null",
"MyType");
}
catch (Exception^ ex)
{
Console::WriteLine(ex->Message);
}
}
/* This example produces output similar to the following:
Resolving MyAssembly, Version=1.2.3.4, Culture=neutral, PublicKeyToken=null
Resolving MyAssembly, Version=1.2.3.4, Culture=neutral, PublicKeyToken=null
...
Resolving MyAssembly, Version=1.2.3.4, Culture=neutral, PublicKeyToken=null
Resolving MyAssembly, Version=1.2.3.4, Culture=neutral, PublicKeyToken=null
Process is terminated due to StackOverflowException.
*/
AssemblyResolve'ı işlemenin doğru yolu
Olay işleyicisinden AssemblyResolve derlemeleri çözümlerken, işleyici veya AppDomain.Load yöntemini çağırırsa Assembly.Load sonunda bir StackOverflowException oluşturulur. Bunun yerine, olayı tetiklemediği AssemblyResolve
için veya LoadFrom yöntemlerini kullanınLoadFile.
MyAssembly.dll
Yürütme derlemesinin yakınında, bilinen bir konumda yer aldığını, derlemenin yolu verildiğinde çözümlenebileceğini Assembly.LoadFile
düşünün.
using System;
using System.IO;
using System.Reflection;
class CorrectExample
{
static void Main()
{
AppDomain ad = AppDomain.CreateDomain("Test");
ad.AssemblyResolve += MyHandler;
try
{
object obj = ad.CreateInstanceAndUnwrap(
"MyAssembly, version=1.2.3.4, culture=neutral, publicKeyToken=null",
"MyType");
}
catch (Exception ex)
{
Console.WriteLine(ex.Message);
}
}
static Assembly MyHandler(object source, ResolveEventArgs e)
{
Console.WriteLine("Resolving {0}", e.Name);
var path = Path.GetFullPath("../../MyAssembly.dll");
return Assembly.LoadFile(path);
}
}
Imports System.IO
Imports System.Reflection
Class CorrectExample
Shared Sub Main()
Dim ad As AppDomain = AppDomain.CreateDomain("Test")
AddHandler ad.AssemblyResolve, AddressOf MyHandler
Try
Dim obj As Object = ad.CreateInstanceAndUnwrap(
"MyAssembly, version=1.2.3.4, culture=neutral, publicKeyToken=null",
"MyType")
Catch ex As Exception
Console.WriteLine(ex.Message)
End Try
End Sub
Shared Function MyHandler(ByVal source As Object,
ByVal e As ResolveEventArgs) As Assembly
Console.WriteLine("Resolving {0}", e.Name)
Dim fullPath = Path.GetFullPath("../../MyAssembly.dll")
Return Assembly.LoadFile(fullPath)
End Function
End Class
using namespace System;
using namespace System::IO;
using namespace System::Reflection;
ref class Example
{
internal:
static Assembly^ MyHandler(Object^ source, ResolveEventArgs^ e)
{
Console::WriteLine("Resolving {0}", e->Name);
String^ fullPath = Path::GetFullPath("../../MyAssembly.dll");
return Assembly::LoadFile(fullPath);
}
};
void main()
{
AppDomain^ ad = AppDomain::CreateDomain("Test");
ad->AssemblyResolve += gcnew ResolveEventHandler(&Example::MyHandler);
try
{
Object^ obj = ad->CreateInstanceAndUnwrap(
"MyAssembly, version=1.2.3.4, culture=neutral, publicKeyToken=null",
"MyType");
}
catch (Exception^ ex)
{
Console::WriteLine(ex->Message);
}
}