【问题标题】:ASP.NET Core Dependency Injection error: Unable to resolve service for type while attempting to activateASP.NET Core 依赖注入错误:尝试激活时无法解析服务类型
【发布时间】:2017-04-15 11:41:59
【问题描述】:

我创建了一个 .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);
        }
    }
}

我不确定我做错了什么。有什么想法吗?

【问题讨论】:

  • 我知道这是一个老问题,但是......您不应该在服务中处理数据库上下文。 db 上下文由作用域解析器自动释放。如果你在服务中释放它,它可能会在调用同一请求/范围内的下一个服务时被释放。
  • 确保使用 ´services.AddTransient();´ 添加服务(缺少的类)

标签: c# dependency-injection asp.net-core asp.net-core-mvc


【解决方案1】:

我所做的只是在 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")));
    }

【讨论】:

  • 这对现有答案有何影响?
【解决方案2】:

如果您使用的是dotnet 5及以下版本,您还可以检查您是否在服务中注册了存储库。

【讨论】:

    【解决方案3】:

    我收到此错误消息,其中 ILogger注入 到 .NET 5 类中。我需要添加类类型来修复它。

    ILogger 记录器 --> ILogger 记录器

    【讨论】:

      【解决方案4】:

      分解错误信息:

      在尝试激活“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();
      

      对于其他包 - 始终阅读文档。

      【讨论】:

      • 令人惊讶的是,忽略一个字符是多么容易......谢谢!
      • 什么冠军,在使用HttpContextAccessor 课程时收到了这个,结果我需要IHttpContextAccessor
      • 非常恼火,因为我在这上面花了 30 多分钟。Mac 上最差的 VS 给你“donet exit unexpectedly”错误。必须在终端上运行才能得到正确的错误,然后我遇到了这个解决方案。
      • 同样,我无意中激活了Startup.cs 中的错误对象。我有services.AddTransient&lt;FooService, FooService&gt;(); 而不是services.AddTransient&lt;IFooService, FooService&gt;();。那些讨厌的字母大声笑。感谢您为我指明正确的方向!
      • 我只是来这里说 DavidG,你的回答很好地解释了事情。我真的很感激阅读这篇文章,我只是想让你知道!
      【解决方案5】:

      对我来说,在ConfigureServices 中添加数据库上下文是有效的,如下所示:

      services.AddDBContext<DBContextVariable>();
      

      【讨论】:

        【解决方案6】:

        你可能错过了这个:

        services.AddScoped<IDependencyTwoThatIsDependentOnDependencyOne, DependencyTwoThatIsDependentOnDependencyOne>();
        

        【讨论】:

          【解决方案7】:

          我在尝试使用下面的 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();
          

          这也展示了如何在 .net 核心 (IConfiguration) 中从

          注入一个已经预定义的依赖项

          【讨论】:

            【解决方案8】:

            将 BloggerRepository 更改为 IBloggerRepository

            【讨论】:

              【解决方案9】:

              在我的例子中,.Net Core 3.0 API 在 启动.cs, 在方法中

              public void ConfigureServices(IServiceCollection services)
              

              我必须添加

              services.AddScoped<IStateService, StateService>();
              

              【讨论】:

              • 嘿伙计!那是为我做的。我知道在我的情况下是这个修复。
              【解决方案10】:

              我换了

              services.Add(new ServiceDescriptor(typeof(IMyLogger), typeof(MyLogger)));
              

              services.AddTransient<IMyLogger, MyLogger>();
              

              它对我有用。

              【讨论】:

                【解决方案11】:

                解析服务甚至在到达类代码之前就完成了,所以我们需要检查我们的依赖注入。

                就我而言,我添加了

                        services.AddScoped<IMeasurementService, MeasurementService>();
                

                在 StartupExtensions.cs 中

                【讨论】:

                  【解决方案12】:

                  我遇到了同样的问题,发现我的代码在初始化之前就使用了注入。

                  services.AddControllers(); // Will cause a problem if you use your IBloggerRepository in there since it's defined after this line.
                  services.AddScoped<IBloggerRepository, BloggerRepository>();
                  

                  我知道这与问题无关,但自从我被发送到此页面后,我发现它对其他人有用。

                  【讨论】:

                    【解决方案13】:
                    Public void ConfigureServices(IServiceCollection services)
                    {
                        services.AddScoped<IEventRepository, EventRepository>();           
                    }
                    

                    您忘记在启动ConfigureServices 方法中添加“services.AddScoped”。

                    【讨论】:

                      【解决方案14】:

                      在项目的 Startup.cs 文件的 ConfigureServices 方法中添加 services.AddSingleton();

                      public void ConfigureServices(IServiceCollection services)
                          {
                              services.AddRazorPages();
                              // To register interface with its concrite type
                              services.AddSingleton<IEmployee, EmployeesMockup>();
                          }
                      

                      更多详情请访问此网址: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

                      【讨论】:

                        【解决方案15】:

                        我遇到了另一个问题,是的,我的控制器的参数化构造函数已经添加了正确的接口。我所做的很简单。我只是转到我的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

                        希望这会有所帮助。

                        【讨论】:

                        • 这是我忘记添加的。我错过了对服务的 Injector 引用。需要 .AddTransient();谢谢你们!
                        • 太棒了。我的问题是完全忘记在 startup.cs 中注册一个新方法。虽然在我的情况下,services.AddScoped 而不是 services.AddTransient
                        【解决方案16】:

                        哦,谢谢@kimbaudi,我关注了这个 tuts

                        https://dotnettutorials.net/lesson/generic-repository-pattern-csharp-mvc/

                        并得到与您相同的错误。但是在阅读了您的代码后,我发现我的解决方案是添加

                        services.AddScoped(IGenericRepository, GenericRepository);

                        进入 StartUp.cs 文件中的 ConfigureServices 方法 =))

                        【讨论】:

                          【解决方案17】:

                          这个问题是因为您没有使用为其编写的接口注册数据访问组件。尝试如下使用

                          services.AddTransient<IMyDataProvider, MyDataAccess>();`
                          

                          【讨论】:

                            【解决方案18】:

                            我遇到了异常

                                    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()
                            

                            因为我想注册 Factory 来创建 DbContext 派生类 IBlogContextFactory 的实例,并使用 Create 方法来实例化 Blog Context 的实例,这样我就可以使用下面的模式以及依赖注入,也可以使用模拟进行单元测试。

                            我想使用的模式是

                            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 的情况下会处理。

                            【讨论】:

                              【解决方案19】:

                              我必须在 ConfigureServices 中添加这一行才能工作。

                              services.AddSingleton<IOrderService, OrderService>();
                              

                              【讨论】:

                                【解决方案20】:

                                需要在启动时为DBcontext添加新服务

                                默认

                                services.AddDbContext<ApplicationDbContext>(options =>
                                                options.UseSqlServer(
                                                    Configuration.GetConnectionString("DefaultConnection")));
                                

                                添加这个

                                services.AddDbContext<NewDBContext>(options =>
                                                options.UseSqlServer(
                                                    Configuration.GetConnectionString("NewConnection")));
                                

                                【讨论】:

                                • 稍作调整后为我工作。如果有人已经在 DbContext 中配置了 ConnectionString,那么您不需要传递options =&gt; options.UseSqlServer( Configuration.GetConnectionString("NewConnection"))。只需services.AddDbContext&lt;NewDBContext&gt;() 即可。
                                【解决方案21】:

                                我遇到了这个问题,因为在依赖注入设置中我缺少一个存储库的依赖,它是控制器的依赖:

                                services.AddScoped<IDependencyOne, DependencyOne>();    <-- I was missing this line!
                                services.AddScoped<IDependencyTwoThatIsDependentOnDependencyOne, DependencyTwoThatIsDependentOnDependencyOne>();
                                

                                【讨论】:

                                • 解决了我的问题,因为我发现我的服务不在正确的“命名空间”中。
                                【解决方案22】:

                                我遇到这个问题是因为一个相当愚蠢的错误。我忘记在 ASP.NET Core 应用程序中挂钩我的服务配置过程以自动发现控制器。

                                添加这个方法解决了它:

                                // Add framework services.
                                            services.AddMvc()
                                                    .AddControllersAsServices();      // <---- Super important
                                

                                【讨论】:

                                  【解决方案23】:

                                  如果您使用 AutoFac 并收到此错误,则应添加“As”语句来指定具体实现实现的服务。

                                  即。你应该写:

                                  containerBuilder.RegisterType<DataService>().As<DataService>();
                                  

                                  而不是

                                  containerBuilder.RegisterType<DataService>();
                                  

                                  【讨论】:

                                    【解决方案24】:

                                    在我的例子中,我试图对需要构造函数参数的对象进行依赖注入。在这种情况下,在启动期间,我只是提供了配置文件中的参数,例如:

                                    var config = Configuration.GetSection("subservice").Get<SubServiceConfig>();
                                    services.AddScoped<ISubService>(provider => new SubService(config.value1, config.value2));
                                    

                                    【讨论】:

                                      【解决方案25】:

                                      只有遇到和我一样的情况,我正在用现有数据库做EntityFramework的教程,但是当在models文件夹上创建新的数据库上下文时,我们需要在启动时更新上下文,但不仅在 services.AddDbContext 但 AddIdentity 如果你有用户身份验证

                                      services.AddDbContext<NewDBContext>(options =>
                                                      options.UseSqlServer(Configuration.GetConnectionString("DefaultConnection")));
                                      
                                      services.AddIdentity<ApplicationUser, IdentityRole>()
                                                      .AddEntityFrameworkStores<NewDBContext>()
                                                      .AddDefaultTokenProviders();
                                      

                                      【讨论】:

                                        猜你喜欢
                                        • 2019-12-20
                                        • 1970-01-01
                                        • 1970-01-01
                                        • 2023-03-24
                                        • 1970-01-01
                                        相关资源
                                        最近更新 更多