I am trying to implement a simple file upload, but having some troubles. When I hard-code the path it works fine. But for some reason, when I try to use a file upload, the controller name is being appended to the path
Hard coded path (what I'm trying to get):
#"C:\Users\Scott\Documents\The Business\MasterSpinSite\MasterSpin\MasterSpin\LOADME.txt"
Path I am getting an exception with (notice the "appz" controller name):
C:\Users\Scott\Documents\The Business\MasterSpinSite\MasterSpin\MasterSpin\appz\LOADME.txt'
My Controller
public ActionResult Load(spinnerValidation theData, HttpPostedFileBase file)
{
if (file.ContentLength > 0)
{
string filePath = Request.MapPath(file.FileName);
string input = System.IO.File.ReadAllText(filePath);
string[] lines = Regex.Split(input, "#!#");
// ...... do stuff
}
My View
<form action="" method="post" enctype="multipart/form-data">
<label for="file">Filename:</label>
<input type="file" name="file" id="file" />
<input type="submit" value="LOAD ME!">
</form>
What could be causing this behavior ?
You can save yourself the effort of the streams:
string filename = Request.Files["file"].FileName;
string filePath = Path.Combine(Server.MapPath("~/YourUploadDirectory"), filename);
HttpPostedFileBase postedFile = Request.Files["file"] as HttpPostedFileBase;
postedFile.SaveAs(filePath);
string input = File.ReadAllText(filePath);
try this:
public ActionResult Load(spinnerValidation theData, HttpPostedFileBase file)
if (file.ContentLength > 0)
{
var filePath = System.IO.Path.GetFileName(file.FileName);
using (System.IO.StreamReader sr = new System.IO.StreamReader(filePath))
{
var input = sr.ReadToEnd();
var lines = Regex.Split(input, "#!#");
}
}
}
(bug) System.IO.Path.GetFileName(file.FileName) return the name of file
Edit
change System.IO.Path.GetFileName(file.FileName) for Server.MapPath(file.FileName)
public ActionResult Load(spinnerValidation theData, HttpPostedFileBase file)
if (file.ContentLength > 0)
{
var filePath = Server.MapPath(file.FileName);
using (System.IO.StreamReader sr = new System.IO.StreamReader(filePath))
{
var input = sr.ReadToEnd();
var lines = Regex.Split(input, "#!#");
}
}
}
Edit II
or copy to diferent path:
public ActionResult Load(spinnerValidation theData, HttpPostedFileBase file)
if (file.ContentLength > 0)
{
var fileName = System.IO.Path.GetFileName(file.FileName);
var fileUpload = Path.Combine(Server.MapPath("~/App_Data/uploads"), fileName);
file.SaveAs(fileUpload);
if (System.IO.File.Exists(fileUpload))
{
using (System.IO.StreamReader sr = new System.IO.StreamReader(fileUpload))
{
var input = sr.ReadToEnd();
var lines = Regex.Split(input, "#!#");
}
}
}
}
Related
I have a problem with the index page. On this index page, we can see the uploaded Ad details like Ad title, description, and link except for the uploaded image. When I inspect i can see
<img src="/images/Ad/ad2.png" width="50px" height="50px">
On the index page, i use this code
<td>
<img src="#Url.Content(String.Format("/images/Ad/{0}",item.ImagePath))" width="50px" height="50px" />
</td>
This is my Controller
public IActionResult Create([Bind("AdID,Title,ImagePath,Description,Link")] AdTbl adTbl, List<IFormFile> FormFile)
{
if (FormFile != null && FormFile.Count > 0)
{
string folderName = "images/Ad";
string webRootPath = _hostingEnvironment.WebRootPath;
string newPath = Path.Combine(webRootPath, folderName);
if (!Directory.Exists(newPath))
{
Directory.CreateDirectory(newPath);
}
foreach (IFormFile item in FormFile)
{
if (item.Length > 0)
{
string fileName = ContentDispositionHeaderValue.Parse(item.ContentDisposition).FileName.Trim('"');
string fullPath = Path.Combine(newPath, fileName);
adTbl.AdID = Guid.NewGuid();
adTbl.ImagePath = fileName;
using (var stream = new FileStream(fullPath, FileMode.Create))
{
item.CopyTo(stream);
}
_adTblRepository.CreateAd(adTbl);
}
}
_notyf.Success("Advertisement added successfully");
return RedirectToAction(nameof(Index));
}
return View(adTbl);
}
**The main thing is that the same code is using on different pages and that's worked. And I noticed that one thing when we change the location this problem occurs again
I'm trying to save images and videos to a separate folder and not in the database, as from what I read it is best practice not to store there. I am able to take in the photo, then save the URL string to the database. Files are saving to the correct location.
After I pull up the view to display the image, it's not showing up. I can see it is a broken link. But not sure how to correct it.
The controller:
[HttpPost]
public IActionResult AddPost(AddPostViewModel addPost, IFormFile file)
{
//Setting the extra data need for the post
addPost.post.DateModified = DateTime.Now;
addPost.post.DatePosted = DateTime.Now;
//Saving the image to a location
SaveImage saveImage = new SaveImage();
Task<String> filePath = saveImage.UploadFile(file);
addPost.post.PostImageVideo = filePath.Result;
//Adding and saving the post to the database and then returning to the admin panel.
_context.Post.Add(addPost.post);
_context.SaveChanges();
ViewBag.SessionUserFirstName = HttpContext.Session.GetString("UserFirstName");
ViewBag.isAdmin = HttpContext.Session.GetString("IsAdmin");
return RedirectToAction("AdminPanel");
}
The medthod being called to save the image:
public async Task<String> UploadFile(IFormFile file)
{
var fileName = "";
var filePath = "";
//adding the filepath to the database and saving the path.
if (file != null && file.Length > 0)
{
fileName = Path.GetFileName(file.FileName);
filePath = Path.Combine(Directory.GetCurrentDirectory(),#"~/wwwroot/images/", fileName);
using (var fileStream = new FileStream(filePath, FileMode.Create))
{
await file.CopyToAsync(fileStream);
}
}
return filePath.ToString();
}
Then the view that pulls in the link from the entity or pulling from database
#{
ViewData["Title"] = "Post";
}
<div class="container">
<div class="row">
<div class="col-md-12 text-center">
<h1>#Model.post.Title</h1>
</div>
</div>
<div class="row">
<!--This is grabbing the link for the post.-->
<img src="#Model.post.PostImageVideo" />
<div class="col-md-12">
<p>#Model.post.Body</p>
</div>
</div>
</div>
It seems like when I look at the link, it isn't grabbing the wwwroot folder that it is located in, it just goes right into the images. Not sure how to correct it.
I think I have it:
When I called the saveImage method I was returning the filepath. I had it return the filename and put in and additional string in front to save to the database like so:
addPost.post.PostImageVideo = "/images/" + fileName.Result;
Whether that is the correct way or not, not sure, but it works.
You may use FileContentResult to return the image as file to view.
public class ImageController : Controller
{
private readonly IHostingEnvironment _appEnvironment;
public ImageController(IHostingEnvironment appEnvironment)
{
_appEnvironment = appEnvironment;
}
public IActionResult Index()
{
return View();
}
public FileContentResult ShowImage()
{
string fileName = Path.Combine(_appEnvironment.WebRootPath, "images\\avatar.png").Replace("\\", "/");
byte[] imageData = null;
FileInfo fileInfo = new FileInfo(fileName);
long imageFileLength = fileInfo.Length;
FileStream fs = new FileStream(fileName, FileMode.Open, FileAccess.Read);
BinaryReader br = new BinaryReader(fs);
imageData = br.ReadBytes((int)imageFileLength);
return File(imageData, "image/png");
}
}
View..
<img src="#Url.Action("ShowImage", "Image", new { area = "" })" class="user-image" alt="User Image">
I'm creating a page with multiple file uploader in MVC.
What I want to achieve is when I submit values the images uploaded should be named as guid and an incrementing i value, like guid0 , guid1, guid2. I tried for loop but its saving only one image until loop ends . i++ isn't working though.
My controller looks like this:
public ActionResult Home(SomeClass someclass, IEnumerable<HttpPostedFileBase> files)
{
var guid = Guid.NewGuid().ToString();
someclass.filename = guid;
int i = 0;
foreach (var file in files)
{
if (file.ContentLength > 0)
{
var fileName = guid + "" + i + ".jpg";
var path = Path.Combine(Server.MapPath("~/Content/admin/Upload"), fileName);
file.SaveAs(path);
i++;
}
}
db.someclasses.Add(someclass);
db.SaveChanges();
return RedirectToAction("Preview");
}
And my view looks like this
<input type="file" name="files" id=1>
<input type="file" name="files" id=2>
Update : I'm receiving 11 files at the if loop but once they go through the loop there is only single image in the images folder named fdea36c3-545a-4e08-8af4-7fa6bd88bc6b0 . what i'm trying to achieve is all 11 images named as fdea36c3-545a-4e08-8af4-7fa6bd88bc6b0, fdea36c3-545a-4e08-8af4-7fa6bd88bc6b1,fdea36c3-545a-4e08-8af4-7fa6bd88bc6b2.....so on .
Well, I am not very familiar with HTML inputs, but I think you should use "multiple" attribute in you SINGLE file input tag.
Or rename "files" to "files[]".
Look at this
try this way if you have multiple file controls on view.
you can even have Guid initialized for each file and can ignore appending i to the name.
public class MultipleFilesForm
{
public HttpPostedFileBase file1 {get;set;}
public HttpPostedFileBase file2 {get;set;}
}
action method as
public ActionResult Home(MultipleFilesForm form)
{
var guid = Guid.NewGuid().ToString();
someclass.filename = guid;
int i = 0;
if(form.file1 != null)
{
var file = form.file1;
if (file.ContentLength > 0)
{
var fileName = guid + i.ToString() + Path.GetExtension(file.FileName));
var path = Path.Combine(Server.MapPath("~/Content/admin/Upload"), fileName);
file.SaveAs(path);
i++;
}
}
if(form.file2 != null)
{
//handle file
}
...
}
[UPDATE]
try this way
try this as well.
for (int i = 0; i < Request.Files.Count; i++)
{
var file = Request.Files[i];
if (file != null && file.ContentLength > 0)
{
var fileName = guid + i.ToString() + Path.GetExtension(file.FileName));
var path = Path.Combine(Server.MapPath("~/Content/admin/Upload"), fileName);
file.SaveAs(path);
i++;
}
}
I have a kendo ui async file upload with the following options on my view.
<div class="demo-section">
#(Html.Kendo().Upload()
.Name("files")
.Async(a => a
.Save("Save", "Upload")
.AutoUpload(true)
)
)
</div>
In the corresponding action method ,I would like to set my model's properties for filename .Shown below is what i have currently .
public ActionResult Save(IEnumerable<HttpPostedFileBase> files)
{
// The Name of the Upload component is "files"
if (files != null)
{
foreach (var file in files)
{
// Some browsers send file names with full path.
// We are only interested in the file name.
var fileName = Path.GetFileName(file.FileName);
var physicalPath = Path.Combine(Server.MapPath("~/App_Data"), fileName);
// The files are not actually saved in this demo
// file.SaveAs(physicalPath);
}
}
// Return an empty string to signify success
return Content("");
}
If there is a way to do it ,please let me know ..
public ActionResult Save(IEnumerable<HttpPostedFileBase> files)
{
var savedFilePaths = new List<string>();
var applicationPath = System.Web.HttpContext.Current.Request.Url.Scheme + "://" + System.Web.HttpContext.Current.Request.Url.Authority + System.Web.HttpContext.Current.Request.ApplicationPath + "/Content/Images/Others/";
// The Name of the Upload component is "files"
if (files != null)
{
foreach (var file in files)
{
// Some browsers send file names with full path.
// We are only interested in the file name.
var fileName = Path.GetFileName(file.FileName);
if (fileName != null)
{
fileName = DateTime.Now.ToString("yyyyMMddmm-") + fileName;
var physicalPath = Path.Combine(Server.MapPath("~/Upload/Hotel"), fileName);
file.SaveAs(physicalPath);
savedFilePaths.Add(applicationPath + fileName);
}
}
}
// Return an empty string to signify success
return Content("");
}
this is my code in controller
public ActionResult UploadFiles(IEnumerable<HttpPostedFileBase> files)
{
string TempPath = Server.MapPath("~/TempImages/");
foreach (HttpPostedFileBase file in files)
{
string filePath = Path.Combine(TempPath, file.FileName);
Tempdata["paths"] =filePath;
}
}
how in insert every time the path and get it as array / arraylist ?
update:
this is what really goes on for every image readed this action is running
public ActionResult UploadFiles(IEnumerable<HttpPostedFileBase> files)
{
if (!Directory.Exists(Server.MapPath("~/TempImages/")) || files !=null)
{
string TempPath = Server.MapPath("~/TempImages/");
List<string> paths = new List< String> ();
foreach (HttpPostedFileBase file in files)
{
string filePath = Path.Combine(TempPath, file.FileName);
System.IO.File.WriteAllBytes(filePath, ReadData(file.InputStream));
file.SaveAs(filePath);
paths.Add(filePath);
TempData["paths"] = paths;
}
}
return view();
}
Can you not just do
public ActionResult UploadFiles(IEnumerable<HttpPostedFileBase> files)
{
List<string> paths = new List<string>();
foreach (HttpPostedFileBase file in files)
{
string filePath = Path.Combine(TempPath, file.FileName);
paths.Add (filePath);
}
Tempdata["paths"] = paths;
}