2010-08-23 23 views
30

IBootstrapperTask arabirimini uygulayan türleri bulmak için bir ASP.NET MVC uygulamasında tüm Assemblies'lara bakan bir Bootstrapper'ım var ve bunları kaydeder bir IOC Contrainer. Buradaki fikir, IBootstrapperTasks'ınızı istediğiniz yere yerleştirebilmeniz ve Projelerinizi nasıl düzenlediğinizi düzenlemenizdir. Önyükleyicisi içinASP.NET - AppDomain.CurrentDomain.GetAssemblies() - AppDomain yeniden başlatıldıktan sonra Assemblies eksik

Kodu: benim çözümde AppDomain.CurrentDomain.GetAssemblies() döner tüm Meclisleri (bütün GAC kişinin ama bu beni rahatsız etmez dahil) tam bir yapı sonra

public class Bootstrapper 
{ 
    static Bootstrapper() 
    { 
     Type bootStrapperType = typeof(IBootstrapperTask); 

     IList<Assembly> assemblies = AppDomain.CurrentDomain.GetAssemblies(); 

     List<Type> tasks = new List<Type>(); 

     foreach (Assembly assembly in assemblies) 
     { 
      var types = from t in assembly.GetTypes() 
         where bootStrapperType.IsAssignableFrom(t) 
          && !t.IsInterface && !t.IsAbstract 
         select t; 

      tasks.AddRange(types); 
     } 

     foreach (Type task in tasks) 
     { 
      if (!IocHelper.Container().Kernel.HasComponent(task.FullName)) 
      { 
       IocHelper.Container().AddComponentLifeStyle(
        task.FullName, task, LifestyleType.Transient); 
      } 
     } 
    } 

    public static void Run() 
    { 
     // Get all registered IBootstrapperTasks, call Execute() method 
    } 
} 

.

Ancak AppDomain yeniden başlatılırsa, yoksa 'sıçrama' Web.config dosyası (boşluk ekleyerek ve tasarrufu), statik yapıcı yeniden çalıştırılır ancak AppDomain.CurrentDomain.GetAssemblies() çağrıldığında, Meclisleri en eksik IBootstrapperTask türleri içeren bir tane dahil.

Bu soruna nasıl girebilirim? Sanırım System.IO/bin dizinini kullanabilir ve tüm DLL'leri manuel olarak yükleyebilirim, ancak mümkünse bunu önlemek ister misiniz, yoksa tek yol mu? Buna doğru genel yaklaşımı mı kullanıyorum?

Bu, .NET 4.0 üzerinde çalışan bir ASP.NET MVC 2.0 uygulamasıdır, Visual Studio 2010 Cassini web sunucusundaki yerleşik sorunu ve Windows Server 2008'deki Tümleşik Boru Hattı Modunda IIS7.0 ile bu sorunu yaşıyorum.


Düzenleme: sadece bu rastladım SO ihtiyaç duydukları konum olarak AppDomain sadece Meclisleri yükler diyor Difference between AppDomain.GetAssemblies and BuildManager.GetReferencedAssemblies sonrası (örn o Birliğinden bir yöntemi/sınıf ilk çağrıldığında.). Önyükleyici çok erken çalıştığından, bu nedenle montajların neden AppDomain.CurrentDomain.GetAssemblies()'da eksik olduğunu açıklayacağım sanırım. Ben Bootstrapper örn önce eksik Meclisinden 'şey' bir çağrı yerleştirilir eğer

fark ettim:

public class MvcApplication : System.Web.HttpApplication 
{ 
    protected void Application_Start() 
    { 
     MyApp.MissingAssembly.SomeClass someClass = 
      new MyApp.MissingAssembly.SomeClass(); 

     Bootstrapper.Run(); 
    } 
} 

... o sorunu çözmek gibi görünüyor, ama bir kesmek biraz.

+0

Güzel soru ve cevap:

