PostAsync HttpRequestException: Cannot decode raw data - xamarin

I'm trying to make a function to upload a file (pdf, docx, xls) to an http API. I've tried with Postman and it worked fine. But when I try from the application, is not working.
private async Task UploadFile()
{
String fileguid = this.noteModel.Fileguid.ToString();
try
{
var file = await CrossFilePicker.Current.PickFile();
if (file == null)
return;
string fileName = file.FileName;
string url = App.apiServer + "web/Token13/" + App.token + "/" + fileguid;
var content = new MultipartFormDataContent();
content.Headers.ContentType.MediaType = "multipart/form-data";
content.Add(new StreamContent(file.GetStream()), "file", fileName);
var httpClient = new HttpClient();
var response = await httpClient.PostAsync(url, content);
String status = response.StatusCode.ToString();
}
catch (Exception ex)
{
System.Console.WriteLine("Exception choosing file: " + ex.ToString());
}
}
I have the following error at line 'var response = await httpClient.PostAsync(url, content);':
2021-02-12 20:03:58.805 Project.iOS[2202:520692] Exception choosing file: System.Net.Http.HttpRequestException: cannot decode raw data --->
Foundation.NSErrorException: Error Domain=NSURLErrorDomain Code=-1015 "cannot decode raw data"
UserInfo={NSLocalizedDescription=cannot decode raw data,
NSErrorFailingURLStringKey=http://ip/appservertest/web/Token13/id,
NSErrorFailingURLKey=http://ip/appservertest/web/Token13/id,
_NSURLErrorRelatedURLSessionTaskErrorKey=(
"LocalDataTask <FD8D1034-CF42-41C8-A214-BE4D87D1D15D>.<1>"
), _NSURLErrorFailingURLSessionTaskErrorKey=LocalDataTask <FD8D1034-CF42-41C8-A214-BE4D87D1D15D>.<1>, NSUnderlyingError=0x282880000 {Error Domain=kCFErrorDomainCFNetwork Code=-1015 "(null)" UserInfo={NSErrorPeerAddressKey=<CFData 0x2805e64e0 [0x1f6084660]>{length = 16, capacity = 16, bytes = 0x100200505991f6e00
000000000000000}}}}
--- End of inner exception stack trace ---
at System.Net.Http.NSUrlSessionHandler.SendAsync (System.Net.Http.HttpRequestMessage request, System.Threading.CancellationToken cancellationToken) [0x001d4] in /Library/Frameworks/Xamarin.iOS.framework/Versions/14.2.0.12/src/Xamarin.iOS/Foundation/NSUrlSessionHandler.cs:527
at System.Net.Http.HttpClient.FinishSendAsyncBuffered (System.Threading.Tasks.Task`1[TResult] sendTask, System.Net.Http.HttpRequestMessage request, System.Threading.CancellationTokenSource cts, System.Boolean disposeCts) [0x0017e] in /Library/Frameworks/Xamarin.iOS.framework/Versions/Current/src/Xamarin.iOS/external/corefx/src/System.Net.Http/src/System/Net/Http/HttpClient.cs:506
at Project.Views.NotesEdit.UploadFile () [0x0018f] in C:\Repository\Project\Project\Views\NotesEdit.xaml.cs:268
Could you please give me a hint, why is not working?
Thank you in advance!

It seems like you have not completed your header with the MediaTypeHeaderValue. This works for me:
var content = new StreamContent(stream);
content.Headers.ContentDisposition = new ContentDispositionHeaderValue("form-data")
{
FileName = imageName,
Name = imageName
};
content.Headers.ContentType = new MediaTypeHeaderValue("image/jpeg");
var multipartContent = new MultipartFormDataContent();
multipartContent.Add(content);
var result = await client.PostAsync(url, multipartContent.Add);

Related

Unexpected end of MIME multipart stream in web api

Unexpected end of MIME multipart stream. MIME multipart message is not complete error comming when override Stream::GetStream method of MultipartFormDataStreamProvider. I am getting stream in GetStream method and encrypt it and returning it than it gives me this error (Unexpected end of MIME multipart stream). I have done all previous solutions, but doesn't work.
Here is my code:
var Savedfiledata = await Request.Content.ReadAsMultipartAsync(provider).ContinueWith(
(Task<CustomMultipartFormData> readTask) =>
{
CustomMultipartFormData CMF = readTask.Result;// Here Error is comming
// Create response containing information about the stored files.
return CMF.FileData.Select(fileData =>
{
FileInfo info = new FileInfo(fileData.LocalFileName);
ContentDispositionHeaderValue disposition = fileData.Headers.ContentDisposition;
string filename = (disposition != null && disposition.FileName != null) ? disposition.FileName : string.Empty;
CS_FileUpload FileObj = new CS_FileUpload()
{
FileName = filename.Replace("\"", ""),
FileUniqueName = info.Name,
FileSize = (info.Length / 1024),
FilePath = info.DirectoryName,
FileType = info.Extension,
InsertDate = info.LastWriteTimeUtc,
};
DAObj.CS_FileUpload.Add(FileObj);
return FileObj;
}).ToList();
});
public override Stream GetStream(HttpContent filedata, HttpContentHeaders headers)
{
Stream reqStream = filedata.ReadAsStreamAsync().Result;
using (MemoryStream stream = new MemoryStream())
{
reqStream.CopyTo(stream);
MemoryStream getEncBytes = Encrypt(stream, GenerateKey());
return getEncBytes;
}
}

How do you create a client using websocket-sharp?

I'm using ClientWebSocket to subscribe to a REST service but want to be able to use websocket-sharp instead.
static async void MonitorISY(string IPAddress, string userName, string password, IMessageWriter writer)
{
ClientWebSocket client = new ClientWebSocket();
client.Options.AddSubProtocol("ISYSUB");
client.Options.SetRequestHeader("Origin", "com.universal-devices.websockets.isy");
var auth = Convert.ToBase64String(Encoding.Default.GetBytes(userName + ":" + password));
client.Options.SetRequestHeader("Authorization", "Basic " + auth);
await client.ConnectAsync(new Uri("ws://" + IPAddress + "/rest/subscribe"), CancellationToken.None);
var receiveBufferSize = 512;
byte[] buffer = new byte[receiveBufferSize];
writer.Clear();
while (true)
{
var result = await client.ReceiveAsync(new ArraySegment<byte>(buffer), CancellationToken.None);
var resultJson = (new UTF8Encoding()).GetString(buffer);
writer.WriteLn(resultJson);
writer.WriteLn();
}
}
Here is my websocket-sharp attempt. When ws.Connect(); is called, I'm getting a Not a WebSocket handshake response error message. In the working code, I have to setup the Origin, SubProtocol and the RequestHeader. I think I'm doing that correctly for the websocket-sharp code, with the exception of the Request Header. I've been unable to find a working example that specifies authentication.
using (var nf = new Notifier())
using (var ws = new WebSocket("ws://172.16.0.40/rest/subscribe", "ISYSUB"))
{
ws.Log.Level = LogLevel.Trace;
var username = "user";
var password = "pass";
ws.Origin = "com.universal-devices.websockets.isy";
ws.SetCredentials(username, password, true);
ws.OnOpen += (sender, e) => ws.Send("Hi, there!");
ws.OnMessage += (sender, e) =>
nf.Notify(
new NotificationMessage
{
Summary = "WebSocket Message",
Body = !e.IsPing ? e.Data : "Received a ping.",
Icon = "notification-message-im"
}
);
ws.OnError += (sender, e) =>
nf.Notify(
new NotificationMessage
{
Summary = "WebSocket Error",
Body = e.Message,
Icon = "notification-message-im"
}
);
ws.OnClose += (sender, e) =>
nf.Notify(
new NotificationMessage
{
Summary = String.Format("WebSocket Close ({0})", e.Code),
Body = e.Reason,
Icon = "notification-message-im"
}
);
ws.Connect();
I think the best example is https://github.com/sta/websocket-sharp/tree/master/Example3
Although I did have to make a few tiny adjustments to get it to compile in Visual Studio 2017 Enterprise.
The index.html is based on http://www.websocket.org/echo.html

Upload a file to specific folderid using REST Api

I've searched all documents in google drive api and I can't able to find how to upload a file to folderid using REST APi. Can anyone please help me on this?
public void UploadFiletoDrive()
{
var gmodel = GetAccessToken();
WebRequest request = WebRequest.Create("https://www.googleapis.com/upload/drive/v3/files/?uploadType=media");
request.Method = "POST";
request.Headers["Authorization"] = "Bearer " + gmodel.access_token;
request.ContentType = "image/jpeg";
Stream dataStream = request.GetRequestStream();
FileStream filestream = new FileStream(#"C:\Users\Developer\Downloads\unnamed (2).jpg", FileMode.Open, FileAccess.Read);
byte[] buffer = new byte[4096];
int bytesRead = 0;
while ((bytesRead = filestream.Read(buffer, 0, buffer.Length)) != 0)
{
dataStream.Write(buffer, 0, bytesRead);
}
filestream.Close();
dataStream.Close();
WebResponse response = request.GetResponse();
StreamReader reader = new StreamReader(response.GetResponseStream());
string responseFromServer = reader.ReadToEnd();
reader.Close();
response.Close();
}
It seems you've missed the Work with Folders docs.
Inserting a file in a folder using Java:
String folderId = "0BwwA4oUTeiV1TGRPeTVjaWRDY1E";
File fileMetadata = new File();
fileMetadata.setName("photo.jpg");
fileMetadata.setParents(Collections.singletonList(folderId));
java.io.File filePath = new java.io.File("files/photo.jpg");
FileContent mediaContent = new FileContent("image/jpeg", filePath);
File file = driveService.files().create(fileMetadata, mediaContent)
.setFields("id, parents")
.execute();
System.out.println("File ID: " + file.getId());
Implementation for other languages are also included like PHP, Python, NodeJS.
Also, check this SO thread for additional reference.
body.setParents(Arrays.asList(new ParentReference().setId(folderId)));
Your sample code is doing a media upload, ie. no metadata, You should be using a multipart upload so you can specify both metadata such as parent folder id and content.
Uploading a file to google drive using REST API has following steps.
Get parent folderID using list API
Create file with parent="folder ID" using create api and get "fileId" in response
upload file to "fileId
Following is javascript code to upload file using REST API
const url = 'https://www.googleapis.com/upload/drive/v3/files/' + fileId + '?uploadType=media';
if(self.fetch){
// console.log("Fetch found, Using fetch");
var setHeaders = new Headers();
setHeaders.append('Authorization', 'Bearer ' + authToken.access_token);
setHeaders.append('Content-Type', mime);
var setOptions = {
method: 'PATCH',
headers: setHeaders,
body: blob
};
fetch(url,setOptions)
.then(response => { if(response.ok){
// console.log("save to google using fetch");
}
else{
// console.log("Response wast not ok");
}
})
.catch(error => {
// console.log("There is an error " + error.message);
});
}

valence desire 2 learn profile image upload error 404

I'm trying to upload an image profile using the api but I'm getting a Unknown: NOT_FOUND 404 error. the call I am using is POST /d2l/api/lp/1.3/profile/(profileId)/image, I am passing the content type, length and filename (profileImage). I'm passing the image as a dataStream. I've reduced the size of the image as well. Any ideas?
public static void UploadFilesToRemoteUrl(string file, string logpath, NameValueCollection nvc, ID2LUserContext userContext, string accion)
{
var uri = userContext.CreateAuthenticatedUri(accion, "POST");
string boundary = "bde472ff1f1a46539e54e655857c27c1";
HttpWebRequest request = (HttpWebRequest)WebRequest.Create(uri);
request.ContentType = "multipart/form-data; boundary=" +
boundary;
request.Headers.Add("Accept-Encoding", "gzip, deflate, compress");
request.Method = "POST";
request.KeepAlive = true;
request.Proxy.Credentials = new NetworkCredential(Constantes.UsuarioProxy, Constantes.PasswordProxy, Constantes.DominioProxy);
Stream memStream = new System.IO.MemoryStream();
byte[] boundarybytes = System.Text.Encoding.ASCII.GetBytes("\r\n--" +
boundary + "\r\n");
string formdataTemplate = "\r\n--" + boundary +
"\r\nContent-Disposition: form-data; name=\"profileImage\"; filename=\"profileImage.png\" \r\nContent-Type: image/png\r\n";
byte[] formitembytes = System.Text.Encoding.UTF8.GetBytes(formdataTemplate);
memStream.Write(formitembytes, 0, formitembytes.Length);
// Read image File *************************************************************
FileStream fileStream = new FileStream(file, FileMode.Open,FileAccess.Read);
byte[] buffer = new byte[1024];
int bytesRead = 0;
while ((bytesRead = fileStream.Read(buffer, 0, buffer.Length)) != 0)
{
memStream.Write(buffer, 0, bytesRead);
}
fileStream.Close();
//*****************************************************************************
//*********** End Read image file *********************************************
memStream.Write(boundarybytes, 0, boundarybytes.Length);
request.ContentLength = memStream.Length;
Stream requestStream = request.GetRequestStream();
memStream.Position = 0;
byte[] tempBuffer = new byte[memStream.Length];
memStream.Read(tempBuffer, 0, tempBuffer.Length);
memStream.Close();
requestStream.Write(tempBuffer, 0, tempBuffer.Length);
requestStream.Close();
HttpWebResponse response = (HttpWebResponse)request.GetResponse();
StreamReader reader = new StreamReader(response.GetResponseStream(), Encoding.UTF8);
string responseValence = reader.ReadToEnd();
}
It seems most likely that the 404 is coming either from
The API route you're providing (and the back-end service cannot match your API route to a handler method): this could be because of an incorrect profileId value, or a mis-typed route, or an incorrect API version number in the route, and so forth.
That for some reason the back-end service is accepting your profile image data but then unable to assign it to the user's profile.
Here's a capture of some request/response details of what an uploaded profile image packet looks like. When uploading a profile image to "my profile", I use an HTTP header that gets built from these values:
{'Content-Length': '75143',
'User-Agent': 'python-requests/2.2.1 CPython/3.3.3 Darwin/12.5.0',
'Content-Type': 'multipart/form-data; boundary=bde472ff1f1a46539e54e655857c27c1',
'Accept': '*/*',
'Accept-Encoding': 'gzip, deflate, compress'}
Note that this is a multipart/form-data content body, with a boundary marker around a single body part. The body content for the request looks like this:
--bde472ff1f1a46539e54e655857c27c1
Content-Disposition: form-data; name="profileImage"; filename="profile_img-225x225.png"
[actual PNG bytes here]
--bde472ff1f1a46539e54e655857c27c1--
The name property in the Content-Disposition header must be profileImage, and the filename property should be named after the local filename you're using to provide the content (so, as far as the back-end service is concerned, it's value is not particularly relevant).
Finally, there are particular role permissions at play that permit a user to edit someone else's profile image, so you should ensure that your calling user context for the API call has permission to edit someone else's image.
Fixed. This code works correctly:
public static void UploadFilesToRemoteUrl(byte[] profileImage, ID2LUserContext userContext, string accion)
{
//Reference:
//action = "/d2l/api/lp/1.3/profile/" + profileIdentifier + "/image";
//profileImage = the profileImage of user read from disk:
/*
FileStream fileStream = new FileStream(pictureLocalPath, FileMode.Open, FileAccess.Read);
Byte[] img = new Byte[fileStream.Length];
fileStream.Read(img, 0, Convert.ToInt32(img.Length));
fileStream.Close();
*/
var uri = userContext.CreateAuthenticatedUri(accion, "POST");
string boundary = "bde472ff1f1a46539e54e655857c27c1";
HttpWebRequest request = (HttpWebRequest)WebRequest.Create(uri);
request.ContentType = "multipart/form-data; boundary=" +
boundary;
request.Headers.Add("Accept-Encoding", "gzip, deflate, compress");
request.Method = "POST";
request.KeepAlive = true;
request.Proxy.Credentials = new NetworkCredential(Constantes.UsuarioProxy, Constantes.PasswordProxy, Constantes.DominioProxy);
Stream memStream = new System.IO.MemoryStream();
byte[] boundarybytes = System.Text.Encoding.ASCII.GetBytes("\r\n--" +
boundary + "\r\n");
string formdataTemplate = "\r\n--" + boundary +
"\r\nContent-Disposition: form-data; name=\"profileImage\"; filename=\"profileImage.jpg\"\r\nContent-Type: image/jpeg;\r\n\r\n";
byte[] formitembytes = System.Text.Encoding.UTF8.GetBytes(formdataTemplate);
memStream.Write(formitembytes, 0, formitembytes.Length);
//escribo el array de byte de la imagen
memStream.Write(profileImage, 0, profileImage.Length);
byte[] boundaryClose = System.Text.Encoding.ASCII.GetBytes("\r\n--" + boundary + "--");
memStream.Write(boundaryClose, 0, boundarybytes.Length);
StreamReader readerReq = new StreamReader(memStream);
string stringReq = readerReq.ReadToEnd();
request.ContentLength = memStream.Length;
Stream requestStream = request.GetRequestStream();
memStream.Position = 0;
byte[] tempBuffer = new byte[memStream.Length];
memStream.Read(tempBuffer, 0, tempBuffer.Length);
memStream.Close();
requestStream.Write(tempBuffer, 0, tempBuffer.Length);
requestStream.Close();
HttpWebResponse response = (HttpWebResponse)request.GetResponse();
if (response.StatusCode == HttpStatusCode.OK)
{
StreamReader reader = new StreamReader(response.GetResponseStream(), Encoding.UTF8);
string responseValence = reader.ReadToEnd();
response.Close();
}
}

Getting Error 400 while Exchanging Code for Access Token in Google oAuth C#

WebRequest request = WebRequest.Create("https://accounts.google.com/o/oauth2/token");
request.Method = "POST";
string postData = "code=" + code + "&client_id=" + _clientId + "&client_secret=" + _clientSecret + "&redirect_uri=" + _callback_url + "&grant_type=authorization_code";
byte[] byteArray = Encoding.UTF8.GetBytes(postData);
request.ContentType = "application/x-www-form-urlencoded";
request.ContentLength = byteArray.Length;
Stream dataStream = request.GetRequestStream();
dataStream.Write(byteArray, 0, byteArray.Length);
dataStream.Close();
WebResponse response = request.GetResponse();
I have placed a google sign in button in HTML page, on its callback got auth code to call ajax web servcice containing above code. But I am getting Error 400 on GetResponse(), I don't know why. Can any body please help me?
I have found following link workable in my case:
Code on page Page load :
protected void Page_Load(object sender, EventArgs e)
{
if (Request["code"] != null)
{
vCode = Request["code"].ToString();
getRefreshToken();
}
else
{
Response.Redirect(vAuthURL + "?scope=" + vScope + "&state=%2Fprofile&client_id=" + vClientId + "&redirect_uri=" + vRedURL + "&response_type=code&access_type=offline&approval_prompt=force", false);
}
}
Following function is being called in page load when code is available:
private void getRefreshToken()
{
string vClientId = "974762xxxxxx-xxxxxxxxx.apps.googleusercontent.com";
string vSecCode = "xxxxxxxxxxxxxxx";
string vScope = "https%3A%2F%2Fwww.googleapis.com%2Fauth%2Fuserinfo.email+https%3A%2F%2Fwww.googleapis.com%2Fauth%2Fuserinfo.profile+https%3A%2F%2Fwww.googleapis.com%2Fauth%2Fplus.login";
string vRedURL = "http://localhost:50488/wwwroot/member/social/googlesignin.aspx";
string vAuthURL = "https://accounts.google.com/o/oauth2/auth";
StringBuilder authLink = new StringBuilder();
HttpWebRequest webRequest = (HttpWebRequest)WebRequest.Create("https://accounts.google.com/o/oauth2/token");
webRequest.ContentType = "application/x-www-form-urlencoded";
webRequest.Method = "POST";
authLink.AppendFormat("code={0}", vCode);
authLink.AppendFormat("&client_id={0}", vClientId);
authLink.AppendFormat("&client_secret={0}", vSecCode);
authLink.AppendFormat("&redirect_uri={0}", vRedURL);
authLink.Append("&grant_type=authorization_code");
UTF8Encoding utfenc = new UTF8Encoding();
byte[] bytes = utfenc.GetBytes(authLink.ToString());
Stream os = null;
webRequest.ContentLength = bytes.Length; // Count bytes to send
os = webRequest.GetRequestStream();
os.Write(bytes, 0, bytes.Length); // Send it
HttpWebResponse webResponse = (HttpWebResponse)webRequest.GetResponse();
if (webResponse == null) { Response.Write("null"); }
StreamReader sr = new StreamReader(webResponse.GetResponseStream());
string jsonStr = sr.ReadToEnd().Trim();
}
Probably the important thing was to get code with server side code instead of mixing the client code and server side access_token getting script. Hope this works for you too.

Resources