I wanna to try generic but I get some problem.
and this is my step
step 1. I create a database Model also inheritance class
public class DBRepo { }
public partial class UserAccount : DBRepo
{
public int Id { get; set; }
public string Account { get; set; }
public string Pwd { get; set; }
}
step 2. I wish all CRUD action can using this interface. so I do this
public class DBServices
{
public interface IDBAction<TEntity> where TEntity : DBRepo
{
void InsertData(TEntity entity);
}
public class dbCRUD<TEntity> : IDBAction<TEntity> where TEntity : DBRepo
{
private readonly CoreContext _db;
private DbSet<TEntity> dbSet;
public dbCRUD(CoreContext _db)
{
this._db = _db;
this.dbSet = _db.Set<TEntity>();
}
public void InsertData(TEntity _entity)
{
this.dbSet.Add(_entity);
this._db.SaveChanges();
}
}
}
and then I usine ServiceProvider like
ServiceProvider provider = new ServiceCollection()
.AddSingleton<IDBAction<DBRepo>>()
.BuildServiceProvider();
provider.GetService<IDBAction<DBRepo>>().InsertData(_ua);
and I'll get this error
Cannot instantiate implementation type ....
so I change to try other way like.
in Constructor
private readonly IDBAction<DBRepo> dBAction;
public HomeController( IDBAction<DBRepo> _dBAction)
{
this.dBAction = _dBAction;
}
....
this.dBAction.InsertData(_ua);
sure.I get error again
InvalidOperationException: Unable to resolve service for type...
have some can teach me how to fix the problem?
-> Update
I try to change like but it's failed
ServiceProvider provider = new ServiceCollection()
.AddScoped<IDBAction<DBRepo>, dbCRUD<DBRepo>>()
.AddScoped<CoreContext>()
.BuildServiceProvider();
error same this
Unable to resolve service for type...
it's my DBContext
public virtual DbSet<UserAccount> UserAccount { get; set; }
public CoreContext(DbContextOptions<CoreContext> options)
: base(options)
{
}
protected override void OnConfiguring(DbContextOptionsBuilder optionsBuilder)
{
if (!optionsBuilder.IsConfigured)
{
optionsBuilder.UseSqlServer(#"Connection String");
}
}
protected override void OnModelCreating(ModelBuilder modelBuilder)
{
modelBuilder.Entity<UserAccount>(entity =>
{
entity.Property(e => e.Account).IsRequired();
entity.Property(e => e.Pwd)
.IsRequired()
.HasMaxLength(20);
});
}
You are registering it in the wrong way. You must provide the implementation of your (generic) and also the DbContext must be registered.
ServiceProvider provider = new ServiceCollection()
.AddSingleton<IDBAction<DBRepo>, dbCRUD<DBRepo>>()
.BuildServiceProvider();
provider.GetService<IDBAction<DBRepo>>().InsertData(_ua);
Also registering it as a singleton will cause problems with change-tracking of entity-framework. So you should register it like this:
ServiceProvider provider = new ServiceCollection()
.AddScoped<IDBAction<DBRepo>, dbCRUD<DBRepo>>()
.AddScoped<CoreContext>()
.BuildServiceProvider();
provider.GetService<IDBAction<DBRepo>>().InsertData(_ua);
You could also implement a real generic like this
public interface IEntity
{
Guid Id { get; set; }
}
public class DbAction<TEntity> : IDbAction<TEntity> where TEntity: class, IEntity, new()
{
public void InsertData(TEntity entity)
{
...
}
}
Now register it as a generic
ServiceProvider provider = new ServiceCollection()
.AddScoped(typeof(IDbAction<>), typeof(DbAction<>))
.AddScoped<CoreContext>()
.BuildServiceProvider();
provider.GetService<IDBAction<DBRepo>>().InsertData(_ua);
Small example, but would work.
Edit:
DbContextOptions must of course be passed to the DbContext for the IoC to work.
.AddDbContext<CoreContext>(options => options.UseSqlServer("my-conntection-string")); // change provider if necessary, this will only work with MS SQL Server
Related
I am working with .net core 5.0 with code first approach
I am working crud operation on product and category I inject the both service in startup.cs class but still get an below error :
'Some services are not able to be constructed (Error while validating the service descriptor
'ServiceType: CrudDemo.Services.IService`2[CrudDemo.Models.Category,System.Int32] Lifetime: Scoped ImplementationType:
CrudDemo.Services.CategoryService': Unable to resolve service for type 'CrudDemo.Models.AmazonDbContext' while attempting to activate
'CrudDemo.Services.CategoryService'.) (Error while validating the service descriptor 'ServiceType:
CrudDemo.Services.IService`2[CrudDemo.Models.Product,System.Int32] Lifetime: Scoped ImplementationType: CrudDemo.Services.ProductService':
Unable to resolve service for type 'CrudDemo.Models.AmazonDbContext' while attempting to activate 'CrudDemo.Services.ProductService'.)'
startup.cs
public void ConfigureServices(IServiceCollection services)
{
services.AddDbContext<ApplicationDbContext>(options =>
{
options.UseSqlServer(Configuration.GetConnectionString("AppConnectionString"));
});
services.AddControllersWithViews();
services.AddScoped<IService<Category,int>, CategoryService>();
services.AddScoped<IService<Product, int>, ProductService>();
}
appsetting.json
"ConnectionStrings": {
"AppConnectionString": "Data Source=localhost,Initial Catalog=databasename;User Id=**;Password=************"
}
ApplicationDbContext.cs
public class ApplicationDbContext: IdentityDbContext
{
public ApplicationDbContext(DbContextOptions<ApplicationDbContext> options):base(options)
{
}
}
Iservice.cs
public interface IService<TEntity, in TPk> where TEntity : class
{
Task<IEnumerable<TEntity>> GetAsync();
Task<TEntity> GetAsync(TPk id);
Task<TEntity> CreateAsync(TEntity entity);
}
DepartmentController.cs
public class DepartmentController : Controller
{
private readonly IService<Category, int> catServ;
public DepartmentController(IService<Category, int> serv)
{
catServ = serv;
}
AmazonDbContext.cs
public class AmazonDbContext : DbContext
{
public DbSet<Category> Categories { get; set; }
public DbSet<Product> Products { get; set; }
public AmazonDbContext()
{
}
protected override void OnConfiguring(DbContextOptionsBuilder optionsBuilder)
{
optionsBuilder.UseSqlServer("Data Source=localhost;Initial Catalog=*****;User Id=*********;Password=***********");
}
}
CategoryService.cs
public class CategoryService : IService<Category,int>
{
private readonly AmazonDbContext ctx;
public CategoryService(AmazonDbContext ctx)
{
this.ctx = ctx;
}
public async Task<Category> CreateAsync(Category cat)
{
try
{
var res = await ctx.Categories.AddAsync(cat);
await ctx.SaveChangesAsync();
return res.Entity;
}
catch (Exception ex)
{
throw ex;
}
}
public async Task<IEnumerable<Category>> GetAsync()
{
return await ctx.Categories.ToListAsync();
}
public async Task<Category> GetAsync(int id)
{
return await ctx.Categories.FindAsync(id);
}
need help
Is it a type in your question CrudDemo.Models.AmazonDbContext? AmazonDbContext instead of ApplicationDbContext ?
public void ConfigureServices(IServiceCollection services)
{
Application not Amazon
| |
v v
services.AddDbContext<ApplicationDbContext>(options =>
{
...
});
You should register AmazonDbContext in ConfigureServices, but before that, as your commented error said, you must add a constructor that receives a parameter of type DbContextOptions<AmazonDbContext> into your AmazonDbContext class :
public AmazonDbContext(DbContextOptions<AmazonDbContext> options)
: base(options)
{ }
then register it:
services.AddDbContext<AmazonDbContext>(options => {
...
});
OR if for any reason you don't want your constructor have any parameter of DbContextOptions type, register your AmazonDbContext class like below:
services.AddDbContext<AmazonDbContext>();
I am facing an error while accesing data from database table saying InvalidOperationException: No database provider has been configured for this DbContext. A provider can be configured by overriding the DbContext.OnConfiguring method or by using AddDbContext on the application service provider. If AddDbContext is used, then also ensure that your DbContext type accepts a DbContextOptions<TContext> object in its constructor and passes it to the base constructor for DbContext.
I have used generic repository pattern. I have my DbContext i.e BlazorContext and model class in seperate class library project.
Any help will be grate.
Below is my connection string in appsettings.json
"ConnectionStrings": {
"myconn": "server=DESKTOP-VM2VP34; database=BlazorDB;Trusted_Connection=True;"
},<br><br>
Below is my startup.cs
services.AddDbContext<BlazorContext>(item => item.UseSqlServer(Configuration.GetConnectionString("myconn")));
Below is my DbContext i.e BlazorContext
namespace Blazor.Model.Models
{
public class BlazorContext:DbContext
{
public BlazorContext()
{
}
public BlazorContext(DbContextOptions<BlazorContext> options)
: base(options)
{
Database.EnsureCreated();
}
public DbSet<Person> Persons { get; set; }
}
}
Below is my generic repository implementation where it show error
namespace Blazor.Repository.Implementation
{
public class GenericRepository<T> : IGenericRepository<T> where T : class
{
protected BlazorContext _entities;
protected readonly DbSet<T> _dbset; // error in this line
public GenericRepository(BlazorContext context)
{
_entities = context;
_dbset = context.Set<T>();
}
public IEnumerable<T> GetAll()
{
return _dbset.AsEnumerable();
}
}
}
Below is my GenericUnitOfWork
namespace Blazor.Repository.Implementation
{
public sealed class GenericUnitOfWork : IGenericUnitOfWork, IDisposable
{
private BlazorContext entities = null;
public GenericUnitOfWork()
{
entities = new BlazorContext();
}
public Dictionary<Type, object> repositories = new Dictionary<Type, object>();
public IGenericRepository<T> Repository<T>() where T : class
{
if (repositories.Keys.Contains(typeof(T)) == true)
{
return repositories[typeof(T)] as IGenericRepository<T>;
}
var t = typeof(T);
IGenericRepository<T> repo = new GenericRepository<T>(entities);//error in this line
repositories.Add(typeof(T), repo);
return repo;
}
}
}
Your connection string template is not correct for the MS SQL server. Try to use something like this:
"Data Source=localhost;Initial Catalog=BlazorDB;Integrated Security=SSPI;Persist Security Info=True;"
If it doesn't work then you use not MS SQL server and so in your startup you have to replace "item => item.UseSqlServer" with other provider.
I have an interface that is being attached in my DI
builder.RegisterType<TaskTempo>().As<ITaskTempo>();
This is being done because ITaskTempo is dynamic and could be one of multiple objects, but sharing same interface.
Anyway, I have DbContext where I map the DbSet with entity manually
// DI register
builder.RegisterType<MapperFor890>().As<IEntityMapper>();
// ...
// DbContext
public partial class MyDBContext : DbContext
{
private readonly IEntityMapper _entityMapper;
// Please not that I do not want to manually add all of diff implementations of ITaskTempo here
// public virtual DbSet<TaskTempo1> TaskTempo { get; set; }
public MyDBContext(DbContextOptions<MyDBContext> options, IEntityMapper mapper)
: base(options)
{
_entityMapper = mapper;
}
protected override void OnModelCreating(ModelBuilder modelBuilder)
{
// Map Entities
_entityMapper.Map(modelBuilder, this);
}
}
// ...
// EntityMapper
public class MapperFor890 : IEntityMapper
{
public void Map(ModelBuilder modelBuilder, DbContext context)
{
modelBuilder.Entity<TaskTempo1>(entity =>
{
// Map here the properties
});
}
}
Then, I am able to fetch data from EfRepository:
// Global Repository
public class EfRepository<TEntity> : IRepository<TEntity> where TEntity : class
{
protected readonly DbContext Context;
protected readonly ILogger<EfRepository<TEntity>> Logger;
public EfRepository(DbContext context,
ILogger<EfRepository<TEntity>> logger)
{
Context = context;
Logger = logger;
}
public virtual IQueryable<TEntity> Find(Expression<Func<TEntity, bool>> predicate)
{
Logger.LogDebug($"Finding '{typeof(TEntity).Name}' with predicate");
return Context.Set<TEntity>().Where(predicate);
}
}
// TaskTempo Repository
public class TaskTempoRepository<TTaskTempo> : EfRepository<TTaskTempo>, ITaskScanRepository<TTaskTempo> where TTaskTempo : class, ITaskTempo
{
public MyDBContext DbContext => Context as MyDBContext;
public TaskScanRepository(MyDBContext context, ILogger<TaskScanRepository<TTaskTempo>> logger) : base(context,logger)
{
}
}
// DI injection
builder.RegisterType<TaskTempo1>().As<ITaskTempo>();
builder.RegisterType<TaskTempoRepository<ITaskTempo>>().As<ITasTempoRepository<ITaskTempo>>();
Once I fetch
_taskTempoRepository.Find(t => t.Id = 3);
I am getting the following error:
Cannot create a DbSet for 'ITaskTempo' because this type is not included in the model for the context
I am using repository pattern on EF Core and Autofac in a windows service.
I have a service that needs to connect with the some dozen databases which have the same schema (same dbcontext) but only different data.
How can I achieve this in my service using Autofac? Belo
public class ReportRepository : IReportRepository
{
private readonly ReportDbContext dbContext;
public ReportRepository(ReportDbContext dbContext)
{
this.dbContext = dbContext
}
public SomeModel GetData()
{
return dbContext.SalesData;
}
}
public class ReportService : IReportService
{
private readonly IReportRepository reportRepositoryEUServer;
public ReportService(IReportRepository reportRepositoryEUServer)
{
this.reportRepositoryEUServer = reportRepositoryEUServer
}
public SomeModelDto GenerateReport()
{
var euData = reportRepositoryEUServer.GetData();
// I need to call other servers (e.g LATAM) here and get the data and aggregate them with euData
}
}
Create base context including all settings, dbsets etc:
public abstract class BaseContext : DbContext
{
public BaseContext(DbContextOptions options)
: base(options)
{ }
public DbSet<object> FirstSet { get; set; }
...
}
inherit from BaseContext for both DBs
public class LATAMContext : BaseContext
{
public LATAMContext(DbContextOptions<LATAMContext> options) : base(options)
{
}
}
public class EUContext : BaseContext
{
public EUContext(DbContextOptions<EUContext> options) : base(options)
{
}
}
and register both in Startup.cs
public IServiceProvider ConfigureServices(IServiceCollection services)
{
services.AddDbContext<LATAMContext>(options => options.UseSqlServer(Configuration.GetConnectionString("LATAMConnectionString")));
services.AddDbContext<EUContext>(options => options.UseSqlServer(Configuration.GetConnectionString("EUConnectionString")));
// Autofac
var builder = new ContainerBuilder();
// needed only if you plan to inject ICollection<BaseContext>
builder.RegisterType<LATAMContext>().As<BaseContext>();
builder.RegisterType<EUContext>().As<BaseContext>();
builder.Populate(services);
return new AutofacServiceProvider(builder.Build());
}
add connection strings in appsettings.json
"ConnectionStrings": {
"LATAMConnectionString": "Server=(localdb)\\mssqllocaldb;Database=ContosoUniversity1;Trusted_Connection=True;MultipleActiveResultSets=true",
"EUConnectionString": "Server=(localdb)\\mssqllocaldb;Database=ContosoUniversity1;Trusted_Connection=True;MultipleActiveResultSets=true"
}
and now you can inject both contexts
public class ReportRepository : IReportRepository
{
private readonly LATAMContext latamDbContext;
private readonly EUContext euDbContext;
public ReportRepository(LATAMContext latamDbContext, EUContext euDbContext)
{
this.latamDbContext = latamDbContext;
this.euDbContext = euDbContext;
}
}
or if you plan to inject collection of contexts
public class ReportRepository : IReportRepository
{
private readonly ICollection<BaseContext> dbContexts;
public ReportRepository(ICollection<BaseContext> dbContexts)
{
this.dbContexts = dbContexts;
}
}
to access specific context
var _euContext = dbContexts.FirstOrDefault(x => x is EUContext) as EUContext;
var _latamContext = dbContexts.FirstOrDefault(x => x is LATAMContext) as LATAMContext;
I am Creating a web api using Repository pattern and 3 tier architecture. i also made a IOC Container (Autofac) for hadling dependencies. But i am keep getting error, in tried everything. The Error is: An error occurred when trying to create a controller of type 'StudentsController'. Make sure that the controller has a parameterless public constructor.
Here is my Code:
My Context Class:
public class StudentContext: DbContext
{
public StudentContext(): base("name=StudentDB")
{
//Database.SetInitializer<StudentContext>(null);
}
public new IDbSet<TEntity> Set<TEntity>() where TEntity : class
{
return base.Set<TEntity>();
}
protected override void OnModelCreating(DbModelBuilder modelBuilder)
{
modelBuilder.Configurations.Add(new StudentMap());
}
public DbSet<Student> Students { get; set; }
}
My Repository Class:
public class Repository<T> : IRepository<T> where T : class
{
public readonly StudentContext context;
public IDbSet<T> entities;
public Repository(StudentContext _context)
{
this.context = _context;
entities = _context.Set<T>();
}
public IQueryable<T> Table()
{
return this.Entities;
}
public void Insert (T entity)
{
this.Entities.Add(entity);
this.Save();
}
private IDbSet<T> Entities
{
get
{
if (entities == null)
entities = context.Set<T>();
return this.entities;
}
}
public void Save()
{
context.SaveChanges();
}
}
My Services Class is as:
public class StudentService: IStudentService
{
public IRepository<Student> _StudentRepository;
public StudentService(IRepository<Student> sturepo)
{
this._StudentRepository = sturepo;
}
public IQueryable<Student> GetAllStudents()
{
return _StudentRepository.Table();
}
public void InsertStudent(Student std)
{
_StudentRepository.Insert(std);
}
}
My API Controller:
public class StudentsController : ApiController
{
public IStudentService studentservice;
public StudentsController(IStudentService stuservce)
{
this.studentservice = stuservce;
}
public IList<Student> GetStudents()
{
List<Student> student = studentservice.GetAllStudents().ToList();
return student.ToList();
}
}}
Autofac Container Class:
public class AutofacConfig
{
public static void ConfigureContainer()
{
var builder = new ContainerBuilder();
// Get your HttpConfiguration.
var config = GlobalConfiguration.Configuration;
builder.RegisterAssemblyTypes(Assembly.GetExecutingAssembly()).Where(t => !t.IsAbstract && typeof(ApiController).IsAssignableFrom(t))
.InstancePerMatchingLifetimeScope();
// Register your Web API controllers.
builder.RegisterApiControllers(Assembly.GetExecutingAssembly());
// OPTIONAL: Register the Autofac filter provider.
builder.RegisterWebApiFilterProvider(config);
// OPTIONAL: Register the Autofac model binder provider.
builder.RegisterWebApiModelBinderProvider();
// Set the dependency resolver to be Autofac.
var container = builder.Build();
config.DependencyResolver = new AutofacWebApiDependencyResolver(container);
}
}
Calling Autofac in Global.Ascx:
protected void Application_Start()
{
AutofacConfig.ConfigureContainer();
GlobalConfiguration.Configure(WebApiConfig.Register);
FilterConfig.RegisterGlobalFilters(GlobalFilters.Filters);
RouteConfig.RegisterRoutes(RouteTable.Routes);
BundleConfig.RegisterBundles(BundleTable.Bundles);
}