Files uploaded but not appearing on server - asp.net-web-api2

I use the code stated here to upload files through a webapi http://bartwullems.blogspot.pe/2013/03/web-api-file-upload-set-filename.html. I also made the following api to list all the files I have :
[HttpPost]
[Route("sharepoint/imageBrowser/listFiles")]
[SharePointContextFilter]
public async Task<HttpResponseMessage> Read()
{
string pathImages = HttpContext.Current.Server.MapPath("~/Content/images");
DirectoryInfo d = new DirectoryInfo(pathImages);//Assuming Test is your Folder
FileInfo[] Files = d.GetFiles(); //Getting Text files
List<object> lst = new List<object>();
foreach (FileInfo f in Files)
{
lst.Add(new
{
name = f.Name,
type = "f",
size = f.Length
});
}
return Request.CreateResponse(HttpStatusCode.OK, lst);
}
When calling this api, all the files uploaded are listed. But when I go to azure I dont see any of them (Content.png is a file I manually uploaded to azure)
Why are the files listed if they dont appear on azure.

According to your description, I suggest you could firstly use azure kudu console to locate the right folder in the azure web portal to see the image file.
Open kudu console:
In the kudu click the debug console and locate the site\wwwroot\yourfilefolder
If you find your file is still doesn't upload successfully, I guess there maybe something wrong with your upload codes. I suggest you could try below codes.
Notice: You need add image folder in the wwwort folder.
{
public class UploadingController : ApiController
{
public async Task<HttpResponseMessage> PostFile()
{
// Check if the request contains multipart/form-data.
if (!Request.Content.IsMimeMultipartContent())
{
throw new HttpResponseException(HttpStatusCode.UnsupportedMediaType);
}
string root = Environment.GetEnvironmentVariable("HOME").ToString() + "\\site\\wwwroot\\images";
//string root = HttpContext.Current.Server.MapPath("~/images");
var provider = new FilenameMultipartFormDataStreamProvider(root);
try
{
StringBuilder sb = new StringBuilder(); // Holds the response body
// Read the form data and return an async task.
await Request.Content.ReadAsMultipartAsync(provider);
// This illustrates how to get the form data.
foreach (var key in provider.FormData.AllKeys)
{
foreach (var val in provider.FormData.GetValues(key))
{
sb.Append(string.Format("{0}: {1}\n", key, val));
}
}
// This illustrates how to get the file names for uploaded files.
foreach (var file in provider.FileData)
{
FileInfo fileInfo = new FileInfo(file.LocalFileName);
sb.Append(string.Format("Uploaded file: {0} ({1} bytes)\n", fileInfo.Name, fileInfo.Length));
}
return new HttpResponseMessage()
{
Content = new StringContent(sb.ToString())
};
}
catch (System.Exception e)
{
return Request.CreateErrorResponse(HttpStatusCode.InternalServerError, e);
}
}
}
public class FilenameMultipartFormDataStreamProvider : MultipartFormDataStreamProvider
{
public FilenameMultipartFormDataStreamProvider(string path) : base(path)
{
}
public override string GetLocalFileName(System.Net.Http.Headers.HttpContentHeaders headers)
{
var name = !string.IsNullOrWhiteSpace(headers.ContentDisposition.FileName) ? headers.ContentDisposition.FileName : Guid.NewGuid().ToString();
return name.Replace("\"", string.Empty);
}
}
}
Result:

Related

Download the file as a zip in ASP.NET Core

