.net core 3.0/3.1 write custom response to http request - .net-core-3.0

I'm writing an Api gateway and implementing the custom aggregators that we need. To do this I am taking the any incoming http request via the middleware, interrogating the request to see if this is one I need to handle and, if so, making multiple downstream calls to different apis to get the fragments I need to re-assemble back together to make the response. If it's not one I want to handle, I just forward it to the downstream system (e.g. like a reverse proxy), so I'm not implementing web api controllers just middleware interception.
In .net core 2.x I'd use something like originalIncomingRequest.CreateResponse to create my custom response after all the aggregated calls have finished and then write to the response body my stitched together json response.
This extension method doesn't appear to exist in .net core 3.x
it looks like I'm stuck with this (e.g.)
var json = JsonConvert.SerializeObject(aggregation);
var b = Encoding.UTF8.GetBytes(json);
originalIncomingRequest.HttpContext.Response.StatusCode = 200;
await request.HttpContext.Response.Body.WriteAsync(b, 0, b.Length);
but this is a pattern from a very long time ago.... is there something simpler in .net core 3.x to achieve this goal?

If you want to use this code as a middleware you should try some code like this:
app.Use(async (context, next) =>
{
var json = JsonConvert.SerializeObject(<aggregation>);
var b = Encoding.UTF8.GetBytes(json);
context.Response.StatusCode = 200;
await context.Response.Body.WriteAsync(b, 0, b.Length);
});

Related

Get external api request body in .NET Core

I have an api call and in this calling another api. My requirement to store all api calls request body i.e., for any issues we can check application insights data with api URL information and parameters.
Using the code shown here, I was able to get first api request body but unable to read external api request body.
Please let me know the best way to achieve the task
Thanks in advance
private async Task LogRequest(HttpContext context, string correlationID)
{
context.Request.EnableBuffering();
aiLogger.LogPageView(context.Request.Path.Value);
using (var requestStream = _recyclableMemoryStreamManager.GetStream())
{
await context.Request.Body.CopyToAsync(requestStream);
string requestBody = ReadStreamInChunks(requestStream);
}
}

Get the raw request that is sent with HttpClient and HttpRequestMessage

In my C# code running .NET 6 (Azure Function) I am sending an HttpRequestMessage using HttpClient. It doesn't work but it should work, so I want to get the raw request that I am sending, including the header, so I can compare with the documentation and see the differences.
In the past I have used Fiddler but it doesn't work for me now, probably because of some security settings on my laptop. So I am looking for a solution within the world of Visual Studio 2022 or .NET 6 where I can get the raw request out for troubleshooting purposes.
This question is not really about code, but here is my code anyway.
HttpRequestMessage request = new HttpRequestMessage(HttpMethod.Post, "https://myendpoint.com/rest/something");
var apiToken = "AOU9FrasdgasdfagtHJNV";
request.Headers.Add("Authorization", "Basic " + apiToken);
var message = new
{
sender = "Hey",
message = "Hello world",
recipients = new[] { new { id = 12345678} }
};
request.Content = new StringContent(JsonSerializer.Serialize(message), Encoding.UTF8, "application/json");
request.Headers.Add("Accept", "application/json, text/javascript");
HttpResponseMessage response = await httpClient.SendAsync(request);
When SendAsync is invoked, I wish to know what exactly is sent, both header and content.
If you cannot use any proxy solution (like Fiddler) then I can see 2 options. One is described in comments in your question to use DelegatingHandler. You can read more about this in documentation. What is interesting is that HttpClient supports logging out of the box which is described in this section https://learn.microsoft.com/en-us/aspnet/core/fundamentals/http-requests?view=aspnetcore-6.0#logging of the article which describes DelegatingHandlers
If you are worried that something will manipulate the outgoing request then you can implement option 2. This is to create temporary asp.net core application with .UseHttpLogging() middleware plugged in into pipeline as described here https://learn.microsoft.com/en-us/aspnet/core/fundamentals/http-logging/?view=aspnetcore-6.0 That way you will know exactly how your request looks like from application which is being requested point of view. Now if you will point your azure function to you temporary app - you should see what gets send
Hope it helps

How to post form data with ASP.NET MVC 6 from backend to another url?

