Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

请问Autofac如何接入 #30

Closed
christan-duplicate opened this issue Apr 15, 2019 · 14 comments
Closed

请问Autofac如何接入 #30

christan-duplicate opened this issue Apr 15, 2019 · 14 comments

Comments

@christan-duplicate
Copy link

请问Autofac如何接入

@beetlex-io
Copy link
Owner

@christan-duplicate
组件提供一个控制器创建事件,可以通过事件引用来创建控制器

 mApiServer.ActionFactory.ControllerInstance += (o, e) =>
            {
                //e.Controller
                //e.Type
            };

设置e.Controller属性

@christan-duplicate
Copy link
Author

请问有具体的例子吗?

@beetlex-io
Copy link
Owner

@christan-duplicate
暂有没有,具体操作就是用Autofac根据e.type创建控制器设置到e.Controller上
控制器设置成

[Controller(SingleInstance = false)]

表示每次请求都重新创建控制器

@christan-duplicate
Copy link
Author

如果不设为 [Controller(SingleInstance = false)]
会有影响吗?

@beetlex-io
Copy link
Owner

@christan-duplicate
没有,只是在加载时执行一次初始化为单实例控制器ControllerInstance事件定义必须在Register方法之前

@christan-duplicate
Copy link
Author

christan-duplicate commented Apr 16, 2019

写了个,没加 SingIeInstance = false,暂时没发现问题:

apiServer.ActionFactory.ControllerInstance += (o, e) =>
            {
                var type = e.Type;
                var constructors = type.GetConstructors();
                var parameters = constructors.Max(c => c.GetParameters());
                if (parameters.Length <= 0) return;
                var args = new object[parameters.Length];
                for (var i = 0; i < parameters.Length; i++)
                {
                    if (AutofacContainer.Container.IsRegistered(parameters[i].ParameterType))
                    {
                        args[i] = AutofacContainer.Resolve(parameters[i].ParameterType);
                    }
                    else
                    {
                        args[i] = parameters[i].ParameterType.IsValueType ? Activator.CreateInstance(parameters[i].ParameterType) : null;
                    }
                }
                e.Controller = Activator.CreateInstance(type, args);
            };

@nodyang
Copy link

nodyang commented Jun 15, 2019

AutofacContainer 能否提供下源码

@christan-duplicate
Copy link
Author

christan-duplicate commented Jun 17, 2019

1、AutofacContainer.cs

/// <summary>
    /// Autofac容器
    /// </summary>
    public class AutofacContainer
    {
        public static IContainer Container { get; private set; }

        public static void Set(IContainer c)
        {
            Container = c;
        }

        public static T Resolve<T>()
        {
            if (Container == null) throw new ArgumentNullException(nameof(Container));
            return Container.Resolve<T>();
        }

        public static object Resolve(Type serviceType)
        {
            if (Container == null) throw new ArgumentNullException(nameof(Container));
            return Container.Resolve(serviceType);
        }
    }

2、GenericHostAutofacServiceProviderFactory.cs

internal class GenericHostAutofacServiceProviderFactory : IServiceProviderFactory<ContainerBuilder>
    {
        private readonly AutofacServiceProviderFactory _default;

        public GenericHostAutofacServiceProviderFactory(Action<ContainerBuilder> configure = null)
        {
            _default = new AutofacServiceProviderFactory(configure);
        }

        public ContainerBuilder CreateBuilder(IServiceCollection services)
        {
            var host = services.Last(sd => sd.ServiceType == typeof(IHost) && sd.ImplementationType != null);
            services.Remove(host);
            var newSd = new ServiceDescriptor(host.ImplementationType, host.ImplementationType, host.Lifetime);
            services.Add(newSd);

            var builder = _default.CreateBuilder(services);
            builder.Register(ctx => new HostDecorator((IHost)ctx.Resolve(host.ImplementationType),
                    ctx.Resolve<ILifetimeScope>(), ctx.Resolve<ILogger<Container>>()))
                .As<IHost>().ExternallyOwned();
            return builder;
        }

        public IServiceProvider CreateServiceProvider(ContainerBuilder containerBuilder)
        {
            return _default.CreateServiceProvider(containerBuilder);
        }

        private class HostDecorator : IHost
        {
            private readonly IHost _host;
            private ILifetimeScope _scope;
            private readonly ILogger<Container> _logger;

            public HostDecorator(IHost host, ILifetimeScope scope, ILogger<Container> logger)
            {
                _host = host;
                _scope = scope;
                _logger = logger;
            }

            public void Dispose()
            {
                var scope = Interlocked.CompareExchange(ref _scope, null, null);
                if (scope != null)
                {
                    scope = Interlocked.CompareExchange(ref _scope, null, scope);
                    if (scope != null)
                    {
                        scope.Dispose();
                        _logger.LogInformation("Autofac container disposed");
                    }
                }

            }

            public Task StartAsync(CancellationToken cancellationToken = new CancellationToken())
                => _host.StartAsync(cancellationToken);

            public Task StopAsync(CancellationToken cancellationToken = new CancellationToken())
                => _host.StopAsync(cancellationToken);

            public IServiceProvider Services => _host.Services;
        }
    }

