Access Web API deserialization/serialization methods within controller body - c#

Is there a way to deserialize/serialize JSON POST content/response within the body of a Web API controller in the same exact way that the controller would deserialize/serialize the JSON content/response had it been an argument/explicit type?
My motivation is that I am trying to build a "magic" API controller that can provide access to my service commands quickly if developers do not have enough time to build a strongly-typed action to access them. Say I have the following actions:
public Brownie Brownie(BrownieInputModel inputModel)
{
...
var brownie = brownieService.GetBrownie(inputModel);
return brownie;
}
public Pizza Pizza(PizzaInputModel inputModel)
{
...
var pizza = pizzaService.GetPizza(inputModel);
return pizza;
}
Would it be possible to do something like this (in psuedo-code):
public object FoodStuff(string methodName)
{
var inputModel = WebApi.Deserialize(Request.JsonContent); // <-- pseudo
var serviceMethod = GetServiceMethodFromMethodName(methodName);
var result = serviceMethod.Execute();
return WebApi.Serialize(result); // <-- pseudo
}

I think HttpRequestMessage and HttpResponseMessage classes can help you solve this problem. Using them you code can look like that:
public async Task<HttpResponseMessage> Post(
string methodName, HttpRequestMessage request)
{
HttpResponseMessage response;
switch (methodName)
{
case "brownie":
response = await HandleBrownieAsync(request);
break;
case "pizza":
response = await HandlePizzaAsync(request);
break;
default:
throw new NotSupportedException();
}
return response;
}
private async Task<HttpResponseMessage> HandleBrownieAsync(HttpRequestMessage request)
{
var brownie = await GetRequestContentAsync<Brownie>(request);
return await CreateJsonResponseAsync(brownie);
}
private async Task<HttpResponseMessage> HandlePizzaAsync(HttpRequestMessage request)
{
var pizza = await GetRequestContentAsync<Pizza>(request);
return await CreateJsonResponseAsync(pizza);
}
private async Task<T> GetRequestContentAsync<T>(HttpRequestMessage request)
{
var contentString = await request.Content.ReadAsStringAsync();
return await JsonConvert.DeserializeObjectAsync<T>(contentString);
}
private async Task<HttpResponseMessage> CreateJsonResponseAsync<T>(T content)
{
var response = new HttpResponseMessage(HttpStatusCode.OK)
{
Content = new StringContent(
await JsonConvert.SerializeObjectAsync(content),
Encoding.UTF8,
"application/json")
};
return response;
}
And if you use these simplified models:
public class Brownie
{
public bool HasNuts { get; set; }
}
public class Pizza
{
public string CheeseType { get; set; }
}
Then you can make POST requests:
URL: http://api.url?methodName=brownie,
Body: {"hasNuts":true}
or
URL: http://api.url?methodName=pizza,
Body: {"cheeseType":"Mozzarella"}

Related

Error while returning HttpResponseMessage in.NET core

I have a simple API gateway controller which returns an IActionResult. The issue is I am not able to read the body of the response.
If I comment out the using block in ExecuteResultAsync it seems to work fine but there is not content/body.
Not sure how to get this working with the httpbody being returned. RouteRequest returning HttpResponseMessage is not an option as it puts the response from the microservice as the body of the response from the Gateway.
So I need to use the HttpResponseMessageResult middleware, which works as expected for headers but not for the body.
public async Task<IActionResult> RouteRequest()
{
// Calls a method which send a request and gets a response and constructs a HttpResponseMessage
_contextAccessor.HttpContext.Response.RegisterForDispose(response);
return new HttpResponseMessageResult(response);
}
public class HttpResponseMessageResult : IActionResult
{
private readonly HttpResponseMessage _responseMessage;
public HttpResponseMessageResult(HttpResponseMessage responseMessage)
{
_responseMessage = responseMessage;
}
public async Task ExecuteResultAsync(ActionContext context)
{
context.HttpContext.Response.StatusCode = (int)_responseMessage.StatusCode;
var responseMessageHeadersArray = _responseMessage.Headers.ToArray();
for (int i = 0; i < responseMessageHeadersArray.Length; i++)
{
var header = responseMessageHeadersArray[i];
context.HttpContext.Response.Headers.TryAdd(header.Key, new StringValues(header.Value.ToArray()));
}
using (var stream = await _responseMessage.Content.ReadAsStreamAsync())
{
await stream.CopyToAsync(context.HttpContext.Response.Body);
await context.HttpContext.Response.Body.FlushAsync();
}
}
}
Try this out, based on this good answer to a similar question, I used the ObjectResult class instead of manually manipulating the streams. When I run it with response from one of our API's (JSON), I get the same amount of data in the body of objectResult when it calls ExecuteAsync as were in the initial response.
public class HttpResponseMessageResult : IActionResult
{
private readonly HttpResponseMessage _responseMessage;
public HttpResponseMessageResult(HttpResponseMessage responseMessage)
{
_responseMessage = responseMessage;
}
public async Task ExecuteResultAsync(ActionContext context)
{
var objectResult = new ObjectResult(await _responseMessage.Content.ReadAsStreamAsync())
{StatusCode = (int)_responseMessage.StatusCode};
foreach (KeyValuePair<string, IEnumerable<string>> h in _responseMessage.Headers)
{
context.HttpContext.Response.Headers.TryAdd(h.Key, string.Join("", h.Value));
}
await objectResult.ExecuteResultAsync(context);
}
}

How to return an html document from WebApi 2 action using IHttpActionResult interface?

I need to build an html document and return it in my web api. All available answers on the net and the forum suggest using HttpResponseMessage. I would like to achieve this by IHttpActionResult. Below is what I have thus far:
[ResponseType(typeof(HttpResponseMessage))]
public async Task<IHttpActionResult> GetNotesViewModels()
{
var note = await GetHtmlText();
var response = new HttpResponseMessage();
response.Content = new StringContent(note);
response.Content.Headers.ContentType = new MediaTypeHeaderValue("text/html");
return Ok(ResponseMessage(response));
}
I am not receiving what I would like. What is missing here?
You could implement your own HtmlResult, like following (free-handed):
public class HtmlActionResult : IHttpActionResult
{
public HtmlActionResult (HttpRequestMessage request, string content)
{
Request = request;
Content= content;
}
public string Content { get; private set; }
public HttpRequestMessage Request { get; private set; }
public Task<HttpResponseMessage> ExecuteAsync(CancellationToken cancellationToken)
{
return Task.FromResult(ExecuteResult());
}
public HttpResponseMessage ExecuteResult()
{
var response = new HttpResponseMessage();
if (!string.IsNullOrWhiteSpace(Content))
response.Content = new StringContent(Content, Encoding.UTF8, "text/html");
response.RequestMessage = Request;
return response;
}
}
And use it like this:
public async Task<IHttpActionResult> GetNotesViewModels()
{
var note = await GetHtmlText();
return new HtmlActionResult(Request, note);
}

separation of layers when performing CRUD operations

