2

我正在查看 ASP.NET MVC 4 RC,但找不到 DefaultHttpControllerFactory 甚至 IHttpControllerFactory 以允许我选择的 IoC 容器(Castle Windsor)挂接到 Web Api 控制器的框架中。我最终使用了 IDependencyResolver,这使得发布组件有点棘手,但最终得到了以下结果。在 IDependencyResolver 具有 Release 方法之前,它会起作用/不会发生内存泄漏吗?Global.asax 最终为:

public class WebApiApplication : System.Web.HttpApplication
{
    private IWindsorContainer container;

    protected void Application_Start()
    {
        AreaRegistration.RegisterAllAreas();

        FilterConfig.RegisterGlobalFilters(GlobalFilters.Filters);
        RouteConfig.RegisterRoutes(RouteTable.Routes);
        BundleConfig.RegisterBundles(BundleTable.Bundles);

        Windsor();
    }

    protected void Application_End()
    {
        container.Dispose();
    }

    private void Windsor()
    {
        container = new WindsorContainer().Install(FromAssembly.This());

        // mvc:
        var mvcControllerFactory = new WindsorControllerFactory(container.Kernel);
        ControllerBuilder.Current.SetControllerFactory(mvcControllerFactory);

        // web api:
        var httpDependencyResolver = new WindsorHttpDependencyResolver(container.Kernel);
        GlobalConfiguration.Configuration.DependencyResolver = httpDependencyResolver;
    }
}

WindsorControllerFactory 是 Mvc 控制器的 DefaultControllerFactory 的扩展,并且有一个 Windsor 安装程序。WindsorHttpDependencyResolver 最终结果为:

public class WindsorHttpDependencyResolver : System.Web.Http.Dependencies.IDependencyResolver
{
    private readonly IKernel kernel;

    public WindsorHttpDependencyResolver(IKernel kernel)
    {
        this.kernel = kernel;
    }

    public IDependencyScope BeginScope()
    {
        return kernel.Resolve<IDependencyScope>(); // instances released suitably (at end of web request)
    }

    public object GetService(Type serviceType)
    {
        // for ModelMetadataProvider and other MVC related types that may have been added to the container
        // check the lifecycle of these registrations
        return kernel.HasComponent(serviceType) ? kernel.Resolve(serviceType) : null;
    }

    public IEnumerable<object> GetServices(Type serviceType)
    {
        return kernel.HasComponent(serviceType) ? kernel.ResolveAll(serviceType) as IEnumerable<object> : Enumerable.Empty<object>();
    }

    public void Dispose()
    {
       // Nothing created so nothing to dispose - kernel will take care of its own
    }
}

从理论上讲,这意味着 Windsor 现在将在安装 Api 控制器后提供它们:

public class ApiControllersInstaller : IWindsorInstaller
{
    public void Install(IWindsorContainer container, IConfigurationStore store)
    {
        container.AddFacility<TypedFactoryFacility>();
        container.Register(Component.For<ITypedFactoryComponentSelector>().ImplementedBy<WebApiTypedFactoryComponentSelector>());
        container.Register(Component.For<IDependencyScope>().AsFactory(tfc => tfc.SelectedWith<WebApiTypedFactoryComponentSelector>()).LifestylePerWebRequest());

        container.Register(Classes.FromAssemblyContaining<ValuesController>().BasedOn<IHttpController>().LifestyleTransient());
    }
}

我正在使用类型化工厂工具为我实现 IDependencyScope,这意味着当框架在请求结束时处理它时,它将隐式释放控制器及其依赖项。通过使用 Per Web Request 生命周期,Windsor 也将释放工厂本身。这只是留下了自定义类型化工厂组件选择器,因为 GetService(s) 不会在容器中找到任何东西:

public class WebApiTypedFactoryComponentSelector : DefaultTypedFactoryComponentSelector
{
    protected override string GetComponentName(System.Reflection.MethodInfo method, object[] arguments)
    {
        if (method.Name == "GetService" || method.Name == "GetServices")
        {
            return (arguments[0] as Type).FullName;
        }
        return base.GetComponentName(method, arguments);
    }

    protected override Type GetComponentType(System.Reflection.MethodInfo method, object[] arguments)
    {
        if (method.Name == "GetService" || method.Name == "GetServices")
        {
            return arguments[0] as Type;
        }
        return base.GetComponentType(method, arguments);
    }
}

希望这是有用的。

4

1 回答 1

3

我最终使用了这篇博客文章中的代码(由 Mark Seemann 的一篇文章进一步增强),它为每个请求创建一个范围并负责释放创建的对象。这与您采用的方法略有不同。

于 2012-07-31T10:52:57.997 回答