I am designing an educational site. When the user downloads a training course, I want this download (training course) to be done in the form of compression (zipper), please give a solution
My code:
public Tuple<byte[],string,string> DownloadFile(long episodeId)
{
var episode=_context.CourseEpisodes.Find(episodeId);
string filepath = Path.Combine(Directory.GetCurrentDirectory(),
"wwwroot/courseFiles",
episode.FileName);
string fileName = episode.FileName;
if(episode.IsFree)
{
byte[] file = System.IO.File.ReadAllBytes(filepath);
return Tuple.Create(file, "application/force-download",fileName);
}
if(_httpContextAccessor.HttpContext.User.Identity.IsAuthenticated)
{
if(IsuserIncorse(_httpContextAccessor.HttpContext.User.Identity.Name,
episode.CourseId))
{
byte[] file = System.IO.File.ReadAllBytes(filepath);
return Tuple.Create(file, "application/force-download", fileName);
}
}
return null;
}
I write a demo to show how to download zip file from .net core:
First , Add NuGet package SharpZipLib , create an Image Folder in wwwroot and put some picture in it.
controller
public class HomeController : Controller
{
private IHostingEnvironment _IHosting;
public HomeController(IHostingEnvironment IHosting)
{
_IHosting = IHosting;
}
public IActionResult Index()
{
return View();
}
public FileResult DownLoadZip()
{
var webRoot = _IHosting.WebRootPath;
var fileName = "MyZip.zip";
var tempOutput = webRoot + "/Images/" + fileName;
using (ZipOutputStream IzipOutputStream = new ZipOutputStream(System.IO.File.Create(tempOutput)))
{
IzipOutputStream.SetLevel(9);
byte[] buffer = new byte[4096];
var imageList = new List<string>();
imageList.Add(webRoot + "/Images/1202.png");
imageList.Add(webRoot + "/Images/1data.png");
imageList.Add(webRoot + "/Images/aaa.png");
for (int i = 0; i < imageList.Count; i++)
{
ZipEntry entry = new ZipEntry(Path.GetFileName(imageList[i]));
entry.DateTime= DateTime.Now;
entry.IsUnicodeText = true;
IzipOutputStream.PutNextEntry(entry);
using (FileStream oFileStream = System.IO.File.OpenRead(imageList[i]))
{
int sourceBytes;
do
{
sourceBytes = oFileStream.Read(buffer, 0, buffer.Length);
IzipOutputStream.Write(buffer, 0, sourceBytes);
}while (sourceBytes > 0);
}
}
IzipOutputStream.Finish();
IzipOutputStream.Flush();
IzipOutputStream.Close();
}
byte[] finalResult = System.IO.File.ReadAllBytes(tempOutput);
if (System.IO.File.Exists(tempOutput)) {
System.IO.File.Delete(tempOutput);
}
if (finalResult == null || !finalResult.Any()) {
throw new Exception(String.Format("Nothing found"));
}
return File(finalResult, "application/zip", fileName);
}
}
when I click the downloadZip ,it will download a .zip file
The simple example that follows illustrates the use of the static ZipFile.CreateFromDirectory method which, despite the fact that it is in the System.IO.Compression namespace , actually resides in the System.IO.Compression.FileSystem assembly, so you need to add a reference to that in your controller.
[HttpPost]
public FileResult Download()
{
List<string> files = new List<string> { "filepath1", "filepath2" };
var archive = Server.MapPath("~/archive.zip");
var temp = Server.MapPath("~/temp");
// clear any existing archive
if (System.IO.File.Exists(archive))
{
System.IO.File.Delete(archive);
}
// empty the temp folder
Directory.EnumerateFiles(temp).ToList().ForEach(f => System.IO.File.Delete(f));
// copy the selected files to the temp folder
files.ForEach(f => System.IO.File.Copy(f, Path.Combine(temp, Path.GetFileName(f))));
// create a new archive
ZipFile.CreateFromDirectory(temp, archive);
return File(archive, "application/zip", "archive.zip");
}
Answer from Source - MikesDotNetting

ASP.Net Core - EC2 to S3 file upload with Access Denied