I have some data in my app's backend that I need to post from my application to another application.
I was thinking about creating form, filling it with the data and auto-posting with javascript within onLoad. But this seems somehow outdated practice for me. What would be the correct way to post from backend to some other application's url using ASP.NET 5 & MVC6 features?
Note: preferably, it should be JSON & RESTful design (controller will be accepting the data on another end), though I don't think this should change anything.
You should be able to use e.g. ordinary HttpClient. This is an example from the MS blog.
using System.Net.Http;
using (var client = new HttpClient())
{
var baseUri = "http://playapi.azurewebsites.net/api/products";
client.BaseAddress = new Uri(baseUri);
client.DefaultRequestHeaders.Accept.Clear();
var response = await client.GetAsync(baseUri);
if (response.IsSuccessStatusCode)
{
var responseJson = await response.Content.ReadAsStringAsync();
//do something with the response here. Typically use JSON.net to deserialise it and work with it
}
}
This is a GET example, but POST should be pretty similar. If you control both servers, then you can use a fancy thing called Swagger (and Swashbuckle nuget package for .NET). It is kind of WSDL for the REST API, it can generate full proxy to access your API, similar to what WCF does + a nice page with documentation and testing forms.
P.S. Not sure of the state of Swashbuckle for ASP.NET Core, but the pre-release version is available on Nuget as well.

Do I need to do something special in the ASP.NET MVC app to read a Json response from a Web API 2 application?

Is there something special I need to define in an ASP.NET MVC application to read an incoming response from a ASP.NET Web API?
From my MVC app, I make a request to an ASP.NET Web API using System.Net.HttpClient. The API receives the request and processes it fine and returns a valid response. However, the MVC application, it appears, never gets the response. I have a break point on the line that makes the request. The flow of control never comes back after executing that line. The MVC app just keeps waiting and times-out after a very long time.
However, I can confirm that the API returns a valid Json response. I have tried composing this request in Chrome Postman and see that the API returns a valid response.
Here's the code from my MVC app that makes the request to the Web API:
public async Task<R> PostAsJsonAsync<T, R>(string uri, T value)
{
using (var client = new HttpClient())
{
client.BaseAddress = new Uri(_baseUri);
client.DefaultRequestHeaders.Accept.Clear();
client.DefaultRequestHeaders.Accept.Add(new MediaTypeWithQualityHeaderValue("application/json"));
var response = await client.PostAsJsonAsync(uri, value);
if (response.IsSuccessStatusCode) return await response.Content.ReadAsAsync<R>();
else return default(R);
}
}
In the past, i.e. before Web API 2, I've had MVC apps talk to the Web API without any problem. I don't know if I am missing something that has been introduced in Web API 2.
I have a feeling you are getting a deadlock. Are you using .Result anywhere? You should be using async all the way. I mean your MVC action method should also be async method and they should await and not use .Result. Read this log post by Stephen Cleary for more info. http://blog.stephencleary.com/2012/07/dont-block-on-async-code.html

Handling redirected URL within Flex app?

We have a Flex client and a server that is using the Spring/Blazeds project.
After the user logs in and is authenticated, the spring security layer sends a redirect to a new URL which is where our main application is located.
However, within the flex client, I'm currently using HTTPService for the initial request and I get the redirected page sent back to me in its entirety.
How can I just get the URL so that I can use navigatetourl to get where the app to go where it needs to?
Any help would greatly be appreciated. Thanks!
One solution would be to include a token inside a comment block on the returned page, for instance:
<!-- redirectPage="http://localhost/new-location" -->
then check for it's presence inside the HTTPService result handler. The token's value could then be used in your call to navigateToURL.
Another solution would be to examine the HTTP response headers and extract the value of the "Location" header using ActionScript. Consider using the AS3 HTTP Client lib.
From the examples page http://code.google.com/p/as3httpclientlib/wiki/Examples To determine the 'Location' header from the response:
var client:HttpClient = new HttpClient();
var uri:URI = new URI("http://localhost/j_security_check");
client.listener.onStatus = function(event:HttpStatusEvent):void {
var response:HttpResponse = event.response;
// Headers are case insensitive
var redirectLocation:String = response.header.getValue("Location");
// call navigateToURL with redirectLocation
// ...
};
// include username and password in the request
client.post(uri);
NOTE: AS3 HTTP Client depends on AS3 Core and AS3 Crypto libs.
You can also simply use the URLLoader class, no need for external code. One of the events it dispatches is HTTPStatusEvent.HTTP_RESPONSE_STATUS. Just plug into that and retrieve the redirected url:
urlLoader.addEventListener(HTTPStatusEvent.HTTP_RESPONSE_STATUS, onHTTPResponseStatus);
private function onHTTPResponseStatus(event:HTTPStatusEvent):void
{
var responseURL:String = event.responseURL;
}
I am (successfully) using this code right now, so if it doesn't work for some reason, let me know.

Resources