3、AutofacHostBuilderExtensions.cs

public static class AutofacHostBuilderExtensions
    {
        public static IHostBuilder UseAutofac(this IHostBuilder builder, Action<ContainerBuilder> configure = null)
        {
            builder.UseServiceProviderFactory(new GenericHostAutofacServiceProviderFactory(configure));
            
            builder.ConfigureContainer<ContainerBuilder>((_, cb) => cb.RegisterBuildCallback(AutofacContainer.Set));
            return builder;
        }

        public static IHostBuilder ConfigureAutofac(this IHostBuilder builder, Action<HostBuilderContext, ContainerBuilder> configure) => builder.ConfigureContainer(configure);

        public static IHostBuilder ConfigureAutofac(this IHostBuilder builder, Action<ContainerBuilder> configure) => builder.ConfigureAutofac((_, cb) => configure(cb));

        public static IHostBuilder AddAutofacModule<T>(this IHostBuilder builder) where T : IModule => builder.ConfigureAutofac((ctx, cb) =>
        {
            var constructors = typeof(T).GetConstructors();
            var knownTypes = new Dictionary<Type, object>
            {
                [typeof(IConfiguration)] = ctx.Configuration,
                [typeof(IHostingEnvironment)] = ctx.HostingEnvironment,
                [typeof(HostBuilderContext)] = ctx
            };
            var cnt = -1;
            ConstructorInfo constructor = null;
            ParameterInfo[] constrParams = null;
            foreach (var item in constructors)
            {
                var parameters = item.GetParameters();
                if (parameters.Length <= cnt) continue;
                if (!parameters.All(info => knownTypes.ContainsKey(info.ParameterType))) continue;

                cnt = parameters.Length;
                constructor = item;
                constrParams = parameters;
            }

            if (constructor == null)
                throw new DependencyResolutionException(
                    $"Cannot find compatible constructor for module {typeof(T)}, can have parametrized constructor with {nameof(IConfiguration)}, {nameof(IHostingEnvironment)} or/and {nameof(HostBuilderContext)} parameters");

            var args = constrParams.Select(p => knownTypes[p.ParameterType]).ToArray();

            var module = (IModule) constructor.Invoke(args);
            cb.RegisterModule(module);
        });

        public static IHostBuilder AddAutofacModule(this IHostBuilder builder, IModule module) => builder.ConfigureAutofac(cb => cb.RegisterModule(module));

        public static IHostBuilder AddAutofacModule(this IHostBuilder builder, Func<HostBuilderContext, IModule> factory) => builder.ConfigureAutofac((ctx, cb) => cb.RegisterModule(factory(ctx)));

    }

4、AutofacAutoRegisterAttribute.cs

/// <inheritdoc />
    /// <summary>
    /// AutoFac 自动注入属性
    /// </summary>
    public class AutofacAutoRegisterAttribute : Attribute
    {
    }

5、Consoles.cs

class Program
    {
        static void Main(string[] args)
        {
            var builder = new HostBuilder()
                .UseAutofac((cb) =>
                {
                    var assemblies = new[]
                       {
//这里加上你自己的
                                Assembly.Load("My.Domain"),
                                Assembly.Load("My.Service"),
                                Assembly.Load("My.Api.Server.Controllers"),
                                Assembly.Load("My.Api.Server")
                        };
//AutofacAutoRegisterAttribute,这个是我自己写的空Attribute,只有标志这个的才使用
                    cb.RegisterAssemblyTypes(assemblies)
                        .Where(t => t.GetCustomAttribute<AutofacAutoRegisterAttribute>() != null)
                        .AsImplementedInterfaces()
                        .InstancePerLifetimeScope();
                })
                .ConfigureServices((hostContext, services) =>
                {
//这个就是FastHttpApi的HttpServerHosted了。。。
                    services.AddHostedService<HttpServerHosted>();
                });

            builder.Build().Run();
        }
    }

