How to Use Runtime Messages in Asp.net Core

1. Introduction

When you are creating the APIs, you should need to handle many messages and return them to the client, for example, if there is an error or can’t find the data, you need to return the corresponding messages, you can hardcode these messages in the API functions, but just thinking about if your API in the UAT and maybe users want to change the messages again and again, and you will need to find these messages in codes and re-publish them again and again.

If we put all of the messages in the XML files and can be updated in runtime, then we don’t need to change and re-publish the source code, that’s would be great, right?

Ok, let’s start!

Do you want to be a good trading in cTrader?   >> TRY IT! <<

2. Define the XML file

As we want to put the messages into XML file, we need to define the XML format, we can base on the XML attribute to get the node’s value, so the format as below

<?xml version="1.0" encoding="utf-8" ?>
<Messages>
 <Item id="NoDataFound">There is no data found!</Item>
 <Item id="InvalidDateFormat">The date value is invalid!</Item>
</Messages>

We can split the XML file based on each function, this can be easier to manage and you can find the message quickly, for example:

Common.xml
User.xml

3. May the key of messages

There is an id attribute in our XML file, we need to get the message based on this id, but I don’t want to hardcode it so we need to create mapping keys below

public static class MsgKey
{
    public static class Common
    {
        public const string NoDataFound = "NoDataFound";
        public const string InvalidDateFormat = "InvalidDateFormat";
    }

    public static class User
    {
        public const string NoUserFound = "NoUserFound";
        public const string UserExist = "UserExist";
        public const string UserInvalid = "UserInvalid";
    }
}

4. Create the message helper

We need to handle the message from different XML files, so we need to load all files in runtime

//load specify XML files based on the function or section
List<string> xmlFiles = files.Split(',').ToList();
foreach (var file in xmlFiles)
{
    //handle the XML file one by one
    LoadMessages(file);
}

Handle the XML file

private void LoadMessages(string xmlFile)
{
    var filePath = Path.Combine(Directory.GetCurrentDirectory(), $"Messages\\{xmlFile}.xml");
    var xdoc = XDocument.Load(filePath);
    var items = xdoc.Descendants("Item")
              .Select(item => new
              {
                  Id = item.Attribute("id").Value,
                  Value = item.Value
              });
    foreach (var msg in items)
    {
        var id = msg.Id;
        var message = msg.Value;
        if (id != null && !Msg.ContainsKey(id))
        {
            Msg[id] = message;
        }
    }
}

the completed codes below

using System.Xml.Linq;

public class MessageHelper
{
    public MessageHelper() { }

    public Dictionary<string, string> Msg { get; private set; }

    public void Init(string files)
    {
        Msg = new Dictionary<string, string>();

        List<string> xmlFiles = files.Split(',').ToList();
        foreach (var file in xmlFiles)
        {
            LoadMessages(file);
        }
    }

    private void LoadMessages(string xmlFile)
    {
        var filePath = Path.Combine(Directory.GetCurrentDirectory(), $"Messages\\{xmlFile}.xml");
        var xdoc = XDocument.Load(filePath);

        var items = xdoc.Descendants("Item")
                  .Select(item => new
                  {
                      Id = item.Attribute("id").Value,
                      Value = item.Value
                  });

        foreach (var msg in items)
        {
            var id = msg.Id;
            var message = msg.Value;
            if (id != null && !Msg.ContainsKey(id))
            {
                Msg[id] = message;
            }
        }
    }
}

5. Usage

1) Register the message helper in program.cs

builder.Services.AddScoped<MessageHelper>();

2) Create a testing API controller MessageTesterController, inject the message helper and pass the XML file name

protected readonly ILogger<MessageTesterController> _logger;
private MessageHelper _messageHelper;
public MessageTesterController(ILogger<MessageTesterController> logger, MessageHelper messageHelper)
{
    this._logger = logger;
     _messageHelper = messageHelper;
     //pass the XML file name in Message folder
     _messageHelper.Init("Common,User");
}

Use the key to get the message:

var noDataFoundMsg = _messageHelper.Msg[MsgKey.Common.NoDataFound];
var userInvalidMsg = _messageHelper.Msg[MsgKey.User.UserInvalid];

The completed codes below:

namespace MyDemo.Controllers
{
    [ApiController]
    [Route("api/[controller]")]
    public class MessageTesterController : ControllerBase
    {
        protected readonly ILogger<MessageTesterController> _logger;

        private MessageHelper _messageHelper;

        public MessageTesterController(ILogger<MessageTesterController> logger, MessageHelper messageHelper)
        {
            this._logger = logger;
            _messageHelper = messageHelper;
            _messageHelper.Init("Common,User");
        }

        /// <summary>
        /// Get the dynamic messages
        /// </summary>
        /// <returns></returns>
        [HttpGet("get-message")]
        public async Task<ActionResult<Object>> GetMessage()
        {
            var apiResult = new ApiResult<Object>();

            try
            {
                var noDataFoundMsg = _messageHelper.Msg[MsgKey.Common.NoDataFound];
                var userInvalidMsg = _messageHelper.Msg[MsgKey.User.UserInvalid];

                _logger.LogDebug("noDataFoundMsg ================ {0}", noDataFoundMsg);
                _logger.LogDebug("userInvalidMsg ================ {0}", userInvalidMsg);

                var returnObj = new
                {
                    noDataFound = noDataFoundMsg,
                    userInvalid = userInvalidMsg
                };

                apiResult.Data = returnObj;

                return Ok(apiResult);

            }
            catch (Exception ex)
            {
                _logger.LogError(ex, "MessageTester Exception");
                apiResult.Success = false;
                apiResult.Message = ex.Message;
                return StatusCode(500, apiResult);
            }
        }

    }
}

And you can find the result in the log file:

6. Conclusion

Put the messages in XML files can be easy to manage, and you can update the messages in runtime, this can save you time to re-build and publish your project again and again, also, you can handle the internationalization with this approach, please feel free to let me know if you have any other ideas 🙂

And you can find the completed source code and demo project on my github.

Loading

Views: 0
Total Views: 181 ,

Oh hi there 👋
It’s nice to meet you.

Sign up to receive awesome content in your inbox.

We don’t spam! Read our privacy policy for more info.

Oh hi there 👋 It’s nice to meet you.

Sign up to receive awesome content in your inbox.

We don’t spam! Read our privacy policy for more info.

Ads Blocker Image Powered by Code Help Pro

Ads Blocker Detected!!!

We have detected that you are using extensions to block ads. Please support us by disabling these ads blocker.

Thank you so much!