aşağıdaki benim Montaj bulucu kodunu yeniden kaleme aldık! Size bir blog turu attınız - iyi şeyler yazıyorsunuz. –

cevap

50

ASP.NET MVC 2.0 kaynak kodunu inceledim ve AreaRegistration.RegisterAllAreas();'un nasıl uygulandığını inceledim. Bu satır genellikle, Global.asax Application_Start() yöntemine yerleştirilir ve dahili olarak, tüm Toplantıları AreaRegistration soyut türünü uygulayan türler için tarar. Bu benim peşinde olduğum davranış.

Bu RegisterAllAreas() yeterince MVC o zaman bazı deneyler ve BuildManager.GetReferencedAssemblies (yaptık

:-) benim için yeterince iyi için iyi de eğer BuildManager.GetReferencedAssemblies() bir çağrı yapar) bile bulacaktır görünür adhoc, rasgele DLL dosyaları, Visual Studio çözümündeki herhangi bir projeye referans olmasa bile/bin klasörüne düştü. Dolayısıyla, AppDomain.Current.GetAssemblies()'dan çok daha güvenilir görünüyor.

using System.Collections.Generic; 
using System.Collections.ObjectModel; 
using System.IO; 
using System.Linq; 
using System.Reflection; 
using System.Web; 
using System.Web.Compilation; 

public static class AssemblyLocator 
{ 
    private static readonly ReadOnlyCollection<Assembly> AllAssemblies; 
    private static readonly ReadOnlyCollection<Assembly> BinAssemblies; 

    static AssemblyLocator() 
    { 
     AllAssemblies = new ReadOnlyCollection<Assembly>(
      BuildManager.GetReferencedAssemblies().Cast<Assembly>().ToList()); 

     IList<Assembly> binAssemblies = new List<Assembly>(); 

     string binFolder = HttpRuntime.AppDomainAppPath + "bin\\"; 
     IList<string> dllFiles = Directory.GetFiles(binFolder, "*.dll", 
      SearchOption.TopDirectoryOnly).ToList(); 

     foreach (string dllFile in dllFiles) 
     { 
      AssemblyName assemblyName = AssemblyName.GetAssemblyName(dllFile); 

      Assembly locatedAssembly = AllAssemblies.FirstOrDefault(a => 
       AssemblyName.ReferenceMatchesDefinition(
        a.GetName(), assemblyName)); 

      if (locatedAssembly != null) 
      { 
       binAssemblies.Add(locatedAssembly); 
      } 
     } 

     BinAssemblies = new ReadOnlyCollection<Assembly>(binAssemblies); 
    } 

    public static ReadOnlyCollection<Assembly> GetAssemblies() 
    { 
     return AllAssemblies; 
    } 

    public static ReadOnlyCollection<Assembly> GetBinFolderAssemblies() 
    { 
     return BinAssemblies; 
    } 
} 
+0

Bu problemle karşılaştım ve çözümünüzü kullandım. Oyvermek! Teşekkürler! – ajma

+0

Çok teşekkür ederim! Bu konuda da takıldım. Zamanımı kurtardın. – Azat

1

Kendi sorununuzu çözdüğünüz anlaşılıyor.

Düzenleme: Şahsen, aslında montajları birer birer numaralandırır, yükler ve arabirimi arardım. AppDomain'in yaptıklarından ziyade dosyaları temel alır.

+0

Son kod örneği MyApp.MissingAssembly.SomeClass vs mi demek istiyorsun? Eğer öyleyse, bu gerçekten bir çözüm değil, Bootstrapper.Run() 'dan önce farklı Assemblies'e kukla çağrılar eklemem gerekiyor. –

+0

Sanırım, dosyalardan geçerek onları açıkça yüklemeniz gerektiği anlamına geliyor. Ardından, bir aramaya yüklediğinizin olup olmadığına bağlı olmayacaksınız. –

İlgili konular