I have a windows service that is uploading a multipart data form in C#. It is uploading a csv with authentication variables in the form: a key, a context, and a uuid. The variables are set in a custom Token class. Each time I try to upload, I get a 403 error.
using System;
using System.Collections.Generic;
using System.IO;
using System.Linq;
using System.Net;
using System.Net.Http;
using System.Net.Http.Headers;
using System.Text;
using System.Threading;
using System.Threading.Tasks;
namespace UploadScheduler.Service
{
class UploadHttp
{
// HttpClient is instantiated once per application
static readonly HttpClient client = new HttpClient();
//myUserKey and myUuid are redacted values
public static string userKey = "myUserKey";
public static string uuid = "myUuid";
public static void UploadFile(FileInfo file, Token token, DateTime lwt, DateTime nwt)
{
FileInfo fi = new FileInfo(file.FullName);
string fileName = fi.Name;
byte[] fileContents = File.ReadAllBytes(fi.FullName);
Uri webService = new Uri(token.Url);
HttpRequestMessage requestMessage = new HttpRequestMessage(HttpMethod.Post, webService);
requestMessage.Headers.ExpectContinue = false;
HttpWebRequest webRequest = WebRequest.CreateHttp(token.Url);
webRequest.ServicePoint.Expect100Continue = false;
MultipartFormDataContent multiPartContent = new MultipartFormDataContent();
ByteArrayContent byteArrayContent = new ByteArrayContent(fileContents);
byteArrayContent.Headers.Add("Content-Type", "text/csv");
multiPartContent.Add(byteArrayContent, "file", fileName);
multiPartContent.Add(new StringContent(token.Key), "key");
multiPartContent.Add(new StringContent(token.Context), "context");
multiPartContent.Add(new StringContent(token.Uuid), "uuid");
requestMessage.Content = multiPartContent;
try
{
//Task<HttpResponseMessage> httpRequest = client.SendAsync(requestMessage, HttpCompletionOption.ResponseContentRead, CancellationToken.None);
Task<HttpResponseMessage> httpRequest = client.PostAsync(token.Url, multiPartContent, CancellationToken.None);
HttpResponseMessage httpResponse = httpRequest.Result;
HttpStatusCode statusCode = httpResponse.StatusCode;
HttpContent responseContent = httpResponse.Content;
if (responseContent != null)
{
Task<String> stringContentsTask = responseContent.ReadAsStringAsync();
String stringContents = stringContentsTask.Result;
Library.RecordUpload(file, lwt, nwt);
}
}
catch (Exception ex)
{
Library.WriteLog("Upload Error: " + file.Name + " " + ex.Message);
//Library.WriteLog(ex.StackTrace);
}
}
}
}
I am trying to upload to an Amazon S3 Bucket, and the bucket is handled through a third party. I have been told that my request is malformed; however, when I try this in http://www.webhook.com, it successfully uploads and shows the form values as entered.
Is there something that I am missing in my code? Or is it a policy/permission issue from the third party? This multipartformdata & httpclient is new to me, so I don't what I'm missing, if anything.
Original code: https://dotnetcodr.com/2013/01/10/how-to-post-a-multipart-http-message-to-a-web-service-in-c-and-handle-it-with-java/
AWS S3 Errors: https://aws.amazon.com/premiumsupport/knowledge-center/s3-403-forbidden-error/
In my development process, I did create my own S3 bucket and I added the NuGet AWS S3 class, which was able to upload files successfully. Now that I am uploading to a 3rd party bucket, I keep getting a 403 error. Thanks!
I went the route of using Postman to create my request, then got the generated code for C# with the RestSharp NuGet Package.
public static void UploadFile(FileInfo file, Token token, DateTime lwt, DateTime nwt)
{
string status = "";
string reason = "";
try
{
var client = new RestClient(token.Url);
client.Timeout = -1;
var request = new RestRequest(Method.POST);
request.AddParameter("key", token.Key);
request.AddParameter("uuid", token.Uuid);
request.AddParameter("context", token.Context);
request.AddFile("file", file.FullName);
IRestResponse response = client.Execute(request);
status = response.StatusCode.ToString();
reason = response.ErrorMessage.ToString();
Library.RecordUploadSuccess(file, lwt, nwt);
}
catch (Exception ex)
{
Library.RecordUploadError(file, status, reason);
//Library.RecordUploadError(file, ex.Message, ex.StackTrace);
}
}
Highly recommend going that route for multipart form-data.
Related
How do I delete a video in my Vimeo account using the Vimeo API using C# in .Net Core?
The following works if you have a Vimeo account (at least it works at the Plus level and above) and have created an app, given that app permission to delete, gotten an access token for that app, and have a video number for the video you want to delete.
Within a class put the following code:
HttpClient httpClient = new HttpClient();
public async Task deleteVideo(string videoNumber, string accessToken)
{
try
{
string vimeoApiUrl = "https://api.vimeo.com/videos/" + videoNumber; // Vimeo URL
var body = "{}";
HttpContent content = new StringContent(body);
using (var requestMessage = new HttpRequestMessage(HttpMethod.Delete, vimeoApiUrl))
{
requestMessage.Headers.Authorization =
new AuthenticationHeaderValue("Bearer", accessToken);
requestMessage.Headers.Add("Accept", "application/vnd.vimeo.*+json;version=3.4");
requestMessage.Headers.Add("ContentType", "application/x-www-form-urlencoded");
requestMessage.Content = content;
var response = await httpClient.SendAsync(requestMessage).ConfigureAwait(false);
response.EnsureSuccessStatusCode();
}
}
catch (Exception err)
{
var errMessage = err.Message;
Console.WriteLine("In deleteVideo() error: " + err.Message);
}
}
To call it from within that class:
await deleteVideo(videoNumber, accessToken).ConfigureAwait(false);
I'm creating a messenger app, currently working on the client side, and I already have programmed most of the API (server side).
I am trying to send a POST request to the server, but it places \r\n after every element of the packet (eg:-, content-type header = application/json\r\n)
This means that when my server attempts to validate whether the incoming traffic is in JSON format, it throws it off.
I have used WireShark to see what the packets look like, here's a screenshot:
The code that I have used to send the request:
using Newtonsoft.Json;
using System.Net.Http;
public async static Task<HttpResponseMessage> PostRequestAsync(string path, object data)
{
var request = new HttpRequestMessage
{
RequestUri = new Uri(Main.ServerAddress + ":" + Main.ServerPort.ToString() + path),
Method = HttpMethod.Post,
};
MessageBox.Show("Content: " + JsonConvert.SerializeObject(data));
request.Content = new StringContent(JsonConvert.SerializeObject(data));
request.Content.Headers.ContentType = new MediaTypeHeaderValue("application/json");
MessageBox.Show(request.ToString());
var response = new HttpResponseMessage();
using (HttpClient client = new HttpClient())
{
response = await client.SendAsync(request);
}
return response;
}
The object that is being serialised as json / sent to server:
public class UserCreds{
public string username;
public string password;
}
Thanks in advance.
EDIT
Here's the server code:
#server.route("/1/signup", methods=["POST"]) # Sign up a user.
def sign_up_user():
if request.is_json == False:
return make_response(), 400
userJson = request.get_json()
uName = userJson['username']
pWord = userJson['password']
#try:
file = open(userCredsFile, 'r')
fileRaw = file.read()
creds = {}
if fileRaw != "":
creds = json.loads(fileRaw)
if uName in creds:
return create_status_response("User already exists.")
else:
creds[uName] = pWord
file.close()
file = open(userCredsFile, 'w')
file.write(json.dumps(creds))
file.close();
return make_response(), 201
#except e:
# return create_status_response("Something happened.")
I need to send a GCM Notification On A button click in the android application made through xamarin.
I Have followed this tutorial https://developer.xamarin.com/guides/cross-platform/application_fundamentals/notifications/android/remote_notifications_in_android/
Button btnCLick = Findviewbyid<button>(resource.id.btnclikc);
btnCLick.Click += btnCLick_CLICK;
void btnCLick_Click (object sender, System.EventArgs e)
{
// Here i need to send my notification. I am not able to get it.
}
I Use a MessageSender.exe to send my notification but i cant make it into my application.
using System;
using System.Net.Http;
using System.Net.Http.Headers;
using System.Text;
using System.Threading.Tasks;
using Newtonsoft.Json.Linq;
namespace MessageSender
{
class Program
{
public const string API_KEY = "API_KEY";
public const string MESSAGE = "MESSAGE";
static void Main(string[] args)
{
var jGcmData = new JObject();
var jData = new JObject();
jData.Add("message", MESSAGE);
jGcmData.Add("to", "/topics/global");
jGcmData.Add("data", jData);
var url = new Uri("https://gcm-http.googleapis.com/gcm/send");
try
{
using (var client = new HttpClient())
{
client.DefaultRequestHeaders.Accept.Add(
new MediaTypeWithQualityHeaderValue("application/json"));
client.DefaultRequestHeaders.TryAddWithoutValidation(
"Authorization", "key=" + API_KEY);
Task.WaitAll(client.PostAsync(url,
new StringContent(jGcmData.ToString(), Encoding.Default, "application/json"))
.ContinueWith(response =>
{
Console.WriteLine(response);
Console.WriteLine("Message sent: check the client device notification tray.");
}));
}
}
catch (Exception e)
{
Console.WriteLine("Unable to send GCM message:");
Console.Error.WriteLine(e.StackTrace);
}
}
}
}
I need to make this into my application button click in xamarin.Android
How Should i do that??
If I get your question right than your need a cross-platform HttpClient usage implementation for xamarin, right?
Try this: Consuming a RESTful Web Service. The topic might be a bit misleading but you should just get the HttpClient code you need.
async void MyNotificationPost(Uri uri, string json)
{
HttpClient client = new HttpClient();
var content = new StringContent (json, Encoding.UTF8, "application/json");
HttpResponseMessage response = await client.PostAsync(uri, content);
...
if (response.IsSuccessStatusCode)
{
...
}
}
In this example, the crossplatform Microsoft HTTP Client Libraries are used. If you do not like that you can use the conventional HttpWebRequest which is available in stock.
Task<WebResponse> HTTPRequestSend(
Uri uri,
byte[] bodyData,
CancellationToken cancellationToken)
{
HttpWebRequest request = WebRequest.CreateHttp(uri);
request.Method = "POST";
request.Headers["Accept"] = "application/json";
return Task.Factory.FromAsync<Stream>(
request.BeginGetRequestStream,
request.EndGetRequestStream,
null).ContinueWith(
reqStreamTask =>
{
using (reqStreamTask.Result)
{
reqStreamTask.Result.Write(bodyData, 0, bodyData.Length);
}
return Task.Factory.FromAsync<WebResponse>(
request.BeginGetResponse,
request.EndGetResponse,
null).ContinueWith(
resTask =>
{
return resTask.Result;
},
cancellationToken);
},
cancellationToken).Unwrap();
}
If you need that synchronous, be very careful not to get stuck in a deadlock. Do not forget to use ConfigureAwait(false) or the like.
P.S. I see you are using the ContinueWith and do not care for it's danger. Have a look here: ContinueWith is Dangerous, Too and do not miss the main article: StartNew is Dangerous
Actually I used the same as given in the question.
string API_KEY = "APIKEY";
var jGcmData = new JObject();
var jData = new JObject();
jData.Add("message", message);
jGcmData.Add("to", "/topics/global");
jGcmData.Add("data", jData);
var url = new Uri("https://gcm-http.googleapis.com/gcm/send");
try
{
using (var client = new HttpClient())
{
client.DefaultRequestHeaders.Accept.Add(
new MediaTypeWithQualityHeaderValue("application/json"));
client.DefaultRequestHeaders.TryAddWithoutValidation(
"Authorization", "key=" + API_KEY);
Task.WaitAll(client.PostAsync(url,
new StringContent(jGcmData.ToString(), Encoding.Default, "application/json"))
.ContinueWith(response =>
{
Console.WriteLine(response);
Console.WriteLine("Message sent: check the client device notification tray.");
}));
}
}
catch (Exception e)
{
Console.WriteLine("Unable to send GCM message:");
Console.Error.WriteLine(e.StackTrace);
}
It worked. Thanks for your Help. Brother #ZverevEugene
I have an incoming POST request from a program that consists of JSON data.
This is my server code:
static HttpListener _httpListener = new HttpListener();
static void ResponseThread()
{
while (true)
{
HttpListenerContext context = _httpListener.GetContext(); // get a context
// Now, you'll find the request URL in context.Request.Url
HttpListenerRequest request = context.Request;
string test = "";
using (http://System.IO (http://System.IO).Stream body = request.InputStream) // here we have data
{
using (http://System.IO (http://System.IO).StreamReader reader = new http://System.IO (http://System.IO).StreamReader(body, request.ContentEncoding))
{
test = reader.ReadToEnd();
}
}
Console.WriteLine(test);
byte[] _responseArray = Encoding.UTF8.GetBytes(test); // get the bytes to response
context.Response.OutputStream.Write(_responseArray, 0, _responseArray.Length); // write bytes to the output stream
context.Response.KeepAlive = false; // set the KeepAlive bool to false
context.Response.Close(); // close the connection
Console.WriteLine("Respone given to a request.");
}
}
static void Main(string[] args)
{
Console.WriteLine("Starting server...");
_httpListener.Prefixes.Add("http://localhost:5000/ (http://localhost:5000/)"); // add prefix "http://localhost:5000/ (http://localhost:5000/)"
_httpListener.Start(); // start server (Run application as Administrator!)
Console.WriteLine("Server started.");
Thread _responseThread = new Thread(ResponseThread);
_responseThread.Start(); // start the response thread
}
This is the posting code i'm using outside of the server code in a different project
static string httpPost(string json)
{
var httpWebRequest = (HttpWebRequest)WebRequest.Create("http://localhost:5000/");
httpWebRequest.ContentType = "text/json";
httpWebRequest.Method = "POST";
using (var streamWriter = new StreamWriter(httpWebRequest.GetRequestStream()))
{
streamWriter.Write(json);
streamWriter.Flush();
streamWriter.Close();
}
var httpResponse = (HttpWebResponse)httpWebRequest.GetResponse();
using (var streamReader = new StreamReader(httpResponse.GetResponseStream()))
{
var result = streamReader.ReadToEnd();
return result;
}
}
and I want to display the "test" variable in my browser but for right now it isn't working at all. Nothing is displayed but if I just send some html it works. Is there anyway to get this working or parse it out so that it does work?
To augment my comment on your question, here's a "Hello World" of sorts using the Owin self hosted server. It mimics what your question was trying to do. First install NuGet package Microsoft.Owin.SelfHost. Then include the System.Net.Http and System.Net.Http.Formatting .Net framework references. Included also is a code example to call the self-hosted server.
using Microsoft.Owin;
using Microsoft.Owin.Hosting;
using Owin;
using System;
using System.IO;
using System.Net.Http;
using System.Text;
using System.Threading.Tasks;
namespace StackOverflowAnswer
{
class Startup
{
public void Configuration(IAppBuilder app)
{
app.Use<RespondToRequestMiddleware>();
}
}
class RespondToRequestMiddleware : OwinMiddleware
{
public RespondToRequestMiddleware(OwinMiddleware next)
: base(next)
{
}
public async override Task Invoke(IOwinContext context)
{
// Perform request stuff...
// Could verify that the request Content-Type == application/json
// Could verify that the request method was POST.
bool isPost = context.Request.Method == "POST";
string test = null;
if (isPost)
{
using (StreamReader reader = new StreamReader(context.Request.Body))
{
test = await reader.ReadToEndAsync();
}
}
await Next.Invoke(context); // pass off request to the next middleware
if (isPost)
{
// Perform response stuff...
context.Response.ContentType = "application/json";
context.Response.StatusCode = 200;
await context.Response.WriteAsync(test);
Console.WriteLine("Response given to a request.");
}
}
}
class Program
{
static void Main(string[] args)
{
string url = "http://localhost:5000/";
using (WebApp.Start<Startup>(url))
{
Console.WriteLine($"Listening on {url}...");
using (HttpClient httpClient = new HttpClient())
{
string json = "{\"key\":\"value\", \"otherKey\":\"secondValue\"}";
// Typically use the extensions in System.Net.Http.Formatting in order to post a strongly typed object with HttpClient.PostAsJsonAsync<T>(url)
StringContent content = new StringContent(json, Encoding.UTF8, "application/json");
HttpResponseMessage response = httpClient.PostAsync(url, content).Result; // IMPORTANT: use await in an async method in the real world.
if (response.IsSuccessStatusCode)
{
string responseJson = response.Content.ReadAsStringAsync().Result; // Again: use await in an async method in the real world.
Console.WriteLine(responseJson); // In your method, return the string.
}
else
{
Console.WriteLine($"Unsuccessful {response.StatusCode} : {response.ReasonPhrase}");
}
}
Console.ReadLine(); // keep console from closing so server can keep listening.
}
}
}
}
In action:
Check out the Microsoft Owin/Katana site for more info.
I have been asked to do the following in C#:
/**
* 1. Create a MultipartPostMethod
* 2. Construct the web URL to connect to the SDP Server
* 3. Add the filename to be attached as a parameter to the MultipartPostMethod with parameter name "filename"
* 4. Execute the MultipartPostMethod
* 5. Receive and process the response as required
* /
I have written some code that has no errors, however, the file is not attached.
Can someone have a look at my C# code to see if I have written the code incorrectly?
Here is my code:
var client = new HttpClient();
const string weblinkUrl = "http://testserver.com/attach?";
var method = new MultipartFormDataContent();
const string fileName = "C:\file.txt";
var streamContent = new StreamContent(File.Open(fileName, FileMode.Open));
method.Add(streamContent, "filename");
var result = client.PostAsync(weblinkUrl, method);
MessageBox.Show(result.Result.ToString());
Posting MultipartFormDataContent in C# is simple but may be confusing the first time.
Here is the code that works for me when posting a .png .txt etc.
// 2. Create the url
string url = "https://myurl.com/api/...";
string filename = "myFile.png";
// In my case this is the JSON that will be returned from the post
string result = "";
// 1. Create a MultipartPostMethod
// "NKdKd9Yk" is the boundary parameter
using (var formContent = new MultipartFormDataContent("NKdKd9Yk"))
{
formContent.Headers.ContentType.MediaType = "multipart/form-data";
// 3. Add the filename C:\\... + fileName is the path your file
Stream fileStream = System.IO.File.OpenRead("C:\\Users\\username\\Pictures\\" + fileName);
formContent.Add(new StreamContent(fileStream), fileName, fileName);
using (var client = new HttpClient())
{
// Bearer Token header if needed
client.DefaultRequestHeaders.Add("Authorization", "Bearer " + _bearerToken);
client.DefaultRequestHeaders.Accept.Add(new MediaTypeWithQualityHeaderValue("multipart/form-data"));
try
{
// 4.. Execute the MultipartPostMethod
var message = await client.PostAsync(url, formContent);
// 5.a Receive the response
result = await message.Content.ReadAsStringAsync();
}
catch (Exception ex)
{
// Do what you want if it fails.
throw ex;
}
}
}
// 5.b Process the reponse Get a usable object from the JSON that is returned
MyObject myObject = JsonConvert.DeserializeObject<MyObject>(result);
In my case I need to do something with the object after it posts so I convert it to that object with JsonConvert.
I debugged this the problem is here:
method.Add(streamContent, "filename");
This 'Add' doesn't actually put the file in the BODY of Multipart Content.
I know this is an old post But to those searching for a solution, to provide a more direct answer, here's what I've found:
using System.Diagnostics;
using System.Net;
using System.Net.Http;
using System.Threading.Tasks;
using System.Web;
using System.Web.Http;
public class UploadController : ApiController
{
public async Task<HttpResponseMessage> PostFormData()
{
// Check if the request contains multipart/form-data.
if (!Request.Content.IsMimeMultipartContent())
{
throw new HttpResponseException(HttpStatusCode.UnsupportedMediaType);
}
string root = HttpContext.Current.Server.MapPath("~/App_Data");
var provider = new MultipartFormDataStreamProvider(root);
try
{
// Read the form data.
await Request.Content.ReadAsMultipartAsync(provider);
// This illustrates how to get the file names.
foreach (MultipartFileData file in provider.FileData)
{
Trace.WriteLine(file.Headers.ContentDisposition.FileName);
Trace.WriteLine("Server file path: " + file.LocalFileName);
}
return Request.CreateResponse(HttpStatusCode.OK);
}
catch (System.Exception e)
{
return Request.CreateErrorResponse(HttpStatusCode.InternalServerError, e);
}
}
}
Here's where I found it:
http://www.asp.net/web-api/overview/advanced/sending-html-form-data,-part-2
For a more Elaborate implementation:
http://galratner.com/blogs/net/archive/2013/03/22/using-html-5-and-the-web-api-for-ajax-file-uploads-with-image-preview-and-a-progress-bar.aspx
Specify the third parameter which is a fileName.
Something like this:
method.Add(streamContent, "filename", "filename.pdf");