Unable to send modified HttpResponse back to Response.Body - asp.net-core

I am creating a proxy using middleware in ASP.NET Core 2.1 that makes 3rd party API (OData endpoint) call to
Get data
Do some changes
Send response to Response.Body
I took a reference from here
Below is the code snippet that works fine as whatever response I am getting from API, I am sending it further
using (var responseMessage = await _httpClient.SendAsync(targetRequestMessage, HttpCompletionOption.ResponseHeadersRead, context.RequestAborted))
{
context.Response.StatusCode = (int)responseMessage.StatusCode;
CopyFromTargetResponseHeaders(context, responseMessage);
await responseMessage.Content.CopyToAsync(context.Response.Body);
}
However, If I modify the response here, for example, like this, it does not work and it shows blank page without any error.
using (var responseMessage = await _httpClient.SendAsync(targetRequestMessage, HttpCompletionOption.ResponseHeadersRead, context.RequestAborted))
{
context.Response.StatusCode = (int)responseMessage.StatusCode;
CopyFromTargetResponseHeaders(context, responseMessage);
var output = new StringContent("some sample string or may be JSON", Encoding.UTF8, "application/json");
await output.CopyToAsync(context.Response.Body);
}
It looks like we are not allowed to make any change in the response received from API call. Can anyone please tell me how can send modified content back to Response.Body?

I am able to solve the problem by updating "Content-Length" response header before rendering modified response to context.Response.Body something like this:
context.Response.Headers.Remove("Content-Length");
context.Response.Headers.Add("Content-Length", modifiedResponseStream.Length.ToString());

You might run into a System.InvalidOperationException: Response Content-Length mismatch: too few bytes written or similar exception (which you should see in the Output window). So do not use the Content-Length and maybe Content-Type headers from the response, because they probably don't match with the Content-Length and Content-Type of your modified content, e.g.:
private void CopyFromTargetResponseHeaders(HttpContext context, HttpResponseMessage responseMessage)
{
...
foreach (var header in responseMessage.Content.Headers)
{
// do not use the content headers from the response because the content will be modified
// context.Response.Headers[header.Key] = header.Value.ToArray();
}
...
}

Related

How to download Blazor server page html result

Under Asp.Net MVC I used to build the body of my mailing messages on a MVC view which the system downloaded through System.Net.HttpWebRequest.
Now that I am migrating to Blazor server, I can browse the page but if I try to download it to fill the body of the message I always get next body:
Loading... An unhandled exception has occurred. See browser dev
tools for details. Reload X
I tried both through a Blazor page and through a Cshtml razor page. My browser can see both successfully but I always get the same exception.
This is the code I use to download the page:
HttpResponseMessage response = await http.GetAsync(url);
if (response.IsSuccessStatusCode)
{
var contentType = response.Content?.Headers?.ContentType?.MediaType;
if (contentType == "application/json" | contentType == "text/html")
{
string responseText = await response.Content?.ReadAsStringAsync() ?? "";
if (typeof(T) == typeof(string))
retval.Value = (T)(object)responseText;
else
retval.Value = Newtonsoft.Json.JsonConvert.DeserializeObject<T>(responseText);
}
else
{
byte[] result = await response.Content.ReadAsByteArrayAsync();
retval.Value = (T)Convert.ChangeType(result, typeof(T));
}
}
}
I finally discovered the problem was on Program.cs from my .Net7 Server side Blazor app.
I was registering HttpClient as follows:
var http = new HttpClient();
builder.Services.AddScoped(sp => http);
This was Ok to access API data, but for some reason if you try to download a Html page source it throws a System.ObjectDisposedException: Cannot access a disposed object.
The right way to register the service to avoid this exception is:
builder.Services.AddHttpClient();
The problem is I no longer have a http variable in Program.cs, which I used to preload data from Api before the index page was ready.
Need a bit more detail:
What line threw the exception?
What was the exception?
What was value of string responseText or byte[] result?
I suspect either the DeserializeObject or Convert.ChangeType call failed. You should debug this; the answer will probably become apparent as you step through the code.

How to read the html out of spa website with asp.net.core

As there are no API for this I need to get the HTML of the following website with WebClient response method.
HttpClient client = new HttpClient();
try
{
HttpResponseMessage response = await client.GetAsync("https://www.datawrapper.de/_/UPFwh/");
response.EnsureSuccessStatusCode();
string responseBody = await response.Content.ReadAsStringAsync();
}
catch(HttpRequestException e)
{
}
client.Dispose(true);
The problem is, when I do that I get only the source code of normal javascripts of this single page application and not the real HTML.
Anybody know how to grab the real html with
I profiled the traffic a bit and it looks like the response from that URL you're using is indeed mainly a script, which eventually will load the rest of the website.
Looking through the details the HTML part of the main data seems to be available under a different URL:
https://datawrapper.dwcdn.net/UPFwh/34/
Consider using that instead. Hope this helps!

