I was told to migrate a post request written in HttpWebRequest to HttpRequestMessage.
I've provided the old code and the new code that I've developed below.
In the old code they are sending the byte stream over to the
endpoint. I'm not sure whether using HttpWebRequest demands data to be sent as bytes or not.
In the new code, I've created a StringContent to be sent to the endpoint. Are both the codes equivalent and works the intended way?
If not, some help to modify the new code is appreciated.
Using HttpWebRequest (old code)
//postData -> data to be sent(type string)
HttpWebRequest req = (HttpWebRequest)WebRequest.Create("someurl.net");
req.ContentType = "application/xml";
req.Accept = "application/xml";
byte[] postBytes = Encoding.UTF8.GetBytes(postData);
req.ContentLength = postBytes.Length;
Stream postStream = req.GetRequestStream();
postStream.Write(postBytes, 0, postBytes.Length);
postStream.Flush();
postStream.Close();
WebResponse resp = req.GetResponse();
Using HttpRequestMessage (new code)
//postData -> data to be sent(type string)
var request = new HttpRequestMessage(HttpMethod.Post, $"{address}");
request.Headers.Add("Accept", "application/xml");
request.Headers.Add("Content-Type", "application/xml");
request.Content = new StringContent(RSAEncryptDecrypt.EncryptResponse(postData));
await _client.SendAsync(request, HttpCompletionOption.ResponseHeadersRead, cancellationToken)
I suppose it depends on what the intent was originally :-)
HttpWebRequest is very flexible to what it will send out. Byte[], FormUrlEncodedContent, Multipart Content, Stream, String, ...you get the idea.
There are some performance considerations, again depending on your content. End of the day if you test it and it passes within the required parameters, then you should be OK. Given someone is telling you to do it, it might be in your best interest to ask said someone a few additional questions.
One thing that does stick out to me, in the original code your string is encoded in UTF8 and your new code appears to perhaps be something else. May want to explicitly call out the encoding parameter of StringContent if you choose to keep going that way.
Here's a quick example that should get you up and going. A little inflated, but hopefully it helps you out :-)
public static void PostSomeContent(string data_parameter, string uri_parameter){
HttpRequestMessage _httpRequestMessage;
MemoryStream _memoryStream;
StreamWriter _streamWriter;
StreamContent _streamContent;
HttpClient _client;
HttpResponseMessage _httpResponse;
//Initilize a HttpRequest Message
_httpRequestMessage =
new HttpRequestMessage();
//Set the end point
//You could also do this in the intilization
_httpRequestMessage.RequestUri =
new Uri(uri_parameter);
//Set your headers
_httpRequestMessage.Headers.Add("Accept", "application/xml");
_httpRequestMessage.Headers.Add("Content-Type", "application/xml");
//Set the methood
_httpRequestMessage.Method =
HttpMethod.Post;
//I'm asuming you want it to be async
Task.Run(async()=>{
//Set up the stream
using(_memoryStream = new MemoryStream()){
using(_streamWriter = new StreamWriter(_memoryStream)){
_streamWriter.Write(data_parameter);
_streamWriter.Flush();
_memoryStream.Seek(
offset:0,
loc: System.IO.SeekOrigin.Begin
);
using(_streamContent = new StreamContent(_memoryStream)){
_httpRequestMessage.Content = _streamContent;
_client =
new HttpClient();
try{
//Use the client to send your message
//Configure what you want back via completion option
using(_httpResponse = await _client.SendAsync(
request: _httpRequestMessage,
completionOption: HttpCompletionOption.ResponseHeadersRead)){
//Or however you would like to make sure there was no error
_httpResponse.EnsureSuccessStatusCode();
//If you want the response as a string:
string _content = await _httpResponse.Content.ReadAsStringAsync();
//Or response in a stream:
using(Stream _responseStream = await _httpResponse.Content.ReadAsStreamAsync()){
}
}
}
catch(Exception){
//Handle your exception
}
}
}
}
});
}
Related
I have an Infopath Form Template on Sharepoint, I want to add a button there so when the user clicks on it, it will POST an string to the following Web API. The following web API is tested and returns an excel file as shown:
I want to Post the FileName of the excel file using post request and it is important for me the request method to be POST type. and then the user will download a file with the specified 'FileName'.
Actually i want to use post method because at the next stage i will send the content of the excel file too.
Important Note: I only can use .Net FrameWork 3.5 because this is the only framework supported in InfoPath Form Templates.
[HttpPost]
public HttpResponseMessage Post([FromBody]string FileName)
{
string reqBook = "c:\somefile.xlsx";
//converting Excel(xlsx) file into bytes array
var dataBytes = File.ReadAllBytes(reqBook);
//adding bytes to memory stream
var dataStream = new MemoryStream(dataBytes);
HttpResponseMessage httpResponseMessage = Request.CreateResponse(HttpStatusCode.OK);
httpResponseMessage.Content = new StreamContent(dataStream);
httpResponseMessage.Content.Headers.ContentDisposition = new System.Net.Http.Headers.ContentDispositionHeaderValue("attachment");
httpResponseMessage.Content.Headers.ContentDisposition.FileName = FileName;
httpResponseMessage.Content.Headers.ContentType = new System.Net.Http.Headers.MediaTypeHeaderValue("application/octet-stream");
return httpResponseMessage;
}
When you perform the HttpPost on the client side, you will want to read the HttpResponseStream to get the byte data of the response stream.
Once you have the response stream data, you can then deserialize it to the type of object in C# you want, or you could alternatively just write it to the disk as
File.WriteAllBytes("someexcel.xlsx",data);
An easy way to do it would be with the HttpClient class.
HttpClient client = new HttpClient();
var response = client.PostAsync("", null).Result;
var content = response.Content.ReadAsByteArrayAsync().Result;
File.WriteAllBytes("excel.xlsx", content);
Just fill in the PostAsync bit with the Url and the content you wish to post.
I am using .Result to keep everything synchronous - but you can use 'await' if you prefer.
If you are working with HttpWebRequests - then the process becomes more complicated, as you need to manage the streams yourself.
The HttpClient will manage and handle it all for you - so I recommend it, unless there is something special it needs to do that it currently does not.
Due to your .Net 3.5 requirement:
private static HttpWebResponse MakeRequest(string url, string postArgument)
{
HttpWebRequest request = (HttpWebRequest)WebRequest.Create(url);
request.Method = "POST";
request.ContentType = "multipart/form-data;";
Stream stream = request.GetRequestStream();
string result = string.Format("arg1={0}", postArgument);
byte[] value = Encoding.UTF8.GetBytes(result);
stream.Write(value, 0, value.Length);
stream.Close();
return (HttpWebResponse)request.GetResponse();
}
You can then do:
var response = MakeRequest("http://mywebsite.com/ProcessExcel", "accounts.xlsx");
And then do
Stream objStream = response .GetResponseStream();
BinaryReader breader = new BinaryReader(objStream);
byte[] data= breader.ReadBytes((int)webresponse.ContentLength);
File.WriteAllBytes("excel.xlsx",data);
I have a problem with the POST method. I have a REST server programmed in C#, and I want to consume this REST service in C#, but I don't know how. The problem is that my method accepts a POST, receives a JSON payload and returns an HTTPStatusCode and a number:
id_task= planificadorService.CreaTarea(tareaDTO);//tareaDTO is a JSON
if (id_tarea == 0)
{
response = Request.CreateResponse(HttpStatusCode.NotFound, "Cannot create task ");
return response;
}
response = Request.CreateResponse(HttpStatusCode.Created);
response.Content = new StringContent(JsonConvert.SerializeObject(id_task), Encoding.UTF8, "application/json");
return response;
It was easy to do it using the GET method with the WebRequest and HttpWebResponse classes, but I don't know how to do it with the POST method. After many attempts, I ended up with something like this:
public void PostTareas(Tarea tarea)
{
var httpWebRequest = (HttpWebRequest)WebRequest.Create(url_base + "/v1/tareas");
httpWebRequest.ContentType = "application/json";
httpWebRequest.Method = "POST";
string json = JsonConvert.SerializeObject(tarea);
var client = new HttpClient()
{
BaseAddress = new Uri(url_base + "/v1/tareas")
};
client.DefaultRequestHeaders.Accept.Clear();
client.DefaultRequestHeaders.Accept.Add(new MediaTypeWithQualityHeaderValue("application/json"));
HttpResponseMessage response;
response.Content= new StringContent(JsonConvert.SerializeObject(tarea).ToString(), Encoding.UTF8, "application/json");
response = client.PostAsync(url_base + "/v1/tareas", json)).Result;
}
I'm on the right track? How can I do this so that I am able to access the Json content? Thanks
P.D- Excuse my english, it is not my native language and I know there may be faults in expressing myself
With WebRequest you need to write the JSON in the POST request payload, use WebRequest.GetRequestStream:
var httpWebRequest = (HttpWebRequest)WebRequest.Create(url_base + "/v1/tareas");
...
using(var requestStream = request.GetRequestStream()) {
// Write the serialized json into the stream, it will be send as payload
using(TextWriter writer = new StreamWriter(requestStream)) {
writer.WriteLine(JsonConvert.Serialize(tarea));
}
}
var response = request.GetResponse();
or you can use HttpClient and call PostAsync, as you're doing in your second part of your code. Either way is fine, but stick to one :)
You should also consider using a high(er) level library, like RestSharp. Ultimately consider exposing your server API with Swagger via Swashbuckle, generate a client with swagger-codegen and spend your time at the higher level abstraction of the API, not the HTTP/Json layer.
I want to do a web request in a asp.net core project. I tried the following but it doesn't seem to send the data in the request:
using System.Net;
...
//encoder
UTF8Encoding enc = new UTF8Encoding();
//data
string data = "[\"some.data\"]";
//Create request
WebRequest request = WebRequest.Create(url);
request.Method = "POST";
request.ContentType = "application/json";
request.Credentials = new NetworkCredential(user, secret);
//Set data in request
Stream dataStream = await request.GetRequestStreamAsync();
dataStream.Write(enc.GetBytes(data), 0, data.Length);
//Get the response
WebResponse wr = await request.GetResponseAsync();
Stream receiveStream = wr.GetResponseStream();
StreamReader reader = new StreamReader(receiveStream, Encoding.UTF8);
string content = reader.ReadToEnd();
I don't get an error, the request was send but it doesn't seem to send the data with the request.
I also can't give the length of the data with the request. Is this a core issue? (ps: The credentials are send correctly)
Can anyone help me?
You may be facing a synchronization context problem.
Try to await the asynchronous methods like GetRequestStreamAsync() and GetResponseAsync() instead of getting the Result property.
//Set data in request
Stream dataStream = await request.GetRequestStreamAsync();
//Get the response
WebResponse wr = await request.GetResponseAsync();
Finally solved it. There was a bug in my external API code where I resolved the API request. The code in my question works (If someone wants to use it).
PS: I edit the code with the remark of ycrumeyrolle
I've been fiddling quite a bit with my uploading to vimeo.
I've made a ticket request.
I've uploaded the file.
I've checked the file if its uploaded.
I need to run the method DELETE with the complete_uri response i should get from my ticket.
However, im not receiving any complete_URI from the ticket response.
Here is my code:
public static dynamic GenerateTicket()
{
const string apiUrl = "https://api.vimeo.com/me/videos?type=streaming";
var req = (HttpWebRequest)WebRequest.Create(apiUrl);
req.Accept = "application/vnd.vimeo.*+json;version=3.0";
req.Headers.Add(HttpRequestHeader.Authorization, "bearer " + AccessToken);
req.Method = "POST";
var res = (HttpWebResponse)req.GetResponse();
var dataStream = res.GetResponseStream();
var reader = new StreamReader(dataStream);
var result = Json.Decode(reader.ReadToEnd());
return result;
}
This response gives me:
form
ticket_id
upload_link
upload_link_secure
uri
user
In order to finish my upload i need to run step 4 in this guide: https://developer.vimeo.com/api/upload
Sending parameter type=streaming as body:
ASCIIEncoding encoding = new ASCIIEncoding();
string stringData = "type=streaming"; //place body here
byte[] data = encoding.GetBytes(stringData);
req.Method = "PUT";
req.ContentLength = data.Length;
Stream newStream = req.GetRequestStream();
newStream.Write(data, 0, data.Length);
newStream.Close();
At the moment, type=streaming must be sent in the body of the request, not as a url parameter.
This will probably change to allow either option.
the important point is :
"The first thing you need to do is request upload access for your application. You can do so from your My Apps page."
If you get all values without complete_uri, it means: you dont have an upload access token. So go to your apps and make an upload request
I'm trying to migrate a Windows C# library to Windows Phone 8 and I'm forced to make some changes in how the library gets data from an online URI.
I'm using the BCL's HttpClient to perform my data retrieval and everything's fine for now.
The library also requires an upload feature, and I can't find a way to do this using th HttpClient.
Here's the code:
// Client setup
var httpclient = new HttpClient();
var request = new HttpRequestMessage(HttpMethod.Post, string.Format(SubmitURI, value));
// Add the headers
request.Headers.Add("header", header);
var postData = GetPostData();
var data = Encoding.UTF8.GetBytes(postData);
// Side question -> Content is null here!
request.Content.Headers.Add("ContentType", "multipart/form-data; boundary=" + Boundary);
// BEGIN ORIGINAL CODE
var stream = request.GetRequestStream();
stream.Write(data, 0, data.Length);
stream.Close();
// END ORIGINAL CODE
// Get response
var response = await httpclient.SendAsync(request);
var responseContent = new StreamReader(await response.Content.ReadAsStreamAsync()).ReadToEnd();
Between the BEGIN ORIGINAL CODE and END ORIGINAL CODE comments, there's the code that I'm not able to migrate, so that you can understand what it does and I may need to make it work on WP.
The other of the code is already working on WP, except for the
request.Content.Headers.Add("ContentType", "multipart/form-data; boundary=" + Boundary);
because, for some reasons, request.Content is null.
So my question is: how can I migrate those 3 lines to WP using HttpClient (or any better way)?
And, as a little side question, why is request.Content null?
EDIT: based on #Johan van der Slikke's answer I've edited my code. It compiles, but the server reports that no file was uploaded, so I guess that there are still some issues.
var stream = new MemoryStream(data);
var streamContent = new StreamContent(stream);
request.Content = streamContent;
request.Content.Headers.Add("ContentType", "multipart/form-data; boundary=" + Boundary);
// Get response
var response = await httpclient.SendAsync(request);
You should wrap your stream in the StreamContent class (a subclass of HttpContent) and send it with the HttpClient using the PostAsync or PutAsync methods.
Edit
You don't need to use HttpRequestMessage.
var stream = new MemoryStream(data);
var streamContent = new StreamContent(stream);
// Get response
var response = await httpclient.PostAsync(streamContent)
Also you don't need to create a MemoryStream with your byte array. You can wrap it in a ByteArrayContent directly.
var response = await httpclient.PostAsync(new ByteArrayContent(data))
Maybe (because I see you using multipart/form-data header) you should use MultipartFormDataContent classes or FormUrlEncodedContentClasses.
You can send multi-part content like this,
var client = new HttpClient();
var content = new MultipartContent();
content.Add(new ByteArrayContent(data));
var response = await client.PostAsync(SubmitUrl, content);
However, I am curious what media type your "PostData" is. You may want to set the content-type header on the ByteArrayContent.