Adding multiple allow headers is only adding the last header in http response - asp.net-core

I am attempting to add multiple Allow Headers to the HttpResponse in aspnetcore v1.1.2. When I run the code below, the headers are added to the IHeaderDictionary on the HttpResponse, however only the last header (in this case "POST") in the collection is actually added to the http response when serialized. Has anyone else experienced this, or am I doing something wrong??
Here is the code I am using.
public override async Task OnResultExecutionAsync(ResultExecutingContext context, ResultExecutionDelegate next)
{
context.HttpContext.Response.Headers.Add("Allow", new StringValues(new [] {"GET", "POST"}));
await next();
}
I am doing this within a ResultFilterAttribute.
Many Thanks...

This should fix the issue:
context.HttpContext.Response.Headers.Add("Allow", "GET, POST");

Your code is fine, the only place that you may need to change is your response parsing logic. Double check your response - it contains 2 Allow headers, not one header with 2 values:
Allow: GET
Allow: POST
Simple example:
Lets say you have next controller action:
[Route("api/[controller]")]
public class ValuesController : Controller
{
// GET api/values
[HttpGet]
[AddHeader]
public IEnumerable<string> Get()
{
return new string[] { "value1", "value2" };
}
}
Get request using curl:
curl -X GET http://localhost:5000/api/values -i
Response:
HTTP/1.1 200 OK
Date: Fri, 23 Jun 2017 22:23:24 GMT
Content-Type: application/json; charset=utf-8
Server: Kestrel
Transfer-Encoding: chunked
Allow: GET
Allow: POST
["value1","value2"]

Related

Correctly perform the DELETE with RestSharp

Till now I've used RestSharp to perform POST/GET passing a JSON payload as parameter/body.
Now I've to perform a delete (you can see the example form documentation just here)
DELETE https://api.xxx.it/shipment
HTTP/1.1 Accept-Encoding: gzip,deflate
Content-Type: application/x-www-form-urlencoded
X-API-KEY: APIKEY123456789
Content-Length: 10 Host: api.xxx.it
Connection: Keep-Alive
User-Agent: Apache-HttpClient/4.1.1 (java 1.5)
id=1234567
and my code below.
public Task PerformShipmentDeleteAsync(ShipmentDeleteRequest objectRequest)
{
var client = new RestClient(settingsService.Endpoint);
var request = new RestRequest("shipment", DataFormat.Json);
request.AddHeader(Constants.XApiKey, settingsService.ApiXKey);
request.AddParameter( "text/plain",$"id={objectRequest.Id}", ParameterType.RequestBody);
var res = client.Delete(request);
return Task.CompletedTask;
}
and ShipmentDeleteRequest.cs
public class ShipmentDeleteRequest
{
[JsonProperty("id")]
public int Id { get;set; }
}
The only way I've found is to format the string in this way, but It's a hack.
How do I correctly pass the body as the example without passing a string but just the C# object?

PostAsJsonAsync posts null

I am trying to post an object using PostAsJsonAsync, but it is always null at the receiving API. The calling code is here:
public async Task UploadDocument(FileDto model)
{
var response = await _httpClient.PostAsJsonAsync("file/UploadDocument", model);
response.EnsureSuccessStatusCode();
}
The signature of the receiving code is here:
[HttpPost]
[Route("UploadDocument")]
public async Task<IHttpActionResult> UploadDocument(FileDto document)
FileDto is identical in both projects and only contains one string property "FileName"
The problem is that the document is always null.
I can use PostAsync which works fine:
public async Task UploadDocument(FileDto model)
{
string inputJson = Newtonsoft.Json.JsonConvert.SerializeObject(model);
HttpContent inputContent = new StringContent(inputJson, Encoding.UTF8, "application/json");
var response = await _httpClient.PostAsync("file/UploadDocument", inputContent);
response.EnsureSuccessStatusCode();
}
Looking at Fiddler, with the first (not working) example, the request looks like this:
POST http://localhost:59322/api/file/UploadDocument HTTP/1.1
Accept: application/json
Transfer-Encoding: chunked
Content-Type: application/json; charset=utf-8
Host: localhost:59322
28
{"FileName":"File-0000004157.jpg"}
0
The second (working) example looks like this in Fiddler:
POST http://localhost:59322/api/file/UploadDocument HTTP/1.1
Accept: application/json
Transfer-Encoding: chunked
Content-Type: application/json; charset=utf-8
Host: localhost:59322
{"FileName":"File-0000004157.jpg"}
The first example appears to have added extra text - see the "28" and "0".
Where is this text coming from. I can just go with PostAsync, but it seems a shame to add the extra code when PostAsJsonAsync does it for you.
Anybody have any ideas?
You need to return IActionResult instead of IHttpActionResult in asp.net core
[HttpPost]
[Route("UploadDocument")]
public async Task<IActionResult> UploadDocument(FileDto document)
{
return Ok(document);
}
https://learn.microsoft.com/en-us/aspnet/core/migration/webapi?view=aspnetcore-3.0
ASP.NET Core Web Api Error for IhttpActionResult
There seems to be an issue with PostAsJsonAsync in .net core : It returns a content-length of 0 causing the receiving ends to ignore the declared empty body.
https://github.com/aspnet/AspNetWebStack/issues/252
HttpClient PostAsJsonAsync behaving different in .NET Core and Classic .NET
The workaround is to use... PostAsync

Ionic CORS Error, But Server Has CORS Enabled

