Multi-Tier Integration Service
C# Service for integrating multi-tier applications
Updated: 03 September 2023
For applications that span multiple tiers or make use of a separate data accesss and web application layers a generic integration service can be used to communicate between tiers
Service Definition
The service enables you to call controllers on the underlying tier by their route, provided that complex objects are supplied in the request body where needed
1public class IntegrationService2{3 private string _apiBaseUrl;4 private WebProxy _proxy;5
6 public IntegrationService(string apiBaseUrl, WebProxy proxy = null)7 {8 _apiBaseUrl = apiBaseUrl;9 _proxy = proxy;10 }11
12 /// <summary>13 /// Creates a new HttpClient instance that can be used to make HTTP requests to the API endpoint with the endpoint and proxy precofigured14 /// Supports basic HTTP methods and configurations. Essentially enables client to call a function on another application's route with15 /// params as a single POST DTO if necessary16 /// </summary>17 /// <returns></returns>18 public HttpClient GetClient()19 {20 HttpClient client;21
22 if (_proxy != null)23 {24 var handler = new HttpClientHandler()25 {26 Proxy = _proxy27 };28 client = new HttpClient(handler);29 }30 else31 {32 client = new HttpClient();33 }34
35 client.BaseAddress = new Uri(_apiBaseUrl);36
37 return client;38 }39
40 #region GET Methods41 public async Task<string> Get(string path)42 {43 using (var client = GetClient())44 {45 var response = await client.GetStringAsync(path);46 return response;47 }48 }49
50 public async Task<T> Get<T>(string path)51 {52 using (var client = GetClient())53 {54 var response = await client.GetStringAsync(path);55 var data = JsonConvert.DeserializeObject<T>(response);56 return data;57 }58 }59 #endregion60
61 #region POST Methods62 public async Task<string> Post(string path, object requestData)63 {64 using (var client = GetClient())65 {66 var requestContent = new StringContent(67 JsonConvert.SerializeObject(requestData),68 Encoding.UTF8,69 "application/json"70 );71
72 var response = await client.PostAsync(path, requestContent);73 var responseString = await response.Content.ReadAsStringAsync();74
75 return responseString;76 }77 }78
79 public async Task<T> Post<T>(string path, object requestData)80 {81 using (var client = GetClient())82 {83 var requestContent = new StringContent(84 JsonConvert.SerializeObject(requestData),85 Encoding.UTF8,86 "application/json"87 );88
89 var response = await client.PostAsync(path, requestContent);90 var responseString = await response.Content.ReadAsStringAsync();91 var data = JsonConvert.DeserializeObject<T>(responseString);92
93 return data;94 }95 }96 #endregion97
98 #region PUT Methods99 public async Task<string> Put(string path, object requestData)100 {101 using (var client = GetClient())102 {103 var requestContent = new StringContent(104 JsonConvert.SerializeObject(requestData),105 Encoding.UTF8,106 "application/json"107 );108
109 var response = await client.PutAsync(path, requestContent);110 var responseString = await response.Content.ReadAsStringAsync();111
112 return responseString;113 }114 }115
116 public async Task<T> Put<T>(string path, object requestData)117 {118 using (var client = GetClient())119 {120 var requestContent = new StringContent(121 JsonConvert.SerializeObject(requestData),122 Encoding.UTF8,123 "application/json"124 );125
126 var response = await client.PutAsync(path, requestContent);127 var responseString = await response.Content.ReadAsStringAsync();128 var data = JsonConvert.DeserializeObject<T>(responseString);129
130 return data;131 }132 }133 #endregion134
135 #region DELETE Methods136 public async Task<string> Delete(string path)137 {138 using (var client = GetClient())139 {140 var response = await client.DeleteAsync(path);141 var responseString = await response.Content.ReadAsStringAsync();142
143 return responseString;144 }145 }146
147 public async Task<T> Delete<T>(string path)148 {149 using (var client = GetClient())150 {151 var response = await client.DeleteAsync(path);152 var responseString = await response.Content.ReadAsStringAsync();153 var data = JsonConvert.DeserializeObject<T>(responseString);154
155 return data;156 }157 }158 #endregion159}160
161/// <summary>162/// Proxy settings, needed for accessing accross tiers163/// </summary>164public class ProxySettings165{166 public string Endpoint { get; set; }167 public bool BypassOnLocal { get; set; } = true;168 public bool EnvironmentHasProxy() => !string.IsNullOrEmpty(Endpoint);169}
Confugure the Service
You can configure the service in your startup.cs
as follows:
1 services.AddScoped<IntegrationService>(s =>2 {3 var proxySettings = Configuration4 .GetSection("ProxySettings")5 .Get<ProxySettings>();6
7 var intBaseUrl = Configuration.GetValue<string>("IntegrationUrl");8
9 if (proxySettings.EnvironmentHasProxy())10 {11 var proxy = new WebProxy(12 proxySettings.Endpoint,13 proxySettings.BypassOnLocal14 );15
16 return new IntegrationService(intBaseUrl, proxy);17 }18 else19 {20 return new IntegrationService(intBaseUrl);21 }22 });
The above is a bit overkill as it does the proxy checking too, but you don’t need that if you know your proxy configuration beforehand or are not using a proxy
Using the Service
To use the service you need to request it in a controller constructor via Dependency Injection
1public class MyController : Controller {2
3 private IntegrationService _integrationService;4
5 public MyController(IntegrationService integrationService)6 {7 _integrationService = integrationService;8 }9
10 public async task<MyObject> MyFunction(ComplexObject data)11 {12 var result = await integrationService.Post<MyObject>("api/DoStuff", data);13
14 return result;15 }16}
You will need the following in your appsettings.json
1...,2"ProxySettings: {3 "Endpoint": "",4 "BypassOnLocal": true5},6...