У меня есть Bootstrapper, который просматривает все сборки в приложении ASP.NET MVC для поиска типов, реализующих интерфейс IBootstrapperTask
, а затем регистрирует их с помощью IOC Contrainer. Идея состоит в том, что вы можете буквально разместить свои объекты IBootstrapperTasks в любом месте и организовать свои проекты, как вам нравится.
Код для Bootstrapper:
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
}
}
После полной сборки AppDomain.CurrentDomain.GetAssemblies()
возвращает все сборки в моем решении (включая все GAC, но это меня не беспокоит).
Однако, если AppDomain перезагружается или я отказываюсь от файла Web.Config(добавляя пробел и сохранение), статический конструктор запускается снова, но когда вызывается AppDomain.CurrentDomain.GetAssemblies()
, большинство сборок отсутствуют, включая те, которые содержат мои типы IBootstrapperTask.
Как мне обойти эту проблему? Думаю, я мог бы использовать каталог System.IO в каталоге /bin и загружать все библиотеки DLL там вручную, но предпочел бы избежать этого, если это возможно, или это единственный способ? Я принимаю правильный общий подход к этому?
Это приложение ASP.NET MVC 2.0, работающее на .NET 4.0, я получаю эту проблему со встроенным веб-сервером Visual Studio 2010 Cassini и с IIS7.0 в режиме Integrated Pipeline Mode на Windows Server 2008.
Изменить: Я только что наткнулся на эту публикацию SO после Разница между AppDomain.GetAssemblies и BuildManager.GetReferencedAssemblies, в которой говорится, что AppDomain загружает только сборки поскольку они необходимы (например, когда сначала вызывается метод/класс из этой Ассамблеи). Я предполагаю, что это объясняет, почему Ассамблей не хватает на AppDomain.CurrentDomain.GetAssemblies()
, поскольку Bootstrapper запускается очень рано.
Я заметил, что если я поместил вызов "что-то" из отсутствующей сборки перед Bootstrapper, например:
public class MvcApplication : System.Web.HttpApplication
{
protected void Application_Start()
{
MyApp.MissingAssembly.SomeClass someClass =
new MyApp.MissingAssembly.SomeClass();
Bootstrapper.Run();
}
}
... похоже, проблема устранена, но это немного взломан.