简体   繁体   English

ASP.Net Core 3.0 依赖注入忽略工厂方法?

[英]ASP.Net Core 3.0 Dependency Injection ignoring Factory Methods?

I recently migrated to ASP.NET Core 3.0 and facing the DI issue while startups... they were working fine for ASP.NET Core 2.2.我最近迁移到 ASP.NET Core 3.0 并在启动时面临 DI 问题......他们在 ASP.NET Core 2.2 上运行良好。 If I use the old WebHostBuilder in ASP.NET CORE 3.0 then I do not see the issues.如果我在 ASP.NET CORE 3.0 中使用旧的 WebHostBuilder,那么我看不到问题。 Not sure is the issues are specific to new HostBuilder in Program.cs or DI has changed in 3.0.不确定问题是否特定于 Program.cs 中的新 HostBuilder 或 DI 在 3.0 中已更改。

Program.cs程序.cs

public class Program
{
    public static IHostBuilder CreateHostBuilder(string[] args) =>
        Host.CreateDefaultBuilder(args)
            .ConfigureWebHostDefaults(webBuilder =>
            {
                webBuilder.UseStartup<Startup>();
            });

    public static void Main(string[] args)
    {
        CreateHostBuilder(args).Build().Run();
    }
}

I have the UniqueRowKeyUserStore class as below.我有如下的UniqueRowKeyUserStore class。 The constructor takes 4 interfaces.构造函数采用 4 个接口。

public class UniqueRowKeyUserStore : UserStore<UniqueRowKeyUser>
{
    public UniqueRowKeyUserStore(IStoreMetadata storeMetadata, ILookupNormalizer dataNormalizer, IDataProtector dataProtector, ILookupSplitter<StorablePartitionRowKeys> defaultMerger) : base(storeMetadata, dataNormalizer, dataProtector, defaultMerger)
        {        }
}

In configure services, I register a scoped service with a factory function在配置服务中,我向工厂 function 注册了范围服务

services.AddScoped<UniqueRowKeyUserStore>(StartupService.NewUserStore);

StartupService.NewUserStore is a factory method that creates an instance of UniqueRowKeyUserStore StartupService.NewUserStore是创建 UniqueRowKeyUserStore 实例的工厂方法

public static UniqueRowKeyUserStore NewUserStore(IServiceProvider arg)
{
return new UniqueRowKeyUserStore(new DefaultMetadata(), new DefaultNormalizer(), new DefaultProtecttor(), new DefaultSplitter());
}

As you can see that I am using the Factory method to create the instance so the expectation is that DI should not complain about IStoreMetadata or other interfaces which are expected in constructor.正如您所看到的,我使用 Factory 方法来创建实例,因此期望DI 不应该抱怨 IStoreMetadata 或构造函数中预期的其他接口。

But I get the error during startup, it does look like the DI in asp.net core 3.0 is ignoring the factory method ?但是我在启动过程中收到错误,它看起来确实像 asp.net 核心 3.0 中的 DI 忽略了工厂方法

InvalidOperationException: Unable to resolve service for type 'IStoreMetadata' while attempting to activate 'UniqueRowKeyUserStore'. InvalidOperationException:尝试激活“UniqueRowKeyUserStore”时无法解析“IStoreMetadata”类型的服务。

I am not sure what I am doing wrong in ASP.NET Core 3.0我不确定我在 ASP.NET Core 3.0 中做错了什么

It may happen if something else injects that same class later (for example, AddIdentity ).如果其他东西稍后注入相同的 class (例如, AddIdentity ),可能会发生这种情况。

I cannot reproduce the problem you are describing and do not have the same classes in my Identity package (I guess you are using an extended one?), so I have to create my own:我无法重现您描述的问题,并且在我的身份 package 中没有相同的类(我猜您使用的是扩展的?),所以我必须创建自己的:

        services.AddScoped<MyUserStore>(sp => new MyUserStore(new DefaultComponent2()));
        services.AddScoped<MyUserStore>(sp => new MyUserStore(new DefaultComponent()));
        services.AddScoped<MyUserStore>();

If I have only the first 2 lines, whenever I request MyUserStore , I get DefaultComponent() .如果我只有前两行,那么每当我请求MyUserStore时,我都会得到DefaultComponent() However, if I add the 3rd line (and I never registered any IComponent ), I get the same error message as you described.但是,如果我添加第 3 行(并且我从未注册任何IComponent ),我会收到与您描述的相同的错误消息。

.AddUserStore<UniqueRowKeyUserStore>() is what is causing the problem right there. .AddUserStore<UniqueRowKeyUserStore>()是导致问题的原因。

/// <summary>
/// Adds an <see cref="IUserStore{TUser}"/> for the <see cref="UserType"/>.
/// </summary>
/// <typeparam name="TStore">The user store type.</typeparam>
/// <returns>The current <see cref="IdentityBuilder"/> instance.</returns>
public virtual IdentityBuilder AddUserStore<TStore>() where TStore : class
    => AddScoped(typeof(IUserStore<>).MakeGenericType(UserType), typeof(TStore));

Source 资源

Note how it is added as IUserStore<>注意它是如何添加为IUserStore<>

So you are correct that it is not calling your registration of your implementation.所以你是正确的,它没有调用你的实现注册。 It is looking for the abstraction.它正在寻找抽象。

Credits to @LukeVo and @Nkosi... the comments helped me debug the issue.感谢@LukeVo 和@Nkosi ......评论帮助我调试了这个问题。 I have no idea why the exact same code worked in asp.net core 2.2 but the DI in asp.net core 3.0 will complain about duplicate registration for service and ignore the factory method.我不知道为什么完全相同的代码在 asp.net 核心 2.2 中工作,但 asp.net 核心 3.0 中的 DI 会抱怨重复注册服务并忽略工厂方法。

I have custom UserStore and UserRoleStore and I use Identity to register as below... I had to remove the .AddUserStore() and .AddUserRoleStore() as I am going to register my cutomer stores with factory method so that I can pass additional data (interfaces IStoreMetaData, ILookupNormalizer etc...)我有自定义 UserStore 和 UserRoleStore 并且我使用 Identity 注册如下...我必须删除.AddUserStore().AddUserRoleStore()因为我要用工厂方法注册我的客户商店,以便我可以传递其他数据(接口 IStoreMetaData、ILookupNormalizer 等...)

services.AddIdentity<UniqueRowKeyUser, UserRole>()
                        .AddRoles<UserRole>()
                        .AddUserManager<UserManager<UniqueRowKeyUser>>()
                        .AddRoleManager<RoleManager<UserRole>>()
                        .AddSignInManager<SignInManager<UniqueRowKeyUser>>()
                        .AddErrorDescriber<TranslatedIdentityErrorDescriptor>()
                        .AddDefaultTokenProviders();

Now for registering the Factory method, the below code will not work as DI is not able to map to the store types registered by AddIdentity as explained above.现在注册 Factory 方法,下面的代码将不起作用,因为 DI 无法 map 到 AddIdentity 注册的存储类型,如上所述。

services.AddScoped<UniqueRowKeyUserStore>(StartupService.NewUserStore);
services.AddScoped<UserRoleStore>(StartupService.NewUserRoleStore);

So I had to change service registration and use IUserStore and IRoleStore with my factory methods and now its working...所以我不得不更改服务注册并使用 IUserStore 和 IRoleStore与我的工厂方法,现在它的工作......

 services.AddScoped<IUserStore<UniqueRowKeyUser>, UniqueRowKeyUserStore>(StartupService.NewUserStore);
 services.AddScoped<IRoleStore<UserRole>, UserRoleStore>(StartupService.NewUserRoleStore);

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM