I am using the .NET pattern where my controller action has a signature as such
public async Task<IHttpActionResult> GetTimeSeries(string deviceId, string tag) { ... }
and inside the controller I want to send a custom error message adhering to the JSON API Spec
My goal is when encountering an error to use
return BadRequest(someJSONErrorObject);
or
return NotFound(someJSONErrorObject);
rather than throw an exception.
Currently if I do
return BadRequest(JsonConvert.SerializeObject(someJSONErrorObject));
the JSON I get back looks like
{
"Message": "{\"data\":null,\"errors\":[{\"detail\":\"The string was not recognized as a valid DateTime. There is an unknown word starting at index 0.\"}],\"meta\":null}"
}
Create a custom IHttpActionResult
public class CustomResponseResult<T> : IHttpActionResult {
public CustomResponseResult(HttpStatusCode statusCode, T content, HttpRequestMessage request) {
Content = content;
Request = request;
StatusCode = statusCode;
}
public T Content { get; private set; }
public HttpRequestMessage Request { get; private set; }
public HttpStatusCode StatusCode { get; private set; }
public Task<HttpResponseMessage> ExecuteAsync(CancellationToken cancellationToken) {
return Task.FromResult(Execute());
}
private HttpResponseMessage Execute() {
var response = Request.CreateResponse(StatusCode, Content);
response.RequestMessage = Request;
response.ReasonPhrase = StatusCode.ToString();
return response;
}
}
and then in order to maintain usability create extension methods
public static class ApiControllerExtensions {
public static IHttpActionResult BadRequest<T>(this ApiController controller, T content) {
return controller.CustomResponse(HttpStatusCode.BadRequest, content);
}
public static IHttpActionResult NotFound<T>(this ApiController controller, T content) {
return controller.CustomResponse(HttpStatusCode.NotFound, content);
}
public static IHttpActionResult CustomResponse<T>(this ApiController controller, HttpStatusCode statusCode, T content) {
var request = controller.Request;
var result = new CustomResponseResult<T>(statusCode, content, request);
return result;
}
}
that allowed the calls wanted
return this.BadRequest(someJSONErrorObject);
or
return this.NotFound(someJSONErrorObject);
Create custom error class where you can set the http status and error message. Create a custom exception class to throw your custome error messag. Create a Global Exception filter which will send you custom exception in json format.
Related
I am sending an object from my web project to my API project within the same solution. I have a class that uses RestSharp and acts as the sender to the API for all services.
Currently, there is one API controller that is receiving the object, but not all of the parameters are being retained and show up with null values via PUT. However, a different controller using the ApiClient's 'PutAsync' receives its own object with all the values intact.
I've even tried changing the method to receive as a POST, but still no success.
Am I missing something, or is there something wrong that is happening with the serialization/de-serialization of the object?
public class UserInfo
{
public int UserId { get; set; }
public string FirstName { get; private set; }
public string LastName { get; private set; }
public string EmailAddress { get; private set; }
}
internal class WebService : IWebService
{
public async Task<bool> UpdateProfile(UserInfo userInfo)
{
try
{
var url = "/User/UpdateProfile";
return await apiClient.PutAsync<UserInfo, bool>(url, userInfo);
}
catch (Exception ex)
{
this.logger.LogError("Error in UpdateProfile", ex);
throw;
}
}
}
RestSharp Setup
internal class ApiClient : IApiClient
{
public async Task<TOut> PutAsync<TIn, TOut>(string url, TIn data) where TIn : new()
{
return await PushData<TIn, TOut>(url, data, Method.PUT);
}
private async Task<TOut> PushData<TIn, TOut>(string url, TIn data, Method method) where TIn : new()
{
var request = new RestRequest(url, method);
request.AddHeader(HttpRequestHeader.Authorization.ToString(), $"Bearer {GetApiAccessToken()}");
request.AddJsonBody(data);
var result = await client.ExecuteAsync<TOut>(request);
if (result.StatusCode != HttpStatusCode.OK)
{
throw new Exception("Unable to push API data");
}
return result.Data;
}
}
Data in the request prior to being sent out, found under the Parameters, are as followed:
Data sent to API UserController
[Produces("application/json")]
[ApiController]
[Authorize]
[Route("api/[controller]")]
public class UserController : ControllerBase
{
[HttpPut]
[Route("UpdateProfile")]
public async Task<IActionResult> UpdateProfile([FromBody] ProfileUpdateInfo profileInfo)
{
try
{
var status = await this.service.UpdateProfile(profileInfo);
return Ok(status);
}
catch (Exception ex)
{
return BadRequest("Error in updating profile");
}
}
}
This is the Data that shows up in the parameter:
Data Consumed by API UserController
After reviewing my code again, the problem was that I had the set accessor to private on all string properties, which is why the int property was still coming through.
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;
}
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;
}
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"}
I'm trying to return a status code of 304 not modified for a GET method in a web api controller.
The only way I succeeded was something like this:
public class TryController : ApiController
{
public User GetUser(int userId, DateTime lastModifiedAtClient)
{
var user = new DataEntities().Users.First(p => p.Id == userId);
if (user.LastModified <= lastModifiedAtClient)
{
throw new HttpResponseException(HttpStatusCode.NotModified);
}
return user;
}
}
The problem here is that it's not an exception, It's just not modified so the client cache is OK.
I also want the return type to be a User (as all the web api examples shows with GET) not return HttpResponseMessage or something like this.
I did not know the answer so asked the ASP.NET team here.
So the trick is to change the signature to HttpResponseMessage and use Request.CreateResponse.
[ResponseType(typeof(User))]
public HttpResponseMessage GetUser(HttpRequestMessage request, int userId, DateTime lastModifiedAtClient)
{
var user = new DataEntities().Users.First(p => p.Id == userId);
if (user.LastModified <= lastModifiedAtClient)
{
return new HttpResponseMessage(HttpStatusCode.NotModified);
}
return request.CreateResponse(HttpStatusCode.OK, user);
}
You can also do the following if you want to preserve the action signature as returning User:
public User GetUser(int userId, DateTime lastModifiedAtClient)
If you want to return something other than 200 then you throw an HttpResponseException in your action and pass in the HttpResponseMessage you want to send to the client.
Change the GetXxx API method to return HttpResponseMessage and then return a typed version for the full response and the untyped version for the NotModified response.
public HttpResponseMessage GetComputingDevice(string id)
{
ComputingDevice computingDevice =
_db.Devices.OfType<ComputingDevice>()
.SingleOrDefault(c => c.AssetId == id);
if (computingDevice == null)
{
return this.Request.CreateResponse(HttpStatusCode.NotFound);
}
if (this.Request.ClientHasStaleData(computingDevice.ModifiedDate))
{
return this.Request.CreateResponse<ComputingDevice>(
HttpStatusCode.OK, computingDevice);
}
else
{
return this.Request.CreateResponse(HttpStatusCode.NotModified);
}
}
*The ClientHasStale data is my extension for checking ETag and IfModifiedSince headers.
The MVC framework should still serialize and return your object.
NOTE
I think the generic version is being removed in some future version of the Web API.
In MVC 5, things got easier:
return new StatusCodeResult(HttpStatusCode.NotModified, this);
For ASP.NET Web Api 2, this post from MS suggests to change the method's return type to IHttpActionResult. You can then return a built in IHttpActionResult implementation like Ok, BadRequest, etc (see here) or return your own implementation.
For your code, it could be done like:
public IHttpActionResult GetUser(int userId, DateTime lastModifiedAtClient)
{
var user = new DataEntities().Users.First(p => p.Id == userId);
if (user.LastModified <= lastModifiedAtClient)
{
return StatusCode(HttpStatusCode.NotModified);
}
return Ok(user);
}
I hate bumping old articles but this is the first result for this in google search and I had a heck of a time with this problem (even with the support of you guys). So here goes nothing...
Hopefully my solution will help those that also was confused.
namespace MyApplication.WebAPI.Controllers
{
public class BaseController : ApiController
{
public T SendResponse<T>(T response, HttpStatusCode statusCode = HttpStatusCode.OK)
{
if (statusCode != HttpStatusCode.OK)
{
// leave it up to microsoft to make this way more complicated than it needs to be
// seriously i used to be able to just set the status and leave it at that but nooo... now
// i need to throw an exception
var badResponse =
new HttpResponseMessage(statusCode)
{
Content = new StringContent(JsonConvert.SerializeObject(response), Encoding.UTF8, "application/json")
};
throw new HttpResponseException(badResponse);
}
return response;
}
}
}
and then just inherit from the BaseController
[RoutePrefix("api/devicemanagement")]
public class DeviceManagementController : BaseController
{...
and then using it
[HttpGet]
[Route("device/search/{property}/{value}")]
public SearchForDeviceResponse SearchForDevice(string property, string value)
{
//todo: limit search property here?
var response = new SearchForDeviceResponse();
var results = _deviceManagementBusiness.SearchForDevices(property, value);
response.Success = true;
response.Data = results;
var statusCode = results == null || !results.Any() ? HttpStatusCode.NoContent : HttpStatusCode.OK;
return SendResponse(response, statusCode);
}
.net core 2.2 returning 304 status code. This is using an ApiController.
[HttpGet]
public ActionResult<YOUROBJECT> Get()
{
return StatusCode(304);
}
Optionally you can return an object with the response
[HttpGet]
public ActionResult<YOUROBJECT> Get()
{
return StatusCode(304, YOUROBJECT);
}
I don't like having to change my signature to use the HttpCreateResponse type, so I came up with a little bit of an extended solution to hide that.
public class HttpActionResult : IHttpActionResult
{
public HttpActionResult(HttpRequestMessage request) : this(request, HttpStatusCode.OK)
{
}
public HttpActionResult(HttpRequestMessage request, HttpStatusCode code) : this(request, code, null)
{
}
public HttpActionResult(HttpRequestMessage request, HttpStatusCode code, object result)
{
Request = request;
Code = code;
Result = result;
}
public HttpRequestMessage Request { get; }
public HttpStatusCode Code { get; }
public object Result { get; }
public Task<HttpResponseMessage> ExecuteAsync(CancellationToken cancellationToken)
{
return Task.FromResult(Request.CreateResponse(Code, Result));
}
}
You can then add a method to your ApiController (or better your base controller) like this:
protected IHttpActionResult CustomResult(HttpStatusCode code, object data)
{
// Request here is the property on the controller.
return new HttpActionResult(Request, code, data);
}
Then you can return it just like any of the built in methods:
[HttpPost]
public IHttpActionResult Post(Model model)
{
return model.Id == 1 ?
Ok() :
CustomResult(HttpStatusCode.NotAcceptable, new {
data = model,
error = "The ID needs to be 1."
});
}
Try this :
return new ContentResult() {
StatusCode = 404,
Content = "Not found"
};
If you need to return an IHttpActionResult and want to return the error code plus a message, use:
return ResponseMessage(Request.CreateErrorResponse(HttpStatusCode.NotModified, "Error message here"));
Another option:
return new NotModified();
public class NotModified : IHttpActionResult
{
public Task<HttpResponseMessage> ExecuteAsync(CancellationToken cancellationToken)
{
var response = new HttpResponseMessage(HttpStatusCode.NotModified);
return Task.FromResult(response);
}
}
public HttpResponseMessage Post(Article article)
{
HttpResponseMessage response = Request.CreateResponse<Article>(HttpStatusCode.Created, article);
string uriToTheCreatedItem = Url.Route(null, new { id = article.Id });
response.Headers.Location = new Uri(Request.RequestUri, uriToTheCreatedItem);
return response;
}
An update to #Aliostads answer using the more moden IHttpActionResult introduced in Web API 2.
https://learn.microsoft.com/en-us/aspnet/web-api/overview/getting-started-with-aspnet-web-api/action-results#ihttpactionresult
public class TryController : ApiController
{
public IHttpActionResult GetUser(int userId, DateTime lastModifiedAtClient)
{
var user = new DataEntities().Users.First(p => p.Id == userId);
if (user.LastModified <= lastModifiedAtClient)
{
return StatusCode(HttpStatusCode.NotModified);
// If you would like to return a Http Status code with any object instead:
// return Content(HttpStatusCode.InternalServerError, "My Message");
}
return Ok(user);
}
}
I know there are several good answers here but this is what I needed so I figured I'd add this code in case anyone else needs to return whatever status code and response body they wanted in 4.7.x with webAPI.
public class DuplicateResponseResult<TResponse> : IHttpActionResult
{
private TResponse _response;
private HttpStatusCode _statusCode;
private HttpRequestMessage _httpRequestMessage;
public DuplicateResponseResult(HttpRequestMessage httpRequestMessage, TResponse response, HttpStatusCode statusCode)
{
_httpRequestMessage = httpRequestMessage;
_response = response;
_statusCode = statusCode;
}
public Task<HttpResponseMessage> ExecuteAsync(CancellationToken cancellationToken)
{
var response = new HttpResponseMessage(_statusCode);
return Task.FromResult(_httpRequestMessage.CreateResponse(_statusCode, _response));
}
}