Retrieving Error Messages - NeoSOFT-Technologies/rest-dot-net-core GitHub Wiki

we have implemented two methods to get error messages in our project.

  • Retrieving Error Messages from database
  • Retrieving Error Messages from resource file

Retrieving Error Messages from database

Description

We have stored all error messages in database and retrieving it whenever required. We have also implemented caching of error messages.

Code Snippet

We have to create a entity class named Message inside Entities folder of Domain layer as shown below,

public class Message
    {
        public Guid MessageId { get; set; }
        public string Code { get; set; }
        public string MessageContent { get; set; }
        public string Language { get; set; }
        public MessageType Type { get; set; }

        public enum MessageType
        {
            Information,
            Error,
            Warning
        }
    }

Now, we have to add table name in the GloboTicketDbContext file Persistence layer. Add following line of code there.

public DbSet<Message> Messages { get; set; }

Also we have added three static rows for Messages table as shown below,

modelBuilder.Entity<Message>()
                .Property(s => s.Type)
                .HasConversion<string>();

            modelBuilder.Entity<Message>().HasData(new Message
            {
                MessageId = Guid.Parse("{253C75D5-32AF-4DBF-AB63-1AF449BDE7BD}"),
                Code = "1",
                MessageContent = "{PropertyName} is required.",
                Language = "en",
                Type = Message.MessageType.Error
            });

            modelBuilder.Entity<Message>().HasData(new Message
            {
                MessageId = Guid.Parse("{ED0CC6B6-11F4-4512-A441-625941917502}"),
                Code = "2",
                MessageContent = "{PropertyName} must not exceed {MaxLength} characters.",
                Language = "en",
                Type = Message.MessageType.Error
            });

            modelBuilder.Entity<Message>().HasData(new Message
            {
                MessageId = Guid.Parse("{FAFE649A-3E2A-4153-8FD8-9DCD0B87E6D8}"),
                Code = "3",
                MessageContent = "An event with the same name and date already exists.",
                Language = "en",
                Type = Message.MessageType.Error
            });

Now, create an interface named IMessageRepository inside Contracts folder of Application layer and implement that interface in MessageRepository inside Repositories folder of Persistence layer service class as below,

public interface IMessageRepository : IAsyncRepository<Message>
    {
        public Task<Message> GetMessage(string Code, string Lang);
    }
public class MessageRepository : BaseRepository<Message>, IMessageRepository
    {
        private readonly string cacheKey = $"{typeof(Message)}";
        private readonly ILogger _logger;
        private readonly ICacheService _cacheService;
        public MessageRepository(GloboTicketDbContext dbContext, ILogger<Message> logger, ICacheService cacheService) : base(dbContext, logger)
        {
            _logger = logger;
            _cacheService = cacheService;
        }

        public async Task<Message> GetMessage(string Code, string Lang)
        {
            _logger.LogInformation("GetMessage Initiated");
            if (!_cacheService.TryGet(cacheKey, out IReadOnlyList<Message> cachedList))
            {
                cachedList = await _dbContext.Set<Message>().ToListAsync();
                _cacheService.Set(cacheKey, cachedList);
            }
            _logger.LogInformation("GetMessage Completed");
            return cachedList.FirstOrDefault(x => x.Code == Code && x.Language == Lang);
        }
    }

The ICacheService interface and its implementation class MemoryCacheService are as shown below,

public interface ICacheService
    {
        bool TryGet<T>(string cacheKey, out T value);
        T Set<T>(string cacheKey, T value);
        void Remove(string cacheKey);
    }
public class MemoryCacheService : ICacheService
    {
        private readonly IMemoryCache _memoryCache;
        private readonly MemoryCacheEntryOptions _cacheOptions;
        public MemoryCacheService(IMemoryCache memoryCache, IOptions<CacheConfiguration> cacheConfig)
        {
            _memoryCache = memoryCache;
            var _cacheConfig = cacheConfig.Value;
            if (_cacheConfig != null)
            {
                _cacheOptions = new MemoryCacheEntryOptions
                {
                    AbsoluteExpiration = DateTime.Now.AddHours(_cacheConfig.AbsoluteExpirationInHours),
                    Priority = CacheItemPriority.High,
                    SlidingExpiration = TimeSpan.FromMinutes(_cacheConfig.SlidingExpirationInMinutes)
                };
            }
        }
        public bool TryGet<T>(string cacheKey, out T value)
        {
            _memoryCache.TryGetValue(cacheKey, out value);
            if (value == null) return false;
            else return true;
        }
        public T Set<T>(string cacheKey, T value)
        {
            return _memoryCache.Set(cacheKey, value, _cacheOptions);
        }
        public void Remove(string cacheKey)
        {
            _memoryCache.Remove(cacheKey);
        }
    }

We have localization support in our application to serve people from any culture who use any language.

Localization is the process to transalate the content to fulfil the demands of a particular culture / language. This does not limit to just transalting the texts, but also numbers, date and time formats, currency , symbols and so on.

We need to add ApplicationConstants helper class inside Helper folder of Application layer as shown below,

public static class ApplicationConstants
    {
        public const string LANG_ENG = "en";
        public const string LANG_AR = "ar";
    }

Here we have support for English and Arabic languages.

We have used this MessageRepository inside the CreateCategoryCommandValidator command of Category as shown below,

public class CreateCategoryCommandValidator: AbstractValidator<CreateCategoryCommand>
    {
        private readonly IMessageRepository _messageRepository;
        public CreateCategoryCommandValidator(IMessageRepository messageRepository)
        {
            _messageRepository = messageRepository;

            RuleFor(p => p.Name)
                .NotEmpty().WithMessage(GetMessage("1", ApplicationConstants.LANG_ENG))
                .NotNull()
                .MaximumLength(10).WithMessage(GetMessage("2", ApplicationConstants.LANG_ENG));
        }

        private string GetMessage(string Code, string Lang)
        {
            return _messageRepository.GetMessage(Code, Lang).Result.MessageContent.ToString();
        }
    }

With that done, let’s run the application and run post category with empty category name and see how the error get’s displayed on Swagger.

ErrorMsg1

⚠️ **GitHub.com Fallback** ⚠️