How Upload Files on Server using WebClient Windows phone? - windows-phone-8

I want upload a file (any type) on a server.
I have my file which is saved like this (I use FileAssociation)
await SharedStorageAccessManager.CopySharedFileAsync(ApplicationData.Current.LocalFolder, "fileToSave" + fileext, NameCollisionOption.ReplaceExisting, NavigationContext.QueryString["filetoken"]);
Then I get the saved file
StorageFolder folder = ApplicationData.Current.LocalFolder;
var file = await folder.GetFileAsync("fileToSave" + fileext);
Stream data = Application.GetResourceStream(new Uri(file.Path, UriKind.Relative)).Stream;
string filename = System.IO.Path.GetFileName(file.Path);
ServerFunctions.UploadFile(filename,data);
Then I start the Upload
internal void UploadFile(string fileName,Stream data)
{
WebClient web = new WebClient();
if (!string.IsNullOrEmpty(dataRequestParam.AuthentificationLogin))
{
System.Net.NetworkCredential account = new NetworkCredential(dataRequestParam.AuthentificationLogin, dataRequestParam.AuthentificationPassword);
web.Credentials = account;
}
web.AllowReadStreamBuffering = true;
web.AllowWriteStreamBuffering = true;
web.OpenWriteCompleted += (sender, e) =>
{
PushData(data, e.Result);
e.Result.Close();
data.Close();
};
web.OpenWriteAsync(dataRequestParam.TargetUri,"POST");
}
private void PushData(Stream input, Stream output)
{
byte[] buffer = new byte[4096];
int bytesRead;
while ((bytesRead = input.Read(buffer, 0, buffer.Length)) != 0)
{
output.Write(buffer, 0, bytesRead);
}
}
The web server is supposed to send me as a response a xml with an error code or succes code inside.
None error is thrown but it doesnt work.And I don't understand why the e.result is a stream object. As I said the server should return a string...(xml file)
Could you bring me some explannations of what is happening in my code and if it will work with all types of files ?
Thanks

I think part of the problem here is that you're attempting to get this to behave like a streaming protocol when it seems you intend a request/response type architecture. For those purposes, you should consider working with a WebRequest object.
Bear with me as I fully qualify the namespace of the objects used inline, so it may get a little verbose, but I want you to know where to find these things.
internal async void UploadFile(string fileName, System.IO.Stream data)
{
// Specify URI, method, and credentials for the request
System.Net.WebRequest web = System.Net.HttpWebRequest.CreateHttp(dataRequestParam.TargetUri);
web.Method = "POST";
if (!string.IsNullOrEmpty(dataRequestParam.AuthenticationLogin))
{
web.Credentials = new System.Net.NetworkCredential(dataRequestParam.AuthenticationLogin, dataRequestParam.AuthenticationPassword);
}
// Create the request payload from the provided stream
System.IO.Stream requestStream =
await System.Threading.Tasks.Task<System.IO.Stream>.Factory.FromAsync(web.BeginGetRequestStream, web.EndGetRequestStream, null);
await data.CopyToAsync(requestStream);
// Get a response from the server
System.Net.WebResponse response =
await System.Threading.Tasks.Task<System.Net.WebResponse>.Factory.FromAsync(web.BeginGetResponse, web.EndGetResponse, null);
// Possibly parse the response with an XmlReader (example only)
System.Xml.XmlReader reader = System.Xml.XmlReader.Create(response.GetResponseStream());
string responseText = reader.ReadInnerXml(); // TODO: Real work here
}
The one oddity here is using the Task factory to create a task from the begin and end methods from getting both the request stream and the response. This makes it much simpler to consume these methods as you get a Task back which can be awaited for its return object, which you can then manipulate directly.
I'm not sure what form your response from the server takes on success versus failure, so I've simply shown how to create an XML reader to parse XML from the resulting stream. You can do whatever parsing is necessary yourself on these lines, but this should at least give you a look at what your server is returning in response.

The final code I use.
WebRequest web = HttpWebRequest.CreateHttp(dataRequestParam.TargetUri);
web.ContentType = dataRequestParam.ContentType;
web.Method = "POST";
web.ContentLength = data.Length;
if (!string.IsNullOrEmpty(dataRequestParam.AuthentificationLogin))
{
web.Credentials = new NetworkCredential(dataRequestParam.AuthentificationLogin, dataRequestParam.AuthentificationPassword);
}
using (var requestStream = await Task<Stream>.Factory.FromAsync(web.BeginGetRequestStream, web.EndGetRequestStream, web))
{
await data.CopyToAsync(requestStream);
}
WebResponse responseObject = await Task<WebResponse>.Factory.FromAsync(web.BeginGetResponse, web.EndGetResponse, web);
var responseStream = responseObject.GetResponseStream();
var sr = new StreamReader(responseStream);
string received = await sr.ReadToEndAsync();
return received;
}