I have developed a .NET Core 3.1 Web API which allows the users to upload their documents to S3 bucket. When I deploy the API to AWS ElasticBeansTalk EC2 instance and call the endpoint which uploads the file to S3, I get an error "Access Denied".
By the way, I have created IAM policy and role to give full access to S3 from my EC2 instance. I have also copied the .aws folder which contains credentials file onto the EC2 instance.
API Controller Action
public async Task<ApiResponse> UpdateProfilePic([FromBody]UploadProfilePicRequest model)
{
using (Stream stream = model.profilePicData.Base64StringToStream(out string header))
{
var tags = new List<KeyValuePair<string, string>>();
var metaData = new List<KeyValuePair<string, string>>();
metaData.Add(new KeyValuePair<string, string>("Content-Disposition", $"attachment; filename=\"{model.filename}\""));
if (_host.IsDevelopment())
{
tags.Add(new KeyValuePair<string, string>("public", "yes"));
}
await AmazonS3Uploader.UploadFileAsync(stream, "myDir/", model.fileId, tags, metaData);
}
}
The AmazonS3Helper class shown below:
using Amazon;
using Amazon.Runtime;
using Amazon.Runtime.CredentialManagement;
using Amazon.S3;
using Amazon.S3.Model;
using Amazon.S3.Transfer;
using System;
using System.Collections.Generic;
using System.IO;
using System.Threading.Tasks;
namespace UploderApp.Services
{
public static class AmazonS3Uploader
{
private static readonly RegionEndpoint bucketRegion = RegionEndpoint.APSouth1;
private static readonly IAmazonS3 s3Client = new AmazonS3Client(GetAwsCredentials(), bucketRegion);
private static readonly string S3Bucket = "abc-test";
private static AWSCredentials GetAwsCredentials()
{
var chain = new CredentialProfileStoreChain();
if (chain.TryGetAWSCredentials("MYPROFILE", out AWSCredentials awsCredentials))
{
return awsCredentials;
}
return null;
}
public static async Task UploadFileAsync(Stream fileStream, string virtualDirectory, string keyName)
{
try
{
using (var fileTransferUtility = new TransferUtility(s3Client))
{
//Upload data from a type of System.IO.Stream.
await fileTransferUtility.UploadAsync(fileStream, S3Bucket, virtualDirectory + keyName).ConfigureAwait(true);
}
}
catch (AmazonS3Exception e)
{
throw new Exception($"Error encountered on server. Message:'{e.Message}' when writing an object");
}
}
public static async Task UploadFileAsync(Stream stream, string virtualDirectory, string keyName, List<KeyValuePair<string, string>> tags = null, List<KeyValuePair<string, string>> metadata = null)
{
try
{
// Specify advanced settings.
var fileTransferUtilityRequest = new TransferUtilityUploadRequest
{
BucketName = S3Bucket,
InputStream = stream,
StorageClass = S3StorageClass.Standard,
Key = virtualDirectory + keyName
};
if (metadata != null)
{
foreach (var item in metadata)
{
fileTransferUtilityRequest.Metadata.Add(item.Key, item.Value);
}
}
if (tags != null)
{
fileTransferUtilityRequest.TagSet = new List<Tag>();
foreach (var tag in tags)
{
fileTransferUtilityRequest.TagSet.Add(new Tag { Key = tag.Key, Value = tag.Value });
}
}
using (var fileTransferUtility = new TransferUtility(s3Client))
{
await fileTransferUtility.UploadAsync(fileTransferUtilityRequest).ConfigureAwait(true);
}
}
catch (AmazonS3Exception e)
{
throw new Exception($"Error encountered on server. Message:'{e.Message}' when writing an object");
}
}
}
}
However, if I create a console application and use the above class without any modifications, it uploads the file from the same EC2 instance.
Code from the Main function of my Console Application.
public static void Main()
{
var file = Path.GetDirectoryName(Assembly.GetExecutingAssembly().Location) + "/Screenshot.png";
try
{
var tags = new List<KeyValuePair<string, string>>();
var metaData = new List<KeyValuePair<string, string>>();
metaData.Add(new KeyValuePair<string, string>("Content-Disposition", $"attachment; filename=\"profile-pic.png\""));
using (var stream = new FileStream(file, FileMode.Open))
{
AmazonS3Uploader.UploadFileAsync(stream, "mydir/", "screenshot.png", tags, metaData).GetAwaiter().GetResult();
}
}
catch (Exception ex)
{
Console.WriteLine(ex.Message);
}
}
This is very strange. Can anybody help me to understand the root cause, please?
Edit:1
Output of the aws s3 ls s3://abc-test is shown below
Edit:2
Uploading the EC2 folder to S3

get stream from multipartFileData, file in use

Hello im trying to access an image from a post request with MultipartFormDataStreamProvider.
So far it seems successful other than when i try to create a file steam from the local name, the file is then in use. How do i get the current open stream to read the file, or get the old stream to close?
*Note: Please ignore the not so great try catch.
What I have so far:
[ResponseType(typeof(AdminImage))]
public IHttpActionResult PostAdminImage([FromUri]AdminImage adminImage)
{
if (!Request.Content.IsMimeMultipartContent())
{
throw new HttpResponseException(HttpStatusCode.UnsupportedMediaType);
}
string root = HttpContext.Current.Server.MapPath("~/App_Data");
var provider = new MultipartFormDataStreamProvider(root);
try
{
Request.Content.ReadAsMultipartAsync(provider);
foreach (MultipartFileData file in provider.FileData)
{
FileStream fs = new FileStream(file.LocalFileName, FileMode.Open);
adminImage.ImageContent = adminImage.ImageToByteArray(Image.FromStream(fs));
}
if (!ModelState.IsValid)
{
return BadRequest(ModelState);
}
db.AdminImages.Add(adminImage);
db.SaveChanges();
}
catch (Exception ex)
{
return InternalServerError();
}
return CreatedAtRoute("DefaultApi", new { id = adminImage.Id }, adminImage);
}

ASP.NET WebApi file upload using guid and file extension

