我创建了一个 .NET Core MVC 应用程序并使用依赖注入和存储库模式将存储库注入到我的控制器。但是,我收到一个错误:
InvalidOperationException:尝试激活“WebApplication1.Controllers.BlogController”时无法解析“WebApplication1.Data.BloggerRepository”类型的服务。
模型 (Blog.cs)
namespace WebApplication1.Models
{
public class Blog
{
public int BlogId { get; set; }
public string Url { get; set; }
}
}
DbContext (BloggingContext.cs)
using Microsoft.EntityFrameworkCore;
using WebApplication1.Models;
namespace WebApplication1.Data
{
public class BloggingContext : DbContext
{
public BloggingContext(DbContextOptions<BloggingContext> options)
: base(options)
{ }
public DbSet<Blog> Blogs { get; set; }
}
}
存储库(IBloggerRepository.cs 和 BloggerRepository.cs)
using System;
using System.Collections.Generic;
using WebApplication1.Models;
namespace WebApplication1.Data
{
internal interface IBloggerRepository : IDisposable
{
IEnumerable<Blog> GetBlogs();
void InsertBlog(Blog blog);
void Save();
}
}
using System;
using System.Collections.Generic;
using System.Linq;
using WebApplication1.Models;
namespace WebApplication1.Data
{
public class BloggerRepository : IBloggerRepository
{
private readonly BloggingContext _context;
public BloggerRepository(BloggingContext context)
{
_context = context;
}
public IEnumerable<Blog> GetBlogs()
{
return _context.Blogs.ToList();
}
public void InsertBlog(Blog blog)
{
_context.Blogs.Add(blog);
}
public void Save()
{
_context.SaveChanges();
}
private bool _disposed;
protected virtual void Dispose(bool disposing)
{
if (!_disposed)
{
if (disposing)
{
_context.Dispose();
}
}
_disposed = true;
}
public void Dispose()
{
Dispose(true);
GC.SuppressFinalize(this);
}
}
}
Startup.cs(相关代码)
public void ConfigureServices(IServiceCollection services)
{
// Add framework services.
services.AddDbContext<BloggingContext>(options =>
options.UseSqlServer(Configuration.GetConnectionString("DefaultConnection")));
services.AddScoped<IBloggerRepository, BloggerRepository>();
services.AddMvc();
// Add application services.
services.AddTransient<IEmailSender, AuthMessageSender>();
services.AddTransient<ISmsSender, AuthMessageSender>();
}
控制器 (BlogController.cs)
using System.Linq;
using Microsoft.AspNetCore.Mvc;
using WebApplication1.Data;
using WebApplication1.Models;
namespace WebApplication1.Controllers
{
public class BlogController : Controller
{
private readonly IBloggerRepository _repository;
public BlogController(BloggerRepository repository)
{
_repository = repository;
}
public IActionResult Index()
{
return View(_repository.GetBlogs().ToList());
}
public IActionResult Create()
{
return View();
}
[HttpPost]
[ValidateAntiForgeryToken]
public IActionResult Create(Blog blog)
{
if (ModelState.IsValid)
{
_repository.InsertBlog(blog);
_repository.Save();
return RedirectToAction("Index");
}
return View(blog);
}
}
}
我不确定我做错了什么。有任何想法吗?
要分解错误消息:
尝试激活“WebApplication1.Controllers.BlogController”时无法解析“WebApplication1.Data.BloggerRepository”类型的服务。
也就是说,您的应用程序正在尝试创建 BlogController
的实例,但它不知道如何创建 BloggerRepository
的实例以传递给构造函数。
现在看看你的启动:
services.AddScoped<IBloggerRepository, BloggerRepository>();
也就是说,只要需要 IBloggerRepository
,就创建一个 BloggerRepository
并将其传入。
但是,您的控制器类正在请求具体类 BloggerRepository
,而依赖注入容器在直接请求时不知道该怎么做。
我猜你只是打错了,但一个相当常见的。因此,简单的解决方法是更改您的控制器以接受 DI 容器确实知道如何处理的内容,在这种情况下,接口:
public BlogController(IBloggerRepository repository)
// ^
// Add this!
{
_repository = repository;
}
请注意,某些对象有自己的自定义注册方式,这在您使用外部 Nuget 包时更为常见,因此阅读它们的文档是值得的。例如,如果您收到一条消息说:
无法解析类型“Microsoft.AspNetCore.Http.IHttpContextAccessor”的服务...
然后,您将使用该库提供的 custom extension method 解决该问题,即:
services.AddHttpContextAccessor();
对于其他包 - 始终阅读文档。
我遇到了这个问题,因为在依赖注入设置中,我缺少作为控制器依赖的存储库的依赖:
services.AddScoped<IDependencyOne, DependencyOne>(); <-- I was missing this line!
services.AddScoped<IDependencyTwoThatIsDependentOnDependencyOne, DependencyTwoThatIsDependentOnDependencyOne>();
在我的情况下,我试图对需要构造函数参数的对象进行依赖注入。在这种情况下,在启动期间,我只是提供了配置文件中的参数,例如:
var config = Configuration.GetSection("subservice").Get<SubServiceConfig>();
services.AddScoped<ISubService>(provider => new SubService(config.value1, config.value2));
我遇到了另一个问题,是的,我的控制器的参数化构造函数已经添加了正确的接口。我所做的很简单。我只是转到我的 startup.cs
文件,在那里我可以看到注册方法的调用。
public void ConfigureServices(IServiceCollection services)
{
services.Register();
}
在我的例子中,这个 Register
方法在一个单独的类 Injector
中。所以我不得不在那里添加我新引入的接口。
public static class Injector
{
public static void Register(this IServiceCollection services)
{
services.AddTransient<IUserService, UserService>();
services.AddTransient<IUserDataService, UserDataService>();
}
}
如果你看到了,这个函数的参数是 this IServiceCollection
希望这可以帮助。
services.AddScoped
而不是 services.AddTransient
。
只有当有人和我一样的情况下,我正在使用现有数据库做一个 EntityFramework 教程,但是当在模型文件夹上创建新的数据库上下文时,我们需要在启动时更新上下文,而不仅仅是在服务中。如果您有用户身份验证,则 AddDbContext 但也有 AddIdentity
services.AddDbContext<NewDBContext>(options =>
options.UseSqlServer(Configuration.GetConnectionString("DefaultConnection")));
services.AddIdentity<ApplicationUser, IdentityRole>()
.AddEntityFrameworkStores<NewDBContext>()
.AddDefaultTokenProviders();
您需要在启动时为 DBcontext
添加新服务
默认
services.AddDbContext<ApplicationDbContext>(options =>
options.UseSqlServer(
Configuration.GetConnectionString("DefaultConnection")));
添加这个
services.AddDbContext<NewDBContext>(options =>
options.UseSqlServer(
Configuration.GetConnectionString("NewConnection")));
options => options.UseSqlServer( Configuration.GetConnectionString("NewConnection"))
。只需 services.AddDbContext<NewDBContext>()
即可。
builder.Services.AddDbContext<DbContext>();
将起作用。
Public void ConfigureServices(IServiceCollection services)
{
services.AddScoped<IEventRepository, EventRepository>();
}
您忘记在启动 ConfigureServices
方法中添加“services.AddScoped”。
就我而言,Startup.cs 中的 .Net Core 3.0 API 在方法中
public void ConfigureServices(IServiceCollection services)
我不得不添加
services.AddScoped<IStateService, StateService>();
我必须在 ConfigureServices 中添加这一行才能工作。
services.AddSingleton<IOrderService, OrderService>();
由于一个相当愚蠢的错误,我得到了这个问题。我忘记挂钩我的服务配置过程以在 ASP.NET Core 应用程序中自动发现控制器。
添加此方法解决了它:
// Add framework services.
services.AddMvc()
.AddControllersAsServices(); // <---- Super important
我低于异常
System.InvalidOperationException: Unable to resolve service for type 'System.Func`1[IBlogContext]'
while attempting to activate 'BlogContextFactory'.\r\n at
Microsoft.Extensions.DependencyInjection.ServiceLookup.CallSiteFactory.CreateArgumentCallSites(Type serviceType, Type implementationType, ISet`1 callSiteChain, ParameterInfo[] parameters, Boolean throwIfCallSiteNotFound)\r\n at Microsoft.Extensions.DependencyInjection.ServiceLookup.CallSiteFactory.CreateConstructorCallSite(Type serviceType, Type implementationType, ISet`1 callSiteChain)\r\n at Microsoft.Extensions.DependencyInjection.ServiceLookup.CallSiteFactory.TryCreateExact(ServiceDescriptor descriptor, Type serviceType, ISet`1 callSiteChain)\r\n at Microsoft.Extensions.DependencyInjection.ServiceLookup.CallSiteFactory.TryCreateExact(Type serviceType, ISet`1 callSiteChain)\r\n at Microsoft.Extensions.DependencyInjection.ServiceLookup.CallSiteFactory.CreateCallSite(Type serviceType, ISet`1 callSiteChain)\r\n at Microsoft.Extensions.DependencyInjection.ServiceLookup.CallSiteFactory.CreateArgumentCallSites(Type serviceType, Type implementationType, ISet`1 callSiteChain, ParameterInfo[] parameters, Boolean throwIfCallSiteNotFound)\r\n at Microsoft.Extensions.DependencyInjection.ServiceLookup.CallSiteFactory.CreateConstructorCallSite(Type serviceType, Type implementationType, ISet`1 callSiteChain)\r\n at Microsoft.Extensions.DependencyInjection.ServiceLookup.CallSiteFactory.TryCreateExact(ServiceDescriptor descriptor, Type serviceType, ISet`1 callSiteChain)\r\n at Microsoft.Extensions.DependencyInjection.ServiceLookup.CallSiteFactory.TryCreateExact(Type serviceType, ISet`1 callSiteChain)\r\n at Microsoft.Extensions.DependencyInjection.ServiceLookup.CallSiteFactory.CreateCallSite(Type serviceType, ISet`1 callSiteChain)\r\n at Microsoft.Extensions.DependencyInjection.ServiceProvider.CreateServiceAccessor(Type serviceType, ServiceProvider serviceProvider)\r\n at System.Collections.Concurrent.ConcurrentDictionaryExtensions.GetOrAdd[TKey, TValue, TArg] (ConcurrentDictionary`2 dictionary, TKey key, Func`3 valueFactory, TArg arg)\r\n at Microsoft.Extensions.DependencyInjection.ServiceProvider.GetService(Type serviceType)\r\n at Microsoft.Extensions.Internal.ActivatorUtilities.GetService(IServiceProvider sp, Type type, Type requiredBy, Boolean isDefaultParameterRequired)\r\n at lambda_method(Closure , IServiceProvider , Object[] )\r\n at Microsoft.AspNetCore.Mvc.Controllers.ControllerFactoryProvider.<>c__DisplayClass5_0.<CreateControllerFactory>g__CreateController|0(ControllerContext controllerContext)\r\n at Microsoft.AspNetCore.Mvc.Internal.ControllerActionInvoker.Next(State& next, Scope& scope, Object& state, Boolean& isCompleted)\r\n at Microsoft.AspNetCore.Mvc.Internal.ControllerActionInvoker.InvokeInnerFilterAsync()\r\n at Microsoft.AspNetCore.Mvc.Internal.ResourceInvoker.InvokeNextExceptionFilterAsync()
因为我想注册工厂来创建 DbContext 派生类 IBlogContextFactory 的实例,并使用 Create 方法来实例化博客上下文的实例,这样我就可以使用下面的模式以及依赖注入,也可以使用模拟进行单元测试。
我想使用的模式是
public async Task<List<Blog>> GetBlogsAsync()
{
using (var context = new BloggingContext())
{
return await context.Blogs.ToListAsync();
}
}
但是我想通过构造函数注入工厂而不是 new BloggingContext() ,如下面的 BlogController 类
[Route("blogs/api/v1")]
public class BlogController : ControllerBase
{
IBloggingContextFactory _bloggingContextFactory;
public BlogController(IBloggingContextFactory bloggingContextFactory)
{
_bloggingContextFactory = bloggingContextFactory;
}
[HttpGet("blog/{id}")]
public async Task<Blog> Get(int id)
{
//validation goes here
Blog blog = null;
// Instantiage context only if needed and dispose immediately
using (IBloggingContext context = _bloggingContextFactory.CreateContext())
{
blog = await context.Blogs.FindAsync(id);
}
//Do further processing without need of context.
return blog;
}
}
这是我的服务注册码
services
.AddDbContext<BloggingContext>()
.AddTransient<IBloggingContext, BloggingContext>()
.AddTransient<IBloggingContextFactory, BloggingContextFactory>();
以下是我的模型和工厂课程
public interface IBloggingContext : IDisposable
{
DbSet<Blog> Blogs { get; set; }
DbSet<Post> Posts { get; set; }
}
public class BloggingContext : DbContext, IBloggingContext
{
public DbSet<Blog> Blogs { get; set; }
public DbSet<Post> Posts { get; set; }
protected override void OnConfiguring(DbContextOptionsBuilder optionsBuilder)
{
optionsBuilder.UseInMemoryDatabase("blogging.db");
//optionsBuilder.UseSqlite("Data Source=blogging.db");
}
}
public interface IBloggingContextFactory
{
IBloggingContext CreateContext();
}
public class BloggingContextFactory : IBloggingContextFactory
{
private Func<IBloggingContext> _contextCreator;
public BloggingContextFactory(Func<IBloggingContext> contextCreator)// This is fine with .net and unity, this is treated as factory function, but creating problem in .netcore service provider
{
_contextCreator = contextCreator;
}
public IBloggingContext CreateContext()
{
return _contextCreator();
}
}
public class Blog
{
public Blog()
{
CreatedAt = DateTime.Now;
}
public Blog(int id, string url, string deletedBy) : this()
{
BlogId = id;
Url = url;
DeletedBy = deletedBy;
if (!string.IsNullOrWhiteSpace(deletedBy))
{
DeletedAt = DateTime.Now;
}
}
public int BlogId { get; set; }
public string Url { get; set; }
public DateTime CreatedAt { get; set; }
public DateTime? DeletedAt { get; set; }
public string DeletedBy { get; set; }
public ICollection<Post> Posts { get; set; }
public override string ToString()
{
return $"id:{BlogId} , Url:{Url} , CreatedAt : {CreatedAt}, DeletedBy : {DeletedBy}, DeletedAt: {DeletedAt}";
}
}
public class Post
{
public int PostId { get; set; }
public string Title { get; set; }
public string Content { get; set; }
public int BlogId { get; set; }
public Blog Blog { get; set; }
}
----- 在 .net Core MVC 项目中修复这个问题——我在依赖注册方面做了以下更改
services
.AddDbContext<BloggingContext>()
.AddTransient<IBloggingContext, BloggingContext>()
.AddTransient<IBloggingContextFactory, BloggingContextFactory>(
sp => new BloggingContextFactory( () => sp.GetService<IBloggingContext>())
);
简而言之,.net 核心开发人员负责注入工厂功能,这在 Unity 和 .Net Framework 的情况下得到了处理。
这个问题是因为您没有使用为其编写的接口注册数据访问组件。尝试使用如下
services.AddTransient<IMyDataProvider, MyDataAccess>();`
对我来说,它可以在 ConfigureServices
中添加数据库上下文,如下所示:
services.AddDBContext<DBContextVariable>();
我收到此错误消息,其中将 ILogger 注入到 .NET 5 类中。我需要添加类类型来修复它。
ILogger 记录器 --> ILogger
如果您使用 AutoFac 并收到此错误,则应添加“As”语句来指定具体实现实现的服务。
IE。你应该写:
containerBuilder.RegisterType<DataService>().As<DataService>();
代替
containerBuilder.RegisterType<DataService>();
哦,谢谢@kimbaudi,我跟着这个 tuts
https://dotnettutorials.net/lesson/generic-repository-pattern-csharp-mvc/
并得到与您相同的错误。但是在阅读了您的代码后,我发现我的解决方案正在添加
services.AddScoped(IGenericRepository, GenericRepository);
进入 StartUp.cs 文件中的 ConfigureServices 方法 =))
我遇到了同样的问题,发现我的代码在初始化之前就使用了注入。
services.AddControllers(); // Will cause a problem if you use your IBloggerRepository in there since it's defined after this line.
services.AddScoped<IBloggerRepository, BloggerRepository>();
我知道这与问题无关,但是自从我被发送到此页面后,我发现它对其他人有用。
甚至在到达类代码之前解析服务就完成了,因此我们需要检查我们的依赖注入。
就我而言,我添加了
services.AddScoped<IMeasurementService, MeasurementService>();
在 StartupExtensions.cs
你可能会错过这个:
services.AddScoped<IDependencyTwoThatIsDependentOnDependencyOne, DependencyTwoThatIsDependentOnDependencyOne>();
添加服务。AddSingleton();在项目的 Startup.cs 文件的 ConfigureServices 方法中。
public void ConfigureServices(IServiceCollection services)
{
services.AddRazorPages();
// To register interface with its concrite type
services.AddSingleton<IEmployee, EmployeesMockup>();
}
有关详细信息,请访问此 URL:https://www.youtube.com/watch?v=aMjiiWtfj2M
对于所有方法(即 AddSingleton vs AddScoped vs AddTransient)请访问此 URL:https://www.youtube.com/watch?v=v6Nr7Zman_Y&list=PL6n9fhu94yhVkdrusLaQsfERmL_Jh4XmU&index=44)
我换了
services.Add(new ServiceDescriptor(typeof(IMyLogger), typeof(MyLogger)));
和
services.AddTransient<IMyLogger, MyLogger>();
它对我有用。
遇到同样的问题,我所做的只是在 Startup.cs 中注册我的 DBContext。
问题是您正在调用应用程序尚未注册的 DBContext,因此当您的视图尝试引用它时它不知道该怎么做。
错误消息的关键部分,“尝试激活时”
private readonly SmartPayDBContext _context;
对我有用的解决方案
public void ConfigureServices(IServiceCollection services)
{
services.AddDbContext<ApplicationDbContext>(options =>
options.UseSqlServer(
Configuration.GetConnectionString("DefaultConnection")));
services.AddDbContext<SmartPayDBContext>(options =>
options.UseSqlServer(
Configuration.GetConnectionString("DefaultConnection")));
}
将 BloggerRepository 更改为 IBloggerRepository
我在尝试使用下面的 CreateDefaultBuilder 从我的 Program.cs 文件注入时遇到问题,但最终通过跳过默认活页夹来解决它。 (见下文)。
var host = Host.CreateDefaultBuilder(args)
.ConfigureWebHostDefaults(webBuilder =>
{
webBuilder.ConfigureServices(servicesCollection => { servicesCollection.AddSingleton<ITest>(x => new Test()); });
webBuilder.UseStartup<Startup>();
}).Build();
似乎应该在 ConfigureWebHostDefaults 内部完成构建以使其工作,否则配置将被跳过,但如果我错了,请纠正我。
这种方法效果很好:
var host = new WebHostBuilder()
.ConfigureServices(servicesCollection =>
{
var serviceProvider = servicesCollection.BuildServiceProvider();
IConfiguration configuration = (IConfiguration)serviceProvider.GetService(typeof(IConfiguration));
servicesCollection.AddSingleton<ISendEmailHandler>(new SendEmailHandler(configuration));
})
.UseStartup<Startup>()
.Build();
这也展示了如何从
如果您使用的是 dotnet 5 及以下版本,您还可以检查您是否在服务中注册了存储库。
不确定这是否对其他人有帮助,但我正确地进行了依赖注入,并在尝试访问我的 API 控制器时出现此错误。
在已经将它们添加到我的 startup.cs 类之后,我不得不关闭项目并重新构建 - 出于某种原因,重建让 Visual Studio 能够识别服务类在出现错误之前已正确注册。
不定期副业成功案例分享
HttpContextAccessor
课程时收到了这个,结果我需要IHttpContextAccessor
Startup.cs
中的错误对象。我有services.AddTransient<FooService, FooService>();
而不是services.AddTransient<IFooService, FooService>();
。那些讨厌的字母大声笑。感谢您为我指明正确的方向!