jeudi 10 décembre 2020

Dependency injection management with 'Unit of work' and 'Repository' design patterns using SqlConnection instance

A lot of time, I face a situation where I want to execute a number of statements without re-opening a connection.

So my practice so far is to create a 'unit of work' class, open a connection and pass it to all the repositories.

Here is an example of code that I have:

public class BasicEmailUnitOfWork : IBasicEmailUnitOfWork
{
        private readonly IDNTConnectionFactory _conn; 

        public BasicEmailUnitOfWork(IDNTConnectionFactory connection)
        {
            _conn = connection; 
        }

        public (string, string, string, string, string) RenderEmailTemplate(string emailTemplateEventName, int userId)
        {
            string userPhone = String.Empty;
            string userEmail = String.Empty;
            string emailTitletranslatedContent = String.Empty;
            string emailBodytranslatedContent = String.Empty;
            string smstranslatedContent = String.Empty;

            try
            {
                IDbConnection connectionDb = _conn.GetConnection();

                IEmailSMSTemplateRepository _emailSMSTemplateRepository = new EmailSMSTemplateRepository(connectionDb);

                IUserInformationRepository _userInformationRepository = new UserInformationRepository(connectionDb);

                List<EmailSMSTemplateTDO> emailSmsesList = _emailSMSTemplateRepository.GetAllTemplates(emailTemplateEventName);

                UserInfoDTO userInfoDTO = _userInformationRepository.GetAllInformation(userId);
                userPhone = userInfoDTO.Phone;
                userEmail = userInfoDTO.Email;

                foreach (EmailSMSTemplateTDO emailTemplate in emailSmsesList)
                {
                    emailTitletranslatedContent = TranslateContent(connectionDb, userInfoDTO, emailTemplate.EmailTitle);

                    emailBodytranslatedContent = TranslateContent(connectionDb, userInfoDTO, emailTemplate.EmailBody);

                    if (emailTemplate.IsSMS)
                        smstranslatedContent = TranslateContent(connectionDb, userInfoDTO, emailTemplate.SMSBody);
                }
            }
            catch(Exception ex)
            {
                Console.WriteLine(ex.Message);
            }
            finally
            {
                _conn.CloseConnection();
            }

            return (userPhone, userEmail,emailTitletranslatedContent, emailBodytranslatedContent, smstranslatedContent);
    }

    private string TranslateContent(IDbConnection connectionDb, UserInfoDTO userInfoDTO, string content)
    {
            InterpreterContext intContext = new InterpreterContext();
            intContext.user = userInfoDTO;
            intContext.Content = content;

            IExpression emailSMSContentInterpreter = new EmailSMSContentInterpreter(connectionDb);
            emailSMSContentInterpreter.Interpret(intContext);
            return emailSMSContentInterpreter.BodyContentOutPut;
    }
}

Although, I can unit test the repositories without a problem, I have 2 dependencies in the function: EmailSMSTemplateRepository and UserInformationRepository.

What is the best practice? What other way is there to share the connection, take note also that I need some class to dispose of the connection when the object is being disposed or if there is an error.

By the way, I use Dapper for the application, same micro-ORM that was used to build this site.

Aucun commentaire:

Enregistrer un commentaire