abpframework / abp

Open-source web application framework for ASP.NET Core! Offers an opinionated architecture to build enterprise software solutions with best practices on top of the .NET. Provides the fundamental infrastructure, cross-cutting-concern implementations, startup templates, application modules, UI themes, tooling and documentation.
https://abp.io
GNU Lesser General Public License v3.0
12.76k stars 3.41k forks source link

Dependency injection in custom ABP app fail #18867

Open iddelacruz opened 7 months ago

iddelacruz commented 7 months ago

Is there an existing issue for this?

Description

Hello everyone, I am writing because I am having a problem with dependency injection but not only with this version 8 of ABP, I have had the same incident with version 7 and 6.

Context:

[DependsOn(typeof(AbpDddDomainModule))]
[DependsOn(typeof(AbpAutofacModule))]
public class KernelModule : AbpModule
{

    public override void ConfigureServices(ServiceConfigurationContext context)
    {
        context.Services.AddScoped<Telegram>();
        context.Services.AddTransient<ISentimentProvider, SentimentProvider>();
        context.Services.AddSingleton<IChatGroupCollector, ChatGroupCollector>();
        context.Services.AddTransient<IMessageProvider, MessageProvider>();
        context.Services.AddTransient<ISupervisedChatGroupProvider, SupervisedChatGroupProvider>();

        //local event handlers
        context.Services.AddTransient<ILocalEventHandler<CreateMessageCommand>, CreateOrUpdateMessageCommandHandler>();
        context.Services.AddTransient<ILocalEventHandler<UpdateMessageCommand>, CreateOrUpdateMessageCommandHandler>();

        var config = context.Services.GetConfiguration();

        var section = config.GetSection("xx");

        if (section != null)
            Configure<ApiOptions>(section);
        else
            // ReSharper disable once HeuristicUnreachableCode
            throw new InvalidOperationException("Client section not found.");

        context.Services.AddSingleton(provider =>
        {
            var options = provider.GetRequiredService<IOptions<ApiOptions>>().Value;
            return new Client(options.Config);
        });
    }
}

Why I am having issues with Autofac? reading your doc you remarks that we need to have installed autofac in all modules we want to use it. I have the module installed an loaded in all modules and I continue having the problem.

Reproduction Steps

Expected behavior

I want to get registered all the event handlers and use it in CQRS architecture.

Actual behavior

Local event handlers are never registered by ABP dependency injection system

Regression?

No response

Known Workarounds

No response

Version

8 but I am having this issue in version 7 and 6

User Interface

Common (Default)

Database Provider

None/Others

Tiered or separate authentication server

Separate Auth Server

Operation System

macOS

Other information

No response

EngincanV commented 7 months ago

Hi, did you call the UseAutofac() method in the Program.cs file as described in the documentation?

iddelacruz commented 7 months ago

Hi, yes this is the program:


public static async Task<int> Main(string[] args)
    {
        Log.Logger = new LoggerConfiguration()
#if DEBUG
            .MinimumLevel.Debug()
#else
            .MinimumLevel.Information()
#endif
            .MinimumLevel.Override("Microsoft", LogEventLevel.Information)
            .Enrich.FromLogContext()
            .WriteTo.Async(c => c.File("Logs/logs.txt"))
            .WriteTo.Async(x => x.Console())
            .CreateLogger();

        try
        {
            Log.Information("Starting chat group collector...");
            var builder = WebApplication.CreateBuilder(args);

            builder.Host.AddAppSettingsSecretsJson()
                .UseAutofac()
                .UseSerilog();

            await builder.AddApplicationAsync<EyeModule>();
            var app = builder.Build();
            await app.InitializeApplicationAsync();

            Log.Information("Chat group collector started...");

            await app.RunAsync();
            return 0;
        }
        catch (Exception ex)
        {
            if (ex is HostAbortedException)
            {
                throw;
            }

            Log.Fatal(ex, "Host terminated unexpectedly!");
            return 1;
        }
        finally
        {
            await Log.CloseAndFlushAsync();
        }
    }```
iddelacruz commented 7 months ago

Since it is not being registered through interfaces or attributes, this method apparently is not taking it, so it cannot subscribe to the events. Can be?

iddelacruz commented 7 months ago

I found something: I have the command handler:

CreateMessageCommandHandler:ILocalEventHandler<CreateMessageCommand>, ITransientDependency

If I use only ITransientDependency the command handler is never registered. And if I register the command handler: context.Services.AddTransient<ILocalEventHandler<ICreateOrUpdateCommand>, CreateOrUpdateMessageCommandHandler>(); without the ITransientDependency the handler is registered but when I need to send an event the system not found the command handler and throw an exception:

[ERR] The requested service 'Kernel.Commands.CreateOrUpdateMessageCommandHandler' has not been registered. To avoid this exception, either register a component to provide the service, check for service registration using IsRegistered(), or use the ResolveOptional() method to resolve an optional dependency.

Then I need classic registration and the interface to put the handler ready for working. How can I fix this problem with autofac to register only using interfaces or attributes