Base solution for your next web application
Open Closed

Reading from Read Replica database and write to primary database #9857


User avatar
0
bulutyonetim created

Prerequisites

  • What is your product version? v9.0.1
  • What is your product type (Angular or MVC)? ASP.NET CORE & Angular (single solution)
  • What is product framework type (.net framework or .net core)? .NET Core 3.1

If issue related with ABP Framework

  • What is ABP Framework version? 5.10.1

Hi

We are using Amazon Relational Database Service (RDS). We have one primery database which is read/write databse. also we have one Read Replica database which is only read-only. Both database schema's are exactly same and the data is almost same but maybe with a few milsecond dely.

When we want to write any record to database we should connect to 1st database, but when we want to read we need to connect to read replica database. (also sometimes we may need to read from 1st database).

Can you guide me how to achive this via Asp.net Zero?

Thanks


5 Answer(s)
  • User Avatar
    0
    zony created
    Support Team

    Hi bulutyonetim, There are two ways to achieve this:

    1. Use multiple DbContexts, DbContext1 reads data, DbContext2 writes data. This is an example.
    2. The database connection string of DbContext is parsed from IConnectionStringResolver, you can reimplement it and add your own logic.
  • User Avatar
    0
    bulutyonetim created

    Hi Zony,

    Thanks for answer.

    I saw first solution, but it is not good solution for my scenario because In that case I will have all tables and Dbsets and etc.. duplicated and project will turn into mess.

    Can you describe second solution a bit more? Is ther any documentation for this. any code sample?

    Thanks

  • User Avatar
    0
    bulutyonetim created

    Hi,

    I managed to override IConnectionStringResolver successfully and now I can change connection string dynamically but how should I know that this is a read request so I should change connection string to Read Replica database?

    I found this solution in one of support tickets. It says:

    You can define an attribute (for Get only) and use it the operations you want to use read-only database.

    Can you show me how to add attribute to ConnectionStringResolveArgs for example when calling a get method in any repository? So, in this case I can decide based on that attribute inside my custom IConnectionStringResolver and change connection string.

  • User Avatar
    0
    zony created
    Support Team

    Hi bulutyonetim, ConnectionStringResolveArgs will only be assigned when the DbContext is created by the unit of work, and it is generally not recommended to change it. You can try to use IAmbientDataContext to share configuration, such as the following pseudo code:

        public class YourAppService : ApplicationService
        {
            private readonly IAmbientDataContext _ambientDataContext;
            public const string ReadOrWrite = nameof(ReadOrWrite);
    
            public YourAppService(IAmbientDataContext ambientDataContext)
            {
                _ambientDataContext = ambientDataContext;
            }
    
            public async Task YourAction()
            {
                _ambientDataContext.SetData(ReadOrWrite,"Write");
    
                await Task.CompletedTask;
            }
        }
    
        public class YourConnectionStringResolver : IConnectionStringResolver
        {
            private readonly IAmbientDataContext _ambientDataContext;
    
            public YourConnectionStringResolver(IAmbientDataContext ambientDataContext)
            {
                _ambientDataContext = ambientDataContext;
            }
    
            public string GetNameOrConnectionString(ConnectionStringResolveArgs args)
            {
                if ((string) _ambientDataContext.GetData(YourAppService.ReadOrWrite) == "Write")
                {
                    return "Write Database";
                }
                else
                {
                    return "Read Database";
                }
            }
        }
    

    Another idea is to combine HTTP Header and inject IHttpContextAccessor in ConnectionStringResolveArgs to get a specific request header (depending on you). Switch to different databases according to different request headers.

  • User Avatar
    0
    bulutyonetim created

    IAmbientDataContext helped me to achive what I need.

    Thanks @zony.