Home Repository Pattern İle .NET 6 Web API Üzerinde Multiple DbContext Kullanımı
Post
Cancel

Repository Pattern İle .NET 6 Web API Üzerinde Multiple DbContext Kullanımı

Merhabalar bu makalede bir Asp .Net Web API projesinde multiple DbContext kullanımına değineceğim. Senaryoda 2 farklı veritabanına Repository Pattern yardımıyla DbContext değiştirerek bağlantı yapacağım. Öncelikle bir Asp .Net Web API (6.0) projesi oluşturuyorum. İlk iş olarak EntityFrameWork paketlerini yüklüyorum.

1
2
3
Install-Package Microsoft.EntityFrameworkCore -Version 6.0.4
Install-Package Microsoft.EntityFrameworkCore.SqlServer -Version 6.0.4
Install-Package Microsoft.EntityFrameworkCore.Tools -Version 6.0.4

Paket yüklemesi tamamlandığında DbContext sınıflarını oluşturuyorum. Proje dizinine Data isminde klasör ekliyorum. Data klasörüne DbOneContext, DbTwoContext ve BaseContext isminde üç class ekliyorum. BaseContext clasını DbContext sınıfından türetip constructor ile DbContextOptions parametresini alıyorum.

1
2
3
4
5
6
7
8
9
10
11
using Microsoft.EntityFrameworkCore;

namespace MultipleDbContext.Data;

public class BaseContext : DbContext
{
    public BaseContext(DbContextOptions options): base(options)
    {
        
    }
}

DbOneContext ve DbTwoContext sınıfları BaseContext den türetip aşağıdaki şekilde implemente ediyorum.

1
2
3
4
5
6
7
8
9
10
11
using Microsoft.EntityFrameworkCore;

namespace MultipleDbContext.Data;

public class DbOneContext : BaseContext
{
    public DbOneContext(DbContextOptions<DbOneContext> options) : base(options)
    {

    }
}
1
2
3
4
5
6
7
8
9
10
using Microsoft.EntityFrameworkCore;

namespace MultipleDbContext.Data;

public class DbTwoContext : BaseContext
{
    public DbTwoContext(DbContextOptions<DbTwoContext> options) : base(options)
    {
    }
}

DbConext sınıflarını oluşturduktan sonra appsettings.json dosyasına girip ConnectionString tanımlarını yapıyorum.

1
2
3
4
5
6
7
8
9
10
11
12
13
{
  "Logging": {
    "LogLevel": {
      "Default": "Information",
      "Microsoft.AspNetCore": "Warning"
    }
  },
  "AllowedHosts": "*",
  "ConnectionStrings": {
    "DbOneContext": "Data Source=.;Initial Catalog=DBONE;User ID=sa;Password=Pw123456",
    "DbTwoContext": "Data Source=.;Initial Catalog=DBTWO;User ID=sa;Password=Pw123456"
  }
}

Daha sonra Program.cs dosyasının içerisinde projeye contextleri tanıtıyorum.

1
2
3
4
5
builder.Services.AddDbContext<DbOneContext>(options =>
    options.UseSqlServer(builder.Configuration.GetConnectionString("DbOneContext")));

builder.Services.AddDbContext<DbTwoContext>(options =>
    options.UseSqlServer(builder.Configuration.GetConnectionString("DbTwoContext")));

Projeye Models isminde bir klasör ekliyorum. İçerisine veritabanı tablosunu oluşturacağım entity için bir Book isminde class ekliyorum.

1
2
3
4
5
6
7
8
9
namespace MultipleDbContext.Models
{
    public class Book
    {
        public int Id { get; set; }
        public string Name { get; set; }
        public string Anchor { get; set; }
    }
}

Daha sonra BaseContext içerisinde DbSet ile Book entity sınıfını tanıtıyorum.

1
2
3
4
5
6
7
8
9
10
11
12
13
14
using Microsoft.EntityFrameworkCore;
using MultipleDbContext.Models;

namespace MultipleDbContext.Data;

public class BaseContext : DbContext
{
    public BaseContext(DbContextOptions options): base(options)
    {
        
    }

    public DbSett<Book> Books { get; set; }
}

Data klasörüne DbContextFactory isminde bir sınıf oluşturuyorum. Bu sınıfta bir IDictionary içersinde contextName değeri ile ilgili BaseContext nesnesini geri alıyoruz.

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
namespace MultipleDbContext.Data
{
    public class DbContextFactory
    {
        private readonly IDictionary<string, BaseContext> _context;

        public DbContextFactory(IDictionary<string, BaseContext> context)
        {
            _context = context;
        }

        public BaseContext GetContext(string contextName)
        {
            return _context[contextName];
        }
    }
}

Artık Repository yapısını oluşturabilirim. Öncelikle proejeye Repository isminde bir klasör oluşturup içerisine IBookReposiory adında bir interface ve BookRepository adında bir class ekliyorum.

1
2
3
4
5
6
7
8
9
10
using MultipleDbContext.Models;

namespace MultipleDbContext.Repository;

public interface IBookRepository
{
    void Add(Book entity,string contextName);
    void Update(Book entity, string contextName);
    List<Book> Get(string contextName);
}

ContextName bilgisini parametre ile gönderiyorum. Bu şekilde DbContext ayrımını yapacağım.

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
using Microsoft.EntityFrameworkCore;
using MultipleDbContext.Data;
using MultipleDbContext.Models;

namespace MultipleDbContext.Repository
{
    public class BookRepository : IBookRepository
    {
        DbContextFactory _contexts;

