J'ai créé une application .NET Core MVC et j'utilise Dependency Injection and Repository Pattern pour injecter un référentiel dans mon contrôleur. Cependant, j'obtiens une erreur:
InvalidOperationException: impossible de résoudre le service pour le type «WebApplication1.Data.BloggerRepository» lors de la tentative d'activation de «WebApplication1.Controllers.BlogController».
Modèle (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; }
}
}
Référentiel (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 (code pertinent)
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>();
}
Contrôleur (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);
}
}
}
Je ne suis pas sûr de ce que je fais de mal. Des idées?
Réponses:
L'exception indique qu'il ne peut pas résoudre le service
WebApplication1.Data.BloggerRepository
car le constructeur de votre contrôleur demande la classe concrète au lieu de l'interface. Alors changez simplement cela:public BlogController(IBloggerRepository repository) // ^ // Add this! { _repository = repository; }
la source
HttpContextAccessor
classe, il s'avère que j'avais besoin duIHttpContextAccessor
J'ai rencontré ce problème car dans la configuration d'injection de dépendance, il me manquait une dépendance d'un référentiel qui est une dépendance d'un contrôleur:
services.AddScoped<IDependencyOne, DependencyOne>(); <-- I was missing this line! services.AddScoped<IDependencyTwoThatIsDependentOnDependencyOne, DependencyTwoThatIsDependentOnDependencyOne>();
la source
Dans mon cas, j'essayais de faire une injection de dépendance pour un objet nécessitant des arguments de constructeur. Dans ce cas, au démarrage, je viens de fournir les arguments du fichier de configuration, par exemple:
var config = Configuration.GetSection("subservice").Get<SubServiceConfig>(); services.AddScoped<ISubService>(provider => new SubService(config.value1, config.value2));
la source
J'avais un problème différent, et oui, le constructeur paramétré pour mon contrôleur a déjà été ajouté avec la bonne interface. Ce que j'ai fait était quelque chose de simple. Je vais juste à mon
startup.cs
dossier, où je pourrais voir un appel à la méthode d'enregistrement.public void ConfigureServices(IServiceCollection services) { services.Register(); }
Dans mon cas, cette
Register
méthode était dans une classe distincteInjector
. J'ai donc dû y ajouter mes interfaces nouvellement introduites.public static class Injector { public static void Register(this IServiceCollection services) { services.AddTransient<IUserService, UserService>(); services.AddTransient<IUserDataService, UserDataService>(); } }
Si vous voyez, le paramètre de cette fonction est
this IServiceCollection
J'espère que cela t'aides.
la source
Seulement si quelqu'un a la même situation que moi, je fais un tutoriel sur EntityFramework avec la base de données existante, mais lorsque le nouveau contexte de base de données est créé sur les dossiers de modèles, nous devons mettre à jour le contexte au démarrage, mais pas seulement dans les services. AddDbContext mais AddIdentity aussi si vous avez l'authentification des utilisateurs
services.AddDbContext<NewDBContext>(options => options.UseSqlServer(Configuration.GetConnectionString("DefaultConnection"))); services.AddIdentity<ApplicationUser, IdentityRole>() .AddEntityFrameworkStores<NewDBContext>() .AddDefaultTokenProviders();
la source
Public void ConfigureServices(IServiceCollection services) { services.AddScoped<IEventRepository, EventRepository>(); }
Vous avez oublié d'ajouter "services.AddScoped" dans la
ConfigureServices
méthode de démarrage .la source
Vous devez ajouter un nouveau service pour
DBcontext
au démarrageDéfaut
services.AddDbContext<ApplicationDbContext>(options => options.UseSqlServer( Configuration.GetConnectionString("DefaultConnection")));
Ajoute ça
services.AddDbContext<NewDBContext>(options => options.UseSqlServer( Configuration.GetConnectionString("NewConnection")));
la source
J'ai dû ajouter cette ligne dans les ConfigureServices pour pouvoir travailler.
la source
J'ai eu ce problème à cause d'une erreur plutôt stupide. J'avais oublié de raccorder ma procédure de configuration de service pour découvrir automatiquement les contrôleurs dans l'application ASP.NET Core.
L'ajout de cette méthode l'a résolu:
// Add framework services. services.AddMvc() .AddControllersAsServices(); // <---- Super important
la source
Dans mon cas, l'API .Net Core 3.0 dans Startup.cs, dans la méthode
public void ConfigureServices(IServiceCollection services)
Je devais ajouter
la source
J'étais en dessous de l'exception
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()
Parce que je voulais enregistrer Factory pour créer des instances de la classe DbContext Derived IBlogContextFactory et utiliser la méthode Create pour instancier une instance de Blog Context afin que je puisse utiliser le modèle ci-dessous avec l'injection de dépendances et que je puisse également utiliser la simulation pour les tests unitaires.
le modèle que je voulais utiliser est
public async Task<List<Blog>> GetBlogsAsync() { using (var context = new BloggingContext()) { return await context.Blogs.ToListAsync(); } }
Mais au lieu du nouveau BloggingContext (), je veux injecter l'usine via le constructeur comme ci-dessous la classe 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; } }
voici mon code d'enregistrement de service
et ci-dessous mes modèles et classes d'usine
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; } }
----- Pour résoudre ce problème dans le projet .net Core MVC - J'ai fait ci-dessous les modifications sur l'enregistrement des dépendances
services .AddDbContext<BloggingContext>() .AddTransient<IBloggingContext, BloggingContext>() .AddTransient<IBloggingContextFactory, BloggingContextFactory>( sp => new BloggingContextFactory( () => sp.GetService<IBloggingContext>()) );
En bref, dans .net, le développeur principal est responsable d'injecter la fonction d'usine, ce qui dans le cas de Unity et .Net Framework a été pris en charge.
la source
Ce problème est dû au fait que vous n'avez pas enregistré le composant d'accès aux données avec l'interface écrite pour lui. Essayez d'utiliser comme suit
la source
Si vous utilisez AutoFac et obtenez cette erreur, vous devez ajouter une instruction "As" pour spécifier le service que l'implémentation concrète implémente.
C'est à dire. vous devriez écrire:
au lieu de
la source
ohh, merci @kimbaudi, j'ai suivi ce tuts
https://dotnettutorials.net/lesson/generic-repository-pattern-csharp-mvc/
et a eu la même erreur que votre. Mais après avoir lu votre code, j'ai découvert que ma solution ajoutait
dans la méthode ConfigureServices dans le fichier StartUp.cs =))
la source
J'ai eu le même problème et j'ai découvert que mon code utilisait l'injection avant son initialisation.
services.AddControllers(); // Will cause a problem if you use your IBloggerRepository in there since it's defined after this line. services.AddScoped<IBloggerRepository, BloggerRepository>();
Je sais que cela n'a rien à voir avec la question, mais depuis que j'ai été envoyé sur cette page, je pense que cela peut être utile à quelqu'un d'autre.
la source
La résolution d'un service est effectuée avant même que le code de classe ne soit atteint, nous devons donc vérifier nos injections de dépendances.
Dans mon cas j'ai ajouté
dans StartupExtensions.cs
la source
Ajouter des services.AddSingleton (); dans votre méthode ConfigureServices du fichier Startup.cs de votre projet.
public void ConfigureServices(IServiceCollection services) { services.AddRazorPages(); // To register interface with its concrite type services.AddSingleton<IEmployee, EmployeesMockup>(); }
Pour plus de détails, veuillez visiter cette URL: https://www.youtube.com/watch?v=aMjiiWtfj2M
pour toutes les méthodes (c'est-à-dire AddSingleton vs AddScoped vs AddTransient) Veuillez visiter cette URL: https://www.youtube.com/watch?v=v6Nr7Zman_Y&list=PL6n9fhu94yhVkdrusLaQsfERmL_Jh4XmU&index=44 )
la source
j'ai remplacé
services.Add(new ServiceDescriptor(typeof(IMyLogger), typeof(MyLogger)));
Avec
Et cela a fonctionné pour moi.
la source
Changer BloggerRepository en IBloggerRepository
la source
J'ai eu des problèmes en essayant d'injecter à partir de mon fichier Program.cs , en utilisant CreateDefaultBuilder comme ci-dessous, mais j'ai fini par le résoudre en ignorant le classeur par défaut. (voir ci-dessous).
var host = Host.CreateDefaultBuilder(args) .ConfigureWebHostDefaults(webBuilder => { webBuilder.ConfigureServices(servicesCollection => { servicesCollection.AddSingleton<ITest>(x => new Test()); }); webBuilder.UseStartup<Startup>(); }).Build();
Il semble que la construction aurait dû être effectuée à l'intérieur de ConfigureWebHostDefaults pour que cela fonctionne, sinon la configuration sera ignorée, mais corrigez-moi si je me trompe.
Cette approche a bien fonctionné:
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();
Cela montre également comment injecter une dépendance déjà prédéfinie dans .net core ( IConfiguration ) à partir de
la source
J'ai eu cette erreur parce que j'ai déclaré une variable (au-dessus de la méthode ConfigureServices) de type qui était mon contexte. J'avais:
Je ne sais pas à quoi je pensais. Je sais que c'est légal de faire cela si vous passez un paramètre à la méthode Configure.
la source
J'ai reçu l'erreur: "impossible de résoudre la dépendance xxxxxxxx pour toutes les versions de .net core". J'ai essayé tout ce qui est disponible sur Internet et je suis resté coincé pendant des jours. La seule solution que j'ai trouvée était d'ajouter le fichier nuget.config dans le projet, puis d'utiliser la restauration dotnet pour le faire fonctionner.
Contenu du fichier nuget.config:
<?xml version="1.0" encoding="utf-8"?> <configuration> <packageSources> <add key="AspNetCore" value="https://dotnet.myget.org/F/aspnetcore-ci-dev/api/v3/index.json" /> <add key="AspNetCoreTools" value="https://dotnet.myget.org/F/aspnetcore-tools/api/v3/index.json" /> <add key="NuGet" value="https://api.nuget.org/v3/index.json" /> </packageSources> </configuration>
la source