На днях, разрабатывая приложения для Windows Phone 8 я наткнулся на одну проблем, все еще актуальную при разработке клиент-серверных приложений с бэк-эндом на PHP(и не только).
Проблема в общих чертах обрисовывалась так "Как отправить изображение POST запросом на PHP сервер с Windows Phone". И Stackoverflow буквально разрывается от подобных вопросов, но осмысленных или правильных(работающих по сей день я не нашел).
Но после двух дней мучений я все же нашел решение.
Занимаясь разработкой под Windows RT я очень привык к HTTPClient, который большинство дел берет на себя и тебе не приходиться много париться. Но начиная разработку под Windows Phone, понимаешь что Microsoft учли все ошибки допущенные в Windows Phone и исправили их Windows RT, что кстати прекрасно.
Но у меня получился Downgrade. И без моего любимого HTTPClient мне пришлось тяжко.
У меня на вооружении были 2 варианта работы с HTTP: первый это WebClient(предшественник HTTPClient) и HTTPWebRequest. Разница между ними в том что WebClient проще, а HTTPWebRequest дает больше возможностей и контроля. И я решил использовать второй вариант.
Начнем с создания кнопки и привязывания к ней метода:
Кнопка:
<shell:ApplicationBarIconButton IconUri="/Images/Camera.png" Text="Изменить аватар" Click="EditAvatarApp" />
Метод обработки события:
private void EditAvatarApp(object sender, EventArgs e)
{
selectphoto = new PhotoChooserTask();
selectphoto.Completed += new EventHandler<PhotoResult>(selectphoto_Completed); selectphoto.Show();
}
Тут видно, что после того как мы выбрали изображение нужно вызывать метод:
selectphoto_Completed.(описание ниже) Что мы и делаем.
void selectphoto_Completed(object sender, PhotoResult e)
{
feed = new UploadAvatar();
if (e.TaskResult == TaskResult.OK)
{
var memoryStream = new MemoryStream();
e.ChosenPhoto.CopyTo(memoryStream);
byte[] results = memoryStream.ToArray();
WebRequest request = HttpWebRequest.Create("http://mysite.com/upload.php");
request.Method = "POST";
request.ContentType = "application/x-www-form-urlencoded";
request.BeginGetRequestStream((reqResult) =>
{
using (Stream strm = request.EndGetRequestStream(reqResult))
using (StreamWriter writer = new StreamWriter(strm))
{
writer.Write("&message=" + HttpUtility.UrlEncode("Im testing upload"));
writer.Write("&avatar=" + HttpUtility.UrlEncode(System.Convert.ToBase64String(results)));
}
request.BeginGetResponse((result) =>
{
try
{
var response = request.EndGetResponse(result);
using (var rstrm = response.GetResponseStream())
{
var serializer = new DataContractJsonSerializer(typeof(UploadAvatar));
var postResponse = serializer.ReadObject(rstrm) as UploadAvatar;
feed = postResponse;
localSettings.Remove("avatar");
localSettings.Add("avatar", postResponse.link);
}
}
catch (Exception ex)
{
}
}, null);
}, null);
MessageBox.Show("Ваш аватар успешно обновлен");
}
}
Если коротко мы превращаем выбранное изображение в поток,а поток кодируем в base64 и отправляем на сервер в виде одного из аргументов.
Теперь посмотрим на серверную часть:
if (isset($_POST['avatar']))
{
$date=time();
$img = base64_decode($_POST["avatar"]);
$im = imagecreatefromstring($img);
if ($im !== false) {
header('Content-Type: image/png');
imagepng($im,"/public/avatars/".$date.".jpg");
imagedestroy($im);
}
else {
echo 'An error occurred.';
}
}
$avatar = $date.".jpg";
$responce["success"] = 1;
$responce["link"] = "http://mysite.com/public/avatars/".$avatar;
$responce = json_encode($responce);
echo $responce;
Сервер принимает пост, и декодирует Base64 и штатными методами создает изображение и сохраняет там где нам нужно. И сервер отвечает json.
Теперь поговорим немного о получении и десериализации ответа сервера.
Вас немогли не ввести в недоумение эти строчки:
feed = new UploadAvatar();
var serializer = new DataContractJsonSerializer(typeof(UploadAvatar));
var postResponse = serializer.ReadObject(rstrm) as UploadAvatar;
feed = postResponse;
Скажу сразу, чтобы получить и сохранить ответ сервера нужен идентичный ответу, класс. Например в нашем случае Upload avatar:
public class UploadAvatar
{
public int success { get; set; }
public string link { get; set; }
}
И как мы видим наш класс полностью идентичен ответу сервера.
$responce["success"] = 1;
$responce["link"] = "http://mysite.com/public/avatars/".$avatar;
$responce = json_encode($responce);
echo $responce;
Вот и вся магия.
С вами был я. Подписываетесь на мой твиттер: @khojabergen