I'm currently trying to upload an image through my webservice. I have this piece of code:
public async Task<Webservice> editProfile(List<KeyValuePair<string, string>> values, byte[] image)
{
String strUrl = String.Format("http://********/nl/webservice/abc123/members/update");
var HttpClientUpload = new HttpClient();
HttpMultipartFormDataContent requestUploadContent = new HttpMultipartFormDataContent();
Stream streamImage = new System.IO.MemoryStream(image);
HttpStreamContent streamContent = new HttpStreamContent(streamImage.AsInputStream());
requestUploadContent.Add(streamContent, "myFile", "image.jpg");
foreach (var keyValuePair in values)
{
requestUploadContent.Add(new HttpStringContent(keyValuePair.Value), keyValuePair.Key);
}
HttpResponseMessage responseLogin = await HttpClientUpload.PostAsync(new Uri(strUrl), requestUploadContent);
responseLogin.EnsureSuccessStatusCode();
if (responseLogin.StatusCode == Windows.Web.Http.HttpStatusCode.Ok && responseLogin.Content != null)
{
var data = new Webservice { Status = responseLogin.StatusCode };
data.Data = await responseLogin.Content.ReadAsStringAsync();
Debug.WriteLine(data.Data);
return data;
}
return new Webservice { Status = new Windows.Web.Http.HttpStatusCode() };
}
But I always get the following exception: 'System.ExecutionEngineException' on the following line:
HttpStreamContent streamContent = new HttpStreamContent(streamImage.AsInputStream());
Can anyone help please, struggling with this problem for days now....
Thanks in advance!
EDIT
I've changed my function:
public async Task<Webservice> editProfile(List<KeyValuePair<string, string>> values, byte[] image)
{
try
{
using (IsolatedStorageFile iso = IsolatedStorageFile.GetUserStoreForApplication())
{
using (IsolatedStorageFileStream stream = iso.OpenFile("image.jpg", FileMode.Open, FileAccess.Read))
{
String strUrl = String.Format("http://membr.sanmax.be/nl/webservice/abc123/members/update");
HttpMultipartFormDataContent requestUploadContent = new HttpMultipartFormDataContent();
//Stream streamImage = new System.IO.MemoryStream(stream);
HttpStreamContent streamContent = new HttpStreamContent(stream.AsInputStream());
requestUploadContent.Add(streamContent, "picture", "photo.jpg");
foreach (var keyValuePair in values)
{
requestUploadContent.Add(new HttpStringContent(keyValuePair.Value), keyValuePair.Key);
}
HttpResponseMessage responseLogin = await httpClient.PostAsync(new Uri(strUrl), requestUploadContent);
responseLogin.EnsureSuccessStatusCode();
if (responseLogin.StatusCode == Windows.Web.Http.HttpStatusCode.Ok && responseLogin.Content != null)
{
var data = new Webservice { Status = responseLogin.StatusCode };
data.Data = await responseLogin.Content.ReadAsStringAsync();
Debug.WriteLine(data.Data);
return data;
}
}
}
}
catch (Exception e)
{
Debug.WriteLine(e);
}
return new Webservice { Status = new Windows.Web.Http.HttpStatusCode() };
}
But now it stops in the catch part with this exception:
WinRT information: Response status code does not indicate success: 413 (Request Entity Too Large).
System.Exception: Request entity too large (413).
Related
I have this working Xunit code.
[Fact]
public async Task When_DocumentTypeInvalidFileType_Then_ShouldFail()
{
using (var client = new HttpClient())
{
var filePath = #"D:\Files\test.pdf";
using (var stream = File.OpenRead(filePath))
{
using (var form = new MultipartFormDataContent())
{
form.Add(new StringContent(Guid.NewGuid().ToString()), "Id");
var file = new StreamContent(stream);
file.Headers.ContentType = new MediaTypeHeaderValue("application/pdf");
form.Add(file, "File", Path.GetFileName(filePath));
// Act
var response = await client.PostAsync("/ABC/Document", form);
var responseString = await response.Content.ReadAsStringAsync();
_output.WriteLine("response: {0}", responseString);
HttpStatusCode statusCode = response.StatusCode;
Assert.Equal(HttpStatusCode.BadRequest, statusCode);
var result = JsonConvert.DeserializeObject<ResponseMessage>(responseString);
Assert.Equal("Invalid file type.", result.file[0]);
}
}
}
But the above only test for one scenario. How do I use XUnit InlineData so that I can insert multiple test data for MultipartFormDataContent?
[Theory]
[InlineData(MediaTypeNames.Application.Pdf, #"D:\Files\test.pdf")]
[InlineData(MediaTypeNames.Application.Xml, #"D:\Files\test.xml")]
// else files what you need
public async Task When_DocumentTypeInvalidFileType_Then_ShouldFail(string contentType, string filePath)
{
using (var client = new HttpClient())
{
using (var stream = File.OpenRead(filePath))
{
using (var form = new MultipartFormDataContent())
{
form.Add(new StringContent(Guid.NewGuid().ToString()), "Id");
var file = new StreamContent(stream);
file.Headers.ContentType = new MediaTypeHeaderValue(contentType);
form.Add(file, "File", Path.GetFileName(filePath));
// Act
var response = await client.PostAsync("/ABC/Document", form);
var responseString = await response.Content.ReadAsStringAsync();
_output.WriteLine("response: {0}", responseString);
HttpStatusCode statusCode = response.StatusCode;
Assert.Equal(HttpStatusCode.BadRequest, statusCode);
var result = JsonConvert.DeserializeObject<ResponseMessage>(responseString);
Assert.Equal("Invalid file type.", result.file[0]);
}
}
}
}
OR
[Theory]
[MemberData(nameof(TestGenerator.GetTestData), MemberType = typeof(TestGenerator))]
public async Task When_DocumentTypeInvalidFileType_Then_ShouldFail(string contentType, string filePath)
{
using (var client = new HttpClient())
{
using (var stream = File.OpenRead(filePath))
{
using (var form = new MultipartFormDataContent())
{
form.Add(new StringContent(Guid.NewGuid().ToString()), "Id");
var file = new StreamContent(stream);
file.Headers.ContentType = new MediaTypeHeaderValue(contentType);
form.Add(file, "File", Path.GetFileName(filePath));
// Act
var response = await client.PostAsync("/ABC/Document", form);
var responseString = await response.Content.ReadAsStringAsync();
_output.WriteLine("response: {0}", responseString);
HttpStatusCode statusCode = response.StatusCode;
Assert.Equal(HttpStatusCode.BadRequest, statusCode);
var result = JsonConvert.DeserializeObject<ResponseMessage>(responseString);
Assert.Equal("Invalid file type.", result.file[0]);
}
}
}
}
class TestGenerator
{
public static IEnumerable<object[]> GetTestData() => new List<object[]>
{
new object[] { MediaTypeNames.Application.Pdf, #"D:\Files\test.pdf" },
new object[] { MediaTypeNames.Application.Xml, #"D:\Files\test.xml" }
};
}
My app will retrieve a list of all images from a specific folder and attempt to upload them to a server via an API endpoint
Due to the above requirements, an image picker is not suited
Below is the method in the shared code that is passed a list of UIImages (I am trying to get it to work with just ios for now but the same scenario will eventually be applied to Android also)
The below does not work, as when I view the image on the server(AWS), it is in code format. It also says the content type is application/json on the server which I don't understand as I'm setting it to image/png
private async Task UploadImages(List<UIImage> images)
{
HttpClient client = new HttpClient();
var contentType = new MediaTypeWithQualityHeaderValue("image/png");
client.DefaultRequestHeaders.Accept.Add(contentType);
client.DefaultRequestHeaders.Add("Id-Token", Application.Current.Properties["id_token"].ToString());
foreach (var image in images)
{
try
{
string baseUrl = $"https://********/dev/ferret-test/media/team1/user1/device1/test1.png";
client.BaseAddress = new Uri(baseUrl);
//UploadModel uploadModel = new UploadModel
//{
// image_file = image.AsPNG()
//};
byte[] bArray = null;
Stream pst = image.AsPNG().AsStream();
using (MemoryStream ms = new MemoryStream())
{
ms.Position = 0;
pst.CopyTo(ms);
bArray = ms.ToArray();
}
//string stringData = JsonConvert.SerializeObject(bArray);
//var contentData = new StringContent(stringData,
//System.Text.Encoding.UTF8, "image/png");
//Byte[] myByteArray = new Byte[imageData.Length];
//System.Runtime.InteropServices.Marshal.Copy(imageData.Bytes, myByteArray, 0, Convert.ToInt32(imageData.Length));
var postRequest = new HttpRequestMessage(HttpMethod.Put, baseUrl)
{
Content = new ByteArrayContent(bArray)
};
var response = await client.SendAsync(postRequest);
response.EnsureSuccessStatusCode();
string stringJWT = response.Content.ReadAsStringAsync().Result;
}
catch (Exception ex)
{
Console.WriteLine(ex);
}
}
}
I archived uploading multiple files to the server by using the following snippet, you can give it a try...
foreach (SQLiteAccess.Tables.Image image in images.OrderByDescending(x => x.Id)) //Here is the collection of all the file at once (Documents + Images)
{
int documentId = UploadImageToServerAndroid(image).Result;
// My other code implementation
.
.
.
}
private async Task<int> UploadImageToServerAndroid(SQLiteAccess.Tables.Image image)
{
int documentId = 0;
if (!Admins.ConnectedToNetwork()) return documentId;
MyFile = FileSystem.Current.GetFileFromPathAsync(image.Path).Result;
if (MyFile == null) return documentId;
Stream stream = MyFile.OpenAsync(FileAccess.Read).Result;
byte[] byteArray;
byteArray = new byte[stream.Length];
stream.Read(byteArray, 0, (int)stream.Length);
if( !image.IsDocument )
{
try
{
byteArray = DependencyService.Get<IImageUtilities>().CompressImage(byteArray); //Its custom code to compress the Image.
}
catch (Exception ex)
{
UoW.Logs.LogMessage(new LogDTO { Message = ex.Message, Ex = ex });
}
}
string url = "Your URL";
using (HttpClient client = new HttpClient(new RetryMessageHandler(new HttpClientHandler())))
{
try
{
client.DefaultRequestHeaders.Add(Properties.Resources.Authorization, Sessions.BearerToken);
client.DefaultRequestHeaders.Add("DocumentSummary", image.Comment);
client.DefaultRequestHeaders.Add("DocumentName", Path.GetFileName(image.Path));
MultipartFormDataContent multiPartContent = new MultipartFormDataContent();
ByteArrayContent byteContent = new ByteArrayContent(byteArray);
byteContent.Headers.ContentType = MediaTypeHeaderValue.Parse("image/jpeg");
multiPartContent.Add(byteContent, "image", Path.GetFileName(image.Path));
HttpResponseMessage response = await client.PostAsync(url, multiPartContent);
if (response.IsSuccessStatusCode && response.Content != null)
{
string jsonString = response.Content.ReadAsStringAsync().Result;
DocumentDTO result = JsonConvert.DeserializeObject<DocumentDTO>(jsonString);
documentId = result.DocumentId;
}
}
catch(Exception ex)
{
UoW.Logs.LogMessage( new LogDTO { Message = ex.Message, Ex = ex });
return documentId;
}
}
return documentId;
}
If documentid is 0(if something went wrong, for any of reason), it's marked as not uploaded & will try to upload it again when the internet is available.
If you need some more help, you can ask...:)
You could try to use MultipartFormDataContent and set content type to application/octet-stream.
You could refer the two links one and two.
I'm working on UWP apps, In that i need to upload the image for that i'm calling the web service to post the details. I'm using the below code to serialize the image.
byte[] fileBytes = 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);
}
}
docs.Document = fileBytes;
docs.DocumentName = file.Name;
docs.DocumentTypeOtherDescription = "ProfilePicture";
var docsAsJson = JsonConvert.SerializeObject(docs);
StringContent stringContent = new StringContent(docsAsJson, System.Text.Encoding.UTF8);
ByteArrayContent byteContent = new ByteArrayContent(fileBytes);
MultipartFormDataContent httpContent = new MultipartFormDataContent();
httpContent.Add(byteContent, file.Name);
httpContent.Add(stringContent);
using (var httpClient = new HttpClient())
{
var request = new HttpRequestMessage {Method = HttpMethod.Post};
request.Headers.Add("authorization", App.TokenType + " " + App.AccessToken);
request.RequestUri = new Uri(App.BaseUrl + "api/User/UploadUserDocument");
request.Content = httpContent;
request.Content.Headers.Add(#"Content-Length", fileBytes.Length.ToString());
var response = httpClient.SendAsync(request).Result;
var data = response.Content.ReadAsStringAsync();
if (response.IsSuccessStatusCode)
{
}
}
This is my side to serialize the image and in service side they deserialize the image and saved in database. But i'm getting StatusCode: 500, ReasonPhrase: 'Internal Server Error' this error, Any one please help me to solve this issue.
Here is my Service Code:
public IHttpActionResult UpdateUserWithProfilePic(FormData userviewmodel)
{
var error = string.Empty;
var userJson = new StringBuilder();
foreach (var items in userviewmodel.Fields)
{
if (items.Name == "}")
{
if (!userJson.ToString().EndsWith(",")) continue;
userJson.Remove(userJson.Length - 1, 1);
userJson.Append("}");
}
else
userJson.Append((items.Name.Replace("%22", "\"")) + ":" + items.Value);
}
var userView = JsonConvert.DeserializeObject<UserViewModel>(userJson.ToString());
var result = UpdateUser(userView, error);
if (result.ResultType != ResultType.Success) return daHttpActionResult(result.Result, result);
if (userviewmodel.Files != null && userviewmodel.Files.Count > 0)
{
userView.ProfileDocument = new UserDocument
{
DocumentName = userviewmodel.Files[0].Name,
Document = userviewmodel.Files[0].Value.Buffer,
UserID = UserId,
DocumentType = DocumentTypeEnum.ProfilePicture,
DocumentTypeOtherDescription = userviewmodel.Files[0].Value.MediaType,
};
}
return AdHttpActionResult(result.Result, result);
}
Thanks & Regards,
Cristina
I have a problem in the GCM Section. we have thousands of devices registered in our database, but some of them are not receiving messages. The newly registered devices are not receiving messages. Below is the code I am using to send the GCM. Can anybody help to find out the issue?
//++ Send GCM
private string sendGCM(string apiKey, string message, IEnumerable<string> registrationIds)
{
if (apiKey == null)
{
throw new ArgumentNullException("apiKey");
}
if (message == null)
{
throw new ArgumentNullException("message");
}
if (registrationIds == null)
{
throw new ArgumentNullException("registrationIds");
}
HttpWebRequest request = (HttpWebRequest)HttpWebRequest.Create("https://android.googleapis.com/gcm/send");
request.Method = "POST";
request.ContentType = "application/json";
request.Headers["Authorization"] = "key=" + apiKey;
JObject jo = new JObject();
JArray ids = new JArray();
foreach (var regId in registrationIds)
{
ids.Add(regId);
}
jo["registration_ids"] = ids;
JObject data = new JObject();
//data["message"] = edtMessage.Text;
data["message"] = message;
jo["data"] = data;
string query = jo.ToString();
byte[] buff = Encoding.UTF8.GetBytes(query);
Stream stream1 = request.GetRequestStream();
MemoryStream mstream1 = new MemoryStream(buff);
mstream1.CopyTo(stream1);
stream1.Close();
Stream stream2 = request.GetResponse().GetResponseStream();
MemoryStream mstream2 = new MemoryStream();
stream2.CopyTo(mstream2);
String responseString = Encoding.UTF8.GetString(mstream2.GetBuffer());
return responseString;
}
objGCM = new clsGCM();
Int64 intGCMID = Convert.ToInt64(e.CommandArgument);
objGCM.execGetInfo(intGCMID);
string strMessage = objGCM.InfoMessage;
if (strMessage != null && strMessage != "")
{
//++ Send to the devices
objDeviceInfo = new clsDeviceInfo();
DataTable dtDeviceInfo = objDeviceInfo.Load();
for (int i = 0; i < dtDeviceInfo.Rows.Count; i = i + 1000)
{
IEnumerable<string> strDeviceToken = from g in dtDeviceInfo.AsEnumerable().Where(w => w.Field<Int32>("DeviceID") > i).Take(1000)
select g.Field<string>("DeviceToken");
sendGCM("Myapikeyhere", strMessage, strDeviceToken);
}
//++ Mark as sent
objGCM.execUpdateStatus(intGCMID);
}
Response.Redirect("~/Forms/frmGCM.aspx", false);
I was using the following code to send fromData contains 2 values (File and String) to a WebAPI using javascript.
var formData = new FormData();
formData.append('name', 'previewImg');
formData.append('upload', $('input[type=file]')[0].files[0]);
$.ajax({
url: 'WebAPI url',
data: formData,
contentType: false,
processData: false,
// ... Other options like success and etc
})
I want to do the same thing using C# Windows Application, I need to write a Method accepts 2 paramters (FilePath and String) then send the file and the string to WebAPI.
I tried the following code but it returns an error from the service( I am trying to contact with koemei upload service) , although it works fine when I call it from Js :
void SendData(string filepath,string name){
var url = "URL";
HttpContent fileContent = new ByteArrayContent(System.IO.File.ReadAllBytes(filepath));
using (var client = new HttpClient())
{
using (var formData = new MultipartFormDataContent())
{
formData.Add(fileContent, "upload");
formData.Add(new StringContent(name), "name");
//call service
var response = client.PostAsync(url, formData).Result;
if (!response.IsSuccessStatusCode)
{
throw new Exception();
}
else
{
if (response.Content.GetType() != typeof(System.Net.Http.StreamContent))
throw new Exception();
var stream = response.Content.ReadAsStreamAsync();
var content = stream.Result;
var path = #"name.txt";
using (var fileStream = System.IO.File.Create(path))
{
content.CopyTo(fileStream);
}
}
}
}
}
Here is a sample
private List<ByteArrayContent> GetFileByteArrayContent(HashSet<string> files)
{
List<ByteArrayContent> list = new List<ByteArrayContent>();
foreach (var file in files)
{
var fileContent = new ByteArrayContent(File.ReadAllBytes(file));
fileContent.Headers.ContentDisposition = new ContentDispositionHeaderValue("attachment")
{
FileName = Path.GetFileName(file)
};
list.Add(fileContent);
}
return list;
}
private List<ByteArrayContent> GetFormDataByteArrayContent(NameValueCollection collection)
{
List<ByteArrayContent> list = new List<ByteArrayContent>();
foreach (var key in collection.AllKeys)
{
var dataContent = new ByteArrayContent(Encoding.UTF8.GetBytes(collection[key]));
dataContent.Headers.ContentDisposition = new ContentDispositionHeaderValue("attachment")
{
Name = key
};
list.Add(dataContent);
}
return list;
}
And here is how to post the data and files
using (HttpClient client = new HttpClient())
{
client.DefaultRequestHeaders.Accept.Add(new MediaTypeWithQualityHeaderValue("text/xml"));//set how to get data
using (var content = new MultipartFormDataContent())//post by content type multipart/form-data
{
NameValueCollection dataCollection;//the datas you want to post
HashSet<string> filePaths;//the files you want to post
var formDatas = this.GetFormDataByteArrayContent(dataCollection);//get collection
var files = this.GetFileByteArrayContent(filePaths);//get collection
Action<List<ByteArrayContent>> act = (dataContents) =>
{//declare an action
foreach (var byteArrayContent in dataContents)
{
content.Add(byteArrayContent);
}
};
act(formDatas);//process act
act(files);//process act
try
{
var result = client.PostAsync(this.txtUrl.Text, content).Result;//post your request
}
catch (Exception ex)
{
//error
}
}
}