        public BookRepository(DbContextFactory contexts)
        {
            _contexts = contexts;
        }
        public void Add(Book entity, string contextName)
        {
            var context = _contexts.GetContext(contextName);
            var addedEntity = context.Attach(entity);
            addedEntity.State = EntityState.Added;
            context.SaveChanges();
        }

        public void Update(Book entity, string contextName)
        {
            var context = _contexts.GetContext(contextName);
            var updatedEntity = context.Entry(entity);
            updatedEntity.State = EntityState.Modified;
            context.SaveChanges();
        }

        public List<Book> Get(string contextName)
        {
            var context = _contexts.GetContext(contextName);
            return context.Books.ToList();
        }
    }
}

Bu sınıfta constructor içerisinde DbContextFactory ile DbContext nesnelerini Repository içerisine taşıyorum. Parametre ile gönderilen DbContexti çalıştırıyorum. Bu yapılandırma için AutoFac IOC container’ını projeye ekliyorum.

1
2
Install-Package Autofac -Version 6.3.0
Install-Package Autofac.Extensions.DependencyInjection -Version 7.2.0

Paketi indirdikten sonra hemen Program.cs içerisinde AutoFac yapılandırmasını yapıyorum.

1
2
builder.Host.UseServiceProviderFactory(new AutofacServiceProviderFactory());
builder.Host.ConfigureContainer<ContainerBuilder>(b => b.RegisterModule(new AutoFacModule()));

Burada registerModule ile kendi oluşturduğum AutoFacModule clasını tanımlıyorum.

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
public class AutoFacModule : Module
{
    protected override void Load(ContainerBuilder builder)
    {
        builder.RegisterType<DbOneContext>().As<BaseContext>();
        builder.RegisterType<DbTwoContext>().As<BaseContext>();
        builder.Register(ctx =>
        {
            var allContext = new Dictionary<string, BaseContext>();
            allContext.Add("DbOneContext", ctx.Resolve<DbOneContext>());
            allContext.Add("DbTwoContext", ctx.Resolve<DbTwoContext>());
            return new DbContextFactory(allContext);

        });
        builder.RegisterType<BookRepository>().As<IBookRepository>();

    }
}

AutoFac IOC yapılandırması sonrasında controllers klasörüne BookController isminde bir web api controller ekliyorum.

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
using Microsoft.AspNetCore.Http;
using Microsoft.AspNetCore.Mvc;
using MultipleDbContext.Models;
using MultipleDbContext.Repository;

namespace MultipleDbContext.Controllers
{
    [Route("api/[controller]")]
    [ApiController]
    public class BookController : ControllerBase
    {
        private IBookRepository _bookRepository;

        public BookController(IBookRepository bookRepository)
        {
            _bookRepository = bookRepository;
        }

        [HttpGet]
        [Route("{contextName}")]
        public List<Book> Get([FromRoute] string contextName)
        {
            var books = _bookRepository.Get(contextName);
            return books;
        }

        [HttpPost]
        [Route("{contextName}")]
        public IActionResult Post([FromRoute] string contextName,[FromBody] Book book)
        {
            try
            {
                _bookRepository.Add(book,contextName);
                return Ok();
            }
            catch (Exception e)
            {
                return BadRequest(e.Message);
            }
        }

        [HttpPut]
        [Route("{contextName}")]
        public IActionResult Put([FromRoute] string contextName, [FromBody] Book book)
        {
            try
            {
                _bookRepository.Update(book, contextName);
                return Ok();
            }
            catch (Exception e)
            {
                return BadRequest(e.Message);
            }
        }
    }
}

BookController’da görüldüğü üzere contextName parametresi ile hangi dbContext’e bağlanacağımı alıyorum. Daha sonra BookRepository yardımıyla CRUD işlemlerini yapacağım. Controller yapısını oluşturduktan sonra Migration yardımıyla DbOne ve DbTwo veritabanlarını oluşturuyorum. Birden fazla DbContext dosyası olduğu için migration işlemi yaparken hangisini oluşturacağını belirtmek gerekiyor.

1
2
Add-Migration -Context DbOneContext
Update-Database -Context DbOneContext
1
2
Add-Migration -Context DbTwoContext
Update-Database -Context DbTwoContext

Migration işlemleri sonrasında aşağıdaki gibi veritabanlarının oluşmuş olduğunu görebilirsiniz.

MultipleContext

Artık projeyi çalıştırıp Swagger yardımı ile CRUD işlemlerini yapmaya başlıyorum. DbOneContext için Post ve Get isteklerini yapıyorum.

MultipleContextPost DbOneContext-Post

MultipleContextGet DbOneContext-Get

DbOneContext parametresi ile DbOne veritabanına Post ve Get aksiyonları ile CRUD işlemleri yaptım. Aynı Şeklide DbTwoContext parametresi ile DbTwo veritabanına CRUD işlemlerini yapıyorum.

DbTwoContext-Post DbTwoContext-Post

DbTwoContext-Get DbTwoContext-Get

Veritabanı Verileri Veritabanı Verileri

Bu şekilde birden fazla dbcontext yapısını nasıl çalıştırabileceğimiz ile ilgili bir örnek gerçekleştirdik. Proje dosyalarını buradan indirebilirsiniz. Bir sonraki makalede görüşmek üzere.

This post is licensed under CC BY 4.0 by the author.

ASP.NET Core Distributed Redis Cache Kullanımı

ASP.NET Core Web API Üzerinde Middleware ve Attribute ile API Key Yetkilendirmesi