Post request error when sending "application/octet-stream" to an ASP.NET Core Web API service - asp.net-core

I need to create an ASP.NET Core 3 Web API that understand this URL
http://myapp.com/MyASPNetCore3WebApi/myController/myWebMethod?user=A0001
and one zipfile which goes as a content. This is the code that calls the needed API, which I need to create:
HttpWebRequest httpWebRequest = (HttpWebRequest)WebRequest.Create(URI);
httpWebRequest.Timeout = -1;
httpWebRequest.KeepAlive = false;
httpWebRequest.Method = "POST";
httpWebRequest.ProtocolVersion = HttpVersion.Version10;
httpWebRequest.ContentType = "application/octet-stream";
httpWebRequest.Accept = "application/octet-stream";
httpWebRequest.ContentLength = data.Length;
Stream requestStream = httpWebRequest.GetRequestStream();
requestStream.Write(data, 0, data.Length);
requestStream.Close();
HttpWebResponse httpWebResponse = (HttpWebResponse)httpWebRequest.GetResponse();
The code above is working fine, it is used everyday, sending data to a java web service, now I am replacing that system for a new one in ASP.NET Core and I can't change the caller's code, that's why I need to create a Web API that understand that URL.
I have wrote this code in my Web API, but I guess I am missing something that I canĀ“t figure it out because I get an error ion the client (code above)
[HttpPost("myWebMethod")]
public FileStreamResult myWebMethod(string user, [FromBody] Stream compress)
{
byte[] zip = ((MemoryStream)compress).ToArray();
byte[] data = ZipHelper.Uncompress(zip);
.....................
}
The error I get in the client is this:-
[System.Net.WebException] {"The remote server returned an error: (415)
Unsupported Media Type."} System.Net.WebException
Thanks in advance for any help

If the goal is to read the raw request content, this can be done using HttpContext controller property. HttpContext has Request property that provides access to the actual HTTP request.
No additional model properties or controller arguments are needed to access raw request stream. It's important to note that FromBody and FromForm binding should not be used in this case.
There are couple notes regarding the code in the example from the original question.
byte[] zip = ((MemoryStream)compress).ToArray();
byte[] data = ZipHelper.Uncompress(zip);
The HttpContext.Request.Body property does not return MemoryStream, it returns its own implementation of a Stream. It means that there is no ToArray method.
When reading the entire content of a request directly into the server's memory, it is better to check the content length, otherwise the client can crash the server by sending a large enough request.
Using *Async methods when reading the content of the request will improve performance.

Related

Restrict size of response from client side

Is there a way to restrict the size of the http response content while forming the http request? We use the following piece of code to execute a GET request and intend to handle responses of size <= 1MB
HttpUriRequest httpUriRequest = new HttpGet(this.getResolvedEndpoint());
HttpClientContext context = HttpClientContext.create();
context.setAttribute(HttpClientContext.COOKIE_STORE, this.cookieStore);
HttpResponse response = httpClient.execute(httpUriRequest, context);
HttpEntity entity = response.getEntity();
axios provides support for a parameter maxContentLength which helps in capping the size of the http response size. We are looking for an equivalent solution in JAVA.

HttpRequestMessage.Content is null in receiving Controller action

I've looked at some similar posts, but all had some relevant detail that does not apply in my case. I have an existing Shopper service with a Register method. It is built on .NET Framework 4.6.1 Web API. I have a number of working scenarios in which another .NET Framework 4.6.1 Web API service calls the Shopper service using HttpClient and HttpRequestMessage. I do this with GET, PUT, and POST methods and successfully pass data to the PUT and POST methods using
request.Content = new ObjectContent<MemberAddress>(memberAddress, new System.Net.Http.Formatting.JsonMediaTypeFormatter());
I'm now developing a new service, this one built on ASP.NET Core Web API. I'm attempting to call a POST action in the Shopper service. I'm getting my HttpClient from IHttpClientFactory.CreateClient. The HttpRequestMessage set up is, I think, the same as in my other calling services.
var request = new HttpRequestMessage(HttpMethod.Post, updateShopperUrl);
request.Content = new ObjectContent<MemberRegistration>(memberRegistration, new System.Net.Http.Formatting.JsonMediaTypeFormatter(), "application/json");
The call to the service looks like this:
var httpClient = _clientFactory.CreateClient();
var response = await httpClient.SendAsync(request);
I can inspect request.Content.Value before the call and it contains the object/data I expect. The controller action code on the other end looks like this:
[Route("{shopperId}/register")]
[Route("~/api/shopper/{shopperId}/register")]
[HttpPost]
public IHttpActionResult RegisterNewMember(string shopperId, [FromBody] MemberRegistration memberRegistration)
{
But the memberRegistration parameter is always null. The [FromBody] attribute is recent addition in an attempt to solve this problem, but it did not help. FromBody should be the default behavior for a complex object parameter anyway. I can POST to that endpoint with Postman and the memberRegistration data comes through.
Either I'm just missing something obvious or maybe there's something different happening in the ASP.NET Core calling side of the equation.
It appears you are trying to post JSON data
Try changing the approach a bit and see if it make a difference.
var json = JsonConvert.SerializeObject(memberRegistration);
var content = new StringContent(json, Encoding.UTF8,"application/json");
var httpClient = _clientFactory.CreateClient();
var response = await httpClient.PostAsync(updateShopperUrl, content);
The above manually serializes the object to JSON and Posts it to the web API.
It is possible there could have been an issue with the formatter used with the ObjectContent

JIRA - pass credentials for a webrequest to API?

Trying to build a service that will grab info on a JIRA ticket based on an ID passed to it.
I'm calling the API to take the ID passed to the service, tack it onto the URL for the API and get the JSON object.
Problem is, it appears one must be logged on or registered on JIRA in order to use the API.
So if I use the code below to make my request, I get a 404 error, as I do on any browser which I've not used to log onto Jira
public string Get(string id)
{
string html = string.Empty;
string url = #"https://company.atlassian.net/rest/api/latest/issue/" + id;
HttpWebRequest request = (HttpWebRequest)WebRequest.Create(url);
using (HttpWebResponse response = (HttpWebResponse)request.GetResponse())
using (Stream stream = response.GetResponseStream())
using (StreamReader reader = new StreamReader(stream))
{
html = reader.ReadToEnd();
}
return html;
}
I can add credentials to the request like so
request.Credentials = new NetworkCredential("vinnie#company.com","mypassword");
but I've no idea exactly what needs sending. I've tried the email address with which I'm set up in Jira but that doesn't work.
I have a suspicion that Jira adds a cookie to my browser which it uses to validate after the initial config - is that so? If so, what can I add/include on my web request to get it to run?
Am I just wildly off on the right way to access it? Or are there changes that can be made to the Jira side to allow requests?
You have to encode your credentials in Base64 format first and then these credentials can be put into your request as shown below:
string mergedCredentials = string.Format("{0}:{1}", m_Username, m_Password);
byte[] byteCredentials = UTF8Encoding.UTF8.GetBytes(mergedCredentials);
string base64Credentials = Convert.ToBase64String(byteCredentials);
request.Headers.Add("Authorization", "Basic " + base64Credentials);
Hope you're able to solve your problem by this approach!

.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;
}
}

