In one controller (MVC ASP.NET) I need to download some web pages, and analyze them.
Currently I'm using Visual Studio 2019, and .NET Framework 4.8.
My code is like this (simplified):
public async void GetHtmlStream(Uri urlAddr)
{
HttpClient client = new HttpClient();
using (HttpResponseMessage Resp = client.GetAsync(urlAddr).Result)
{
using (HttpContent content = Resp.Content)
{
Stream stream = await content.ReadAsStreamAsync().Result;
}
}
}
The line Stream stream = await content.ReadAsStreamAsync().Result; does not compile:
"Error CS1061 'Stream' does not contain definition for 'GetAwaiter' ..."
In a test program, avoiding async and await, i have a line like this:
string result = content.ReadAsStringAsync().Result;
and all works fine.
In the controller, of course nothing works.
I saw a lot of similar issues but I don't understand what should I do to solve the problem.
Try
Stream stream = await content.ReadAsStreamAsync();
instead.
Related
I'm currently in the process of migrating several Azure Function Apps to .NET 6. One of these involves returning various content files via a HTTP request.
Previously (on .NET 3.1) this works fine for both json/text files, and HTML:
var callbackFileLocation = Path.Combine(Helper.GetFunctionPath(), "Files", filename);
var stream = new FileStream(callbackFileLocation, FileMode.Open, FileAccess.Read)
{
Position = 0
};
var okObjectResult = new OkObjectResult(stream);
okObjectResult.ContentTypes.Clear();
if (filename.Contains(".html"))
{
okObjectResult.ContentTypes.Add(new Microsoft.Net.Http.Headers.MediaTypeHeaderValue("text/html"));
}
else
{
okObjectResult.ContentTypes.Add(new Microsoft.Net.Http.Headers.MediaTypeHeaderValue("application/json"));
}
return okObjectResult;
This doesn't return the same results on .NET Core 6 - you tend to just get given the object type as a name e.g. Microsoft.AspNetCore.Mvc.OkObjectResult or System.IO.FileStream. It's easy enough to fix for the json files, as I can just convert them into text, and make sure the function app is returning that as the payload.
HTML seems trickier - I've tried reading the stream to end, and various methods mentioned here and on other sites, e.g:
public static HttpResponseMessage Run(string filename)
{
var callbackFileLocation = Path.Combine(Helper.GetFunctionPath(), "Files", filename);
var response = new HttpResponseMessage(HttpStatusCode.OK);
var stream = new FileStream(callbackFileLocation, FileMode.Open);
response.Content = new StreamContent(stream);
response.Content.Headers.ContentType = new MediaTypeHeaderValue("text/html");
return response;
}
Or returning the HTML text within FileContentResult ("application/octet-stream") or ContentResult, e.g:
new ContentResult { Content = content, ContentType = "text/html", StatusCode = 200 };
The closest I've got is the HTML as raw text, but want the HTML rendered in the browser.
Any suggestions? Documentation around this on .NET 6 seems thin...thanks!
Not the best answer (and thanks for the help #Jonas Weinhardt) - but I couldn't find a way to do this using dotnet-isolated process.
It worked fine when moved back to non-isolated. (I guess it's something to do with the new GRPC functions or something like that?)
I am writing some unit test to check my end points of webservice. Fortunately I write some of the test cases for get/post request and it works fine except the one.
I want to write the test case to check the file uploading method of webservice. The webservice endpoint on PostMan is :
The body of the request takes userID and fileUpload attribute.
I write the basic code for this but don't know how to pass the form data as request body in Nunit test case.
private HttpClient _client;
[Test]
public async Task UploadPDFfile()
{
var response = await _client.PostAsync("http://localhost:5000/documents/");
Assert.AreEqual(HttpStatusCode.OK, response.StatusCode);
}
Can anyone please tell me how I can pass the form-data attribute in PostAsync method in Nunit testing C# to check the file upload functionality.
I like to use foo files in this kind of test.
HttpClient.PostAsync() has a parameter called content.
You should create a HttpContent instance and send it with the post method:
var filePath = "yourFooFilePathHere";
using (var fs = File.OpenRead(filePath))
using (var fileContent = new StreamContent(fs))
{
var content = new MultipartFormDataContent
{
{ fileContent, "file", yourFileName }
};
content.Add(new StringContent(userId.ToString(), Encoding.UTF8, "application/json"));
var response = await _client.PostAsync("http://localhost:5000/documents/", content);
}
Please notice that I'm passing the created HttpContent as a parameter for the PostAsync method.
I'm developing a WPF web client using dotnet Core 3.x, and I'm utilising the System.Text.Json APIs. I am trying to use a Stream to pass the data between objects to minimise peak memory usage, as some large messages are being sent.
The wrapper method I've written thus far looks like the following:
public async Task<TResponse> PutItem<TItem, TResponse>(string path, TItem item)
{
HttpResponseMessage response;
await using (Stream stream = new MemoryStream())
{
await JsonSerializer.SerializeAsync(stream, item);
var requestContent = new StreamContent(stream);
requestContent.Headers.ContentType = new MediaTypeHeaderValue("application/json");
response = await _client.PutAsync(path, requestContent);
}
if (!response.IsSuccessStatusCode || response.Content == null)
{
return default;
}
string content = await response.Content.ReadAsStringAsync();
TResponse decodedResponse = JsonSerializer.Deserialize<TResponse>(content);
return decodedResponse;
}
However it does not appear to be writing any content when PUTting to the server.
I have seen users of earlier APIs utilise the PushStreamContent class, however this doesn't appear to exist in dotnet Core.
Any ideas would be very much appreciated, thanks!
I suppose the reason your current code does not work because you do not reset the stream position to 0 after serializing. However, because you create a MemoryStream you are still serializing to JSON in memory.
PushStreamContent is available by referencing the NuGet package Microsoft.AspNet.WebApi.Client.
Try something like:
var requestContent = new PushStreamContent(async (outputStream, httpContext, transportContext) =>
{
await JsonSerializer.SerializeAsync(outputStream, item);
});
requestContent.Headers.ContentType = new MediaTypeHeaderValue("application/json");
var response = await _client.PutAsync(path, requestContent);
I wrote some simple code with async await, but when I try to run it, the compiler throws a System.InvalidOperationException.
The full error message is:
Unhandled Exception: System.InvalidOperationException: The character set provided in ContentType is invalid. Cannot read content as string using an invalid character set.
System.ArgumentException: 'ISO-8859-2' is not a supported encoding name. For information on defining a custom encoding, see the documentation for the Encoding.RegisterProvider method.
The code:
class Program
{
static async Task Main(string[] args) => await asyncDoItAsync();
private static async Task<string> asyncDoItAsync()
{
HttpClient client = new HttpClient();
Task<string> url = client.GetStringAsync("http://google.pl");
while(!url.IsCompleted)
{
WhenWaiting();
}
string url_length = await url;
return url_length;
}
private static void WhenWaiting()
{
Console.WriteLine("Waiting ...");
Thread.Sleep(90);
}
}
GetStringAsync does not seem to support iso-8859 in the response, and it's basically nothing you can do about it. So you need to start with GetAsync instead. Be sure to clear your existing headers or it probably will still fail. Below works for me for the url you provided (although I'm using ISO-8859-1 and not 2):
var client = new HttpClient();
client.DefaultRequestHeaders.Clear();
string s = null;
var result = await client.GetAsync("http://google.pl");
using (var sr = new StreamReader(await result.Content.ReadAsStreamAsync(), Encoding.GetEncoding("iso-8859-1")))
{
s = sr.ReadToEnd();
}
In .NET Core not all code pages are available by default. See this answer here for details on how to enable more.
Basically, install the System.Text.Encoding and System.Text.Encoding.CodePages packages from Nuget, and then include this line before running any http requests:
Encoding.RegisterProvider(CodePagesEncodingProvider.Instance);
I need to upload a File , process it and then download the processed file within the same POST request.
I didn't find a lot of documentation about Web API covering my requirement, so I've come up with a solution based on different post's found on the net.
My final solution looks like that:
public HttpResponseMessage PostFile(string fileName)
{
try
{
var task = Request.Content.ReadAsStreamAsync();
task.Wait();
var requestStream = task.Result;
var tempFile = System.Web.HttpContext.Current.Server.MapPath(string.Format("~/App_Data/{0}", fileName));
var steam = File.Create(tempFile);
requestStream.CopyTo(steam);
steam.Close();
requestStream.Close();
var modifiedStream = DoStuffToFile(tempFile);
var response = new HttpResponseMessage();
response.Content = new StreamContent(modifiedStream);
response.StatusCode = HttpStatusCode.Created;
return response;
}
catch
{
throw new HttpResponseException(HttpStatusCode.InternalServerError);
}
}
As I have no experience in Web API, I would like to know if this piece of code is ok,
or if I will run into problems?
Edit:
The code works as expected. I'm just not sure if it can cause any problems or side effects for exmaple because I forgot to do something that might be considered by the Web API. Or is it ok that I post a file and send another one back with the response?
Code is also simplified to keep it compact(no check for duplicate files, no cleanup of old files, etc)