I currently am able to save a file being uploaded to a WebAPI controller, but I'd like to be able to save the file as a guid with the correct file name extension so it can be viewed correctly.
Code:
[ValidationFilter]
public HttpResponseMessage UploadFile([FromUri]string AdditionalInformation)
{
var task = this.Request.Content.ReadAsStreamAsync();
task.Wait();
using (var requestStream = task.Result)
{
try
{
// how can I get the file extension of the content and append this to the file path below?
using (var fileStream = File.Create(HttpContext.Current.Server.MapPath("~/" + Guid.NewGuid().ToString())))
{
requestStream.CopyTo(fileStream);
}
}
catch (IOException)
{
throw new HttpResponseException(HttpStatusCode.InternalServerError);
}
}
HttpResponseMessage response = new HttpResponseMessage();
response.StatusCode = HttpStatusCode.Created;
return response;
}
I can't seem to get a handle on the actual filename of the content. I thought headers.ContentDisposition.FileName might be a candidate but that doesn't seem to get populated.
Thanks for the comments above which pointed me in the right direction.
To clarify the final solution, I used a MultipartFormDataStreamProvider which streams the file automatically. The code is in another question I posted to a different problem here:
MultipartFormDataStreamProvider and preserving current HttpContext
My full provider code is listed below. The key to generating the guid file name is to override the GetLocalFileName function and use the headers.ContentDisposition property. The provider handles the streaming of the content to file.
public class MyFormDataStreamProvider : MultipartFormDataStreamProvider
{
public MyFormDataStreamProvider (string path)
: base(path)
{ }
public override Stream GetStream(HttpContent parent, HttpContentHeaders headers)
{
// restrict what images can be selected
var extensions = new[] { "png", "gif", "jpg" };
var filename = headers.ContentDisposition.FileName.Replace("\"", string.Empty);
if (filename.IndexOf('.') < 0)
return Stream.Null;
var extension = filename.Split('.').Last();
return extensions.Any(i => i.Equals(extension, StringComparison.InvariantCultureIgnoreCase))
? base.GetStream(parent, headers)
: Stream.Null;
}
public override string GetLocalFileName(System.Net.Http.Headers.HttpContentHeaders headers)
{
// override the filename which is stored by the provider (by default is bodypart_x)
string oldfileName = headers.ContentDisposition.FileName.Replace("\"", string.Empty);
string newFileName = Guid.NewGuid().ToString() + Path.GetExtension(oldfileName);
return newFileName;
}
}

Cannot Open Files in WinRT Unit Testing

I am writing a unit test to validate the serialization of objects and I am able to successfully save the file without any issue. I can even browse the file and validate the contents are correct. However, when I attempt to open the file for reading I always receive an UnauthorizedAccess exception.
Here is the code used to save the item:
public static async Task SaveItem<T>(string folderName, T item)
where T : BaseBusinessItem
{
if (string.IsNullOrEmpty(folderName))
{
throw new ArgumentNullException("folderName");
}
if (item == null)
{
throw new ArgumentNullException("item");
}
try
{
var folder = await ApplicationData.Current.LocalFolder
.CreateFolderAsync(folderName, CreationCollisionOption.OpenIfExists);
var file =
await
folder.CreateFileAsync(item.UniqueID.GetHashCode().ToString(), CreationCollisionOption.ReplaceExisting);
var stream = await file.OpenAsync(FileAccessMode.ReadWrite);
using (var outStream = stream.GetOutputStreamAt(0))
{
var serializer = new DataContractJsonSerializer(typeof(T));
serializer.WriteObject(outStream.AsStreamForWrite(), item);
await outStream.FlushAsync();
}
}
catch (Exception ex)
{
Debug.WriteLine(ex.ToString());
}
}
Here is the code used to restore the item:
public static async Task<T> RestoreItem<T>(string folderName, string hashCode)
where T : BaseBusinessItem, new()
{
if (string.IsNullOrEmpty(folderName))
{
throw new ArgumentNullException("folderName");
}
if (string.IsNullOrEmpty(hashCode))
{
throw new ArgumentNullException("hashCode");
}
var folder = await ApplicationData.Current.LocalFolder.GetFolderAsync(folderName);
var file = await folder.GetFileAsync(hashCode);
var inStream = await file.OpenSequentialReadAsync();
var serializer = new DataContractJsonSerializer(typeof(T));
var retVal = (T)serializer.ReadObject(inStream.AsStreamForRead());
return retVal;
}
And the unit test:
[TestMethod]
public async Task TestFileSaveLoad()
{
await _ds.SaveItem("TestFolder");
Guid ID = _item.UniqueID;
_ds = await ItemDataSource.LoadItem("TestFolder", ID.GetHashCode().ToString());
}
Any ideas or troubleshooting steps I might be missing. The unit test app manifest includes the following capabilities: Document Library, Internet (Client). The following declarations are in place: File Open Picker, File Save Picker and File Type Associations.
Thanks!
This code snippet helped me accomplish my goal. Hope this is helpful for someone else:
http://codepaste.net/gtu5mq