I get an error 400 Bad Request when I try to upload a file to my OneDrive using the Microsoft Graph API
GetAccessToken method get the access token
upload method take the file path and upload it to my OneDrive account
public class OneDrive
{
public void Upload(string filePath)
{
var token = GetAccessToken();
var url = "https://graph.microsoft.com/v1.0/drive/root:/test/test.pdf:/content";
PostRequest(url, token, filePath).Wait();
}
public string GetAccessToken()
{
var app = ConfidentialClientApplicationBuilder.Create("client id ")
.WithClientSecret("client secret")
.WithAuthority("https://login.microsoftonline.com/{tenant id}/v2.0")
.Build();
string[] scopes = new string[] { "https://graph.microsoft.com/.default" };
try
{
var result = app.AcquireTokenForClient(scopes).ExecuteAsync().Result;
Console.WriteLine(result.TenantId);
return result.AccessToken;
}
catch (MsalServiceException ex) when (ex.Message.Contains("AADSTS70011"))
{
Console.WriteLine(ex.Message);
return null;
}
}
public async Task PostRequest(string webApiUrl, string accessToken, string filePath)
{
HttpContent content = new StreamContent(new MemoryStream(File.ReadAllBytes(filePath)));
HttpClient httpClient = new HttpClient();
if (!string.IsNullOrEmpty(accessToken))
{
var defaultRequestHeaders = httpClient.DefaultRequestHeaders;
httpClient.DefaultRequestHeaders.Accept.Add(new MediaTypeWithQualityHeaderValue("application/octet-stream"));
defaultRequestHeaders.Authorization = new AuthenticationHeaderValue("bearer", accessToken);
HttpResponseMessage response = await httpClient.PutAsync(webApiUrl, content);
if (response.IsSuccessStatusCode)
Console.WriteLine("File Successfuly Uploaded");
else
Console.WriteLine("Error Occur");
}
}
}
After removing this line :
httpClient.DefaultRequestHeaders.Accept.Add(new MediaTypeWithQualityHeaderValue("application/octet-stream"));
Your code works perfectly for me:
There is no need to set accpet header in request.
Related
This is the code below (C#) To upload in https://nft.storage/ It Works fine But when I upload mp4 file (Uploaded successfully) , The uploaded file doesn’t work . Source Code https://github.com/filipepolizel/unity-nft-storage
I used many different HTTPCLIENT example but it same
broken Uploaded mp4 File: http://ipfs.io/ipfs/bafybeibt4jqvncw6cuyih27mujbpdmsjl46pykablvravh3qg63vuvcdqy
// nft.storage API endpoint
private static readonly string nftStorageApiUrl = "https://api.nft.storage/";
// HTTP client to communicate with nft.storage
private static readonly HttpClient nftClient = new HttpClient();
// http client to communicate with IPFS API
private static readonly HttpClient ipfsClient = new HttpClient();
// nft.storage API key
public string apiToken;
void Start()
{
nftClient.DefaultRequestHeaders.Add("Accept", "application/json");
if (apiToken != null)
{
nftClient.DefaultRequestHeaders.Add("Authorization", "Bearer " + apiToken);
}
else
{
// log in console in case no API key is found during initialization
Debug.Log("Starting NFT Storage Client without API key, please call 'SetApiToken' method before using class methods.");
}
}
public async Task<NFTStorageUploadResponse> UploadDataFromFile(string path)
{
StreamReader reader = new StreamReader(path);
string data = reader.ReadToEnd();
reader.Close();
print("Uploading...");
return await UploadDataFromString(data);
}
public async Task<NFTStorageUploadResponse> UploadDataFromString(string data)
{
string requestUri = nftStorageApiUrl + "/upload";
string rawResponse = await Upload(requestUri, data);
NFTStorageUploadResponse parsedResponse = JsonUtility.FromJson<NFTStorageUploadResponse>(rawResponse);
return parsedResponse;
}
private async Task<string> Upload(string uri, string paramString)
{
try
{
using (HttpContent content = new StringContent(paramString))
{
//content.Headers.ContentType = new MediaTypeHeaderValue("application/octet-stream");
content.Headers.ContentType = new MediaTypeHeaderValue("*/*");
HttpResponseMessage response = await nftClient.PostAsync(uri, content);
response.EnsureSuccessStatusCode();
Stream responseStream = await response.Content.ReadAsStreamAsync();
StreamReader reader = new StreamReader(responseStream);
return reader.ReadToEnd();
}
}
catch (HttpRequestException e)
{
Debug.Log("HTTP Request Exception: " + e.Message);
Debug.Log(e);
return null;
}
}
the answer helped me . thanks , I changed the Update method to :
public static async Task<string> Upload(string uri, string pathFile)
{
byte[] bytes = System.IO.File.ReadAllBytes(pathFile);
using (var content = new ByteArrayContent(bytes))
{
content.Headers.ContentType = new MediaTypeHeaderValue("*/*");
//Send it
var response = await nftClient.PostAsync(uri, content);
response.EnsureSuccessStatusCode();
Stream responseStream = await response.Content.ReadAsStreamAsync();
StreamReader reader = new StreamReader(responseStream);
return reader.ReadToEnd();
}
}
It works great now
I am trying to write code to upload file(s) by WinForm app to WebApi.
The WebApi code is like:
[HttpPost]
[Route("UploadEnvelope")]
[HostAuthentication(DefaultAuthenticationTypes.ExternalBearer)]
public Task<HttpResponseMessage> PostUploadEnvelope()
{
HttpRequestMessage request = this.Request;
if (!request.Content.IsMimeMultipartContent())
{
throw new HttpResponseException(HttpStatusCode.UnsupportedMediaType);
}
string root = System.Web.HttpContext.Current.Server.MapPath("~/App_Data/uploads");
var provider = new MultipartFormDataStreamProvider(root);
var task = request.Content.ReadAsMultipartAsync(provider).ContinueWith<HttpResponseMessage>(o =>
{
foreach (MultipartFileData fileData in provider.FileData)
{
if (string.IsNullOrEmpty(fileData.Headers.ContentDisposition.FileName))
{
return Request.CreateResponse(HttpStatusCode.NotAcceptable, "This request is not properly formatted");
}
string fileName = fileData.Headers.ContentDisposition.FileName;
if (fileName.StartsWith("\"") && fileName.EndsWith("\""))
{
fileName = fileName.Trim('"');
}
if (fileName.Contains(#"/") || fileName.Contains(#"\"))
{
fileName = Path.GetFileName(fileName);
}
File.Move(fileData.LocalFileName, Path.Combine(root, fileName));
}
return new HttpResponseMessage()
{
Content = new StringContent("Files uploaded.")
};
}
);
return task;
}
But I am not sure how to call it and pass file in a client app.
static string UploadEnvelope(string filePath, string token, string url)
{
using (var client = new HttpClient())
{
client.DefaultRequestHeaders.Authorization = new System.Net.Http.Headers.AuthenticationHeaderValue("Bearer", token);
// How to pass file here ???
var response = client.GetAsync(url + "/api/Envelope/UploadEnvelope").Result;
return response.Content.ReadAsStringAsync().Result;
}
}
Any help or suggestion is welcome. Thanks in advance!
First you are using Get method which is used for reading. You have to use Post instead.
Try the following:
public static string UploadEnvelope(string filePath,string token, string url)
{
using (var client = new HttpClient())
{
client.DefaultRequestHeaders.Authorization = new System.Net.Http.Headers.AuthenticationHeaderValue("Bearer", token);
using (var content = new MultipartFormDataContent("Envelope" + DateTime.Now.ToString(CultureInfo.InvariantCulture)))
{
content.Add(new StreamContent(new MemoryStream(File.ReadAllBytes(filePath))), "filename", "filename.ext");
using (var message = await client.PostAsync(url + "/api/Envelope/UploadEnvelope", content))
{
var input = await message.Content.ReadAsStringAsync();
return "success";
}
}
}
}
Note: For a large file you have to change configuration on IIS web.config.
I'm currently using Pushbullet API and need to upload a file.
I can successfully get an upload url as specified in the docs using this method:
public static async Task<Uploads> GetUploadUrl(string file_name, string file_type)
{
using (var client = new HttpClient())
{
client.DefaultRequestHeaders.Add("Access-Token", AccessToken);
var json = new JObject
{
["file_name"] = file_name,
["file_type"] = file_type
};
var result = await client.PostAsync(new Uri(_uploadUrl, UriKind.RelativeOrAbsolute), new HttpStringContent(json.ToString(), UnicodeEncoding.Utf8, "application/json"));
if (result.IsSuccessStatusCode)
{
var textresult = await result.Content.ReadAsStringAsync();
return JsonConvert.DeserializeObject<Uploads>(textresult);
}
}
return null;
}
The problem is when I try to upload the file. I'm currently using this method:
public static async Task<bool> UploadFile(StorageFile file, string upload_url)
{
try
{
System.Net.Http.HttpClient client = new System.Net.Http.HttpClient();
var content = new MultipartFormDataContent();
if (file != null)
{
var streamData = await file.OpenReadAsync();
var bytes = new byte[streamData.Size];
using (var dataReader = new DataReader(streamData))
{
await dataReader.LoadAsync((uint)streamData.Size);
dataReader.ReadBytes(bytes);
}
var streamContent = new ByteArrayContent(bytes);
content.Add(streamContent);
}
client.DefaultRequestHeaders.Add("Access-Token", AccessToken);
var response = await client.PostAsync(new Uri(upload_url, UriKind.Absolute), content);
if (response.IsSuccessStatusCode)
return true;
}
catch { return false; }
return false;
}
but I get a Http 400 error. What's the right way to upload a file using multipart/form-data in a UWP app?
HTTP 400 error indicates Bad Request, it means the request could not be understood by the server due to malformed syntax. In the other word, the request sent by the client doesn't follow server's rules.
Let's look at the document, and we can find in the example request it uses following parameter:
-F file=#cat.jpg
So in the request, we need to set the name for the uploaded file and the name should be "file". Besides, in this request, there is no need to use access token. So you can change your code like following:
public static async Task<bool> UploadFile(StorageFile file, string upload_url)
{
try
{
System.Net.Http.HttpClient client = new System.Net.Http.HttpClient();
var content = new MultipartFormDataContent();
if (file != null)
{
var streamData = await file.OpenReadAsync();
var bytes = new byte[streamData.Size];
using (var dataReader = new DataReader(streamData))
{
await dataReader.LoadAsync((uint)streamData.Size);
dataReader.ReadBytes(bytes);
}
var streamContent = new ByteArrayContent(bytes);
content.Add(streamContent, "file");
}
//client.DefaultRequestHeaders.Add("Access-Token", AccessToken);
var response = await client.PostAsync(new Uri(upload_url, UriKind.Absolute), content);
if (response.IsSuccessStatusCode)
return true;
}
catch { return false; }
return false;
}
Then your code should be able to work. You will get a 204 No Content response and UploadFile method will return true.
I am building a mobile app using xamarin while the server is hosted in azure. I am uploading images in the following way:
Client:
public static async Task<string> UploadImage (string url, byte[] imageData)
{
var content = new MultipartFormDataContent();
var fileContent = new ByteArrayContent(imageData);
fileContent.Headers.ContentDisposition = new ContentDispositionHeaderValue("attachment")
{
FileName = Guid.NewGuid() + ".Png"
};
content.Add(fileContent);
using (var client = new HttpClient())
{
try
{
HttpResponseMessage msg = await client.PutAsync (url, content);
if(msg.StatusCode == System.Net.HttpStatusCode.OK)
{
return msg.Headers.GetValues ("ImageUrl").First();
}
return string.Empty;
}
catch (Exception ex)
{
return string.Empty;
}
}
}
and here is the server code:
[HttpPut]
public async Task<HttpResponseMessage> PostNewDishImage(string imageID)
{
try
{
_dishImagescontainer = BlobStorageHandler.GetContainer("dishuserimages");
if (!Request.Content.IsMimeMultipartContent("form-data"))
{
throw new HttpResponseException(Request.CreateResponse(HttpStatusCode.UnsupportedMediaType));
}
var provider = new BlobStorageProvider(_dishImagescontainer);
await Request.Content.ReadAsMultipartAsync(provider);
IList<string> urls = provider.Urls;
if (urls.Count > 0)
{
var response = new HttpResponseMessage();
response.StatusCode = HttpStatusCode.OK;
response.Headers.Add("ImageUrl", urls[0]);
return response;
}
return new HttpResponseMessage(HttpStatusCode.InternalServerError);
}
catch (System.Exception e)
{
return new HttpResponseMessage(HttpStatusCode.InternalServerError) { ReasonPhrase = e.ToString() };
}
}
It works fine but I don't like the way I am returning the new imageurl back to the client (through the http headers) I have tried some other ways but this is the best one so far :)
Does anyone have any better ideas?
Thanks
Returning data to the client in an HTTP header like that does have a bit of a smell. How about returning a DTO serialized to JSON?
An example DTO class:
public class ImageUploadResponse
{
public string Url { get; set; }
}
Then change your server side code to something like this:
var responseDto = new ImageUploadResponse { Url = urls[0] };
var response = new HttpResponseMessage(HttpStatusCode.OK)
{
Content = new StringContent(JsonConvert.SerializeObject(responseDto),
Encoding.UTF8, "application/json")
};
which will send the results back to the client in the content of the HTTP response as JSON. Then the client can parse the JSON into an object (or not) as you see fit. This approach will also be more friendly to making such a call from JavaScript in the future if you desire because the result is standard JSON.
I am trying to send one or more files (.doc) to an ASP.NET Web API 2 service and return a modified version (.docx). I am able to send the file and get a response but the HttpContentMultipartExtensions that I used within the service on the HTTPContent in the request are not available back in the client to use on the response. Is this something that isn't available out of the box that can be wired up, or is this a misuse of multipartform?
There are two apps: the MVC client and Web API service:
Controller for Client (reads sample files from App_Data, POST to serviceserver/api/mpformdata):
public async Task<ActionResult> PostMpFormData()
{
DirectoryInfo dir = new DirectoryInfo(Server.MapPath(#"~\App_Data"));
var files = dir.GetFiles().ToList();
using (HttpClient client = new HttpClient())
{
HttpResponseMessage result = new HttpResponseMessage();
using (MultipartFormDataContent mpfdc = new MultipartFormDataContent())
{
foreach (var file in files)
{
mpfdc.Add(new StreamContent(file.OpenRead()), "File", file.Name);
}
var requestUri = ConfigurationManager.AppSettings["DocumentConverterUrl"] + "/api/mpformdata";
client.DefaultRequestHeaders.Accept.Add(new System.Net.Http.Headers.MediaTypeWithQualityHeaderValue("multipart/form-data"));
result = client.PostAsync(requestUri, mpfdc).Result;
}
ViewBag.ResultStatusCode = result.StatusCode;
ViewBag.ContentLength = result.Content.Headers.ContentLength;
// Fiddler show that it returns multipartform content, but how do I use it?
// var resultContent = result.Content;
}
return View();
}
Controller for Web API service:
public class UploadController : ApiController
{
[HttpPost, Route("api/mpformdata")]
public async Task<HttpResponseMessage> PostMpFormData()
{
if (!Request.Content.IsMimeMultipartContent())
{
throw new HttpResponseException(HttpStatusCode.UnsupportedMediaType);
}
return await UseMultipartFormDataStream();
}
private async Task<HttpResponseMessage> UseMultipartFormDataStream()
{
string root = HttpContext.Current.Server.MapPath("~/App_Data");
var provider = new MultipartFormDataStreamProvider(root);
MultipartFormDataContent mpfdc = new MultipartFormDataContent();
try
{
await Request.Content.ReadAsMultipartAsync(provider);
foreach (MultipartFileData file in provider.FileData)
{
var filename = file.Headers.ContentDisposition.FileName;
Trace.WriteLine(filename);
Trace.WriteLine("Server file path: " + file.LocalFileName);
mpfdc.Add(new ByteArrayContent(File.ReadAllBytes(file.LocalFileName)), "File", filename);
}
var response = Request.CreateResponse();
response.Content = mpfdc;
response.StatusCode = HttpStatusCode.OK;
return response;
}
catch (System.Exception e)
{
return Request.CreateErrorResponse(HttpStatusCode.InternalServerError, e);
}
}
}
Multipart extensions are part of System.Net.Http.Formatting dll. Make sure you have the nuget package Microsoft.AspNet.WebApi.Client installed at your client.