I am confused on where my deserialization logic should go.
I have a controller that returns data to the client specifically for a GET operation:
public accountscontroller:apicontroller
{
[HttpGet]
[Route("", Name = "GetAccount")]
public async Task<IHttpActionResult> GetAccount()
{
var query = Request.RequestUri.PathAndQuery.Split('/')[2];
var response = await _accountService.GetAccount(query);
if (response == null)
{
return NotFound();
}
return Ok(response);
}
//morestuff
}
and the AccountService.GetAccount code is the following:
public class AccountService
{
public async Task<Account> GetAccount(string query)
{
var task = await Client.HTTPCLIENT.GetAsync(Client.HTTPCLIENT.BaseAddress + query);
var jsonString = await task.Content.ReadAsStringAsync();
var value = JsonConvert.DeserializeObject<RootObject>(jsonString);
return value.value.FirstOrDefault();
}
//morestuff
}
as you can see, the deserialization is handled in the AccountService, not the AccountsController
however, if we look at the POST operation:
public class AccountController
{
[HttpPost]
[Route("", Name = "CreateAccount")]
public async Task<IHttpActionResult> CreateAccount([FromBody] JObject account)
{
if (!ModelState.IsValid)
{
return BadRequest(ModelState);
}
var response = await _accountService.Create(account);
var newAccount = await response.Content.ReadAsAsync<object>();
return Ok(newAccount);
}
and the underlying Create method within the AccountService:
public async Task<HttpResponseMessage> Create(JObject account)
{
var request = new HttpRequestMessage(HttpMethod.Post, Client.HTTPCLIENT.BaseAddress + "accounts")
{
Content = new StringContent(account.ToString(), Encoding.UTF8, "application/json")
};
var response = await Client.HTTPCLIENT.SendAsync(request);
var uri = new Uri(response.Headers.GetValues("OData-EntityId").FirstOrDefault());
return await Client.HTTPCLIENT.GetAsync(uri);
}
you will see that in fact the deserialization happens on the controller level.
How can I encapsulate the deserialization logic for CRUD operations, such as GET/PUT/POST for consistency?

Is it possible to specify the response content inside a IHttpActionResult response to be strongly typed? [duplicate]

It is possible and not ideal to do this: (a vastly simplified example!)
[Serializable]
public class MyRecord
{
public string key {get; set;}
public string data {get; set;}
}
public async Task<IHttpActionResult> Get(string SomeKey)
{
if(ExistsInDB(SomeKey))
{
return Ok(SomeRecordFromDB(SomeKey)); //SomeRecord() returns a POCO MyRecord.
}
else
{
//I know I can return NotFound() but not the focus of my Q
return Ok(false); //returns "False"
}
}
Effectively demonstrating no compile time error checking on the return type. This example will return either a JSon serialized POCO class (JSon is set on my accept header) or it will return the text "False" which puts the burden of type checking on the client.
I wouldn't do this by design but my team is refactoring a lot of code from asmx/svc and mistakes creep in. I like it when the compiler helps to trap these kinds of errors rather than waiting for module or unit testing.
Is the right way to go back to using strongly typed method signatures (avoiding the IHttpActionResult and the Ok(), NotFound(), etc helpers or is there something like a IHttpActionResult<T> that can be used to make sure the right type is being returned?
M.
First of all, it is a good practice to return IHttpActionResult, indicating the corresponding http status. Something like:
public async Task<IHttpActionResult> Get(string SomeKey)
{
if(ExistsInDB(SomeKey))
return Ok(SomeRecordFromDB(SomeKey));
return NotFound();
}
But if you really want to have a strongly typed api, you can do something like:
public async Task<StronglyTypeResponse> Get()
{
return new StronglyTypeResponse();
}
Or, create a typed response, and you'll keep the http status code, etc in your response:
public class StronglyTypeResponse
{
}
public class StronglyTypedResult<T> : IHttpActionResult
{
HttpConfiguration _configuration;
T _content;
HttpStatusCode _statusCode;
HttpRequestMessage _request;
public StronglyTypedResult(T content, HttpStatusCode statusCode, HttpRequestMessage request, HttpConfiguration configuration)
{
_content = content;
_request = request;
_configuration = configuration;
_statusCode = statusCode;
}
public Task<HttpResponseMessage> ExecuteAsync(CancellationToken cancellationToken)
{
var response = new HttpResponseMessage(_statusCode)
{
Content = new ObjectContent<dynamic>(_content, _configuration.Formatters.JsonFormatter),
RequestMessage = _request,
ReasonPhrase = "some phrase"
};
return Task.FromResult(response);
}
}
And then you can create your method:
public async Task<StronglyTypedResult<StronglyTypeResponse>> Get()
{
return new StronglyTypedResult<StronglyTypeResponse>(new StronglyTypeResponse(), HttpStatusCode.OK, Request, Configuration);
}
Creating your own custom generic IHttpActionResult
It's basically the same:
public class IHttpActionResult<T> : System.Web.Http.IHttpActionResult
{
HttpConfiguration _configuration;
T _content;
HttpStatusCode _statusCode;
HttpRequestMessage _request;
public IHttpActionResult(T content, HttpStatusCode statusCode, HttpRequestMessage request, HttpConfiguration configuration)
{
_content = content;
_request = request;
_configuration = configuration;
_statusCode = statusCode;
}
public Task<HttpResponseMessage> ExecuteAsync(CancellationToken cancellationToken)
{
var response = new HttpResponseMessage(_statusCode)
{
Content = new ObjectContent<dynamic>(_content, _configuration.Formatters.JsonFormatter),
RequestMessage = _request,
ReasonPhrase = "some phrase"
};
return Task.FromResult(response);
}
}
And now you can return the class you want with a typed IHttpActionResult:
public async Task<IHttpActionResult<YourClass>> Get()
{
var yourclass = new YourClass();
return new IHttpActionResult<YourClass>(yourclass, HttpStatusCode.OK, Request, Configuration);
}
The problem with using strongly typed method signatures is that there is no way for you to return an "error" object if something is wrong with the request, be it validation errors or not found errors.
So if you want to use strongly typed signatures then you either have to included some sort of "error" object reference in your return type or explicitly throw exceptions..
The good thing about using HttpActionResult is that you are not constrained to a specific return type. So you could, for example, return OK(someObject) or BadRequest(errorObject). However, it is up to the developer to write the method correctly and double check that nothing happens like the example you mentioned above.
public class ObjectResult : IHttpActionResult
{
object _value;
HttpRequestMessage _request;
public ObjectResult(object value, HttpRequestMessage request)
{
_value = value;
_request = request;
}
public Task<HttpResponseMessage> ExecuteAsync(CancellationToken cancellationToken)
{
if (_value == null)
return Task.FromResult(_request.CreateResponse(HttpStatusCode.NotFound));
var response = _request.CreateResponse(HttpStatusCode.OK, _value);
return Task.FromResult(response);
}
}
//create your method:
public IHttpActionResult Get()
{
return new ObjectResult(repository.GetAll(), Request);
}
You can refactor your code this way:
public class Answer<T>
{
public T result {get;set;}
public bool success {get;set;}
public string exception {get;set;}
}
public async Task<Answer<MyRecord>> Get(string SomeKey)
{
var answer = new Answer<MyRecord>();
try
{
if(ExistsInDB(SomeKey))
{
answer.result = await SomeRecordFromDB(SomeKey);
answer.success = true;
}
}
catch(Exception e)
{
answer.exception = e.Message;
}
return answer;
}

WebApi2 IHttpActionResult strongly typed return values

It is possible and not ideal to do this: (a vastly simplified example!)
[Serializable]
public class MyRecord
{
public string key {get; set;}
public string data {get; set;}
}
public async Task<IHttpActionResult> Get(string SomeKey)
{
if(ExistsInDB(SomeKey))
{
return Ok(SomeRecordFromDB(SomeKey)); //SomeRecord() returns a POCO MyRecord.
}
else
{
//I know I can return NotFound() but not the focus of my Q
return Ok(false); //returns "False"
}
}
Effectively demonstrating no compile time error checking on the return type. This example will return either a JSon serialized POCO class (JSon is set on my accept header) or it will return the text "False" which puts the burden of type checking on the client.
I wouldn't do this by design but my team is refactoring a lot of code from asmx/svc and mistakes creep in. I like it when the compiler helps to trap these kinds of errors rather than waiting for module or unit testing.
Is the right way to go back to using strongly typed method signatures (avoiding the IHttpActionResult and the Ok(), NotFound(), etc helpers or is there something like a IHttpActionResult<T> that can be used to make sure the right type is being returned?
M.
First of all, it is a good practice to return IHttpActionResult, indicating the corresponding http status. Something like:
public async Task<IHttpActionResult> Get(string SomeKey)
{
if(ExistsInDB(SomeKey))
return Ok(SomeRecordFromDB(SomeKey));
return NotFound();
}
But if you really want to have a strongly typed api, you can do something like:
public async Task<StronglyTypeResponse> Get()
{
return new StronglyTypeResponse();
}
Or, create a typed response, and you'll keep the http status code, etc in your response:
public class StronglyTypeResponse
{
}
public class StronglyTypedResult<T> : IHttpActionResult
{
HttpConfiguration _configuration;
T _content;
HttpStatusCode _statusCode;
HttpRequestMessage _request;
public StronglyTypedResult(T content, HttpStatusCode statusCode, HttpRequestMessage request, HttpConfiguration configuration)
{
_content = content;
_request = request;
_configuration = configuration;
_statusCode = statusCode;
}
public Task<HttpResponseMessage> ExecuteAsync(CancellationToken cancellationToken)
{
var response = new HttpResponseMessage(_statusCode)
{
Content = new ObjectContent<dynamic>(_content, _configuration.Formatters.JsonFormatter),
RequestMessage = _request,
ReasonPhrase = "some phrase"
};
return Task.FromResult(response);
}
}
And then you can create your method:
public async Task<StronglyTypedResult<StronglyTypeResponse>> Get()
{
return new StronglyTypedResult<StronglyTypeResponse>(new StronglyTypeResponse(), HttpStatusCode.OK, Request, Configuration);
}
Creating your own custom generic IHttpActionResult
It's basically the same:
public class IHttpActionResult<T> : System.Web.Http.IHttpActionResult
{
HttpConfiguration _configuration;
T _content;
HttpStatusCode _statusCode;
HttpRequestMessage _request;
public IHttpActionResult(T content, HttpStatusCode statusCode, HttpRequestMessage request, HttpConfiguration configuration)
{
_content = content;
_request = request;
_configuration = configuration;
_statusCode = statusCode;
}
public Task<HttpResponseMessage> ExecuteAsync(CancellationToken cancellationToken)
{
var response = new HttpResponseMessage(_statusCode)
{
Content = new ObjectContent<dynamic>(_content, _configuration.Formatters.JsonFormatter),
RequestMessage = _request,
ReasonPhrase = "some phrase"
};
return Task.FromResult(response);
}
}
And now you can return the class you want with a typed IHttpActionResult:
public async Task<IHttpActionResult<YourClass>> Get()
{
var yourclass = new YourClass();
return new IHttpActionResult<YourClass>(yourclass, HttpStatusCode.OK, Request, Configuration);
}
The problem with using strongly typed method signatures is that there is no way for you to return an "error" object if something is wrong with the request, be it validation errors or not found errors.
So if you want to use strongly typed signatures then you either have to included some sort of "error" object reference in your return type or explicitly throw exceptions..
The good thing about using HttpActionResult is that you are not constrained to a specific return type. So you could, for example, return OK(someObject) or BadRequest(errorObject). However, it is up to the developer to write the method correctly and double check that nothing happens like the example you mentioned above.
public class ObjectResult : IHttpActionResult
{
object _value;
HttpRequestMessage _request;
public ObjectResult(object value, HttpRequestMessage request)
{
_value = value;
_request = request;
}
public Task<HttpResponseMessage> ExecuteAsync(CancellationToken cancellationToken)
{
if (_value == null)
return Task.FromResult(_request.CreateResponse(HttpStatusCode.NotFound));
var response = _request.CreateResponse(HttpStatusCode.OK, _value);
return Task.FromResult(response);
}
}
//create your method:
public IHttpActionResult Get()
{
return new ObjectResult(repository.GetAll(), Request);
}
You can refactor your code this way:
public class Answer<T>
{
public T result {get;set;}
public bool success {get;set;}
public string exception {get;set;}
}
public async Task<Answer<MyRecord>> Get(string SomeKey)
{
var answer = new Answer<MyRecord>();
try
{
if(ExistsInDB(SomeKey))
{
answer.result = await SomeRecordFromDB(SomeKey);
answer.success = true;
}
}
catch(Exception e)
{
answer.exception = e.Message;
}
return answer;
}

Categories