Im using scott hanselmans file upload code:
public ActionResult UploadFiles()
{
var r = new List();
foreach (string file in Request.Files)
{
HttpPostedFileBase hpf = Request.Files[file] as HttpPostedFileBase;
if (hpf.ContentLength == 0)
continue;
string savedFileName = Path.Combine(
AppDomain.CurrentDomain.BaseDirectory,
Path.GetFileName(hpf.FileName));
hpf.SaveAs(savedFileName);
r.Add(new ViewDataUploadFilesResult()
{ Name = savedFileName,
Length = hpf.ContentLength });
}
return View("UploadedFiles",r);
}
I dont want this to exist in the controller. rather call it as a static method in a utils.cs class
is this possible?
Yes, but you'll need to pass your request object in to the function, as an outside library won't have access to it.
public void UploadFile(HttpRequestBase request) { ... }
Related
When posting an image, HttpContext.Current.Request is null.
Is there any simple way to achieve this? I am using dropzone.js on client side.
Project is Angular with Web API (ASP.NET Core 2.0) template.
[HttpPost]
public HttpResponseMessage UploadJsonFile()
{
HttpResponseMessage response = new HttpResponseMessage();
var httpRequest = HttpContext.Current.Request;
if (httpRequest.Files.Count > 0)
{
foreach (string file in httpRequest.Files)
{
var postedFile = httpRequest.Files[file];
var filePath = HttpContext.Current.Server.MapPath("~/UploadFile/" + postedFile.FileName);
postedFile.SaveAs(filePath);
}
}
return response;
}
This is the code which i had done it is working fine.
public void PostFile(IFormFile file)
{
var uploads = Path.Combine("ROOT PATH FOR THE FILES", "uploads");
if (file.Length > 0)
{
var filePath = Path.Combine(uploads, file.FileName);
using (var fileStream = new FileStream(filePath, FileMode.Create))
{
file.CopyTo(fileStream);
}
}
}
First of all we need to enable File Upload in Swagger using IOperationFilter. Create a class which inherits from IOperationFilter. For detail read this article
public class FormFileSwaggerFilter: IOperationFilter
{
private const string formDataMimeType = "multipart/form-data";
private static readonly string[] formFilePropertyNames =
typeof(IFormFile).GetTypeInfo().DeclaredProperties.Select(p => p.Name).ToArray();
public void Apply(Operation operation, OperationFilterContext context)
{
var parameters = operation.Parameters;
if (parameters == null || parameters.Count == 0) return;
var formFileParameterNames = new List<string>();
var formFileSubParameterNames = new List<string>();
foreach (var actionParameter in context.ApiDescription.ActionDescriptor.Parameters)
{
var properties =
actionParameter.ParameterType.GetProperties()
.Where(p => p.PropertyType == typeof(IFormFile))
.Select(p => p.Name)
.ToArray();
if (properties.Length != 0)
{
formFileParameterNames.AddRange(properties);
formFileSubParameterNames.AddRange(properties);
continue;
}
if (actionParameter.ParameterType != typeof(IFormFile)) continue;
formFileParameterNames.Add(actionParameter.Name);
}
if (!formFileParameterNames.Any()) return;
var consumes = operation.Consumes;
consumes.Clear();
consumes.Add(formDataMimeType);
foreach (var parameter in parameters.ToArray())
{
if (!(parameter is NonBodyParameter) || parameter.In != "formData") continue;
if (formFileSubParameterNames.Any(p => parameter.Name.StartsWith(p + "."))
|| formFilePropertyNames.Contains(parameter.Name))
parameters.Remove(parameter);
}
foreach (var formFileParameter in formFileParameterNames)
{
parameters.Add(new NonBodyParameter()
{
Name = formFileParameter,
Type = "file",
In = "formData"
});
}
}
}
Then Register this class in Startup.cs
services.AddSwaggerGen(options =>
{
// Swagger Configuration
// Register File Upload Operation Filter
options.OperationFilter<FormFileSwaggerFilter>();
});
Now Define a method as below in Service file,
public class ExampleAppService : // Inherit from required class/interface
{
public RETURN_TYPE UploadFile([FromForm]IFormFile file)
{
// Save file here
}
}
*** Don't forget to use [FromForm] in method parameter for uploading file, else you will get six more params in swagger ui.
Now, Generating Service file of angular using NSwag will require a parameter of type FileParameter. Now in component,
methodName = (file): void => {
// file is the selected file
this._service
.uploadDocument({ data: file, fileName: file.name } as FileParameter)
.subscribe((res) => {
// Handle Response
});
};
You cannot use app service for uploading image.
Just create a new controller and upload your file.
Return to client the unique filename that you generated in server.
When user saves the whole entity, send the unique filename to server again.
You can derive your controller from AbpController.
https://aspnetboilerplate.com/Pages/Documents/AspNet-Core?searchKey=AbpController
https://aspnetboilerplate.com/Pages/Documents/MVC-Controllers?searchKey=AbpController
first inject IHostingEnvironment to get server path
private IHostingEnvironment _environment;
then use it in the function
[HttpPost]
public void PostFile(IFormFile file)
{
string uploads = Path.Combine(_environment.WebRootPath, "uploads");
if (file.Length > 0)
{
var filePath = Path.Combine(uploads, file.FileName);
using (var fileStream = new FileStream(filePath, FileMode.Create))
{
file.CopyTo(fileStream);
}
}
}
public IEnumerable<IListFileItem> GetFilesInDirectory()
{
var directory = GetFileShareDirectory();
IEnumerable<IListFileItem> allFilesInDirectory = directory.ListFilesAndDirectories();
List<IListFileItem> allFiles = new List<IListFileItem>();
foreach (var file in allFilesInDirectory)
{
string[] fileType = file.GetType().ToString().Split('.');
string type = fileType[fileType.Length - 1];
if (type == "CloudFile")
{
allFiles.Add(file);
}
}
return allFiles;
}
This code returns all the files in the directory on fileshare on azure, is there any way I can change this to an array? The method I am trying to us wants an array. Please advice, Thank you
is there any way I can change this to an array?
If you want to get an array when call this method, you also need to change the return type to IListFileItem[] in addition to add ToArray method.
public IListFileItem[] GetFilesInDirectory()
{
var directory = GetFileShareDirectory();
IEnumerable<IListFileItem> allFilesInDirectory = directory.ListFilesAndDirectories();
List<IListFileItem> allFiles = new List<IListFileItem>();
foreach (var file in allFilesInDirectory)
{
string[] fileType = file.GetType().ToString().Split('.');
string type = fileType[fileType.Length - 1];
if (type == "CloudFile")
{
allFiles.Add(file);
}
}
return allFiles.ToArray();
}
I uploaded an image to server using form fileData:
[Route("upload")]
[HttpPost]
public async Task<HttpResponseMessage> Upload()
{
try
{
if (!Request.Content.IsMimeMultipartContent()) {
Request.CreateResponse(HttpStatusCode.UnsupportedMediaType);
}
var provider = GetMultipartProvider();
var result = await Request.Content.ReadAsMultipartAsync(provider);
//Get Album name from Form
var titleOfAlbum = GetTitleOfAlbum(provider);
//get path to file
var pathToCoverDecoded = result.FileData.First().LocalFileName;
//Encodeing to base 64 path
var bytes = Encoding.UTF8.GetBytes(pathToCoverDecoded);
var base64 = Convert.ToBase64String(bytes);
Album al = new Album();
al.Title = titleOfAlbum;
al.PathToCover = base64;
db.Albums.Add(al);
db.SaveChanges();
return new HttpResponseMessage(HttpStatusCode.OK);
}
catch (System.Exception e)
{
return Request.CreateErrorResponse(HttpStatusCode.InternalServerError, e);
}
}
private string GetDesereleazedFileName(MultipartFileData fileData)
{
var fileName = GetFileName(fileData);
return JsonConvert.DeserializeObject(fileName).ToString();
}
private string GetFileName(MultipartFileData fileData)
{
return fileData.Headers.ContentDisposition.FileName;
}
private MultipartFormDataStreamProvider GetMultipartProvider()
{
var uploadFolder = HttpContext.Current.Server.MapPath("~/Files");
if (Directory.Exists(uploadFolder) == false)
{
Directory.CreateDirectory(uploadFolder);
}
return new MultipartFormDataStreamProvider(uploadFolder);
}
private string GetTitleOfAlbum(MultipartFormDataStreamProvider provider)
{
var titleOfAlbum = "";
foreach(var key in provider.FormData.GetValues(0))
{
titleOfAlbum = key;
}
return titleOfAlbum;
}
}
Path looks like:
"C:\Users\Oops\Documents\Visual Studio 2015\Projects\WebApplication1\ForMyCustomers\WebApplication1\Files\BodyPart_b40d80c5-47dc-41db-8e35-9d39d4e27939"
I getting path from FileData:
and convert it to base64, but it doesn't displays at page
I've got File not found error.
How can I resolve it? if the URL is wrong how can I get correct one?
You cannot use physical path (the one you used) on web. The physical path like "C:\something" is the path that can be used only by your OS.
The URL however, is the path that you need and to use and to do that you need to put your files somewhere that is readable by your host (IIS).
You are already writing your files in "~/Files". so you just need to add the file name at the end.
var url= "~/Files/"+filename;
you need to save the file name when you are uploading your file so when you want to fetch data from DB, fetch the file name from DB and create the url using that.
How do I post a httppostedfile to a webapi?
Basically I want the user to select an excel file and I want to post it to my webapi.
The gui is made with classic asp.net and the webapi is made with new .NET apicontroller.
I have done some api coding before but then I used JSON and that doesn't seem to work very good with this kind of object.
Can someone please just point me in the right direction so that I can continue to search for info. Right now I don't even know what to search for.
I solved this by doing this:
In my controller:
using (var client = new HttpClient())
using (var content = new MultipartFormDataContent())
{
client.BaseAddress = new Uri(System.Configuration.ConfigurationManager.AppSettings["PAM_WebApi"]);
var fileContent = new ByteArrayContent(excelBytes);
fileContent.Headers.ContentDisposition = new ContentDispositionHeaderValue("attachment")
{
FileName = fileName
};
content.Add(fileContent);
var result = client.PostAsync("api/Product", content).Result;
}
And here is my ApiController:
[RoutePrefix("api/Product")]
public class ProductController : ApiController
{
public async Task<List<string>> PostAsync()
{
if (Request.Content.IsMimeMultipartContent())
{
string uploadPath = HttpContext.Current.Server.MapPath("~/uploads");
if (!System.IO.Directory.Exists(uploadPath))
{
System.IO.Directory.CreateDirectory(uploadPath);
}
MyStreamProvider streamProvider = new MyStreamProvider(uploadPath);
await Request.Content.ReadAsMultipartAsync(streamProvider);
List<string> messages = new List<string>();
foreach (var file in streamProvider.FileData)
{
FileInfo fi = new FileInfo(file.LocalFileName);
messages.Add("File uploaded as " + fi.FullName + " (" + fi.Length + " bytes)");
}
return messages;
}
else
{
HttpResponseMessage response = Request.CreateResponse(HttpStatusCode.BadRequest, "Invalid Request!");
throw new HttpResponseException(response);
}
}
}
public class MyStreamProvider : MultipartFormDataStreamProvider
{
public MyStreamProvider(string uploadPath)
: base(uploadPath)
{
}
public override string GetLocalFileName(HttpContentHeaders headers)
{
string fileName = headers.ContentDisposition.FileName;
if (string.IsNullOrWhiteSpace(fileName))
{
fileName = Guid.NewGuid().ToString() + ".xls";
}
return fileName.Replace("\"", string.Empty);
}
}
I found this code in a tutorial so i'm not the one to be credited.
So here i write the file to a folder. And because of the mysreamprovider i can get the same name of the file as the file i first added in the GUI. I also add the ending ".xls" to the file because my program is only going to handle excel files. Therefor i have added some validation to the input in my GUI to so that i know that the file added is an excel file.
I want to return a string from generic handler and get it into angularjs. My code is below.
Generic handler:
public void ProcessRequest(HttpContext context)
{
List<string> path= new List<string>();
if (context.Request.Files.Count > 0)
{
HttpFileCollection files = context.Request.Files;
for (int i = 0; i < files.Count; i++)
{
HttpPostedFile file = files[i];
string fname = context.Server.MapPath("~/upload/" + file.FileName);
//file.SaveAs(fname);
path.Add(fname);
}
}
string abc = path[0].ToString();
context.Response.ContentType = "text/plain";
context.Response.Write(abc);
}
Angularjs Controller:
$scope.uploadFile = function () {
var fd = new FormData()
for (var i in ScopGloble.files) {
// alert("hi I am in");
fd.append("uploadedFile", $scope.files[i])
}
var xhr = new XMLHttpRequest()
xhr.open("POST", "FileuploadTask.ashx")
ScopGloble.progressVisible = true
xhr.send(fd)
//How I can get file path here.
}
How I can get file path.
You want the XHR object's responseText.
However, you can't get it where you have the comment, since XMLHttpRequest is typically asynchronous. You'd need something like
//before we send the request
xhr.onload = function(xhrEventArgs) {
var ThePath = xhr.responseText;
//do something with that string
};
//now, send the request
xhr.send(fd);
You should probably check the request status in there too. See the MDN XHR documentation for more info on that.