EIP – Application Adapter Design Pattern
Summary
Some legacy applications often communicate messages in proprietary formats, or messages the Receiver application needs to translate to make sense of. EDIFACT, X12 are common formats that often require translation/transformation. A common design pattern in C# is to use the Adapter pattern. The Adapter pattern aims to solve incompatibilities between two interfaces – it behaves like a bridge.
C# Implementation
The implementation below is straightforward and used quite often when translating one message format to another. The code below demonstrates how to convert XML to JSON using the Adapter Pattern.
I’ve created the Adapted using the regular Azure Function, however for workloads that require transformations like this, the Application Adapter really should reside in a Durable Function or another Background Service worker function.
using Microsoft.AspNetCore.Http;
using Microsoft.AspNetCore.Mvc;
using Microsoft.Azure.WebJobs;
using Microsoft.Azure.WebJobs.Extensions.Http;
using Microsoft.Extensions.Logging;
using Newtonsoft.Json;
using System;
using System.Collections.Generic;
using System.Linq;
using System.Threading.Tasks;
using System.Xml.Linq;
namespace Application_Adapter
{
public static class AdaptMessage
{
[FunctionName("XMLtoJSON")]
public static async Task<IActionResult> Run(
[HttpTrigger(AuthorizationLevel.Function, "get", "post", Route = null)] HttpRequest req,
ILogger log)
{
log.LogInformation("C# HTTP trigger function processed a request.");
var xmlConverter = new XmlTransform();
var adapter = new XmlToJsonAdapter(xmlConverter);
object customer = adapter.ConvertXmlToJson();
return new OkObjectResult(customer);
}
public class Customer
{
public string Firstname { get; set; }
public string Lastname { get; set; }
public string Email { get; set; }
public string Address1 { get; set; }
public int ID { get; set; }
}
public static class CustomerDataServices
{
public static List<Customer> GetData() =>
new List<Customer>
{
new Customer { Firstname = "Adam", Lastname = "Johnson", Email = "adam.johnson@acme.com", Address1 = "IBM, 123 Fore Street", ID = 20076 },
new Customer { Firstname = "Jacob", Lastname = "Smith", Email = "jacob.smith@acme.com", Address1 = "IBM, ,123 Fore Street", ID = 20077 },
new Customer { Firstname = "Maria", Lastname = "Costa", Email = "maria.costa@acme.com", Address1 = "Microsoft, 100 Linton Drive", ID = 10077 }
};
}
public class XmlTransform
{
public XDocument GetXML()
{
var xmlCustomer = new XDocument();
var xElement = new XElement("Customers");
var xAttributes = CustomerDataServices.GetData()
.Select(customer => new XElement("Customers",
new XAttribute("Firstname", customer.Firstname),
new XAttribute("Lastname", customer.Lastname),
new XAttribute("Email", customer.Email),
new XAttribute("ID", customer.ID)));
xElement.Add(xAttributes);
xmlCustomer.Add(xElement);
Console.WriteLine(xmlCustomer);
return xmlCustomer;
}
}
public class JsonTransform
{
private IEnumerable<Customer> _customer;
public JsonTransform(IEnumerable<Customer> customers)
{
_customer = customers;
}
public object ConvertToJson()
{
var jsonCustomer = JsonConvert.SerializeObject(_customer, Formatting.Indented);
Console.WriteLine($"JSON Conversion: \n {jsonCustomer}");
return jsonCustomer;
}
}
public interface IXmlToJson
{
object ConvertXmlToJson();
}
public class XmlToJsonAdapter : IXmlToJson
{
private readonly XmlTransform _xmlConverter;
public XmlToJsonAdapter(XmlTransform xmlConverter)
{
_xmlConverter = xmlConverter;
}
public object ConvertXmlToJson()
{
var customers = _xmlConverter.GetXML()
.Element("Customers")
.Elements("Customers")
.Select(Customer => new Customer
{
Firstname = Customer.Attribute("Firstname").Value,
Lastname = Customer.Attribute("Lastname").Value,
Email = Customer.Attribute("Email").Value,
ID = Convert.ToInt32(Customer.Attribute("ID").Value)
});
object output = new JsonTransform(customers)
.ConvertToJson();
return output;
}
}
}
}
Application Adapter as a Service
The implementation above takes both a GET and POST HTTP request. In order to turn this into an Application Adapter Service, this implementation would need to be deployed as a self-contained microservice, only accepting HTTP POST method.