Ich habe eine .NET Core MVC-Anwendung erstellt und mit Dependency Injection und Repository Pattern ein Repository in meinen Controller eingefügt. Ich erhalte jedoch eine Fehlermeldung:
InvalidOperationException: Der Dienst konnte für den Typ 'WebApplication1.Data.BloggerRepository' nicht aufgelöst werden, während versucht wurde, 'WebApplication1.Controllers.BlogController' zu aktivieren.
Modell (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; }
}
}
Repository (IBloggerRepository.cs und 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 (relevanter Code)
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>();
}
Controller (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);
}
}
}
Ich bin nicht sicher, was ich falsch mache. Irgendwelche Ideen?
Die Ausnahme besagt, dass der Dienst für WebApplication1.Data.BloggerRepository
nicht aufgelöst werden kann, da der Konstruktor auf Ihrem Controller die konkrete Klasse anstelle der Schnittstelle anfordert. Also einfach das ändern:
public BlogController(IBloggerRepository repository)
// ^
// Add this!
{
_repository = repository;
}
In meinem Fall habe ich versucht, Abhängigkeitsinjektion für ein Objekt durchzuführen, das Konstruktorargumente erfordert. In diesem Fall habe ich während des Startvorgangs nur die Argumente aus der Konfigurationsdatei angegeben, zum Beispiel:
var config = Configuration.GetSection("subservice").Get<SubServiceConfig>();
services.AddScoped<ISubService>(provider => new SubService(config.value1, config.value2));
Nur wenn jemand die gleiche Situation wie ich hat, mache ich ein Tutorial von EntityFramework mit der vorhandenen Datenbank. Wenn jedoch der neue Datenbankkontext in den Modellordnern erstellt wird, müssen wir den Kontext beim Start aktualisieren, nicht nur in den Diensten. AddDbContext, aber auch AddIdentity, wenn Sie über eine Benutzerauthentifizierung verfügen
services.AddDbContext<NewDBContext>(options =>
options.UseSqlServer(Configuration.GetConnectionString("DefaultConnection")));
services.AddIdentity<ApplicationUser, IdentityRole>()
.AddEntityFrameworkStores<NewDBContext>()
.AddDefaultTokenProviders();
Ich hatte ein anderes Problem und ja, der parametrisierte Konstruktor für meinen Controlleroder wurde bereits mit der richtigen Schnittstelle hinzugefügt. Was ich tat, war etwas Unkompliziertes. Ich gehe einfach zu meiner startup.cs
-Datei, wo ich einen Aufruf zur Registrierung sehen kann.
public void ConfigureServices(IServiceCollection services)
{
services.Register();
}
In meinem Fall befand sich diese Register
-Methode in einer separaten Klasse Injector
. Also musste ich meine neu eingeführten Interfaces dort hinzufügen.
public static class Injector
{
public static void Register(this IServiceCollection services)
{
services.AddTransient<IUserService, UserService>();
services.AddTransient<IUserDataService, UserDataService>();
}
}
Wenn Sie sehen, ist der Parameter für diese Funktion this IServiceCollection
Hoffe das hilft.
Ich bin auf dieses Problem gestoßen, weil mir im Abhängigkeitsinjektionssetup eine Abhängigkeit von einem Repository fehlte, das eine Abhängigkeit von einem Controller ist:
services.AddScoped<IDependencyOne, DependencyOne>(); <-- I was missing this line!
services.AddScoped<IDependencyTwoThatIsDependentOnDependencyOne, DependencyTwoThatIsDependentOnDependencyOne>();
Ich habe dieses Problem wegen eines ziemlich dummen Fehlers bekommen. Ich hatte vergessen, mein Dienstkonfigurationsverfahren zu verknüpfen, um Controller automatisch in der ASP.NET Core-Anwendung zu ermitteln.
Das Hinzufügen dieser Methode löste es:
// Add framework services.
services.AddMvc()
.AddControllersAsServices(); // <---- Super important
ohh, danke @ kimbaudi, ich bin diesen Tuts gefolgt
https://dotnettutorials.net/lesson/generic-repository-pattern-csharp-mvc/
und habe den gleichen Fehler wie dein. Aber nachdem ich Ihren Code gelesen hatte, stellte ich fest, dass meine Lösung hinzugefügt wurde
services.AddScoped (IGenericRepository, GenericRepository);
in ConfigureServices Methode in der Datei StartUp.cs =))
Sie müssen im Startup einen neuen Dienst für DBcontext
hinzufügen
Default
services.AddDbContext<ApplicationDbContext>(options =>
options.UseSqlServer(
Configuration.GetConnectionString("DefaultConnection")));
Füge das hinzu
services.AddDbContext<NewDBContext>(options =>
options.UseSqlServer(
Configuration.GetConnectionString("NewConnection")));
Ich musste diese Zeile in den ConfigureServices hinzufügen, um funktionieren zu können.
services.AddSingleton<IOrderService, OrderService>();
Public void ConfigureServices(IServiceCollection services)
{
services.AddScoped<IEventRepository, EventRepository>();
}
Sie haben vergessen, Addscope in der Configureservices
-Startmethode hinzuzufügen.
Wenn Sie AutoFac verwenden und diesen Fehler erhalten, sollten Sie eine "As" -Anweisung hinzufügen, um den Dienst anzugeben, den die konkrete Implementierung implementiert.
Ie. du solltest schreiben:
containerBuilder.RegisterType<DataService>().As<DataService>();
anstatt
containerBuilder.RegisterType<DataService>();
Dieses Problem ist darauf zurückzuführen, dass Sie die Datenzugriffskomponente nicht mit der dafür geschriebenen Schnittstelle registriert haben. Versuchen Sie es wie folgt
services.AddTransient<IMyDataProvider, MyDataAccess>();`
Ich habe services.Add(new ServiceDescriptor(typeof(IMyLogger), typeof(MyLogger)))
durch services.AddTransient<IMyLogger, MyLogger>()
ersetzt
Und es hat bei mir funktioniert.
Ich war unter der Ausnahme
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()
Weil ich wollte, dass Factory registriert wird, um Instanzen der DbContext-abgeleiteten Klasse IBlogContextFactory zu erstellen und die Create-Methode zu verwenden, um die Instanz von Blog Context zu instanziieren, so dass ich das unten stehende Muster zusammen mit der Abhängigkeitsinjektion verwenden und auch Mocking für Komponententests verwenden kann.
das Muster, das ich verwenden wollte, ist
public async Task<List<Blog>> GetBlogsAsync()
{
using (var context = new BloggingContext())
{
return await context.Blogs.ToListAsync();
}
}
Aber anstelle von neuem BloggingContext () möchte ich die Factory über den Konstruktor wie in der folgenden BlogController-Klasse einfügen
[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;
}
}
hier ist mein service registrierungscode
services
.AddDbContext<BloggingContext>()
.AddTransient<IBloggingContext, BloggingContext>()
.AddTransient<IBloggingContextFactory, BloggingContextFactory>();
und unten sind meine Modelle und Fabrikklassen
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; }
}
----- Um dies in .net Core MVC-Projekt zu beheben - Ich habe unten Änderungen an der Abhängigkeitsregistrierung vorgenommen
services
.AddDbContext<BloggingContext>()
.AddTransient<IBloggingContext, BloggingContext>()
.AddTransient<IBloggingContextFactory, BloggingContextFactory>(
sp => new BloggingContextFactory( () => sp.GetService<IBloggingContext>())
);
Kurzum .net Core-Entwickler ist dafür verantwortlich, Factory-Funktionen zu injizieren, die im Falle von Unity und .Net Framework erledigt wurden.
Ich habe diesen Fehler erhalten, weil ich eine Variable (über der ConfigureServices-Methode) des Typs deklariert habe, der mein Kontext war. Ich hatte:
CupcakeContext _ctx
Ich bin mir nicht sicher, was ich dachte. Ich weiß, dass dies zulässig ist, wenn Sie einen Parameter an die Configure-Methode übergeben.