Creating cookie when using odata and web api 2 - c#

How do I set a cookie when using Web api 2 and odata. I am new to this api and traditionally I used the context.Response but it does not seem to be avaliable here.
This is a part of my controller code:
public async Task<IHttpActionResult> Post(Order Order)
{
if (!ModelState.IsValid)
{
return BadRequest(ModelState);
}
context.Orders.Add(Order);
await context.SaveChangesAsync();
return Created(Order);
}

If you are using the IHttpActionResult class there's a function within it Task<System.Net.Http.HttpResponseMessage> ExecuteAsync(CancellationToken cancellationToken);
You can use that function to return the HttpResponseMessage and add cookies to the response message.
I would make another class that implements IHttpActionResult similar to this:
public class OrderResult : IHttpActionResult
{
Order _order;
HttpRequestMessage _request;
public OrderResult(Order order, HttpRequestMessage request)
{
_order = value;
_request = request;
}
public Task<HttpResponseMessage> ExecuteAsync(CancellationToken cancellationToken)
{
var response = new HttpResponseMessage()
{
Content = new StringContent(_value),
RequestMessage = _request
};
var cookie = new CookieHeaderValue("session-id", "6789");
cookie.Expires = DateTimeOffset.Now.AddDays(1);
cookie.Domain = Request.RequestUri.Host;
response.Headers.AddCookies(new CookieHeaderValue[] { cookie });
return Task.FromResult(response);
}
}
You will need to adjust your controller code to call this new class. e.g.
public async Task<IHttpActionResult> Post(Order Order)
{
if (!ModelState.IsValid)
{
return BadRequest(ModelState);
}
context.Orders.Add(Order);
await context.SaveChangesAsync();
return new OrderResult(Order, request /* not sure how you'll get the request in this scope*/);
}

You can write your own DelegatingHandler to add the cookie you need into the response.
Check the part "Example: Set and Retrieve Cookies in a Message Handler":
http://www.asp.net/web-api/overview/working-with-http/http-cookies
For how to insert a message handler, check this:"Per-Route Message Handlers"
http://www.asp.net/web-api/overview/working-with-http/http-message-handlers

Related

How to add header in IHttpActionResult in Web API 2?

Hi i am developing API's using Web API 2. I know how to add header when using HttpResponseMessage. Now I am using IHttpActionResult.
Below is my sample current code.
return Content(HttpStatusCode.OK, LoginResponse);
How can I add a header when I am returning content?
Whenever I use HttpResponseMessage I will be having request object and I can add header.
Below code I tried in HttpResponseMessage.
response.Content.Headers.ContentType = new MediaTypeHeaderValue("application/json");
response.Headers.AddCookies(new[] { cookie });
return response;
In this case where can I add header values?
You can continue to use the HttpResponseMessage as you are accustom to and update the header. After which you can use the IHttpActionResult ResponseMessage(HttpResponseMessage) method to convert to IHttpActionResult
Simple example
public class MyApiController : ApiController {
public IHttpActionResult MyExampleAction() {
var LoginResponse = new object();//Replace with your model
var cookie = new CookieHeaderValue("name", "value");//Replace with your cookie
//Create response as usual
var response = Request.CreateResponse(System.Net.HttpStatusCode.OK, LoginResponse);
response.Content.Headers.ContentType = new MediaTypeHeaderValue("application/json");
response.Headers.AddCookies(new[] { cookie });
//Use ResponseMessage to convert it to IHttpActionResult
return ResponseMessage(response);
}
}
You can create a custom IHttpActionResult which decorates a real one but exposes a way to manipulate the response:
public class CustomResult : IHttpActionResult
{
private readonly IHttpActionResult _decorated;
private readonly Action<HttpResponseMessage> _response;
public CustomResult(IHttpActionResult decorated, Action<HttpResponseMessage> response)
{
_decorated = decorated;
_response = response;
}
public async Task<HttpResponseMessage> ExecuteAsync(CancellationToken cancellationToken)
{
var response = await _decorated.ExecuteAsync(cancellationToken);
_response(response);
return response;
}
}
Then use this in your action:
return new CustomResult(Content(HttpStatusCode.OK, loginResponse), res => res.Headers.AddCookies(new []{ cookie}));
You can add header by using this code:
HttpContext.Current.Response.AppendHeader("Some-Header", value);
or this
response.Headers.Add("Some-Header", value);

CreatedAtRoute with OK(200) code

Whether it's acceptable RESTful design or not, I'd like to give a result as like below code doing but with 200 OK StatusCode.
return CreatedAtRoute("DefaultApi", new { id = model.Id }, model);
Above one provides Location header which utilize given id route variable and json serialized model content.
return Ok(); // how to make it with this?
Note that I'm using ASP.NET WebApi2 (.Net 4.6) template.
What about this, create a custom IHttpActionResult that decorates CreatedAtRouteNegotiatedContentResult and updates the status code:
public class OkWithLocation<T> : IHttpActionResult
{
private readonly CreatedAtRouteNegotiatedContentResult<T> _result;
public OkWithLocation(CreatedAtRouteNegotiatedContentResult<T> result)
{
_result = result;
}
public async Task<HttpResponseMessage> ExecuteAsync(CancellationToken cancellationToken)
{
var response = await _result.ExecuteAsync(cancellationToken).ConfigureAwait(false);
response.StatusCode = HttpStatusCode.OK;
return response;
}
}
And then use this in your controller action:
return new OkWithLocation<Model>(CreatedAtRoute("DefaultApi", new { id = model.Id }, model));
Maybe not the prettiest, but it gets the job done.

How to get content through IHttpActionResult

I have a simple method which returns a IHttpActionResult:
public IHttpActionResult invokeGetAction(HttpRequestMessage _request, String
_forResource)
{
return new GetResourceActionResult(_request, _forResource);
}
The implementation of GetResourceActionResult looks as follows:
public class GetResourceActionResult : IHttpActionResult
{
private readonly HttpRequestMessage _request;
private readonly string _location;
public GetResourceActionResult(HttpRequestMessage request, string location)
{
_request = request;
_location = location;
}
public Task<HttpResponseMessage> ExecuteAsync(CancellationToken cancellationToken)
{
var response = _request.CreateResponse(HttpStatusCode.OK);
response.Headers.Location = new Uri(_location);
return Task.FromResult(response);
}
}
I want to call the invokeGetAction() inside a System.Web.Http.ApiControllers' Get() method to just foward the present request to another API like
[Authorize]
[Route("")]
public IHttpActionResult Get()
{
return _someService.invokeGetAction(Request, "http://mockingsvc.../api/songs");
}
And I can see the HttpStatusCode.OK so I assume I'm not failing right now. But I have no idea where and how to get the content data delivered by the invokeGetAction() - somewhere in ExecuteAsync()?
Ok yes, I forgot something... ;-) My code is now
public Task<HttpResponseMessage> ExecuteAsync(CancellationToken cancellationToken)
{
return Task.FromResult(Execute(_resourceUri));
}
public HttpResponseMessage Execute(String resourceUri)
{
using (var client = new HttpClient())
{
client.BaseAddress = new Uri(resourceUri);
client.DefaultRequestHeaders.Accept.Clear();
client.DefaultRequestHeaders.Accept.Add(new MediaTypeWithQualityHeaderValue("application/json"));
return client.GetAsync("api/songs").Result;
}
}
and it works like a charm.

Access Web API deserialization/serialization methods within controller body

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"}

Returning http status code from Web Api controller

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));
}
}

Categories