1

如果 DefaultControllerFactory 已成为 ASP.NET Core 3 中的内部类,如何使用自定义工厂覆盖默认实现 IControllerFactory 并在正常情况下继续调用 DefaultControllerFactory?

services.AddSingleton<IControllerFactory, MyCustomControllerFactory>();
// this class for .NET core 2
public class MyCustomControllerFactory : DefaultControllerFactory
{
    public override object CreateController(ControllerContext context)
    {
        //custom handling...

        //base handling
        return base.CreateController(context);
    }

    public override void ReleaseController(ControllerContext context, object controller)
    {
        base.ReleaseController(context, controller);
    }
}

.NET 5 中的 DefaultControllerFactory 类是内部的,我不能调用它的 CreateController 方法来尝试在 ASP MVC Core 5 环境中注册常规控制器。

//this class for .NET core 3 or .NET 5 
    public class MyCustomControllerFactory : IControllerFactory
    {
        public object CreateController(ControllerContext context)
        {
            if(/*is custom case*/) 
            { 
                /*custom actions*/ 
                return /*custom IController*/ 
            }
            return /*in this place I want calling base.CreateController(context)*/;
        }

        public void ReleaseController(ControllerContext context, object controller)
        {
            var disposable = controller as IDisposable;
            if (disposable != null) { disposable.Dispose(); }
        }
    }
4

1 回答 1

1

我们可以重载 IControllerActivator 或 IControllerFactory。此方法将始终被调用,从而创建控制器。

public class Startup
{
        public void ConfigureServices(IServiceCollection services)
        {
            services.AddControllersWithViews();
            services.AddSingleton<IControllerActivator, CustomControllerActivator>();
            services.AddMvc(options => { });
        }
}

我们仍然可以调用主要的平台函数来创建控制器。我们只需要获取 IControllerActivator 或 IControllerFactory 的所有已注册实例的列表,并从该列表中逐一排除我们的实现,尝试使用此列表中的每一个创建一个控制器。重要的是要了解此实现已尽可能简化,并且如果重新添加到 DI 则可以循环。

    public class CustomControllerActivator : IControllerActivator
    {
        private static object CreateController(IEnumerable<IControllerActivator> activators, ControllerContext context)
        {
            if (activators is null)
            {
                throw new ArgumentNullException(nameof(activators));
            }

            foreach (IControllerActivator activator in activators)
            {
                object controller = activator.Create(context);

                if (controller != default)
                    return controller;
            }

            return default;
        }

        private readonly IServiceProvider _provider;

        private IEnumerable<IControllerActivator> _otherActivators;

        private IEnumerable<IControllerActivator> OtherActivators
        {
            get
            {
                if (_otherActivators == null)
                    _otherActivators = _provider.GetServices<IControllerActivator>()?
                        .Where(o => !object.ReferenceEquals(this, o));

                return _otherActivators;
            }
        }
        
        public CustomControllerActivator(IServiceProvider provider)
        {
            _provider = provider ?? throw new ArgumentNullException(nameof(provider));
        }
        
        public object Create(ControllerContext controllerContext)
        {
            if (controllerContext == null)
            {
                throw new ArgumentNullException(nameof(controllerContext));
            }

            if (controllerContext.ActionDescriptor == null)
            {
                throw new ArgumentException(nameof(controllerContext.ActionDescriptor));
            }

            var controllerTypeInfo = controllerContext.ActionDescriptor.ControllerTypeInfo;

            if (controllerTypeInfo == null)
            {
                throw new ArgumentException(nameof(controllerContext.ActionDescriptor.ControllerTypeInfo));
            }

            if (!IsNeedThisCustomController(controllerContext))
                return CreateController(OtherActivators, controllerContext);

            return CreateCustomController(controllerContext);
        }

        /// <summary>
        /// Do need to create this custom controller
        /// </summary>
        /// <param name="controllerContext"></param>
        /// <returns></returns>
        private bool IsNeedThisCustomController(ControllerContext controllerContext)
        {
            return false;
        }

        /// <summary>
        /// Сreating a custom controller
        /// </summary>
        /// <param name="controllerContext"></param>
        /// <returns></returns>
        private object CreateCustomController(ControllerContext controllerContext)
        {
            return default;
        }
        
        public void Release(ControllerContext context, object controller)
        {
            if (context == null)
            {
                throw new ArgumentNullException(nameof(context));
            }

            if (controller == null)
            {
                throw new ArgumentNullException(nameof(controller));
            }

            if (controller is IDisposable disposable)
            {
                disposable.Dispose();
            }
        }
    }
于 2021-07-15T15:35:46.117 回答