I have an Ionic 4 app that uses a lambda API hosted on AWS. CORS is enabled on the API Gateway. The following snippet is from a curl request to the API.
< content-type: application/json
< content-length: 42
< date: Sat, 16 Feb 2019 02:19:25 GMT
< x-amzn-requestid: 47a5fcac-3191-11e9-af42-d387861aa6ad
< access-control-allow-origin: *
< access-control-allow-headers: Content-Type,X-Amz-Date,Authorization,X-Api-Key,X-Amz-Security-Token
< x-amz-apigw-id: VK7vFGc4oAMFTqg=
< access-control-allow-methods: POST,OPTIONS
This post discusses a few possible workarounds (change content type, etc.), but they don't work.
Changing the Content-Type header to text/plain or removing that header altogether makes no difference.
The following error is also presented on the Ionic console
Cross-Origin Read Blocking (CORB) blocked cross-origin response
https://mycoolapi.com/GetLegal with MIME type application/json.
See https://www.chromestatus.com/feature/5629709824032768 for more details.
The following is my service code.
getLegal(data: any) {
return new Promise((resolve, reject) => {
let httpHeaders = new HttpHeaders().set('Content-Type', 'application/json');
this.httpClient.post(this.apiUrl+'/GetLegal', JSON.stringify(data), {
headers: httpHeaders,
})
.subscribe(res => {
resolve(new LegalResponse(res));
}, (err) => {
console.log("Oops, there has been an error")
reject(err);
});
});
}
Help?
This ended up being a bug on the Amazon side. The curl snippet was from a GET method, which was sending the CORS headers. The POST method was not. After redeploying the API without changing anything, the GET method was no longer sending the CORS headers and the POST method was. The application is working, for now.

How to concat rows text from a list into a success text msg in .Net Core wep api

concat rows text from a list into a success text msg in .Net Core wep api
Has nothing to do with WebAPI itself. It is more of a framework issue. Use string.Join(delimiter, ienumerable).
However, here is an example:
[Route("api/[controller]")]
public class DemoController : Controller
{
[HttpGet]
public IActionResult Get()
{
var listOfMessages = new[] {"these", "should", "be", "combined"};
var result = string.Join(' ', listOfMessages);
return Ok(result);
}
}
The result looks like this:
HTTP/1.1 200 OK
Content-Type: text/plain; charset=utf-8
Date: Tue, 22 May 2018 10:59:38 GMT
Content-Length: 24
these should be combined

WebAPI 2 with OWIN middleware and token-based authentication: OPTIONS request returns "unsupported_grant_type" error

WEbAPI provides end-point for authentication request: http:\...\token
Authentication request should be sent using Method "POST" and Body like
"grant_type=password&username=name&password=mypassword"
This WebAPI is used by Front-End which is written using AngularJS.
Sometimes before sending "POST" request with valid Body, a "OPTIONS" request is sent without Body.
As result the following error is returned by WebAPI:
Status: 400
{"error":"unsupported_grant_type"}
Is there any solution which can be implemented on Server-side? (in WebAPI)
HTTP Request Method: OPTIONS
Request Header:
Accept:*/*
Accept-Encoding:gzip,deflate,sdch
Accept-Language:en-US,en;q=0.8,de;q=0.6,ru;q=0.4,uk;q=0.2
Access-Control-Request-Headers:accept, authorization, content-type
Access-Control-Request-Method:POST
Cache-Control:no-cache
Host:...
Origin:...
Pragma:no-cache
Proxy-Connection:keep-alive
Referer:...
User-Agent:Mozilla/5.0 (Windows NT 6.3; WOW64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/37.0.2062.120 Safari/537.36
Response Header:
Cache-Control: no-cache
Pragma: no-cache
Content-Length: 34
Content-Type: application/json;charset=UTF-8
Expires: -1
Server: Microsoft-IIS/7.5
Access-Control-Allow-Origin: *
X-Powered-By: ASP.NET
Date: Thu, 11 Sep 2014 18:05:09 GMT
I just ran into the same issue..I'm using ember and ember-simple-auth. Any preflight requests OPTIONS to the /token endpoint were resulting in a 400 HTTP response and the body had the well known: {error: "unsuported_grant_type"}.
SOLUTION:
I inherit from: OAuthAuthorizationServerProvider and override the MatchEndpoint function:
public override Task MatchEndpoint(OAuthMatchEndpointContext context)
{
if (context.OwinContext.Request.Method == "OPTIONS" && context.IsTokenEndpoint)
{
context.OwinContext.Response.Headers.Add("Access-Control-Allow-Methods", new[] {"POST"});
context.OwinContext.Response.Headers.Add("Access-Control-Allow-Headers", new[] { "accept", "authorization", "content-type" });
context.OwinContext.Response.Headers.Add("Access-Control-Allow-Origin", new[] { "*" });
context.OwinContext.Response.StatusCode = 200;
context.RequestCompleted();
return Task.FromResult<object>(null);
}
return base.MatchEndpoint(context); }
That seems to take care of it. Hope it helps.
I got the same error when I forgot to add Content-Type: application/x-www-form-urlencoded to the request header.
I was attempting to test my api with Fiddler and wasn't providing the data in the correct format in the Request Body section. Be sure it's added as a key value list separated by '&'.
grant_type=password&username=testUsername&password=testPassword
In this case OPTIONS is a CORS preflight request. It is sent in order to determine whether the actual request (POST) is safe to send. Cross-site requests are preflighted if uses methods other than GET, HEAD or POST or sets custom headers.
In order to avoid a 400 HTTP response, in your Startup class you should enable CORS for the OWIN middleware using UseCors extension method and define your custom System.Web.Cors.CorsPolicy.
using Microsoft.Owin.Cors;
using Microsoft.Owin.Security.OAuth;
using Owin;
namespace AuthorizationServer
{
public partial class Startup
{
public void ConfigureAuth(IAppBuilder app)
{
app.UseCors(CorsOptions.AllowAll);
app.UseOAuthAuthorizationServer(new OAuthAuthorizationServerOptions()
{
});
}
}
}