How To Set useUnsafeHeaderParsing For .NET Compact Framework

In my Windows CE 6.0 app, I am communicating with a proprietary web server device that is returning bad header information (more specifically, it's returning NO header information).
I believe this lack of header information is the reason why my HttpWebRequest methods are not working properly.
I recall that the .NET "regular" Framework allows for us to programmatically configure the System.Net.Configuration assembly to allow for invalid headers (useUnsafeHeaderParsing).
Unfortunately, for me, the System.Net.Configuration assembly is not included in the Compact Framework.
Is there a similar configuration in CF that is exposed that allows us to programmatically allow for invalid headers?
I was unable to find a work-around for setting the UseUnsafeHeaderParsing. I decided to remove the implementation of the HttpWebRequest class and use the TcpClient instead. Using the TcpClient class will ignore any problems that may exist with the HTTP Headers - the TcpClient doesn't even think in those terms.
Anyway, using the TcpClient I am able to get the data (including the HTTP Headers) from the proprietary web server that I mentioned in my original post .
For the record, here is a sample of how to retrieve data from a web server via the TcpClient:
The code below is essentially sending a client side HTTP Header packet to a web server.
static string GetUrl(string hostAddress, int hostPort, string pathAndQueryString)
{
string response = string.Empty;
//Get the stream that will be used to send/receive data
TcpClient socket = new TcpClient();
socket.Connect(hostAddress, hostPort);
NetworkStream ns = socket.GetStream();
//Write the HTTP Header info to the stream
StreamWriter sw = new StreamWriter(ns);
sw.WriteLine(string.Format("GET /{0} HTTP/1.1", pathAndQueryString));
sw.Flush();
//Save the data that lives in the stream (Ha! sounds like an activist!)
string packet = string.Empty;
StreamReader sr = new StreamReader(ns);
do
{
packet = sr.ReadLine();
response += packet;
}
while (packet != null);
socket.Close();
return (response);
}