.NET Core Web API - Proxy HTTP Request - c#

I have an API which has to do the following:
Incoming HttpRequest -> Logic to decide which endpoint -> Send call to specific endpoint (another API)
HttpResult -> Logic to manipulate response -> Send response back
I was wondering whether there is a clean way to do so? Currently using something like this:
var httpRequestMessage = new HttpRequestMessage()
{
Method = new HttpMethod(Request.Method),
RequestUri = new Uri(endpoint)
};
using (HttpClient httpClient = new HttpClient())
{
httpClient.DefaultRequestHeaders.Add("Authorization", Request.Headers["Authorization"][0]);
using (var response = await httpClient.SendAsync(httpRequestMessage))
{
using (HttpContent content = response.Content)
{
string data = await content.ReadAsStringAsync();
}
}
}
But I'm not really happy about the conversion from HttpRequest to HttpRequestMessage. I'd just like to pass the HttpRequest with another Uri but still be able to put logic in between the requesting and receiving.
When working with proxy middleware are you still able to put logic in between the request and result?

Related

C# REST API File Upload from Client Code gets 400 Bad Request

I have a Rest API written in .Net core that accepts a File as input as Multipart/Form-data. The API works absolutely fine when I run it from Swagger/Postman.
Here is the API endpoint.
[HttpPost("CreateStudy")]
public ActionResult CreateStudy([FromForm] APIRequest request)
{
// rest of the code
Also here is the APIRequest object. it has only one property which is IFormFile Type.
public class APIRequest
{
public IFormFile XMLFile { get; set; }
}
So far it works well. The problem is that I am trying to write a client side code that will call this API and pass the File from C# code.
But I am always getting a 400-Bad request in the client code.
This is the client code I am trying with.
public string CallServiceWithFileAsync(string EndPointURL, string FilePath)
{
string ResultStatusCode;
Uri uri = new Uri(EndPointURL);
var Client = new HttpClient();
Client.DefaultRequestHeaders.Clear();
//Prepare Message
HttpRequestMessage Message = new HttpRequestMessage();
Message.Method = HttpMethod.Post;
Message.Headers.Add("Accept", "application/octet-stream");
Message.RequestUri = new Uri(EndPointURL);
using (Stream fileStream = File.OpenRead(FilePath))
{
var content = new StreamContent(fileStream);
var response = Client.PostAsync(uri, content);
ResultStatusCode = response.Result.StatusCode.ToString();
}
return ResultStatusCode;
}
What am I doing wrong here? What is the correct way of sending a file into REST endpoint ?
[FromForm] expects an accept header with application/x-www-url-formencoded. If this is not the case, check your output-logs to see why the request is not processed.

ASP.net MVC clients consume patch API get Bad request 400 returns

I'm using asp.net MVC 5 to consume API that also developed in asp.net MVC.
For POST and GET requests, I managed to make it work, except for PATCH that always get 400 bad request from web service.
This is what I do in my client controller:
using (HttpClient httpClient1 = new HttpClient())
{
string apiURLGetClientApproval = "/clients/approvals?action=" + actionType;
HttpMethod method = new HttpMethod("PATCH");
HttpRequestMessage message = new HttpRequestMessage(method, new Uri(baseAddress + apiURLGetClientApproval));
StringContent content = new StringContent(json, Encoding.UTF8, "application/json");
httpClient1.DefaultRequestHeaders.Authorization = new AuthenticationHeaderValue("bearer", token.AccessToken);
message.Content = content;
var result = httpClient1.SendAsync(message).Result;
}
This is the content that I pass from my client to API:
{{"clients": [
{
"cn": "1132196",
"hitdate": "04/05/2021"
}]}}
PS :
I access API by postman and ajax from client side with this content, got success reponse.
I have tried with these solution, but same 400 error bad request responsed : PATCH Async requests with Windows.Web.Http.HttpClient class
This is how the parameter of API look like:
[CustomAuth(Roles = "Super Admin, Admin, User")]
[HttpPatch]
[Route("clients/approvals")]
public HttpResponseMessage UpdateClientApproval(HttpRequestMessage request, string action, [FromBody]JObject data)
{..... }
I have been dealing with the same exact problem for 2 days now. I just fixed it. I realised that sending a PATCH request probably required some specific payload [{"op":"replace"....}] as we can tell from using PostMan. However the PUT request doesn't, in fact most of the data on the business object would already be populated, so you modify what you want to change and send a PUT request instead. I just did that. I had to add the PUT action method in my controller and change the HttpClient to send a PUT request and it worked less than 5mins ago.

How do I send an HTTP POST with HTTP Basic Authorization in ASP.NET Core?

I'm trying to use the Reddit API (https://github.com/reddit-archive/reddit/wiki/OAuth2) in my ASP.NET Core MVC app, and to obtain a token I have to make a POST to a URI with HTTP Basic Authorization (username and password being a client id and secret). Currently I use this code:
public async Task<HttpResponseMessage> HttpPost(string uri, string value)
{
HttpClient httpClient = new HttpClient();
HttpResponseMessage httpResponseMessage = await httpClient.PostAsync(uri, new StringContent(value));
return httpResponseMessage;
}
However, this doesn't use the authorization. How can I add authorization? I tried looking at the documentation for HttpClient.PostAsync and HttpContent, but I don't see anything relevant.
You will need to create a base64 encoded string with format: username:password. Then add it to Authorization header for Http Request.
Example:
using (var client = new HttpClient { BaseAddress = new Uri("https://baseUrl") })
{
var authString = Convert.ToBase64String(Encoding.UTF8.GetBytes("username:password"));
client.DefaultRequestHeaders.Authorization = new System.Net.Http.Headers.AuthenticationHeaderValue("Basic", authString);
var response = await client.PostAsync(requestUri, new StringContent(value));
}

404 when accessing Design Automation API v3 through HttpClient

Running calls to the Design Automation API in Postman works just fine but when I try to make the same calls in C# using HttpClient they fail with a 404 that seems to actually hide an authentication error:
{
"developerMessage":"The requested resource does not exist.",
"userMessage":"",
"errorCode":"ERR-002",
"more info":"http://developer.api.autodesk.com/documentation/v1/errors/err-002"
}
That link leads to an authentication error:
<Error>
<Code>AccessDenied</Code>
<Message>Access Denied</Message>
<RequestId>1F52E60A45AEF429</RequestId>
<HostId>
[ Some base64 ]
</HostId>
</Error>
I'm following examples for how to use HttpClient, but I may be missing something. I successfully get the access token, run
var client = new HttpClient
{
BaseAddress = new Uri("https://developer.api.autodesk.com/da/us-east")
};
client.DefaultRequestHeaders.Authorization =
new System.Net.Http.Headers.AuthenticationHeaderValue(TokenType, AccessToken);
then
var result = await client.GetAsync("/v3/forgeapps/me");
and the above json is the result's content. I use the same access token in Postman and it works.
I would wrap up the endpoint, headers, and httpmethod in the HttpRequestMessage. Then send it and assign it to HttpResponseMessage.
var client = new HttpClient
{
BaseAddress = new Uri("https://developer.api.autodesk.com/da/us-east/")
};
//throw the endpoint and HttpMethod here. Could also be HttpMethod.Post/Put/Delete (for your future reference)
var request = new HttpRequestMessage(HttpMethod.Get, "v3/forgeapps/me");
//also maybe try throwing the headers in with the request instead of the client
request.Headers.Add(TokenType, AccessToken);
// send the request, assign to response
HttpResponseMessage response = await client.SendAsync(request);
//then, we can grab the data through the Content
string result = await response.Content.ReadAsStringAsync();

Copy HttpContext request content data to new request

I am building a APIGateway proxy for our dotnet core microservices platform.
I used https://medium.com/#mirceaoprea/api-gateway-aspnet-core-a46ef259dc54 as a starting place, this picks up all requests by using
app.Run(async (context) =>
{
// Do things with context
});
You have the context for the request to the gateway, but how do I copy over the content data from the gateway request to a new request I am going to make to my API?
I see the ability to set the request content to a HttpContent object:
newRequest.Content = new StringContent(requestContent, Encoding.UTF8, "application/json");
But I want my application to take file uploads through the gateway, the only way I found to do it is to create a MultipartFormDataContent, but all examples on how to create a MultipartFormDataContent use a IFormFile instead of a HttpContext.
Is there a way to just copy the content on the initial apigateway request to my internal request:
using (var newRequest = new HttpRequestMessage(new HttpMethod(request.Method), serviceUrl))
{
// Add headers, etc
newRequest.Content = // TODO: how to get content from HttpContext
using (var serviceResponse = await new HttpClient().SendAsync(newRequest))
{
// handle response
}
}
You can use StreamContent for this, passing in the HttpContext.Request.Body Stream as the actual content to use. Here's what that looks like in your example:
newRequest.Content = new StreamContent(context.Request.Body);
As an aside, make sure that you use a shared instance of HttpClient.

Categories

Resources