I am trying to upload a picture from the Pictures Library (on WP7) and save it in a folder on the server.
On the server, I'm using PHP to receive the file using POST Method.
The PHP Code is:
<?php
$uploads_dir = 'files/'; //Directory to save the file that comes from client application.
if ($_FILES["file"]["error"] == UPLOAD_ERR_OK) {
$tmp_name = $_FILES["file"]["tmp_name"];
$name = $_FILES["file"]["name"];
move_uploaded_file($tmp_name, "$uploads_dir/$name");
}
?>
I've already tried some approaches, but they all just seem to fail.
I've already done this job in a Windows Forms application using the Client.UploadFile method but it seems that it cannot be used on a Windows Phone Application.
I think httpwebrequest can help, right?
This is my C# code so far:
public partial class SamplePage : PhoneApplicationPage
{
public SamplePage()
{
InitializeComponent();
}
PhotoChooserTask selectphoto = null;
private void SampleBtn_Click(object sender, RoutedEventArgs e)
{
selectphoto = new PhotoChooserTask();
selectphoto.Completed += new EventHandler<PhotoResult>(selectphoto_Completed);
selectphoto.Show();
}
void selectphoto_Completed(object sender, PhotoResult e)
{
if (e.TaskResult == TaskResult.OK)
{
BinaryReader reader = new BinaryReader(e.ChosenPhoto);
image1.Source = new BitmapImage(new Uri(e.OriginalFileName));
txtBX.Text = e.OriginalFileName;
}
}
}
I read it somewhere that the image is required to be converted to a string of bytes, I don't know for sure.
But, please help me.
Thanks a lot in advance.
I would convert the image to base64 (see System.Convert) then transfer via POST:
HttpWebRequest request = (HttpWebRequest)WebRequest.Create("http://mydomain.cc/saveimage.php");
request.Method = "POST";
request.ContentType = "application/x-www-form-urlencoded";
string postData = String.Format("image={0}", myBase64EncodedImage);
// Getting the request stream.
request.BeginGetRequestStream
(result =>
{
// Sending the request.
using (var requestStream = request.EndGetRequestStream(result))
{
using (StreamWriter writer = new StreamWriter(requestStream))
{
writer.Write(postData);
writer.Flush();
}
}
// Getting the response.
request.BeginGetResponse(responseResult =>
{
var webResponse = request.EndGetResponse(responseResult);
using (var responseStream = webResponse.GetResponseStream())
{
using (var streamReader = new StreamReader(responseStream))
{
string srresult = streamReader.ReadToEnd();
}
}
}, null);
}, null);
}
saveimage.php should look like this:
<?
function base64_to_image( $imageData, $outputfile ) {
/* encode & write data (binary) */
$ifp = fopen( $outputfile, "wb" );
fwrite( $ifp, base64_decode( $imageData ) );
fclose( $ifp );
/* return output filename */
return( $outputfile );
}
if (isset($_POST['image'])) {
base64_to_jpeg($_POST['image'], "my_path_to_store_images.jpg");
}
else
die("no image data found");
?>
Note: I have not tested the code. There might be typos or other errors. It's just to illustrate how I would transfer an image using POST.
Edit as a repy to your comment: I don't have code to encode to base64 at hand but here is how you would decode a base64 encoded image in C#:
byte[] image = Convert.FromBase64String(str);
Related
I am trying to download a file into my app. From what I can see if I put this link into a browser I get a good file downloaded so I know the file is available for me to get. I have other files to download from different sites and they all work well but this one will not download for me in a usable manner. I guess I do not understand something, do you know the key fact I am missing?
After many attempts I have now coded the following
private string url =
"https://coronavirus.data.gov.uk/api/v1/data?filters=areaType=nation&structure={\"Name\":\"areaName\",\"date\":\"date\",\"FirstDose\":\"cumPeopleVaccinatedFirstDoseByPublishDate\",\"SecondDose\":\"cumPeopleVaccinatedSecondDoseByPublishDate\"}&format=csv";
private void btn_wc1_Click(object sender, EventArgs e)
{
WebClient wc = new WebClient();
wc.Encoding = Encoding.UTF8;
wc.DownloadFile(url, "wc1_uk_data.csv");
}
private void btn_wc2_Click(object sender, EventArgs e)
{
using (var webClient = new WebClient())
{
webClient.Encoding = Encoding.UTF8;
string s = webClient.DownloadString(url);
File.WriteAllText(#"wc2_uk_data.csv", s);
}
}
private async void btn_https_Click(object sender, EventArgs e)
{
HttpClient _client = new HttpClient();
byte[] buffer = null;
try
{
HttpResponseMessage task = await _client.GetAsync(url);
Stream task2 = await task.Content.ReadAsStreamAsync();
using (MemoryStream ms = new MemoryStream())
{
await task2.CopyToAsync(ms);
buffer = ms.ToArray();
}
File.WriteAllBytes("https_uk_data.csv", buffer);
}
catch
{
}
}
private void btn_wc3_Click(object sender, EventArgs e)
{
using (var webClient = new WebClient())
{
webClient.Encoding = Encoding.UTF8;
byte[] myDataBuffer = webClient.DownloadData(url);
MemoryStream ms = new MemoryStream(myDataBuffer);
FileStream f = new FileStream(Path.GetFullPath(Path.Combine(Application.StartupPath, "wc3_uk_data.csv")),
FileMode.OpenOrCreate);
ms.WriteTo(f);
f.Close();
ms.Close();
}
}
Using the following UI
All the different functions above will download a file but none of the downloaded files is usable. It seems like it is not the file but maybe something to do with information regarding the file. As my app does not know what to do with this I never reply with what ever the other end wants. I guess if I replied the next set of data I got would be the file.
If I put the URL into a browser then I get a file that is good. This link is good at the moment.
https://coronavirus.data.gov.uk/api/v1/data?filters=areaType=nation&structure={"Name":"areaName","date":"date","FirstDose":"cumPeopleVaccinatedFirstDoseByPublishDate","SecondDose":"cumPeopleVaccinatedSecondDoseByPublishDate"}&format=csv
Anyone got any idea on what I need to do in my app to get the file like the browser does?
You need to set the WebClient.Encoding before calling DownloadString
string url = "https://coronavirus.data.gov.uk/api/v1/data?filters=areaType=nation&structure={\"Name\":\"areaName\",\"date\":\"date\",\"FirstDose\":\"newPeopleReceivingFirstDose\",\"SecondDose\":\"newPeopleReceivingSecondDose\"}&format=csv";
using (var webClient = new WebClient())
{
webClient.Encoding = Encoding.UTF8;
string s = webClient.DownloadString(url);
}
Here is a related question:
WebClient.DownloadString results in mangled characters due to encoding issues, but the browser is OK
I just want to upload a .dat file from a windows phone to a php script.
This is my code, but doesn't work. Can anyone see a reason why?
C#:
string fileBase64 = "UklGRt4lAABXQVZFZm10IBAAAAABAAEARKw...";
HttpWebRequest request = (HttpWebRequest)WebRequest.Create("http://...mysite.../upload.php");
request.Method = "POST";
request.ContentType = "application/octet-stream";
string postData = String.Format("file={0}", fileBase64);
// Getting the request stream.
request.BeginGetRequestStream
(result =>
{
// Sending the request.
using (var requestStream = request.EndGetRequestStream(result))
{
using (StreamWriter writer = new StreamWriter(requestStream))
{
writer.Write(postData);
writer.Flush();
}
}
// Getting the response.
request.BeginGetResponse(responseResult =>
{
var webResponse = request.EndGetResponse(responseResult);
using (var responseStream = webResponse.GetResponseStream())
{
using (var streamReader = new StreamReader(responseStream))
{
string srresult = streamReader.ReadToEnd();
}
}
}, null);
}, null);
PHP:
define("UPLOAD_DIR", "./uploads/");
if(isset($_POST['file']))
{
$base64_string = $_POST['file'];
$ifp = fopen( UPLOAD_DIR.'aaa.dat', "wb" );
fwrite( $ifp, base64_decode($base64_string) );
fclose( $ifp );
echo "ok";
echo $base64_string;
echo base64_decode($base64_string);
}else{
echo "no submit";
}
You’re abusing the HTTP protocol.
Here’s the correct way to upload files to the server. Be sure to read comments, and also you'll probably want to do this asynchronously. For the asynchronous path I'd suggest you try the new async-await feature of the C# language, it's very helpful for such tasks, compared to your Begin/End approach.
I have seen few other examples online doing the same, but I am not sure why its not working for me.
I have created a simple windows phone 7 app, which uses PhotoChooserTask.
It sends image to the server using Web Api.
Here is the code in windows phone project:
void selectphoto_Completed(object sender, PhotoResult e)
{
if (e.TaskResult == TaskResult.OK)
{
var image = new Image();
image.Source = new BitmapImage(new Uri(e.OriginalFileName));
HttpWebRequest request = (HttpWebRequest)WebRequest.Create("http://localhost:59551/api/controllername");
request.Method = "POST";
request.ContentType = "multipart/form-data";
//private method to convert bitmap image to byte
byte[] str = BitmapToByte(image);
// Getting the request stream.
request.BeginGetRequestStream
(result =>
{
// Sending the request.
using (var requestStream = request.EndGetRequestStream(result))
{
using (StreamWriter writer = new StreamWriter(requestStream))
{
writer.Write(str);
writer.Flush();
}
}
// Getting the response.
request.BeginGetResponse(responseResult =>
{
var webResponse = request.EndGetResponse(responseResult);
using (var responseStream = webResponse.GetResponseStream())
{
using (var streamReader = new StreamReader(responseStream))
{
string srresult = streamReader.ReadToEnd();
}
}
}, null);
}, null);
}
On the Web API I got the following code for the POST method:
public Task<HttpResponseMessage> Post()
{
// 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);
// Read the form data and return an async task.
var task = Request.Content.ReadAsMultipartAsync(provider).
ContinueWith<HttpResponseMessage>(t =>
{
if (t.IsFaulted || t.IsCanceled)
{
Request.CreateErrorResponse(HttpStatusCode.InternalServerError, t.Exception);
}
// This illustrates how to get the file names.
foreach (MultipartFileData file in provider.FileData)
{
Image img = Image.FromFile(file.LocalFileName);
Trace.WriteLine(file.Headers.ContentDisposition.FileName);
Trace.WriteLine("Server file path: " + file.LocalFileName);
}
return Request.CreateResponse(HttpStatusCode.OK);
});
return task;
}
}
However I am not sure why IsMimeMultipartContent is returning false always. Even if I bypass this check, no file is saved in the App_Data folder.
Can anyone please help. Thanks.
EDITED
Based on Darrel's response I have modified the POST method in ApiController. But I still do not get any data. A blank image is created on the server. Here is my code:
public HttpResponseMessage Post()
{
var task = Request.Content.ReadAsStreamAsync();
task.Wait();
Stream requestStream = task.Result;
string root = HttpContext.Current.Server.MapPath("~/App_Data");
root = System.IO.Path.Combine(root, "xyz.jpg");
try
{
FileStream fs = System.IO.File.OpenWrite(root);
requestStream.CopyTo(fs);
fs.Close();
}
catch (Exception)
{
throw new HttpResponseException(new HttpResponseMessage(HttpStatusCode.InternalServerError));
}
HttpResponseMessage response = new HttpResponseMessage();
response.StatusCode = HttpStatusCode.Created;
return response;
}
You are not sending a representation that is multipart/form. You are just sending a stream of bytes which is application/octet-stream. Just use Request.Content.ReadAsStreamAsync() on the server and copy the stream to a file.
I am working on a Windows Phone app. This app will let users take pictures and upload them to my server. I have successfully implemented this. However, I've noticed that sometimes the picture does not get uploaded properly. I suspect this happens when someone puts the app to sleep before its done uploading. Or the connectivity gets interrupted. I'm really not sure how to do address this. I've included my code here. I'm hoping someone can provide some insight.
Client Side - Windows Phone App - Picture.cs
--------------------------------------------
public event EventHandler Upload_Succeeded;
public event EventHandler Upload_Failed;
public void Upload()
{
try {
WebRequest request = HttpWebRequest.Create(GetBackendPictureUploadUrl());
request.Method = "POST";
request.ContentType = "application/x-www-form-urlencoded";
request.BeginGetRequestStream(new AsyncCallback(UploadBeginGetRequestStreamCallBack), request);
} catch (Exception ex)
{
Upload_Failed(this, EventArgs.Empty);
}
}
private void UploadBeginGetRequestStreamCallBack(IAsyncResult ar)
{
try {
StringBuilder sb = new StringBuilder();
this.ImageBytes.ToList<byte>().ForEach(x => sb.AppendFormat("{0}.", Convert.ToUInt32(x)));
Dictionary<string, string> parameters = new Dictionary<string, string>();
parameters.Add("username", GetUsername());
parameters.Add("pictureByts", sb.ToString());
string data = string.Empty;
foreach (string key in parameters.Keys)
{
data += key;
data += "=";
data += parameters[key];
data += "&";
}
data = data.Substring(0, data.Length - 1);
HttpWebRequest webRequest = (HttpWebRequest)(ar.AsyncState);
using (Stream postStream = webRequest.EndGetRequestStream(ar))
{
byte[] byteArray = Encoding.UTF8.GetBytes(data);
postStream.Write(byteArray, 0, byteArray.Length);
postStream.Close();
}
webRequest.BeginGetResponse(new AsyncCallback(Upload_Completed), webRequest);
} catch (Exception ex)
{
Upload_Failed(this, EventArgs.Empty);
}
}
private void Upload_Completed(IAsyncResult result)
{
Upload_Succeeded(this, EventArgs.Empty);
}
Server Size - ASP.NET MVC - MyController.cs
-------------------------------------------
[AcceptVerbs(HttpVerbs.Post)]
public ActionResult AddPicture(string username, string pictureBytes)
{
string path = ConfigurationManager.AppSettings["pictureDirectory"] + "/" + username + "/";
if (Directory.Exists(path) == false)
Directory.CreateDirectory(path);
string filePath = path + "/" + Guid.NewGuid().ToString() + ".png";
// Save the picture to the file system
string[] bytesToConvert = pictureBytes.Split('.');
List<byte> fileBytes = new List<byte>();
bytesToConvert.ToList<string>().Where(x => !string.IsNullOrEmpty(x)).ToList<string>().ForEach(x => fileBytes.Add(Convert.ToByte(x)));
using (FileStream fileStream = new FileStream(filePath, FileMode.Create))
{
byte[] bytes = fileBytes.ToArray();
fileStream.Write(bytes, 0, bytes.Length);
fileStream.Close();
}
}
I'm so confused. This code looks right in my opinion. But I've noticed that files are being written on my server. Sometimes they are just grey images. Sometimes it looks like part of the image was written but not the whole thing. What am I doing wrong? How do I ensure that the file is completely uploaded / written properly? There has to be some way of doing this. Clearly Facebook etc. are doing this. What am I doing wrong?
You need to set ContentLength in your Upload method. To do that, you should compute your finished data buffer before you make the async request. Then you will have the length you need (after UTF8 encode). Then supply the data to the stream when the callback occurs.
I just recieve my unique developer API key from Imgur and I'm aching to start cracking on this baby.
First a simple test to kick things off. How can I upload an image using C#? I found this using Python:
#!/usr/bin/python
import pycurl
c = pycurl.Curl()
values = [
("key", "YOUR_API_KEY"),
("image", (c.FORM_FILE, "file.png"))]
# OR: ("image", "http://example.com/example.jpg"))]
# OR: ("image", "BASE64_ENCODED_STRING"))]
c.setopt(c.URL, "http://imgur.com/api/upload.xml")
c.setopt(c.HTTPPOST, values)
c.perform()
c.close()
looks like the site uses HTTP Post to upload images. Take a look at the HTTPWebRequest class and using it to POST to a URL: Posting data with HTTPRequest.
The Imgur API now provide a complete c# example :
using System;
using System.IO;
using System.Net;
using System.Text;
namespace ImgurExample
{
class Program
{
static void Main(string[] args)
{
PostToImgur(#"C:\Users\ashwin\Desktop\image.jpg", IMGUR_ANONYMOUS_API_KEY);
}
public static void PostToImgur(string imagFilePath, string apiKey)
{
byte[] imageData;
FileStream fileStream = File.OpenRead(imagFilePath);
imageData = new byte[fileStream.Length];
fileStream.Read(imageData, 0, imageData.Length);
fileStream.Close();
string uploadRequestString = "image=" + Uri.EscapeDataString(System.Convert.ToBase64String(imageData)) + "&key=" + apiKey;
HttpWebRequest webRequest = (HttpWebRequest)WebRequest.Create("http://api.imgur.com/2/upload");
webRequest.Method = "POST";
webRequest.ContentType = "application/x-www-form-urlencoded";
webRequest.ServicePoint.Expect100Continue = false;
StreamWriter streamWriter = new StreamWriter(webRequest.GetRequestStream());
streamWriter.Write(uploadRequestString);
streamWriter.Close();
WebResponse response = webRequest.GetResponse();
Stream responseStream = response.GetResponseStream();
StreamReader responseReader = new StreamReader(responseStream);
string responseString = responseReader.ReadToEnd();
}
}
}
Why don't you use the NuGet for this: called Imgur.API and for upload
you would have a method like this:
/*
The refresh token and all the values represented by constans are given when you allow the application in your imgur panel on the response url
*/
public OAuth2Token CreateToken()
{
var token = new OAuth2Token(TOKEN_ACCESS, REFRESH_TOKEN, TOKEN_TYPE, ID_ACCOUNT, IMGUR_USER_ACCOUNT, int.Parse(EXPIRES_IN));
return token;
}
//Use it only if your token is expired
public Task<IOAuth2Token> RefreshToken()
{
var client = new ImgurClient(CLIENT_ID, CLIENT_SECRET);
var endpoint= new OAuth2Endpoint(client);
var token = endpoint.GetTokenByRefreshTokenAsync(REFRESH_TOKEN);
return token;
}
public async Task UploadImage()
{
try
{
var client = new ImgurClient(CLIENT_ID, CLIENT_SECRET, CreateToken());
var endpoint = new ImageEndpoint(client);
IImage image;
//Here you have to link your image location
using (var fs = new FileStream(#"IMAGE_LOCATION", FileMode.Open))
{
image = await endpoint.UploadImageStreamAsync(fs);
}
Debug.Write("Image uploaded. Image Url: " + image.Link);
}
catch (ImgurException imgurEx)
{
Debug.Write("Error uploading the image to Imgur");
Debug.Write(imgurEx.Message);
}
}
Also you can find all the reference here: Imgur.API NuGet