我有以下SampleData
类,可以在运行EF Migration
之后生成一些用户数据。
namespace App.Models
{
public interface ISampleData
{
void Initialize();
}
public class SampleData: ISampleData
{
private readonly AppDbContext _context;
private readonly UserManager<ApplicationUser> _userManager;
private readonly RoleManager<IdentityRole> _roleManager;
public SampleData(
AppDbContext context,
UserManager<ApplicationUser> userManager,
RoleManager<IdentityRole> roleManager
)
{
_context = context;
_userManager = userManager;
_roleManager = roleManager;
}
public void Initialize()
{
ApplicationUser user;
IdentityRole myrole = _roleManager.FindByNameAsync("Admin").Result;
if (myrole != null) return;
IdentityResult result = _roleManager.CreateAsync(new IdentityRole { Name = "Admin", NormalizedName = "Admin".ToUpper() }).Result;
string userId1 = Guid.NewGuid().ToString();
if (result.Succeeded)
{
user = new ApplicationUser
{
Id = userId1.ToString(),
UserName = "erkanererkaner@gmail.com",
Email = "erkanererkaner@gmail.com",
FirstName = "Erkan",
LastName = "Er"
};
result = _userManager.CreateAsync(user, "123456Aa*").Result;
if (result.Succeeded) _userManager.AddToRoleAsync(user, "Admin").Wait();
}
}
}
}
从Initialize()
文件中调用Startup
方法,如下所示:
public class Startup
{
private readonly ISampleData _sampleData;
public Startup(IConfiguration configuration, ISampleData sampleData)
{
_sampleData = sampleData;
Configuration = configuration;
}
public void ConfigureServices(IServiceCollection services)
{
//other implementation details
services.AddScoped<ISampleData, SampleData>();
}
}
public void Configure(IApplicationBuilder app, IHostingEnvironment env, IServiceProvider services)
{
//other implementation details
_sampleData.Initialize();
}
但是,出现以下错误:
通过IWebHost访问器使用应用程序服务提供商 '程序'。 System.InvalidOperationException:无法解析服务 尝试激活时输入“ App.Models.ISampleData”类型 'App.Startup'。在 Microsoft.Extensions.DependencyInjection.ActivatorUtilities.ConstructorMatcher.CreateInstance(IServiceProvider 提供者)
我看到这与我实现Dependency Injection
的方式有关。但是我看不到问题。有什么想法吗?
答案 0 :(得分:2)
您不能在启动构造函数中注入IConfiguration
和IHostingEnvironment
以外的类型。原因是Startup类实际上首先配置了依赖项注入容器(通过ConfigureServices
方法)。因此,在您要解析依赖关系(在构造函数中)时,整个DI基础结构甚至还不存在。
相反,您可以在Configure
方法中最早解析服务,该方法在创建依赖项注入容器后称为 。实际上,您可以直接在方法签名中添加依赖项,以使其自动解决:
public void Configure(IApplicationBuilder app, IHostingEnvironment env, ISampleData sampleData)
{
// …
sampleData.Initialize();
}
请注意,对于播种数据库,通常不建议在Configure
方法内进行此操作,因为该方法可能会在您尚未播种数据库的情况下运行(例如,当您进行集成测试,或在命令行中调用dotnet ef
时。
相反,建议的用于播种数据库的模式是在“启动”之外但在Web主机级别进行。因此,在您的Program
类中,您可以像这样修改它:
public class Program
{
public static void Main(string[] args)
{
// create web host
var host = CreateWebHostBuilder(args).Build();
// create service scope for seeding the database
using (var scope = host.Services.CreateScope())
{
// retrieve the sample data service
var sampleData = scope.ServiceProvider.GetRequiredService<ISampleData>();
// run your sample data initialization
_sampleData.Initialize();
}
// run the application
host.Run();
}
public static IWebHostBuilder CreateWebHostBuilder(string[] args)
=> WebHost.CreateDefaultBuilder(args)
.UseStartup<Startup>();
}
答案 1 :(得分:1)
使用ASP.NET Core 2+,您可以通过在Startup
解析之前使用ConfigureServices
上的IWebHostBuilder
方法向您的Startup
类中注入自定义类型来注册服务及其依赖性。
唯一的警告是确保您的类型也已经注册的所有依赖项,在这种情况下,因为这些依赖项是通过AddMvc
方法添加的,因此不太可能。
这只是表明它可以完成。
具有以下自定义类型
public interface IMyCustomType
{
void DoSomethingCustom();
}
public class MyCustomType : IMyCustomType
{
public void DoSomethingCustom()
{
throw new Exception("Custom stuff happens here");
}
}
您可以在Program
实例化和配置的WebHostBuilder
类中进行注册。
public class Program
{
public static void Main(string[] args)
{
CreateWebHostBuilder(args).Build().Run();
}
public static IWebHostBuilder CreateWebHostBuilder(string[] args) =>
WebHost.CreateDefaultBuilder(args)
.ConfigureServices(services => services.AddScoped<IMyCustomType, MyCustomType>())
.UseStartup<Startup>();
}
在此之后,您的Startup
与现在的情况相同或相似-除非您不在此处的ConfigureServices
中进行注册。
public class Startup
{
private readonly IMyCustomType myCustomType;
public Startup(IConfiguration configuration, IMyCustomType myCustomType)
{
Configuration = configuration;
this.myCustomType = myCustomType;
}
public IConfiguration Configuration { get; }
// This method gets called by the runtime. Use this method to add services to the container.
public void ConfigureServices(IServiceCollection services)
{
services.AddMvc().SetCompatibilityVersion(CompatibilityVersion.Version_2_2);
}
// This method gets called by the runtime. Use this method to configure the HTTP request pipeline.
public void Configure(IApplicationBuilder app, IHostingEnvironment env)
{
if (env.IsDevelopment())
{
app.UseDeveloperExceptionPage();
}
myCustomType.DoSomethingCustom();
app.UseMvc();
}
}