@nodyang
Copy link

nodyang commented Jun 17, 2019

3Q

@nodyang
Copy link

nodyang commented Jul 22, 2019

1、AutofacContainer.cs

/// <summary>
    /// Autofac容器
    /// </summary>
    public class AutofacContainer
    {
        public static IContainer Container { get; private set; }

        public static void Set(IContainer c)
        {
            Container = c;
        }

        public static T Resolve<T>()
        {
            if (Container == null) throw new ArgumentNullException(nameof(Container));
            return Container.Resolve<T>();
        }

        public static object Resolve(Type serviceType)
        {
            if (Container == null) throw new ArgumentNullException(nameof(Container));
            return Container.Resolve(serviceType);
        }
    }

2、GenericHostAutofacServiceProviderFactory.cs

internal class GenericHostAutofacServiceProviderFactory : IServiceProviderFactory<ContainerBuilder>
    {
        private readonly AutofacServiceProviderFactory _default;

        public GenericHostAutofacServiceProviderFactory(Action<ContainerBuilder> configure = null)
        {
            _default = new AutofacServiceProviderFactory(configure);
        }

        public ContainerBuilder CreateBuilder(IServiceCollection services)
        {
            var host = services.Last(sd => sd.ServiceType == typeof(IHost) && sd.ImplementationType != null);
            services.Remove(host);
            var newSd = new ServiceDescriptor(host.ImplementationType, host.ImplementationType, host.Lifetime);
            services.Add(newSd);

            var builder = _default.CreateBuilder(services);
            builder.Register(ctx => new HostDecorator((IHost)ctx.Resolve(host.ImplementationType),
                    ctx.Resolve<ILifetimeScope>(), ctx.Resolve<ILogger<Container>>()))
                .As<IHost>().ExternallyOwned();
            return builder;
        }

        public IServiceProvider CreateServiceProvider(ContainerBuilder containerBuilder)
        {
            return _default.CreateServiceProvider(containerBuilder);
        }

        private class HostDecorator : IHost
        {
            private readonly IHost _host;
            private ILifetimeScope _scope;
            private readonly ILogger<Container> _logger;

            public HostDecorator(IHost host, ILifetimeScope scope, ILogger<Container> logger)
            {
                _host = host;
                _scope = scope;
                _logger = logger;
            }

            public void Dispose()
            {
                var scope = Interlocked.CompareExchange(ref _scope, null, null);
                if (scope != null)
                {
                    scope = Interlocked.CompareExchange(ref _scope, null, scope);
                    if (scope != null)
                    {
                        scope.Dispose();
                        _logger.LogInformation("Autofac container disposed");
                    }
                }

            }

            public Task StartAsync(CancellationToken cancellationToken = new CancellationToken())
                => _host.StartAsync(cancellationToken);

            public Task StopAsync(CancellationToken cancellationToken = new CancellationToken())
                => _host.StopAsync(cancellationToken);

            public IServiceProvider Services => _host.Services;
        }
    }

3、AutofacHostBuilderExtensions.cs

