I am wondering if there is a way to avoid repetition in passing Request.Headersto each service method?
[HttpGet]
[Route("accounts({id:guid})")]
[Route("accounts")]
public async Task<HttpResponseMessage> GetAccount()
{
var query = Request.RequestUri.AbsolutePath.Split('/').Last() + Request.RequestUri.Query;
var response = await _accountService.GetAccount(query, Request.Headers);
return response;
}
[HttpGet]
[Route("accounts/{id:guid}")]
public async Task<HttpResponseMessage> GetAccountByID(Guid id)
{
var query = "accounts(" + id + ")";
var response = await _accountService.GetAccount(query, Request.Headers);
return response;
}
[HttpPatch]
[Route("accounts/{id:guid}")]
public async Task<HttpResponseMessage> UpdateAccount([FromBody] JObject account, Guid id)
{
var response = await _accountService.Update(account, id, Request.Headers);
return response;
}
[HttpPost]
[Route("accounts")]
public async Task<HttpResponseMessage> CreateAccount([FromBody] JObject account)
{
return await _accountService.Create(account, Request.Headers);
}
The client code is as follows:
public async Task<HttpResponseMessage> GetAccount(string query)
{
var response = Client.Instance.GetAsync(Client.Instance.BaseAddress + query);
var responseType = response.Result.StatusCode;
if (responseType == HttpStatusCode.NotFound)
{
return new HttpResponseMessage
{
StatusCode = responseType
};
}
return await response;
}
public async Task<HttpResponseMessage> Create(JObject account)
{
var request = new HttpRequestMessage(HttpMethod.Post, Client.Instance.BaseAddress + "accounts")
{
Content = new StringContent(account.ToString(), Encoding.UTF8, "application/json")
};
var response = await Client.Instance.SendAsync(request);
var responseType = response.StatusCode;
if (responseType == HttpStatusCode.BadRequest)
{
return new HttpResponseMessage
{
StatusCode = responseType
};
}
var uri = new Uri(response.Headers.GetValues("OData-EntityId").First());
var content = await Client.Instance.GetAsync(uri);
if (content.StatusCode == HttpStatusCode.BadRequest)
{
return new HttpResponseMessage
{
StatusCode = HttpStatusCode.BadRequest
};
}
return new HttpResponseMessage
{
Content = content.Content,
StatusCode = HttpStatusCode.NoContent == responseType ? HttpStatusCode.Created : responseType
};
}
public async Task<HttpResponseMessage> Update(JObject account, Guid id)
{
var request = new HttpRequestMessage(new HttpMethod("PATCH"), Client.Instance.BaseAddress + "accounts(" + id + ")")
{
Content = new StringContent(account.ToString(), Encoding.UTF8, "application/json")
};
var updateRequest = await Client.Instance.SendAsync(request);
var responseType = updateRequest.StatusCode;
if (responseType == HttpStatusCode.BadRequest)
{
return new HttpResponseMessage
{
StatusCode = responseType
};
}
var uri = new Uri(updateRequest.Headers.GetValues("OData-EntityId").Single());
var updateResponse = await Client.Instance.GetAsync(uri);
return updateResponse;
}
In my refactoring attempts, a very good suggestion was to combine service levels and a controller:
[HttpGet]
[Route("accounts({id:guid})")]
[Route("accounts")]
public async Task<HttpResponseMessage> GetAccount (HttpRequestMessage Request) {
var query = Request.RequestUri.AbsolutePath.Split('/').Last() + Request.RequestUri.Query;
var headers = Request.Headers;
var url = Client.Instance.BaseAddress + query;
var proxy = new HttpRequestMessage(HttpMethod.Get, url);
foreach (var header in headers) {
proxy.Headers.Add(header.Key, header.Value);
}
var response = await Client.Instance.SendAsync(proxy);
var responseType = response.StatusCode;
if (responseType == HttpStatusCode.NotFound)
return new HttpResponseMessage {
StatusCode = responseType
};
return response;
}
However, this does not solve my DRY violation problem.
Then I tried a more functional approach that might ultimately succeed, but perhaps it should be more reliable. He will need to handle different HTTP verbs. As you can see, all functions are static. There are no dependencies and almost no state mutations:
public async Task<HttpResponseMessage> FunctionalGetAccount(HttpRequestMessage globalRequest)
{
var request = new HttpRequest(globalRequest);
var query = CreateQuery(request);
var url = CreateURL(query);
var proxy = CreateProxy(url);
var headers = GetHeaders(request);
AddHeaders(headers, proxy);
var response = await AwaitResponse(proxy);
var httpStatusCode = MapHttpStatusCode(response.StatusCode);
var newHttpResponse = CreateResponse(response, httpStatusCode);
return newHttpResponse;
}
private static HttpStatusCode MapHttpStatusCode(HttpStatusCode input)
{
return HttpStatusCode.NotFound;
}
private static HttpResponseMessage CreateResponse(HttpResponseMessage response, HttpStatusCode newStatusCode)
{
var updatedResponse = response;
return updatedResponse;
}
private static async Task<HttpResponseMessage> AwaitResponse(HttpRequest proxy)
{
foreach (var header in proxy.Request.Headers)
{
Client.Instance.DefaultRequestHeaders.Add(header.Key, header.Value);
}
var response = Client.Instance.SendAsync(proxy.Request);
return await response;
}
private static void AddHeaders(HttpRequestHeaders headers, HttpRequest proxy)
{
foreach (var header in headers)
{
proxy.Request.Headers.Add(header.Key, header.Value);
}
}
private static HttpRequestHeaders GetHeaders(HttpRequest request)
{
var headers = request.Request.Headers;
return headers;
}
private static HttpRequest CreateProxy(string url)
{
var proxy = new HttpRequest(new HttpRequestMessage(HttpMethod.Get, url));
return proxy;
}
private static string CreateURL(string query)
{
var url = Client.Instance.BaseAddress + query;
return url;
}
private static string CreateQuery(HttpRequest Request)
{
var query = Request.Request.RequestUri.AbsolutePath.Split('/').Last() + Request.Request.RequestUri.Query;
return query;
}
Although this is not necessarily central to the issue, I have defined HttpRequest:
public class HttpRequest : ValueObject<HttpRequest>
{
public virtual HttpRequestMessage Request { get; }
public HttpRequest(HttpRequestMessage request)
{
Request = Cloner.CloneHttpRequestMessageAsync(request).Result;
}
protected override bool EqualsCore(HttpRequest other)
{
return other.Request.Content == Request.Content
&& other.Request.Method == Request.Method
&& other.Request.RequestUri == Request.RequestUri;
}
protected override int GetHashCodeCore()
{
return ((Request.Method.GetHashCode() * 397) ^ Request.Content.GetHashCode()) ^ Request.RequestUri.GetHashCode();
}
}
, Request.Headers serivce?
, .