Related

How to upload image to server (using POST) which return json in Windows Phone 8.1 RT?

I am making an app which can upload image to a server (the server works well), and I use this method to upload my image to it, but when I get the respond from the result, it return a null string, can you explain for me what did I do wrong.
I followed this method: How to upload file to server with HTTP POST multipart/form-data
HttpClient httpClient = new HttpClient();
MultipartFormDataContent form = new MultipartFormDataContent();
form.Headers.ContentType = new MediaTypeHeaderValue("multipart/form-data");
byte[] bytes = await Converter.GetBytesAsync(storageFile);
form.Add(new ByteArrayContent(bytes, 0, bytes.Count()), "\"upload-file\"", "\"test.jpg\"");
HttpResponseMessage response = await httpClient.PostAsync("my-url", form);
response.EnsureSuccessStatusCode();
httpClient.Dispose();
string sd = response.Content.ReadAsStringAsync().Result;
Debug.WriteLine("res: " + sd); // this return a null string
The request return like this:
--a81d2efe-5f2e-4f84-83b9-261329bee20b
Content-Disposition: form-data; name="upload-file"; filename="test.jpg"; filename*=utf-8''%22test.jpg%22
����Ivg?�aEQ�.�����(��9%�=��>�C�~/�QG$�֨������(�`������QE��Z��
Can you help me please!
P/s: Here is my convert method
public static async Task<byte[]> GetBytesAsync(StorageFile file)
{
byte[] fileBytes = null;
if (file == null) return null;
using (var stream = await file.OpenReadAsync())
{
fileBytes = new byte[stream.Size];
using (var reader = new DataReader(stream))
{
await reader.LoadAsync((uint)stream.Size);
reader.ReadBytes(fileBytes);
}
}
return fileBytes;
}
This might help
private async Task<string> UploadImage(StorageFile file)
{
HttpClient client = new HttpClient();
MultipartFormDataContent form = new MultipartFormDataContent();
HttpContent content = new StringContent("fileToUpload");
form.Add(content, "fileToUpload");
var stream = await file.OpenStreamForReadAsync();
content = new StreamContent(stream);
content.Headers.ContentDisposition = new ContentDispositionHeaderValue("form-data")
{
Name = "fileToUpload",
FileName = file.Name
};
form.Add(content);
var response = await client.PostAsync("my-url", form);
return response.Content.ReadAsStringAsync().Result;
}
Use ByteArrayContent instead of StringContent. That Should work.
And if you are expecting a stream-response you should use ReadAsStreamAsync instaed of ReadAsStringAsync.

Submitting File and Json data to webapi from HttpClient

I want to send file and json data from HttpClient to web api server.
I cant seem to access the json in the server via the payload, only as a json var.
public class RegulationFilesController : BaseApiController
{
public void PostFile(RegulationFileDto dto)
{
//the dto is null here
}
}
here is the client:
using (var client = new HttpClient())
{
using (var content = new MultipartFormDataContent())
{
client.BaseAddress = new Uri(ConfigurationManager.AppSettings["ApiHost"]);
content.Add(new StreamContent(File.OpenRead(#"C:\\Chair.png")), "Chair", "Chair.png");
var parameters = new RegulationFileDto
{
ExternalAccountId = "1234",
};
JavaScriptSerializer serializer = new JavaScriptSerializer();
content.Add(new StringContent(serializer.Serialize(parameters), Encoding.UTF8, "application/json"));
var resTask = client.PostAsync("api/RegulationFiles", content); //?ApiKey=24Option_key
resTask.Wait();
resTask.ContinueWith(async responseTask =>
{
var res = await responseTask.Result.Content.ReadAsStringAsync();
}
);
}
}
this example will work:HttpClient Multipart Form Post in C#
but only via the form-data and not payload.
Can you please suggest how to access the file and the submitted json And the file at the same request?
Thanks
I have tried many different ways to submit both file data and metadata and this is the best approach I have found:
Don't use MultipartFormDataContent, use only StreamContent for the file data. This way you can stream the file upload so you don't take up too much RAM on the server. MultipartFormDataContent requires you to load the entire request into memory and then save the files to a local storage somewhere. By streaming, you also have the benefit of copying the stream into other locations such as an Azure storage container.
This solves the issue of the binary data, and now for the metadata. For this, use a custom header and serialize your JSON into that. Your controller can read the custom header and deserialize it as your metadata dto. There is a size limit to headers, see here (8-16KB), which is a large amount of data. If you need more space, you could do two separate requests, one to POST the minimum need, and then a PATCH to update any properties that needed more than a header could fit.
Sample code:
public class RegulationFilesController : BaseApiController
{
public async Task<IHttpActionResult> Post()
{
var isMultipart = this.Request.Content.IsMimeMultipartContent();
if (isMultipart)
{
return this.BadRequest("Only binary uploads are accepted.");
}
var headerDto = this.GetJsonDataHeader<RegulationFileDto>();
if(headerDto == null)
{
return this.BadRequest("Missing X-JsonData header.");
}
using (var stream = await this.Request.Content.ReadAsStreamAsync())
{
if (stream == null || stream.Length == 0)
{
return this.BadRequest("Invalid binary data.");
}
//save stream to disk or copy to another stream
var model = new RegulationFile(headerDto);
//save your model to the database
var dto = new RegulationFileDto(model);
var uri = new Uri("NEW URI HERE");
return this.Created(uri, dto);
}
}
private T GetJsonDataHeader<T>()
{
IEnumerable<string> headerCollection;
if (!this.Request.Headers.TryGetValues("X-JsonData", out headerCollection))
{
return default(T);
}
var headerItems = headerCollection.ToList();
if (headerItems.Count() != 1)
{
return default(T);
}
var meta = headerItems.FirstOrDefault();
return !string.IsNullOrWhiteSpace(meta) ? JsonConvert.DeserializeObject<T>(meta) : default(T);
}
}

My Windows Phone app Get empty response (404 Not Found) Scond time, work's great first time;And always work fine if without SSL

I am building my first windowsPhone 8.1 application ,the role of my application is to create connection with server to get information from it, so I am writing the code to do this process by sending json-rpc request to server to get some information ,I am successful to get it in first time but when I send the second request I am receiving an empty response with 404 error (page not found).
But when I call the service without https (http only) it works fine regardless how many time I call it !
public async Task<string> GetDataFromServer(string urlToCall, string JSONData,string RR)
{
string UserName = “XXXXXXX”
string Password = "XXX";
using ( var handler = new HttpClientHandler())
{
handler.Credentials = new NetworkCredential(UserName, Password);
HttpClient client = new HttpClient(handler);
HttpResponseMessage response = null;
try
{
response = await client.PostAsync(urlToCall, new StringContent(JSONData.ToString(), Encoding.UTF8, " application/json"));
string res = response.Content.ReadAsStringAsync().Result;
Windows.UI.Popups.MessageDialog g = new Windows.UI.Popups.MessageDialog(res);
await g.ShowAsync();
return res;
}
catch (Exception ex)
{
Windows.UI.Popups.MessageDialog g = new Windows.UI.Popups.MessageDialog("Error is : " + ex.Message);
g.ShowAsync();
return "Error";
}
finally
{
response.Dispose();
client.CancelPendingRequests();
client.Dispose();
handler.Dispose();
}
}
}
Again, when call the URL of service (start with https) on first time I got response with seeked data, but second time I receive an empty response with 404 error (page not found) !!
Any help please
Please try to use this solution.
public async Task<string> SendJSONData3(string urlToCall, string JSONData)
{
string UserName = "XXXXXXXXX";
string Password = "XXXXXXXXX";
var httpWebRequest = (HttpWebRequest)WebRequest.Create(urlToCall);
httpWebRequest.Credentials = new NetworkCredential(UserName, Password);
httpWebRequest.ContentType = "text/json";
httpWebRequest.Method = "POST";
using (var streamWriter = new StreamWriter(await httpWebRequest.GetRequestStreamAsync()))
{
string json = JSONData;
streamWriter.Write(json);
streamWriter.Flush();
}
var httpResponse = (HttpWebResponse)await httpWebRequest.GetResponseAsync();
using (var streamReader = new StreamReader(httpResponse.GetResponseStream()))
{
var result = streamReader.ReadToEnd();
return result;
}
}
A couple of ideas:
Do not use the .Result property. Just use await instead to avoid deadlocks.
Remove the additional space in front of the media type parameter " application/json"
Enable logging on the webserver and see if the second request arrives on the server.
Get a network trace, for example with Wireshark or Fiddler.
Try puting WebRequest.RegisterPrefix("https://", WebRequestCreator.ClientHttp); in your initialization code, as proposed in this answer.

http web server return zip file in a windows phone 8

hello i'm write a http web server in my app.
I used this code
http://developer.nokia.com/community/wiki/A_simplistic_HTTP_Server_on_Windows_Phone
this procedure works but not have a extentions of file in http response
return a file name without extention (.zip)
private async Task<StringBuilder> HandleRequest(StreamSocket socket)
{
//Initialize IO classes
DataReader reader = new DataReader(socket.InputStream);
reader.InputStreamOptions = InputStreamOptions.Partial;
DataWriter writer = new DataWriter(socket.OutputStream);
writer.UnicodeEncoding = Windows.Storage.Streams.UnicodeEncoding.Utf8;
//handle actual HTTP request
String request = await StreamReadLine(reader);
string[] tokens = request.Split(' ');
if (tokens.Length != 3)
{
throw new Exception("invalid http request line");
}
string httpMethod = tokens[0].ToUpper();
string httpUrl = tokens[1];
//read HTTP headers - contents ignored in this sample
while (!String.IsNullOrEmpty(await StreamReadLine(reader))) ;
try
{
if (httpUrl == "DOWNLOADZIP")
{
using (IsolatedStorageFile storage = IsolatedStorageFile.GetUserStoreForApplication())
{
String content = null;
Stream stream;
byte[] data;
IsolatedStorageFileStream sri = storage.OpenFile("CompressedFiles.zip", FileMode.Open, FileAccess.Read);
if (null != sri)
{
stream = sri;
data = new byte[stream.Length];
stream.Read(data, 0, data.Length);
writer.writebytes(data);
}
}
}
}
catch (Exception ex)//any exception leads to an Internal server error
{
writer.WriteString("HTTP/1.0 500 Internal server error\r\n");
writer.WriteString("Connection: close\r\n");
writer.WriteString("\r\n");
writer.WriteString(ex.Message);
}
}
await writer.StoreAsync();//write data actually to the network interface
socket.Dispose();
return null;
}
this is a solutions
ret.AppendLine("HTTP/1.0 200 OK");
ret.AppendLine("Content-Type: text/html");
ret.AppendLine("Connection: close");
ret.AppendLine("");
ret.AppendLine("Content-Disposition: attachment; filename=myfile.zip");

Send Cookies with HTTPWebRequestion through WP8 App

I have to send the cookies to server for every subsequent HTTPWebRequest. My code goes below.
class APIManager
{
CookieContainer cookieJar = new CookieContainer();
CookieCollection responseCookies = new CookieCollection();
private async Task<string> httpRequest(HttpWebRequest request)
{
string received;
using (var response = (HttpWebResponse)(await Task<WebResponse>.Factory
.FromAsync(request.BeginGetResponse, request.EndGetResponse, null)))
{
using (var responseStream = response.GetResponseStream())
{
using (var sr = new StreamReader(responseStream))
{
cookieJar = request.CookieContainer;
responseCookies = response.Cookies;
received = await sr.ReadToEndAsync();
}
}
}
return received;
}
public async Task<string> Get(string path)
{
var request = WebRequest.Create(new Uri(path)) as HttpWebRequest;
request.CookieContainer = cookieJar;
return await httpRequest(request);
}
public async Task<string> Post(string path, string postdata)
{
var request = WebRequest.Create(new Uri(path)) as HttpWebRequest;
request.Method = "POST";
request.CookieContainer = cookieJar;
byte[] data = Encoding.UTF8.GetBytes(postdata);
using (var requestStream = await Task<Stream>.Factory.FromAsync(request.BeginGetRequestStream, request.EndGetRequestStream, null))
{
await requestStream.WriteAsync(data, 0, data.Length);
}
return await httpRequest(request);
}
}
Every time i ask for the question people say that i have to set the cookie container with request by following code line.
request.CookieContainer = cookieJar;
and i used it but still server returns the 'token does not match' error. Do i need to talk to the vendor for it?
Following image shows my problem and requirement.
I haven't seen you do something with the cookieJar !
//Create the cookie container and add a cookie.
request.CookieContainer = new CookieContainer();
// This example shows manually adding a cookie, but you would most
// likely read the cookies from isolated storage.
request.CookieContainer.Add(new Uri("http://api.search.live.net"),
new Cookie("id", "1234"));
cookieJar in your APIManager is a member, everytime your instance APIManager, the cookieJar is a new instance. you need to make sure cookieJar contains what the website needs.
you can have a look at this How to: Get and Set Cookies