1

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);
            });
        }
3
  • 1
    Am i wrong? You have a problem not with CRUD, but with Dependency Injection here ? Commented Mar 16, 2018 at 8:28
  • Yes,no CRUD is DI Commented Mar 16, 2018 at 8:35
  • Sorry, you use DI in wrong way. Ideally .GetService<>() should be called only once in the application. Think about it and play with dependency injection to understand how it should work. Commented Mar 16, 2018 at 8:37

1 Answer 1

1

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
Sign up to request clarification or add additional context in comments.

7 Comments

Yes, look good, but also fail , I update my quection u can see . thk
You didn't read my answer properly, you are still missing the registration of DbContext. Also still using singletons.
DbContext alway null
Yeah you are not passing the DbContextOptions to the constructor of your DbContext. I updated the post. You should really learn to understand what is IoC and DI
Yes it's can work,But I have other question.in ConfigureServices I already Add DBContext. why I need add again in ServiceProvider
|

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.