Api calling in .net core razor pages

I am working on (built-in web apis) provided by whatsapp business api. As a newbie in .net core razor pages and web apis. I want to know how can I get access to the body of the post request api. Take an example below for sending a message
Post: {URL}/v1/messages
Request Body:
"to": "",
"message_type:"
"message_text:"
"recipient_type: "individual | group""
How can I make a call to the builtin api and access the body parts of it?
Ofcourse, we as a developer can use postman for checking the working of api. But take this as a client and for the client we have some fields like
To:
Message:
How can take these fields and put it into the api call body and then when the user click on the send, the api call works and shows whatever we want to show the user for example a model with send successfully etc.
You can call the API using HttpClient.
Add the URL in await client.PostAsync() function. If you have authorization use client.DefaultRequestHeaders.Authorization otherwise omit it
string myContent = "";
string myJson = <JsonQuery>;
using (HttpClient client = new HttpClient())
{
// If any authorization available
client.DefaultRequestHeaders.Authorization = new AuthenticationHeaderValue("Bearer", tokenLabel.Text.Trim());
using (HttpResponseMessage response = await client.PostAsync("https:url", new StringContent(myJson, Encoding.UTF8, "application/json")))
{
using (HttpContent content = response.Content)
{
myContent = await content.ReadAsStringAsync();
}
}
}
Update
Content
string myJson = "{\"subject\": }";
URL
using (HttpResponseMessage response = await client.PostAsync("{{URL}}/v1/groups", new StringContent(myJson, Encoding.UTF8, "application/json")))
Header
client.DefaultRequestHeaders.Authorization = new AuthenticationHeaderValue("Bearer", "");

How to solve file upload error in Postman?

I use file upload with webapi in my project. I am testing with Postman. However, Request.Content.IsMimeMultipartContent() always returns false.
Postman screenshot:
FileUploadController Code:
public async Task<HttpResponseMessage> UserImageUpload()
{
try
{
if (!Request.Content.IsMimeMultipartContent())
{
throw new HttpResponseException(HttpStatusCode.UnsupportedMediaType);
}
var userImageUploadPath = HttpContext.Current.Server.MapPath(CommonParameters.UserProfileImageServerPath);
var streamProvider = new CustomMultipartFormDataStreamProvider(userImageUploadPath);
await Request.Content.ReadAsMultipartAsync(streamProvider);
var files = new List<string>();
foreach (MultipartFileData file in streamProvider.FileData)
{
files.Add(Path.GetFileName(file.LocalFileName));
}
return Request.CreateResponse(HttpStatusCode.OK, files);
}
catch (Exception exception)
{
logger.ErrorFormat("An error occured in UserImageUpload() Method - Class:FileUploadController - Message:{0}", exception);
return Request.CreateResponse(HttpStatusCode.BadRequest);
}
}
This is Postman bug. Try removing the Content-Type header. When sending the actual Post, the browser will automatically add the proper header and create the boundary.
There is no need to mention Content-Type in headers in Postman, I tried sending attachments without Content-Type it works fine for me.
When i used Content-Type: multipart/formdata it throws an error saying "Could not get any response". Postman sends your file attachments also with Content-Type →text/plain; charset=utf-8.
There are few things to consider:
1) Don't send any Content Type Header if you are using Postman
2) Specify the Key for your choosen file in Body (PFB Screenshot for your reference)
You need to uncheck Content-Type if you have it checked, and let Postman add it for you, like in this picture:
Might by a bit late. I encountered the same error in ARC and resolved by providing a name for the file field (after the blue check mark on your second screenshot)

.NET HttpClient hangs after several requests (unless Fiddler is active)

I am using System.Net.Http.HttpClient to post a sequence of requests from a console application to a REST API and to deserialize the JSON responses into strongly-typed objects. My implementation is like this:
using (var client = new HttpClient())
{
var content = new StringContent(data, Encoding.UTF8, "text/html");
var response = client.PostAsync(url, content).Result;
response.EnsureSuccessStatusCode();
return response.Content.ReadAsAsync<MyClass>().Result;
}
However, I am experiencing a problem very similar to one described in this question, whereby everything works fine when the requests are routed via Fiddler, but it hangs after the 4th or 5th request when Fiddler is disabled.
If the cause of the problem is the same, I assume I need to do something more with HttpClient to get it to fully release its resources after each request but I am unable to find any code samples that show how to do this.
Hoping somebody can point me in the right direction.
Many thanks,
Tim
You are not disposing of the HttpResponseMessage object. This can leave open streams with the server, and after some quota of streams with an individual server is filled, no more requests will be sent.
using (var client = new HttpClient())
{
var content = new StringContent(data, Encoding.UTF8, "text/html");
using(var response = client.PostAsync(url, content).Result)
{
response.EnsureSuccessStatusCode();
return response.Content.ReadAsAsync<MyClass>().Result;
}
}