Aku menciptakan .NET Inti aplikasi MVC dan menggunakan Dependency Injection dan Repositori Pola untuk menyuntikkan sebuah repositori ke controller. Namun, saya mendapatkan error:
InvalidOperationException: tidak Dapat menyelesaikan layanan untuk tipe 'WebApplication1.Data.BloggerRepository' ketika mencoba untuk mengaktifkan 'WebApplication1.Pengendali.BlogController'.
Model (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; }
}
}
Repositori (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 (kode yang relevan)
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);
}
}
}
I'm tidak yakin apa yang saya'm melakukan hal yang salah. Ada ide?
Pengecualian mengatakan itu tidak dapat menyelesaikan layanan untuk WebApplication1.Data.BloggerRepository
karena konstruktor pada controller anda meminta untuk beton kelas bukan dari antarmuka. Jadi hanya perubahan yang:
public BlogController(IBloggerRepository repository)
// ^
// Add this!
{
_repository = repository;
}
Aku berlari ke dalam masalah ini karena di dependency injection setup saya hilang ketergantungan dari repositori yang ketergantungan dari controller:
services.AddScoped<IDependencyOne, DependencyOne>(); <-- I was missing this line!
services.AddScoped<IDependencyTwoThatIsDependentOnDependencyOne, DependencyTwoThatIsDependentOnDependencyOne>();
Dalam kasus saya saya mencoba untuk melakukan dependency injection untuk sebuah objek yang diperlukan konstruktor argumen. Dalam hal ini, selama Startup saya hanya memberikan argumen dari file konfigurasi, misalnya:
var config = Configuration.GetSection("subservice").Get<SubServiceConfig>();
services.AddScoped<ISubService>(provider => new SubService(config.value1, config.value2));
Hanya jika ada yang memiliki situasi yang sama seperti saya, saya melakukan tutorial dari EntityFramework dengan database yang sudah ada, tapi ketika baru database konteks ini dibuat pada model folder, kita perlu update konteks di startup, tetapi tidak hanya dalam pelayanan.AddDbContext tapi AddIdentity juga jika anda memiliki pengguna otentikasi
services.AddDbContext<NewDBContext>(options =>
options.UseSqlServer(Configuration.GetConnectionString("DefaultConnection")));
services.AddIdentity<ApplicationUser, IdentityRole>()
.AddEntityFrameworkStores<NewDBContext>()
.AddDefaultTokenProviders();
Saya memiliki masalah yang berbeda, dan yeah parameter konstruktor untuk controller sudah ditambahkan dengan antarmuka yang benar. Apa yang saya lakukan adalah sesuatu yang mudah. Aku hanya pergi untuk saya startup.cs
file, di mana saya bisa melihat panggilan untuk mendaftar metode.
public void ConfigureServices(IServiceCollection services)
{
services.Register();
}
Dalam kasus saya, ini Register
metode dalam kelas yang terpisah Injector
. Jadi saya harus menambahkan saya baru diperkenalkan Interface yang ada.
public static class Injector
{
public static void Register(this IServiceCollection services)
{
services.AddTransient<IUserService, UserService>();
services.AddTransient<IUserDataService, UserDataService>();
}
}
Jika anda lihat, parameter untuk fungsi ini adalah ini IServiceCollection
Semoga ini bisa membantu.
Anda perlu untuk menambahkan layanan baru untuk DBcontext
di startup
Default
services.AddDbContext<ApplicationDbContext>(options =>
options.UseSqlServer(
Configuration.GetConnectionString("DefaultConnection")));
Tambahkan ini
services.AddDbContext<NewDBContext>(options =>
options.UseSqlServer(
Configuration.GetConnectionString("NewConnection")));
Aku punya masalah ini karena bukan kesalahan konyol. Aku sudah lupa untuk menghubungkan layanan konfigurasi prosedur untuk menemukan pengendali otomatis di ASP.NET aplikasi Inti.
Menambahkan metode ini dipecahkan:
// Add framework services.
services.AddMvc()
.AddControllersAsServices(); // <---- Super important
ohh, Terima kasih @kimbaudi, saya mengikuti ini tuts
https://dotnettutorials.net/lesson/generic-repository-pattern-csharp-mvc/
dan punya kesalahan yang sama seperti anda. Tapi setelah membaca kode anda saya menemukan solusi saya adalah menambah
pelayanan.AddScoped(IGenericRepository
, GenericRepository );
ke ConfigureServices metode di StartUp.cs file =))
Public void ConfigureServices(IServiceCollection services)
{
services.AddScoped<IEventRepository, EventRepository>();
}
Anda're lupa untuk menambahkan "jasa.AddScoped" pada startup Configureservices
metode.
Masalah ini adalah karena anda tidak't daftarkan data akses komponen dengan antarmuka yang ditulis untuk itu. Cobalah menggunakan sebagai berikut
jasa.AddTransient<IMyDataProvider, MyDataAccess>();`
Jika anda menggunakan AutoFac dan mendapatkan kesalahan ini, anda harus menambahkan "Seperti" pernyataan untuk menentukan layanan yang konkret implementasi mengimplementasikan.
Ie. anda harus menulis:
containerBuilder.RegisterType<DataService>().As<DataService>();
bukan
containerBuilder.RegisterType<DataService>();
Saya mendapatkan pengecualian di bawah ini
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()
Karena saya ingin mendaftar Pabrik untuk membuat contoh dari DbContext kelas Turunan IBlogContextFactory Membuat dan menggunakan metode untuk instantiate contoh Blog Konteks sehingga saya dapat menggunakan pola di bawah ini bersama dengan dependency Injection dan dapat juga digunakan untuk mengejek unit testing.
pola yang ingin saya gunakan adalah
public async Task<List<Blog>> GetBlogsAsync()
{
using (var context = new BloggingContext())
{
return await context.Blogs.ToListAsync();
}
}
Tapi Bukannya baru BloggingContext() saya ingin Inject pabrik melalui konstruktor seperti di bawah ini BlogController kelas
[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;
}
}
berikut adalah layanan kode registrasi
services
.AddDbContext<BloggingContext>()
.AddTransient<IBloggingContext, BloggingContext>()
.AddTransient<IBloggingContextFactory, BloggingContextFactory>();
dan di bawah ini adalah model dan pabrik kelas
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; }
}
----- Untuk Memperbaiki hal ini .net Core MVC project -- saya lakukan di bawah ini perubahan pada ketergantungan pendaftaran
services
.AddDbContext<BloggingContext>()
.AddTransient<IBloggingContext, BloggingContext>()
.AddTransient<IBloggingContextFactory, BloggingContextFactory>(
sp => new BloggingContextFactory( () => sp.GetService<IBloggingContext>())
);
Singkatnya dalam .net inti pengembang yang bertanggung jawab untuk menyuntikkan pabrik fungsi, yang dalam hal persatuan dan Kesatuan .Net Framework adalah diambil dari perawatan.
Saya diganti
pelayanan.Add(new ServiceDescriptor(typeof(IMyLogger), typeof(MyLogger)))
Dengan
pelayanan.AddTransient<IMyLogger, MyLogger>()
Dan itu bekerja untuk saya.
Aku punya kesalahan ini karena saya menyatakan variabel (di atas ConfigureServices metode) dari jenis yang saya konteks. Saya:
CupcakeContext _ctx
Tidak yakin apa yang aku pikirkan. Aku tahu itu's hukum untuk melakukan hal ini jika anda melintas di sebuah parameter untuk Mengkonfigurasi metode.
Saya menerima kesalahan: "tidak dapat mengatasi ketergantungan xxxxxxxx untuk semua versi .net core". Aku mencoba segala sesuatu yang tersedia di internet dan terjebak selama berhari-hari. Satu-satunya solusi yang saya datang dengan adalah menambahkan nuget.config file dalam proyek dan kemudian menggunakan dotnet restore untuk membuatnya bekerja.
Isi 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>