I want implement api that upload zip files.
My function working for text files but not for zip file.
Zip file is saved but can not be open.
Do you know whet is good aproach for this?
At client I call api in next action:
[HttpPost]
public async Task<IActionResult> Upload(ICollection<IFormFile> files)
{
using (var client = new HttpClient())
{
foreach (var file in files)
{
if (file.Length > 0)
{
var fileName = ContentDispositionHeaderValue.Parse(file.ContentDisposition).FileName.Trim('"');
var fileContent = new StreamContent(file.OpenReadStream());
fileContent.Headers.Add("X-FileName", fileName);
fileContent.Headers.Add("X-ContentType", file.ContentType);
var response = await client.PostAsync(url2, fileContent);
}
}
}
return View(nameof(this.Index));
}
This is my api:
[HttpPost]
public async Task<IActionResult> Post()
{
var input = new StreamReader(Request.Body).ReadToEnd();
var fileName = Request.Headers["X-FileName"];
var fileType = Request.Headers["X-ContentType"];
using (var sw = new StreamWriter(#"C:\" + fileName))
{
sw.Write(input);
}
await Task.FromResult(0);
return new ObjectResult(true);
}
This is my solutin:
On client API
[HttpPost("{lastModified}")]
public async Task<string> Upload(long lastModified)
{
using (var client = new HttpClient())
{
foreach (var file in Request.Form.Files)
{
if (file.Length > 0)
{
var fileName = ContentDispositionHeaderValue.Parse(file.ContentDisposition).FileName.Trim('"');
var fileContent = new StreamContent(file.OpenReadStream());
var archiveUrl = "path to api with 2 parameters {fileName}/{lastModified}";
var datasetResponse = await client.PostAsync(archiveUrl, fileContent);
var dataset = await datasetResponse.Content.ReadAsStringAsync();
return dataset;
}
}
throw new ApplicationException("Cannot updated dataset to archive");
}
}
On server API
[HttpPost("{fileName}/{lastModified}")]
public async Task<IActionResult> Post(string fileName, long lastModified)
{
var dataSet = getDataSet();
return new ObjectResult(dataSet);
}
Related
I'm trying to upload files via web api, the files are sent as byte[].
I manage to upload only one file per request, but if I select multiple files it only upload one file.
This is the client side code:
var content = new MultipartFormDataContent();
ByteArrayContent byteContent = new ByteArrayContent(_mediaFile);
content.Add(byteContent, "file", _mediaFIleName);
var httpClient = new HttpClient();
var uploadServiceBaseAddress = "http://localhost:1000/api/home/Upload";
var httpResponseMessage = httpClient.PostAsync(uploadServiceBaseAddress, content);
This is the server side code:
var httpRequest = HttpContext.Current.Request;
foreach (string file in httpRequest.Files)
{
var postedFile = httpRequest.Files[file];
var filePath = HttpContext.Current.Server.MapPath("~/uploads" + postedFile.FileName);
postedFile.SaveAs(filePath);
}
Is there another method to do this or am I doing something wrong here in the code above?
see this example
[HttpGet]
public IHttpActionResult SendBytes(string input)
{
string[] paths = input.Split('*');
foreach (var path in paths)
{
var content = new MultipartFormDataContent();
ByteArrayContent byteContent = new ByteArrayContent(File.ReadAllBytes(path));
content.Add(byteContent, "file", path);
var httpClient = new HttpClient();
var uploadServiceBaseAddress = "http://localhost:56381/api/BazarAlborzApp/RecieveBytes";
var httpResponseMessage = httpClient.PostAsync(uploadServiceBaseAddress, content);
}
return Ok<int>(0);
}
[HttpPost]
public IHttpActionResult RecieveBytes()
{
var httpRequest = HttpContext.Current.Request;
foreach (string file in httpRequest.Files)
{
var postedFile = httpRequest.Files[file];
var filePath = Path.Combine(HttpContext.Current.Server.MapPath("/uploads/" + postedFile.FileName));
postedFile.SaveAs(filePath);
}
return Ok<int>(0);
}
I have a Post Web Api Method in a controller and it's already working, I've been testing the method sending file from postman and a my own web application and it works but now I'm trying to send file from console application using Httpclient but always get 404.
Controller Method
public async Task<IHttpActionResult> Post()
{
FileServerConfig config = FileServerConfiguration.ObtenerConfiguracion(ConfigurationManager.AppSettings);
var path = string.Empty;
try
{
if (!Request.Content.IsMimeMultipartContent())
{
return StatusCode(HttpStatusCode.UnsupportedMediaType);
}
var filesReadToProvider = await Request.Content.ReadAsMultipartAsync();
foreach (var stream in filesReadToProvider.Contents)
{
IFileServerWrapper _cliente = FileServerConfiguration.CrearCliente(config);
var name = stream.Headers.ContentDisposition.FileName.Replace("\"", "").Replace("\\", "");
var fileUploaded = await _cliente.FileUpload(path, await stream.ReadAsStreamAsync(), name, false);
}
return Ok();
}
catch (HttpException httpex)
{
if (httpex.GetHttpCode() == (int)HttpStatusCode.Conflict)
{
return Conflict();
}
else
{
return InternalServerError(httpex);
}
}
catch (Exception ex)
{
return InternalServerError(ex);
}
}
Console application
static void Main(string[] args)
{
string filePath = #"C:\Software\itextTifftoPDF.rar";
using (var client = new HttpClient())
using (var content = new MultipartFormDataContent())
{
// Make sure to change API address
//client.BaseAddress = new Uri("http://localhost:80/FileServerAPI/");
client.DefaultRequestHeaders.Add("Accept-Language", "en-GB,en-US;q=0.8,en;q=0.6,ru;q=0.4");
client.DefaultRequestHeaders.CacheControl = CacheControlHeaderValue.Parse("no-cache");
client.DefaultRequestHeaders.Accept.Add(new MediaTypeWithQualityHeaderValue("application/json"));
// Add first file content
var fileContent1 = new ByteArrayContent(File.ReadAllBytes(filePath));
fileContent1.Headers.ContentDisposition = new ContentDispositionHeaderValue("form-data")
{
FileName = "itextTifftoPDF.rar"
};
content.Add(fileContent1);
// Make a call to Web API
var result = client.PostAsync("http://localhost/FileServerAPI/api/File", content).Result;
Console.WriteLine(result.StatusCode);
Console.ReadLine();
}
}
Finally I found a solution. the code is ugly because it was made just to be sure it works but I'll hope it may help others with the same problem.
string filePath = #"C:\temp\webdavtest.txt";
using (HttpClient httpClient = new HttpClient())
{
using (MultipartFormDataContent content =
new MultipartFormDataContent())
{
using (FileStream stream = File.Open(
filePath, FileMode.Open, FileAccess.Read))
{
using (StreamContent streamConent =
new StreamContent(stream))
{
content.Add(
streamConent, "webdavtest.txt", "webdavtest.txt");
var result = await httpClient.PostAsync("http://localhost:3983/api/File?path=/nivel5/", content);
return result.StatusCode.ToString();
}
}
}
}
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.
In my ASP.NET MVC project, I am trying to post image from Controller action method to API controller method. Plan is to leverage this API to other clients to use to upload images.
I am able to successfully hit the API Post method from Controller Action method, but am not able to pass the image object.
Here is my HomeController.cs Upload Action Method
[HttpPost]
public async Task<ActionResult> Upload(FormCollection formCollection)
{
var baseUri = "http://localhost/api/Process";
HttpPostedFileBase file = Request?.Files[0];
if (file == null || (file.ContentLength <= 0) || string.IsNullOrEmpty(file.FileName))
return new EmptyResult();
string fileName = file.FileName;
byte[] fileBytes = new byte[file.ContentLength];
HttpContent stringContent = new StringContent(fileName);
HttpContent fileStreamContent = new StreamContent(file.InputStream);
HttpContent bytesContent = new ByteArrayContent(fileBytes);
using (var formDataContent = new MultipartFormDataContent())
{
formDataContent.Add(stringContent, "fileName", fileName);
formDataContent.Add(fileStreamContent, "inputStream", fileName);
formDataContent.Add(bytesContent, "fileBytes", fileName);
using (var httpClient = new HttpClient())
{
formDataContent.Headers.ContentType =
MediaTypeHeaderValue.Parse("application/x-www-form-urlencoded");
var response = await httpClient.PostAsync(baseUri, formDataContent);
var content = await response.Content.ReadAsStringAsync();
//Handle the response
}
}
return View("Result");
}
In my Process controller which is inheriting from ApiController, I have the following Post method
[HttpPost]
public async Task<string> Post([FromBody]MultipartFormDataContent formDataContent)
{
Task<string> imageContent = Request.Content.ReadAsStringAsync();
string body = imageContent.Result;
ImageResponse imageResponse = null;
//.................
//.................
return someValue
}
Here parameter formDataContent is always null and Request.Content.ReadAsStringAsync() is empty
Try sending from the Controller like this
//...other code removed for brevity
using (var form = new MultipartFormDataContent()) {
var stringContent = new StringContent("fileToUpload");
form.Add(stringContent, "fileToUpload");
var streamContent = new StreamContent(file.InputStream);
streamContent.Headers.ContentType = MediaTypeHeaderValue.Parse(file.ContentType);
streamContent.Headers.ContentLength = file.ContentLength;
streamContent.Headers.ContentDisposition = new ContentDispositionHeaderValue("form-data") {
Name = "fileToUpload",
FileName = file.FileName
};
form.Add(streamContent);
using (var httpClient = new HttpClient()) {
var response = await httpClient.PostAsync(baseUri, form);
//...other code removed for brevity
}
}
And then process it in the ApiController by extracting the information sent ...
[HttpPost]
public async Task<IHttpActionResult> Post() {
var content = Request.Content;
//get file name from content disposition
var fileName = content.Headers.ContentDisposition.FileName;
//Get file stream from the request content
var fileStream = await content.ReadAsStreamAsync();
//...other code removed for brevity
return Ok();
}
Referenced this answer : Upload image using HttpClient
I have the following code, used to download multiple files, create a zip file, and return the file to the user:
//In a WebAPI GET Handler
public async Task<HttpResponseMessage> Get(string id)
{
try
{
var urlList = CacheDictionary<String, List<String>>.Instance[id];
var helper = new Helper();
var zipFile = await helper.CreateZipFormUrls(urlList);
var response = new HttpResponseMessage(HttpStatusCode.OK);
var stream = new MemoryStream();
zipFile.Save(stream);
response.Content = new ByteArrayContent(stream.ToArray());
response.Content.Headers.ContentDisposition = new ContentDispositionHeaderValue("attachment");
response.Content.Headers.ContentType = new MediaTypeHeaderValue("application/zip");
response.Content.Headers.ContentLength = stream.Length;
response.Content.Headers.ContentDisposition.FileName = "download.zip";
return response;
}
catch (Exception)
{
return Request.CreateResponse(HttpStatusCode.BadRequest);
}
}
//In a Helper Class
public async Task<ZipFile> CreateZipFromUrls(List<string> urlList)
{
using (var zip = new ZipFile())
{
var files = await ReturnFileData(urlList);
foreach (var file in files)
{
var e = zip.AddEntry(GetFileNameFromUrlString(file.Key), file.Value);
}
return zip;
}
}
static Task<Dictionary<string, byte[]>> ReturnFileData(IEnumerable<string> urls)
{
Dictionary<Uri, Task<byte[]>> dictionary;
using (var client = new WebClient())
{
dictionary = urls.Select(url => new Uri(url)).ToDictionary(
uri => uri, uri => client.DownloadDataTaskAsync(uri));
await Task.WhenAll(dictionary.Values);
}
return dictionary.ToDictionary(pair => Path.GetFileName(pair.Key.ToString()),
pair => pair.Value.Result);
}
private string GetFileNameFromUrlString(string url)
{
var uri = new Uri(url);
return System.IO.Path.GetFileName(uri.LocalPath);
}
I always get:
An asynchronous module or handler completed while an asynchronous operation was still pending
And cannot reach any breakpoints after the download method is called. What am I doing wrong? Where do I look?
Try await on this
dictionary = urls.Select(url => new Uri(url)).ToDictionary(
uri => uri, uri => client.DownloadDataTaskAsync(uri));
The problem might be that
client.DownloadDataTaskAsync(uri));
is probably still running when the rest of your code is done.