When uploading Photo to Web API always 0 bytes - windows-phone-8

I have the following, and it uploads without errors, but the image is always 0 bytes.
Windows Phone App (this is called after selecting or taking a photo):
private void AddImage(PhotoResult e)
{
if (e.TaskResult == TaskResult.OK)
{
string serviceUri = Globals.GreedURL + #"API/UploadPhoto/test5.jpg";
HttpWebRequest request = (HttpWebRequest)HttpWebRequest.Create(serviceUri);
request.Method = "POST";
request.BeginGetRequestStream(result =>
{
Stream requestStream = request.EndGetRequestStream(result);
e.ChosenPhoto.CopyTo(requestStream);
requestStream.Close();
request.BeginGetResponse(result2 =>
{
try
{
HttpWebResponse response = (HttpWebResponse)request.EndGetResponse(result2);
if (response.StatusCode == HttpStatusCode.Created)
{
this.Dispatcher.BeginInvoke(() =>
{
MessageBox.Show("Upload completed.");
});
}
else
{
this.Dispatcher.BeginInvoke(() =>
{
MessageBox.Show("An error occured during uploading. Please try again later.");
});
}
}
catch
{
this.Dispatcher.BeginInvoke(() =>
{
MessageBox.Show("An error occured during uploading. Please try again later.");
});
}
e.ChosenPhoto.Close();
}, null);
}, null);
}
And here is the Web API:
public class UploadPhotoController : ApiController
{
public HttpResponseMessage Post([FromUri]string filename)
{
var task = this.Request.Content.ReadAsStreamAsync();
task.Wait();
Stream requestStream = task.Result;
// Retrieve storage account from connection string.
CloudStorageAccount storageAccount = CloudStorageAccount.Parse(ConfigurationManager.ConnectionStrings["StorageConnectionString"].ConnectionString);
// Create the blob client.
CloudBlobClient blobClient = storageAccount.CreateCloudBlobClient();
// Retrieve reference to a previously created container.
CloudBlobContainer container = blobClient.GetContainerReference("profilepics");
container.CreateIfNotExists();
var permissions = container.GetPermissions();
permissions.PublicAccess = BlobContainerPublicAccessType.Blob;
container.SetPermissions(permissions);
string uniqueBlobName = string.Format("test.jpg");
CloudBlockBlob blob = container.GetBlockBlobReference(uniqueBlobName);
blob.Properties.ContentType = "image\\jpeg";
blob.UploadFromStream(task.Result);
HttpResponseMessage response = new HttpResponseMessage();
response.StatusCode = HttpStatusCode.Created;
return response;
}
}
Any ideas?
Any help would be appreciated.

Related

Html error when downloading youtube video

I downloaded a Youtube downloader from Github it was a WPF and it works however I want to reproduce this C# for Windows App. The original code from WPF is:
public async Task BeginDownload()
{
if (!CheckInputs())
return;
ChangeButtonStates(false);
string link = videoLink.Text;
string? downloadFormat = null;
string savedDirectory = Properties.Settings.Default.savedDirectory;
if (saveMP3.IsChecked == true)
downloadFormat = "mp3";
else
downloadFormat = "mp4";
try
{
cancellationToken = cancellationTokenSource.Token;
// If the given URL contains "&list" it means it is playlist
if (!link.Contains("&list"))
await DownloadSingle(link, savedDirectory, downloadFormat);
else
await DownloadPlaylist(link, savedDirectory, downloadFormat);
}
catch (Exception ex)
{
new Thread(() =>
{
MessageBox.Show($"An error occurred: \"{ex.Message}\".", "Downloader", MessageBoxButton.OK, MessageBoxImage.Error);
}).Start();
}
ChangeButtonStates(true);
}
My code converted for use with windows form
public async Task BeginDownload()
{
if (!CheckInputs())
return;
ChangeButtonStates(false);
string link = videoLink.Text;
string downloadFormat = null;
string savedDirectory = Properties.Settings.Default.savedDirectory;
if (cmbDownloadType.SelectedIndex == 1)
downloadFormat = "mp3";
else
downloadFormat = "mp4";
try
{
cancellationToken = cancellationTokenSource.Token;
//// If the given URL contains "&list" it means it is playlist
//if (!link.Contains("&list"))
await DownloadSingle(link, savedDirectory, downloadFormat);
//else
//await DownloadPlaylist(link, savedDirectory, downloadFormat);
}
catch (Exception ex)
{
new Thread(() =>
{
MessageBox.Show($"An error occurred: \"{ex.Message}\".", "Downloader", MessageBoxButtons.OK, MessageBoxIcon.Error);
}).Start();
}
ChangeButtonStates(true);
}
for simplicity I commented out playlist I can add it later I only want to start with a single download. When I run my code it get a html error not sure how to troubleshoot the error.
WPF code to download single
public async Task DownloadSingle(string link, string path, string format)
{
// Needed for security
var handler = new HttpClientHandler();
var httpClient = new HttpClient(handler, true);
handler.UseCookies = false;
// Get video data
var youtube = new YoutubeClient(httpClient);
var streamData = await youtube.Videos.GetAsync(link);
var title = ReplaceInvalidCharacters(streamData.Title);
var progress = new Progress<double>(value =>
{
// To split the progress bar into two halves, fill one half and then the next,
// maximum of both progress bars is 50
if (downloadProgressOne.Value != 50)
{
downloadProgressOne.Value = value * 100.00f;
}
else
{
downloadProgressTwo.Value = (value * 100.00f) - 50;
}
// Taskbar icon progress bar
taskbarIcon.ProgressValue = value;
downloadStatus.Text = $"Downloading... {Convert.ToInt32(value * 100.00f)}%";
});
try
{
// Download content
await youtube.Videos.DownloadAsync(link, $"{path}\\{title}.{format}", o => o.SetContainer(format).SetPreset(ConversionPreset.UltraFast), progress, cancellationToken);
}
catch (TaskCanceledException)
{
new Thread(() =>
{
MessageBox.Show($"Successfully cancelled the download of: \"{title}\".", "Downloader", MessageBoxButton.OK, MessageBoxImage.Information);
}).Start();
File.Delete($"{path}\\{title}.{format}");
return;
}
catch (Exception ex)
{
new Thread(() =>
{
MessageBox.Show($"Failed to download video: \"{title}\" due to an error.\n\nReason: \"{ex.Message}\".", "Downloader", MessageBoxButton.OK, MessageBoxImage.Warning);
}).Start();
return;
}
new Thread(() =>
{
MessageBox.Show($"Successfully downloaded video: \"{title}\".", "Downloader", MessageBoxButton.OK, MessageBoxImage.Information);
}).Start();
}
public async Task DownloadPlaylist(string link, string path, string format)
{
// Create a string list incase any videos fail to download
List<string> failedVideosTitles = new();
string finalList = "";
int failedVideosAmount = 0;
// Needed for security
var handler = new HttpClientHandler();
var httpClient = new HttpClient(handler, true);
handler.UseCookies = false;
// Get playlist data
var youtube = new YoutubeClient(httpClient);
var playlistData = await youtube.Playlists.GetAsync(link);
var playlistName = ReplaceInvalidCharacters(playlistData.Title);
var total = await youtube.Playlists.GetVideosAsync(link);
var totalNumber = total.Count;
int currentNumber = 0;
// Foreach video in the playlist try to download them as the desired format
await foreach (var video in youtube.Playlists.GetVideosAsync(playlistData.Id))
{
currentNumber++;
var title = ReplaceInvalidCharacters(video.Title);
// Skip download of video if it already exists
if (File.Exists($"{path}\\{title}.{format}"))
{
downloadStatus.Text = $"Skipping {currentNumber}/{totalNumber}...";
await Task.Delay(100);
continue;
}
var progress = new Progress<double>(value =>
{
// To split the progress bar into two halves, fill one half and then the next,
// maximum of both progress bars is 50
if (value < 0.5f || downloadProgressOne.Value < 50)
{
downloadProgressOne.Value = value * 100.00f;
downloadProgressTwo.Value = 0;
}
else
downloadProgressTwo.Value = (value * 100.00f) - 50;
// Taskbar icon progress bar
taskbarIcon.ProgressValue = value;
downloadStatus.Text = $"Downloading... {currentNumber}/{totalNumber} - {Convert.ToInt32(value * 100.00f)}%";
});
try
{
// Download content
await youtube.Videos.DownloadAsync(video.Id, $"{path}\\{title}.{format}", o => o.SetContainer(format).SetPreset(ConversionPreset.UltraFast), progress, cancellationToken);
}
catch (TaskCanceledException)
{
new Thread(() =>
{
MessageBox.Show($"Successfully cancelled the download of playlist: \"{playlistName}\".\n\nFiles have not been deleted.", "Downloader", MessageBoxButton.OK, MessageBoxImage.Information);
}).Start();
File.Delete($"{path}\\{title}.{format}");
return;
}
catch (Exception ex)
{
new Thread(() =>
{
// Increase the failed videos amount by one and add the title to the list
failedVideosAmount++;
failedVideosTitles.Add($"\"{title}\"");
MessageBox.Show($"Skipping download of video: \"{title}\" due to an error.\n\nReason: \"{ex.Message}\".", "Downloader", MessageBoxButton.OK, MessageBoxImage.Warning);
}).Start();
}
}
if (failedVideosAmount != 0)
{
new Thread(() =>
{
// Show a messagebox telling the user it failed to download X amount of videos
MessageBox.Show($"Downloaded playlist: \"{playlistName}\" but failed to download {failedVideosAmount} of the videos.\n\nPress OK to see list of failed videos.", "Downloader", MessageBoxButton.OK, MessageBoxImage.Warning);
// Loop for the length of the string list, build a final string containing
// a list of titles of failed videos then display it in a messagebox for the user
for (int i = 0; i < failedVideosTitles.Count; i++)
{
if (i == 0) { finalList = $"{finalList}{i + 1}. {failedVideosTitles[i]}."; }
else { finalList = $"{finalList}\n\n{i + 1}. {failedVideosTitles[i]}."; }
}
MessageBox.Show(finalList, "Downloader", MessageBoxButton.OK, MessageBoxImage.Information);
}).Start();
}
else
{
new Thread(() =>
{
// The entire playlist was downloaded successfully
MessageBox.Show($"Successfully downloaded playlist: \"{playlistName}\".", "Downloader", MessageBoxButton.OK, MessageBoxImage.Information);
}).Start();
}
}
my converted code
public async Task DownloadSingle(string link, string path, string format)
{
// Needed for security
var handler = new HttpClientHandler();
var httpClient = new HttpClient(handler, true);
handler.UseCookies = false;
// Get video data
var youtube = new YoutubeClient(httpClient);
var streamData = await youtube.Videos.GetAsync(link);
var title = ReplaceInvalidCharacters(streamData.Title);
var progress = new Progress<double>(value =>
{
// To split the progress bar into two halves, fill one half and then the next,
// maximum of both progress bars is 50
if (downloadProgressOne.Value != 50)
{
downloadProgressOne.Value = (int)(value * 100.00f);
}
else
{
downloadProgressTwo.Value = (int)((value * 100.00f) - 50);
}
// Taskbar icon progress bar
//taskbarIcon.ProgressValue = value;
downloadStatus.Text = $"Downloading... {Convert.ToInt32(value * 100.00f)}%";
});
try
{
// Download content
await youtube.Videos.DownloadAsync(link, $"{path}\\{title}.{format}", o => o.SetContainer(format).SetPreset(ConversionPreset.UltraFast), progress, cancellationToken);
}
catch (TaskCanceledException)
{
new Thread(() =>
{
MessageBox.Show($"Successfully cancelled the download of: \"{title}\".", "Downloader", MessageBoxButtons.OK, MessageBoxIcon.Information);
}).Start();
File.Delete($"{path}\\{title}.{format}");
return;
}
catch (Exception ex)
{
new Thread(() =>
{
MessageBox.Show($"Failed to download video: \"{title}\" due to an error.\n\nReason: \"{ex.Message}\".", "Downloader", MessageBoxButtons.OK, MessageBoxIcon.Warning);
}).Start();
return;
}
new Thread(() =>
{
MessageBox.Show($"Successfully downloaded video: \"{title}\".", "Downloader", MessageBoxButtons.OK, MessageBoxIcon.Information);
}).Start();
}
Argh rookie mistake just had to update the nuget package for codepages.

POST data to web service HttpWebRequest Windows Phone 8

I've been trying without success today to adapt this example to POST data instead of the example GET that is provided.
http://blogs.msdn.com/b/andy_wigley/archive/2013/02/07/async-and-await-for-http-networking-on-windows-phone.aspx
I've replaced the line:
request.Method = HttpMethod.Get;
With
request.Method = HttpMethod.Post;
But can find no Method that will allow me to stream in the content I wish to POST.
This HttpWebRequest seems a lot cleaner than other ways e.g. sending delegate functions to handle the response.
In Mr Wigley's example code I can see POST so it must be possible
public static class HttpMethod
{
public static string Head { get { return "HEAD"; } }
public static string Post { get { return "POST"; } }
I wrote this class some time ago
public class JsonSend<I, O>
{
bool _parseOutput;
bool _throwExceptionOnFailure;
public JsonSend()
: this(true,true)
{
}
public JsonSend(bool parseOutput, bool throwExceptionOnFailure)
{
_parseOutput = parseOutput;
_throwExceptionOnFailure = throwExceptionOnFailure;
}
public async Task<O> DoPostRequest(string url, I input)
{
var client = new HttpClient();
CultureInfo ci = new CultureInfo(Windows.System.UserProfile.GlobalizationPreferences.Languages[0]);
client.DefaultRequestHeaders.Add("Accept-Language", ci.TwoLetterISOLanguageName);
var uri = new Uri(string.Format(
url,
"action",
"post",
DateTime.Now.Ticks
));
string serialized = JsonConvert.SerializeObject(input);
StringContent stringContent = new StringContent(
serialized,
Encoding.UTF8,
"application/json");
var response = client.PostAsync(uri, stringContent);
HttpResponseMessage x = await response;
HttpContent requestContent = x.Content;
string jsonContent = requestContent.ReadAsStringAsync().Result;
if (x.IsSuccessStatusCode == false && _throwExceptionOnFailure)
{
throw new Exception(url + " with POST ends with status code " + x.StatusCode + " and content " + jsonContent);
}
if (_parseOutput == false){
return default(O);
}
return JsonConvert.DeserializeObject<O>(jsonContent);
}
public async Task<O> DoPutRequest(string url, I input)
{
var client = new HttpClient();
CultureInfo ci = new CultureInfo(Windows.System.UserProfile.GlobalizationPreferences.Languages[0]);
client.DefaultRequestHeaders.Add("Accept-Language", ci.TwoLetterISOLanguageName);
var uri = new Uri(string.Format(
url,
"action",
"put",
DateTime.Now.Ticks
));
string serializedObject = JsonConvert.SerializeObject(input);
var response = client.PutAsync(uri,
new StringContent(
serializedObject,
Encoding.UTF8,
"application/json"));
HttpResponseMessage x = await response;
HttpContent requestContent = x.Content;
string jsonContent = requestContent.ReadAsStringAsync().Result;
if (x.IsSuccessStatusCode == false && _throwExceptionOnFailure)
{
throw new Exception(url + " with PUT ends with status code " + x.StatusCode + " and content " + jsonContent);
}
if (_parseOutput == false){
return default(O);
}
return JsonConvert.DeserializeObject<O>(jsonContent);
}
}
Then when I want to call it, I can use it as following :
JsonSend<User, RegistrationReceived> register = new JsonSend<User, RegistrationReceived>();
RegistrationReceived responseUser = await register.DoPostRequest("http://myurl", user);

How to return an Error from a generic method

The title doesn't describe the issue very well so let me explain my problem.
I have a generic function to consume API's via HTTP GET calls. Which looks like this:
public async static Task<T> GetAsync<T>(string Base_Url,string relative_URL, Utility.UriExtensions.NameValueCollection Params, Utility.UriExtensions.NameValueCollection headers = null)
{
Uri CompleteURL = new Uri(Base_Url + relative_URL, UriKind.Absolute);
if (Params != null)
CompleteURL = Utility.UriExtensions.CreateUriWithQuery(CompleteURL, Params);
if(headers!=null)
{
foreach(KeyValuePair<string,string> k in headers)
{
if (ApiHttpClient.DefaultRequestHeaders.ContainsKey(k.Key))
ApiHttpClient.DefaultRequestHeaders[k.Key] = k.Value;
else
ApiHttpClient.DefaultRequestHeaders.Add(k.Key, k.Value);
}
}
Debug.WriteLine("GET : " + CompleteURL);
using (var response = await ApiHttpClient.GetAsync(CompleteURL).AsTask(cancellationToken.Token).ConfigureAwait(false))
{
string responseData="";
if (response.IsSuccessStatusCode)
{
responseData = await response.Content.ReadAsStringAsync();
Debug.WriteLine(responseData);
JsonSerializerSettings settings = new JsonSerializerSettings();
settings.DateParseHandling = DateParseHandling.DateTime;
settings.DefaultValueHandling = DefaultValueHandling.Populate;
settings.NullValueHandling = NullValueHandling.Include;
settings.TypeNameHandling = TypeNameHandling.None;
}
try
{
response.EnsureSuccessStatusCode();
return JsonConvert.DeserializeObject<T>(responseData);
}
catch
{
// Error
Debug.WriteLine(
"Error occurred, the status code is: {0} and Content : {1}",
response.StatusCode, response.Content);
}
return default(T);
}
}
In case of error, the error is handled inside catch body. I want to return these Error informations like StatusCode and Content of response when this happens. But I am unable to make any changes to this generic function. How should handle this.
For this purpose you can use out parameter, which you will pass in your method:
public async static Task<T> GetAsync<T>(string Base_Url,string relative_URL, Utility.UriExtensions.NameValueCollection Params, Utility.UriExtensions.NameValueCollection headers = null, out StatusCode code)
StatusCode statusCode;
GetAsync<Foo>(..., out statusCode);

WP8 Some images not downloading using HttpClient

I am building a WP8 app that downloads images using HttpClient in a background task. My problem is that some images are not downloaded no matter how much time I wait for them to finish. The image sizes are a few megabytes at maximum.
The code I use to download images:
internal static async Task<bool> Download_Wallpaper(string image_url, string file_name, string destination_folder_name)
{
try
{
using (var client = new HttpClient())
{
// 12MB max images
client.Timeout = TimeSpan.FromSeconds(5);
client.MaxResponseContentBufferSize = DeviceStatus.ApplicationMemoryUsageLimit / 2;
//client.Timeout = TimeSpan.FromSeconds(5);
byte[] image_byte_arr;
try
{
/* var requestMessage = new HttpRequestMessage( HttpMethod.Get, image_url );
var responseMessage = await client.SendAsync((requestMessage));
// byte array of image
image_byte_arr = await responseMessage.Content.ReadAsByteArrayAsync();
*/
// byte array of image
image_byte_arr = await client.GetByteArrayAsync(image_url);
}
// Could not download
catch (OutOfMemoryException X)
{
GC.Collect();
return false;
}
var folder = await StorageFolder.GetFolderFromPathAsync(destination_folder_name);
// Create file
StorageFile file = await folder.CreateFileAsync(file_name, CreationCollisionOption.ReplaceExisting);
using (var write_stream = await file.OpenStreamForWriteAsync())
{
write_stream.Write(image_byte_arr, 0, image_byte_arr.Length);
}
Console.WriteLine(DeviceStatus.ApplicationCurrentMemoryUsage);
return true;
}
}
catch (HttpRequestException X)
{
Console.WriteLine(X);
return false;
}
catch (OutOfMemoryException X)
{
GC.Collect();
return false;
}
catch (Exception X)
{
Console.WriteLine(X);
return false;
}
}
This is an example image that fails to download: https://upload.wikimedia.org/wikipedia/commons/9/95/Tracy_Caldwell_Dyson_in_Cupola_ISS.jpg
In my experience all wikimedia images fail to download for some reason.
I see no way of tracking download progress using HttpClient. Is there a way to do so?
Edit: It seems that setting the timeout does not have any function. The HttpRequestException is not thrown after 5 seconds.
Edit2: I tried a different approach, the one that anonshankar suggested. With that method the code would get stuck at the line:
byte[] img = response.Content.ReadAsByteArrayAsync();
So the HttpResponse arrives, but somehow the bytes could not be read out, no matter how much time I gave it. How could this even happen? The hard part is getting the response, reading out the bytes should be simple.
Again, this only happens with some images, most of them downloads correctly. One example is mentioned above.
I have modified my image downloader code, so that it times out after a few seconds. Here is my final code:
internal static async Task<bool> Download_Wallpaper(string image_url, string file_name, string destination_folder_name)
{
try
{
using (var client = new HttpClient())
{
// prevent running out of memory
client.MaxResponseContentBufferSize = DeviceStatus.ApplicationMemoryUsageLimit / 3;
byte[] image_byte_arr = null;
using (CancellationTokenSource cts = new CancellationTokenSource())
{
var task = Task.Factory.StartNew(() =>
{
try
{
image_byte_arr = client.GetByteArrayAsync(image_url).Result;
}
catch (AggregateException X)// Handling read errors, usually image is too big
{
Console.WriteLine(X.Message);
foreach (var v in X.InnerExceptions)
Console.WriteLine(v.Message);
image_byte_arr = null;
}
}, cts.Token);
bool finished_in_time = task.Wait(TimeSpan.FromSeconds(5));
if (!finished_in_time)// Timeout
{
cts.Cancel();
task.Wait();
return false;
}
else if (image_byte_arr == null)// Read error
{
return false;
}
}
var folder = await StorageFolder.GetFolderFromPathAsync(destination_folder_name);
// Create file
StorageFile file = await folder.CreateFileAsync(file_name, CreationCollisionOption.ReplaceExisting);
using (var write_stream = await file.OpenStreamForWriteAsync())
{
write_stream.Write(image_byte_arr, 0, image_byte_arr.Length);
}
Console.WriteLine(DeviceStatus.ApplicationCurrentMemoryUsage);
return true;
}
}
catch (HttpRequestException X)
{
Console.WriteLine(X);
return false;
}
catch (OutOfMemoryException X)
{
GC.Collect();
return false;
}
catch (Exception X)
{
Console.WriteLine(X);
return false;
}
}
Any improvement suggestions are welcome, and I still don't understand why does the method HttpContent.ReadAsByteArrayAsync() gets stuck.
Just try out this snippet which worked for me.
HttpClient client = new HttpClient();
HttpResponseMessage response = await client.GetAsync("give the url");
byte[] img = response.Content.ReadAsByteArray();
InMemoryRandomAccessStream randomAccessStream = new InMemoryRandomAccessStream();
DataWriter writer = new DataWriter(randomAccessStream.GetOutputStreamAt(0));
writer.WriteBytes(img);
await writer.StoreAsync();
BitmapImage b = new BitmapImage();
b.SetSource(randomAccessStream);
pic.Source = b; //(pic is an `<Image>` defined in the `XAML`
Hope it helps!

Http post call in windows phone 8

I'm new to windows phone 8 development.
Could you please help me how to send the xml data to the server through http post calls in windows phone 8?
Thanks
This is a sample code I used in my project. Modify according to your needs
HttpWebRequest req = (HttpWebRequest)WebRequest.Create("url to submit to");
req.Method = "POST";
//Add a Header something like this
//req.Headers["SOAPAction"] = "http://asp.net/ApplicationServices/v200/AuthenticationService/Login";
req.ContentType = "text/xml; charset=utf-8";
//req.UserAgent = "PHP-SOAP/5.2.6";
string xmlData = #"<?xml version=""1.0"" encoding=""UTF-8""?>Your xml data";
// Convert the string into a byte array.
byte[] byteArray = Encoding.UTF8.GetBytes(xmlData);
req.Headers[HttpRequestHeader.ContentLength] = byteArray.Length.ToString();
req.BeginGetRequestStream(ar =>
{
using (var requestStream = req.EndGetRequestStream(ar))
{
// Write the body of your request here
requestStream.Write(byteArray, 0, xmlData.Length);
}
req.BeginGetResponse(a =>
{
try
{
var response = req.EndGetResponse(a);
var responseStream = response.GetResponseStream();
using (var streamRead = new StreamReader(responseStream))
{
// Parse the response message here
string responseString = streamRead.ReadToEnd();
//If response is also XML document, parse it like this
XDocument xdoc = XDocument.Parse(responseString);
string result = xdoc.Root.Value;
if (result == "true")
{
//Do something here
}
else
Dispatcher.BeginInvoke(() =>
{
//result failed
MessageBox.Show("Some error msg");
});
}
}
catch (Exception ex)
{
Dispatcher.BeginInvoke(() =>
{
//if any unexpected exception occurs, show the exception message
MessageBox.Show(ex.Message);
});
}
}, null);
}, null);