public static class AutofacHostBuilderExtensions
    {
        public static IHostBuilder UseAutofac(this IHostBuilder builder, Action<ContainerBuilder> configure = null)
        {
            builder.UseServiceProviderFactory(new GenericHostAutofacServiceProviderFactory(configure));
            
            builder.ConfigureContainer<ContainerBuilder>((_, cb) => cb.RegisterBuildCallback(AutofacContainer.Set));
            return builder;
        }

        public static IHostBuilder ConfigureAutofac(this IHostBuilder builder, Action<HostBuilderContext, ContainerBuilder> configure) => builder.ConfigureContainer(configure);

        public static IHostBuilder ConfigureAutofac(this IHostBuilder builder, Action<ContainerBuilder> configure) => builder.ConfigureAutofac((_, cb) => configure(cb));

        public static IHostBuilder AddAutofacModule<T>(this IHostBuilder builder) where T : IModule => builder.ConfigureAutofac((ctx, cb) =>
        {
            var constructors = typeof(T).GetConstructors();
            var knownTypes = new Dictionary<Type, object>
            {
                [typeof(IConfiguration)] = ctx.Configuration,
                [typeof(IHostingEnvironment)] = ctx.HostingEnvironment,
                [typeof(HostBuilderContext)] = ctx
            };
            var cnt = -1;
            ConstructorInfo constructor = null;
            ParameterInfo[] constrParams = null;
            foreach (var item in constructors)
            {
                var parameters = item.GetParameters();
                if (parameters.Length <= cnt) continue;
                if (!parameters.All(info => knownTypes.ContainsKey(info.ParameterType))) continue;

                cnt = parameters.Length;
                constructor = item;
                constrParams = parameters;
            }

            if (constructor == null)
                throw new DependencyResolutionException(
                    $"Cannot find compatible constructor for module {typeof(T)}, can have parametrized constructor with {nameof(IConfiguration)}, {nameof(IHostingEnvironment)} or/and {nameof(HostBuilderContext)} parameters");

            var args = constrParams.Select(p => knownTypes[p.ParameterType]).ToArray();

            var module = (IModule) constructor.Invoke(args);
            cb.RegisterModule(module);
        });

        public static IHostBuilder AddAutofacModule(this IHostBuilder builder, IModule module) => builder.ConfigureAutofac(cb => cb.RegisterModule(module));

        public static IHostBuilder AddAutofacModule(this IHostBuilder builder, Func<HostBuilderContext, IModule> factory) => builder.ConfigureAutofac((ctx, cb) => cb.RegisterModule(factory(ctx)));

    }

4、AutofacAutoRegisterAttribute.cs

/// <inheritdoc />
    /// <summary>
    /// AutoFac 自动注入属性
    /// </summary>
    public class AutofacAutoRegisterAttribute : Attribute
    {
    }

5、Consoles.cs

class Program
    {
        static void Main(string[] args)
        {
            var builder = new HostBuilder()
                .UseAutofac((cb) =>
                {
                    var assemblies = new[]
                       {
//这里加上你自己的
                                Assembly.Load("My.Domain"),
                                Assembly.Load("My.Service"),
                                Assembly.Load("My.Api.Server.Controllers"),
                                Assembly.Load("My.Api.Server")
                        };
//AutofacAutoRegisterAttribute,这个是我自己写的空Attribute,只有标志这个的才使用
                    cb.RegisterAssemblyTypes(assemblies)
                        .Where(t => t.GetCustomAttribute<AutofacAutoRegisterAttribute>() != null)
                        .AsImplementedInterfaces()
                        .InstancePerLifetimeScope();
                })
                .ConfigureServices((hostContext, services) =>
                {
//这个就是FastHttpApi的HttpServerHosted了。。。
                    services.AddHostedService<HttpServerHosted>();
                });

            builder.Build().Run();
        }
    }

cb.Register(x =>
new MsSqlContext(AutofacContainer.Container.Resolve<IOptions>().Value
.Mdm))
.Keyed(EnumSqlState.Mdm).InstancePerLifetimeScope()
.OnActivated(x =>
{

            })
            .OnRelease((x) =>
            {
                Console.WriteLine("释放资源"+x.ToString());
                
            });

我的数据库连接池没有释放。等程序关闭的时候 才 Console.WriteLine("释放资源"+x.ToString()); 连接池也满了。大神求指导

@nodyang
Copy link

nodyang commented Jul 22, 2019

image
image
SingleInstance = false

1 Controller SingleInstance = false
2 using (var scope = AutofacContainer.Container.BeginLifetimeScope())
我的连接池在释放 也走了 public void Dispose() 实现。目前来看 比较完美

@nodyang
Copy link

nodyang commented Jul 25, 2019

请问Autofac如何接入
我的类实现了dispose 但就是不释放 但我实现了OnRelease 里面什么也没有干。缺释放了数据库链接池
OnRelease 定义
如果你的组件不实现 IDisposable 但仍然需要在生命周期作用域的结尾完成一些释放工作, 你可以使用 释放生命周期事件.
我一直想不明白 autofac 怎么实现的释放。 求大神demo

@Zq986928835
Copy link

这个提示太有用了
ApiServer.ActionFactory.ControllerInstance

image

上面的IContainer _container是下面传入的
image

我发现控制器默认是单例的,所以要放在
mApiServer.Register(assemblies.ToArray());
之前做ApiServer.ActionFactory.ControllerInstance。否则他不会回调该事件

这里面我是手动做Register的,看下有无批量注入,或者说把另外一个大佬的代码提取一下

@Zq986928835
Copy link

image
开心,基于FastHttpApi在做我的小系统这一步很顺利

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

No branches or pull requests

4 participants