【问题标题】:Resolving controllers using Castle Windsor with dynamically loaded DLLs使用 Castle Windsor 和动态加载的 DLL 解析控制器
【发布时间】:2016-05-18 07:13:47
【问题描述】:

加载 Web 应用程序后,Castle Windsor 找不到控制器。找不到路径“”的控制器或未实现 IController。当我查看内核(在 CustomControllerFactory 中)时,我看到所有控制器都已正确注册。

主 MVC 应用程序加载 3 个其他 DLL。当我们在 Visual Studio 中直接引用 DLL 并加载它正在工作的插件类型时。但是当动态加载它时,它说失败。当我请求 URL 时,传递给 GetControllerInstance 的上下文是正确的,但 Type 参数为空。

我正在使用 Assembload.LoadFrom 加载程序集。然后我检索 Types foreach 模块,它是 Plugin 的子类。这导致我有 3 种类型。

Assembly assembly = Assembly.LoadFrom(module);

Type pluginType = assembly.GetTypes()
                    .Single(x => x.IsSubclassOf(typeof(Plugin)));

然后我创建一个插件实例,用于注册路由。

(IPlugin)Activator.CreateInstance(type))

注册路由:

    public static void RegisterRoutes(RouteCollection routes, IEnumerable<IPlugin> plugins)
    {
        routes.IgnoreRoute("{resource}.axd/{*pathInfo}");

        var pluginRouteDefaults = new {action = "Index", id = UrlParameter.Optional};
        foreach (var plugin in plugins)
        {
            var context = new AreaRegistrationContext(plugin.Area, routes);
            context.MapRoute(plugin.Area, $"{plugin.Area}/{{controller}}/{{action}}/{{id}}", pluginRouteDefaults, plugin.GetControllerNamespaces().ToArray());
        }

        routes.MapRoute(
              name: "Default",
              url: "{area}/{controller}/{action}/{id}",
              defaults: new { area = "Framework", controller = "Home", action = "Index", id = UrlParameter.Optional },
              namespaces: new string[] { "Web.Framework.Controllers" }
              );
    }

自定义控制器工厂:

public class CustomControllerFactory : DefaultControllerFactory
{
    private readonly IKernel _kernel;

    public VlcControllerFactory(IKernel kernel)
    {
        this._kernel = kernel;
    }

    public override void ReleaseController(IController controller)
    {
        _kernel.ReleaseComponent(controller);
    }

    protected override IController GetControllerInstance(RequestContext context, Type controllerType)
    {
        if (controllerType == null)
        {
            return base.GetControllerInstance(context, controllerType);
        }
        try
        {
            return (IController)_kernel.Resolve(controllerType);
        }
        catch
        {
            return base.GetControllerInstance(context, controllerType);
        }
    }
}

注册控制器。完成此操作后,我可以看到在 Visual Studio 的“模块”窗口中加载了 DLL。 AppDomain.CurrentDomain.GetAssemblies() 还表示已加载 DLL。

container.Register(
            Classes.FromThisAssembly().BasedOn<IController>().LifestyleTransient());

我找到 Dll 的 MvcApplication 类。

public class MvcApplication : System.Web.HttpApplication
{
    protected void Application_Start()
    {
        var directories = Directory.GetDirectories("C:\Projects\main\modules").Where(x => !x.EndsWith("Framework"));
        string subPath = GetSubPath();

        List<Type> pluginTypes = GetPluginTypes(directories, subPath);
        var plugins = GetIPlugins(pluginTypes);
        Launcher.CreateWindsorContainer(plugins.ToArray());
    }

    private static List<IPlugin> GetIPlugins(List<Type> pluginTypes)
    {
        List<IPlugin> plugins = new List<IPlugin>{new MvcInstaller()};

        pluginTypes.ForEach(type => plugins.Add((IPlugin) Activator.CreateInstance(type)));
        return plugins;
    }

    private static List<Type> GetPluginTypes(IEnumerable<string> directories, string subPath)
    {
        List<Type> pluginTypes = new List<Type>();

        foreach (string directory in directories)
        {
            string module = Directory.GetFiles(directory + subPath).SingleOrDefault(x => x.EndsWith("Plugin.dll"));

            if (!string.IsNullOrEmpty(module))
            {
                Assembly assembly = Assembly.LoadFrom(module);
                Type pluginType = assembly.GetTypes()
                    .Single(x => x.IsSubclassOf(typeof(Plugin)));
                pluginTypes.Add(pluginType);
            }
        }
        return pluginTypes;
    }

    private static string GetSubPath()
    {
        #if DEBUG
        var subPath = @"\bin\Debug\";
        #else
        subPath = @"\bin\Release\";
        #endif

        return subPath;
    }
}

当我省略此代码并直接引用其他 Dll 并执行以下操作时:

Launcher.CreateWindsorContainer(new PluginA(), new PluginB(), new MVCPlugin());

然后它可以完美运行,但是在我加载 Dll 时,控制器的解析失败了。为什么Castle Windsor 请求Controller 时找不到Types?

【问题讨论】:

  • 如何在 Windsor 中注册组件?
  • 编辑了我的问题。在调试该行时,我可以看到控制器已添加并且可以解决。
  • 你的自定义GetControllerInstance被调用了吗?
  • 是的,但是当它被调用时,controllerType 为空。我可以在上下文中看到正在请求正确的区域/控制器/视图。

标签: c# asp.net-mvc dll castle-windsor


【解决方案1】:

这里的问题不在于控制器的温莎分辨率。 DefaultControllerType.GetControllerType() 方法可能返回null,因为您没有将程序集添加到BuildManager(使用BuildManager.AddReferencedAssembly(assembly))。请记住,您只能在应用程序启动之前调用它,因此您需要使用[assembly:PreApplicationStartupMethod(typeof(...SomeType), "PublicStaticVoidMethodOnSomeType")

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 2011-09-03
    • 2012-06-06
    • 2016-02-26
    • 1970-01-01
    • 1970-01-01
    • 2017-02-13
    • 2011-12-17
    相关资源
    最近更新 更多