Context:
I am improving my .dll to execute WebRequests (Get and Post), adding a new feature, that is : automatic encoding detecting after the response
How will it work:
User of the library configures it's default parameters for requests, including Encoding
Library executes the request for a certain url
Library checks if the encoding of the page is the same as the pre-configured one (via checking the value of the meta tag)
If the encodes are not the same, i re-encode the response using the right encoding (the one found on the page)
Code Fragment:
// Executes web request and wait for response
using (HttpWebResponse resp = (HttpWebResponse) m_HttpWebRequest.GetResponse())
{
using (var stream = resp.GetResponseStream ())
{
using (var reader = new StreamReader (stream))
{
// Reading Stream to the end
response = reader.ReadToEnd ();
// Identifying the encode used on the page
// I will not paste method here, but it works
m_PageEncoding = IdentifyEncoding (response);
}
// Checking if the page encode is not the same as the preconfigured one
if (m_PageEncoding != System.Text.Encoding.GetEncoding (m_encoding))
{
using (var encodedReader = new StreamReader (stream, m_PageEncoding))
{
response = encodedReader.ReadToEnd();
}
}
}
}
Problem:
Once i create another Reader, which is the EncodedReaderwith the Encoding argument, an exception is thrown: Stream was not readable.
If, i nest the readers within the responseStream using block, the response value after the second reading is always "empty"
using (var stream = resp.GetResponseStream ())
{
using (var reader = new StreamReader (stream))
{
// Reading Stream to the end
response = reader.ReadToEnd ();
// Identifying the encode used on the page
m_PageEncoding = IdentifyEncoding (response);
// Checking if the page encode is not the one i've used as argument
if (m_PageEncoding != System.Text.Encoding.GetEncoding(m_encoding))
{
using (var encodedReader = new StreamReader(stream, m_PageEncoding))
{
response = encodedReader.ReadToEnd();
}
}
}
}
Question:
How can i execute the ReadToEnd method twice, on the same WebResponse, without executing the request twice, which would be lousy.
Related
I have an issue where a service is returning me a HTTP Header:
Content-Type: application/json; charset=utf-16
When this is serialised by C# this ends up in a UTF-8 stream, which obviously breaks. It seems that utf-16 is a valid encoding in IANA spec. So why is this code not working?
System.Net.Http.HttpClient httpClient ...;
using (var response = await httpClient.SendAsync(request, HttpCompletionOption.ResponseHeadersRead))
{
//response.Content.Headers.ContentType.CharSet = "utf-16"
using (var responseContentStream = await response.Content.ReadAsStreamAsync())
{
using (var streamReader = new StreamReader(stream))
{
//streamReader.CurrentEncoding.BodyName returns utf-8 here?!
}
}
}
so initially the response seems fine but then once it gets as far as the streamReader it seems to of reverted back to utf-8. Why?
You can specify the encoding the StreamReader should use in the constructor.
In your case it should look like this:
using (var streamReader = new StreamReader(stream, Encoding.Unicode, true))
{
// The reader should read the Stream with UTF-16 here
}
We have a created an API for the application which takes the image via POST request process it and sends the result in JSON format.
We tried calling API from different sources like python, postman app, c#. We can successfully call end point using python and postman app but with c# getting error
c# code [Not working]
byte[] img_data = System.IO.File.ReadAllBytes(#"file_path");
string url_ep = "http://ip:port/get";
Dictionary<string, byte[]> fl_image = new Dictionary<string, byte[]>();
fl_image.Add("image", img_data);
string data = JsonConvert.SerializeObject(fl_image);
var dataToSend = Encoding.UTF8.GetBytes(data);
var request = HttpWebRequest.Create(url_ep);
request.ContentType = "application/json";
request.ContentLength = dataToSend.Length;
request.Method = "POST";
request.GetRequestStream().Write(dataToSend, 0, dataToSend.Length);
var response = request.GetResponse();
System.IO.Stream dataStream = response.GetResponseStream();
System.IO.StreamReader reader = new System.IO.StreamReader(dataStream);
// Read the content.
string responseFromServer = reader.ReadToEnd();
Console.WriteLine(responseFromServer);
python code [working]
import requests
url = 'http://ip:port/get'
fl_image = {'image': open('file_path', 'rb')}
res = requests.post(url, files=fl_image)
print(res.json())
API Endpoint
from flask import Flask, request
import numpy as np
import cv2 as cv
#app.route('/get', methods = ['POST'])
def get_image():
if request.method == 'POST':
file = request.files['image']
# Read file
f = file.read()
# convert string of image data to uint8
f1 = np.fromstring(f, np.uint8)
# decode image
f2 = cv.imdecode(f1,cv.IMREAD_COLOR)
There are several issues with the way you are posting data from C#. The most relevant one is that you are trying to post a file as a JSON object, with file contents as string.
This cannot work: your python server is clearly expecting multipart/form-data as content-type.
I also strongly recommend you to use HttpClient and not the old HttpWebRequest class to send HTTP Requests.
var filePath = #"file_path";
var url = "http://ip:port/get";
using (var client = new HttpClient())
using (var content = new MultipartFormDataContent())
using (var fileStream = File.OpenRead(filePath))
{
var imageContent = new StreamContent(fileStream);
// NOTE: the line below is not required, but useful when you know the media type
imageContent.Headers.ContentType = MediaTypeHeaderValue.Parse("image/jpeg");
content.Add(imageContent, "image", Path.GetFileName(filePath));
var response = await client.PostAsync(url, content);
var stringResponse = await response.Content.ReadAsStringAsync();
// do what you need with the response
}
Other minor issues:
Do not read the entire file in memory (using File.ReadAllBytes), but open a stream for reading instead.
Use async/await when possible, do not block on async code (do not use .Result, .Wait() or .GetAwaiter().GetResult() on Task or Task<T>)
Always call Dispose() on IDisposable objects when you have finished using them (wrapping them inside a using block)
You need to dispose the connections
reader.Close();
dataStream.Close();
response.Close();
Hope this helps
Or try using HttpClient for .net within the using block
In case we search for a failure in our application, we want to add the possibility to log all request and responses given by our Nancy service. In order to accomplish this, we added some pipeline hooks.
But unfortunately I'm not able to get the body of our responses. When I execute the delegate that renders the contents to the response stream (Contents), my response stream (ms) is disposed.
public void LogResponse(NancyContext context) {
string CreateResponseMessage() {
return $"Response (Client: {context.Request.UserHostAddress}) [{context.Request.Method}] {context.Request.Url}, " +
$"Status code: {(int) context.Response.StatusCode} {context.Response.StatusCode}";
}
string CreateContentMessage() {
using (var ms = new MemoryStream())
{
// For some reason, when executing this line, my ms is disposed
context.Response.Contents(ms);
ms.Seek(0, SeekOrigin.Begin);
using (var sr = new StreamReader(ms)) {
var headers = FormatHeaders(context.Response.Headers);
var content = sr.ReadToEnd();
return
$"Headers:{NewLine}{headers}{NewLine}" +
$"Body:{NewLine} {content}";
}
}
}
Log.Info(CreateResponseMessage());
Log.Verbose(CreateContentMessage);
}
Is this the wrong way to get the content of the body? Is there a way at all?
I'm trying to read the html page text from site - http://konungstvo.ru/ , which has utf-8 encoding.
var request = _requestCreator.Create(uri);
try
{
using (var response = request.GetResponse())
{
if (response.ContentType.Contains("text/html"))
{
using (var reader = new System.IO.StreamReader(response.GetResponseStream()))
{
string responseText = reader.ReadToEnd();
}
But I'm getting \u001f�\b\01V\u0002X\u0002��X�n\u001b�, and so on, although code works with other sites.
I think you need the character encoding for the Latin/Cyrillic alphabet which could by ISO/IEC 8859-5 or e.g. Windows-1251:
var encoding = Encoding.GetEncoding("iso-8859-5");
using (var reader = new System.IO.StreamReader(response.GetResponseStream(), encoding))
Using this while reading the response stream yields some cyrillic content which unfortunately isn't the correct output, too: https://dotnetfiddle.net/x8jnN8. So, I'm sorry but this isn't a real answer to your problem :/
I have been trying to stream a file to my web service. In my Controller(ApiController) I have a Post function as follows:
public void Post(Stream stream)
{
if (stream != null && stream.Length > 0)
{
_websitesContext.Files.Add(new DbFile() { Filename = Guid.NewGuid().ToString(), FileBytes= ToBytes(stream) });
_websitesContext.SaveChanges();
}
}
I have been trying to stream a file with my web client by doing the following:
public void UploadFileStream(HttpPostedFileBase file)
{
WebClient myWebClient = new WebClient();
Stream postStream = myWebClient.OpenWrite(GetFileServiceUrl(), "POST");
var buffer = ToBytes(file.InputStream);
postStream.Write(buffer, 0,buffer.Length);
postStream.Close();
}
Now when i debug my web service, it gets into the Post function, but stream is always null. Was wondering if anyone may have an idea why this is happening?
Web API doesn't model bind to 'Stream' type hence you are seeing the behavior. You could instead capture the incoming request stream by doing: Request.Content.ReadAsStreamAsync()
Example:
public async Task<HttpResponseMessage> UploadFile(HttpRequestMessage request)
{
Stream requestStream = await request.Content.ReadAsStreamAsync();
Note: you need not even have HttpRequestMessage as a parameter as you could always access this request message via the "Request" property available via ApiController.
You can replace with this code
var uri = new Uri(GetFileServiceUrl());
Stream postStream = myWebClient.OpenWrite(uri.AbsoluteUri, "POST");
RestSharp makes this sort of stuff quite easy to do. Recommend trying it out.