How to display images from local disk in mvc4? - c#

In my MVC(4) application, I'm fetching the image files from the local directory and displaying it in the browser.
I've a model to store the details,and a controller to get the files and a view to display them.
Model
public class ImageModel
{
List<string> _images = new List<string>();
public ImageModel()
{
_images = new List<string>();
}
public List<string> Images
{
get { return _images; }
set { _images = value; }
}
}
Controller
public ActionResult Index()
{
var imageFiles = new ImageModel();
imageFiles.Images.AddRange(Directory.GetFiles(#"c:\mypath"));
return View(imageFiles);
}
View
#for (int imgIndex = 0; imgIndex < Model.Images.Count; imgIndex++)
{
<div >
<img src = #Model.Images[imgIndex] alt="Image" />
</div>
}
But I can not view the images in the browser, its showing empty boxes with alt.
What did I miss here? Should I create a virtual directory instead of physical location.

First, local files require the file:// URI scheme. You seem to use the native file path as img src.
But the browser security model forbids the use of local source from inside a page served by a web server (http://, https:// protocols).
To fix your situation, the implement a controller that take the desired image file name as parameter, and serve its content using the File() action.

The problem is your path names. This might help:
Controller:
public ActionResult Index()
{
var imageFiles = new ImageModel();
imageFiles.Images.AddRange(System.IO.Directory.GetFiles(#"C:\wherever\files\are\"));
for (int i = 0; i < imageFiles.Images.Count; i++)
{
// get rid of the fully qualified path name
imageFiles.Images[i] = imageFiles.Images[i].Replace(#"C:\wherever\files\are\", "");
// change the slashes for web
imageFiles.Images[i] = imageFiles.Images[i].Replace('\\','/');
}
return View(imageFiles);
}
View:
#for (int imgIndex = 0; imgIndex < Model.Images.Count; imgIndex++)
{
<div >
<img src = "#Model.Images[imgIndex]" /> <!-- put the file in quotes -->
</div>
}

looking at the code snippet, it seems to me that you forgot to surround the path with quotes
<img src = "#Model.Images[imgIndex]" alt="Image" />
but looking at the overall code, i would recommend to use relative paths.
UPD:
For a more detailed explanation, i would recomentd this blog post

Related

Request.Files is empty when files come through as an array

I'm doing some integration with a third party form builder software that allows the form to be posted to our own server. The form data and files are then saved to a DB. The issue is when the form contains multiple file upload fields, Request.Files is always empty.
Using Fiddler, I can see the binary files coming through. The only thing that I can think of is that the field name contains brackets in them (because it's being sent as an array) and so the model binder can't bind it properly? The field names that are coming through are tfa_20[0] and tfa_20[1].
Code-wise, it's pretty standard stuff:
var data = new Submission()
{
ConfigurationDetailId = configDetail.Id,
SubmitterEmail = submitterEmail,
SubmissionData = Request.Form.AllKeys.Select(k => new SubmissionData()
{
FieldName = k,
FieldValue = Request.Form[k]
}).ToList(),
SubmissionFiles = new List<SubmissionFile>()
};
// process any files uploaded
if (Request.Files.Count > 0)
{
foreach (string field in Request.Files)
{
var uploadedFile = Request.Files[field];
if (!string.IsNullOrEmpty(fileName))
{
data.SubmissionFiles.Add(GetSubmissionFile(uploadedFile, fileName));
}
}
}
Repository.SaveForm(data);
Any help would greatly be appreciated.
Use HttpPostedFileBase in order to get posted file to your action. in case of multiple files,should be used an HttpPostedFileBase[] array.
To Enable uploading in forms, is necessary to add enctype="multipart/form-data" to your form tag. or if you use razor syntax change your beginForm tag to this.
View.cshtml
#using (Html.BeginForm("action","controller", FormMethod.Post, new { #enctype =
"multipart/form-data" }))
{
}
public ActionResult YourAction(HttpPostedFileBase[] files)
{
var data = new Submission()
{
ConfigurationDetailId = configDetail.Id,
SubmitterEmail = submitterEmail,
SubmissionData = Request.Form.AllKeys.Select(k => new SubmissionData()
{
FieldName = k,
FieldValue = Request.Form[k]
}).ToList(),
SubmissionFiles = new List<SubmissionFile>()
};
if (files.Length > 0)
{
foreach (HttpPostedFileBase file in files)
{
var uploadedFile = file;
if (!string.IsNullOrEmpty(file.FileName))
{
data.SubmissionFiles.Add(GetSubmissionFile(uploadedFile, file.fileName));
}
}
}
return View();
}

NullReferenceException accessing ViewModel containing FileInfo instances

I don't think my question is unique but I will ask as there might be some peculiarities with regards to my question. I have a Business Model that loads files from a folder with and displays them on a webpage for editing and other desired operations. My controller calls on this model like so:
This is the method that handles the listing of files and returns an enumeration of fileinfo objects
public IEnumerable<FileInfo> ListUploadedFiles(HttpContextBase htc)
{
//list all the files from the upload directory
var path = htc.Server.MapPath("~/FileUpload");
var di = new DirectoryInfo(path);
return di.EnumerateFiles();
}
This is the code in the controller action that should populate a viewmodel and pass the viewmodel a view which is where I am having a bit of an issue.
var viewmodel = new List<UploadedImageViewModel>();
var files = uploader.ListUploadedFiles(context);
foreach (var item in files)
{
viewmodel.Add(new UploadedImageViewModel()
{
ImageName = item.Name,
CreatedOn = item.CreationTime,
ImageSize = item.Length,
FileType = item.Extension
});
}
return View("ListFiles", viewmodel);
Now in my view I do this to list out the desired properties on the view:
#using SeeSite.Models
#model IEnumerable<UploadedImageViewModel>
#{
ViewBag.Title = "Upload";
}
#foreach(UploadedImageViewModel items in Model)
{
<li>#items.ImageName <span>Details</span>
<span>Rename</span>
</li>
}
but I keep getting an exception:
System.NullReferenceException: Object reference not set to an instance
of an object.
And points to the line where my foreach begins. Now just to clear things up, if I use ViewBag it works fine though I can only access the details of one file, but using a viewmodel just doesn't work. Been stuck here for a whole day and don't want to waste anymore time. What could be wrong?!
Oh and if I do this in the view:
#foreach (var dir in new DirectoryInfo(Server.MapPath("~/FileUpload"))
.EnumerateFiles())
{
<li>#dir.Name <span>|</span>Details
<span>|</span> Rename</li>
}
it works. So am I missing something here or is this the best solution to do what I am trying to do?

Null Reference Exception while uploading a file in MVC 5

I am developing CMS for a website using MVC 5 and Entity Framework. I have an edit form for editing the events added in the database table. I am uploading the image related to Event in a server folder and storing its URL in database.
Now I want to replace the
#Html.EditorFor(model => model.Image_Url, new { htmlAttributes = new { #class = "form-control" } })
with a input with type File, so that anyone can change the image while editing the Event information. for this I have added following.
A Picture Class
public class Pictures
{
public HttpPostedFileBase File { get; set; }
}
for File Uploading in Edit Action Method of controller
if (picture.File.ContentLength > 0)
{
var fileName = Path.GetFileName(picture.File.FileName);
var path = Path.Combine(Server.MapPath("~/assets/uploads/events/"), fileName);
picture.File.SaveAs(path);
filePath = "~/assets/uploads/events/" + fileName;
}
and finaly in Edit view
<input type="file" id="File" name="File" class="form-control" />
The above logic work perfectly fine when used in Create action method, but when I use the same in edit action method the Null reference exception occur. While debugging I found that the picture.File parameter is null at line if (picture.File.ContentLength > 0).
This is working fine in Create but in Edit action method it returns null.
Any Help on this issue?
I have done it by using Request.Files. below is my code in controller Edit action method.
foreach(string fileName in Request.Files)
{
HttpPostedFileBase file = Request.Files[fileName];
fName = file.FileName;
if (file != null && file.ContentLength > 0)
{
var orgDirectory = new DirectoryInfo(Server.MapPath("~/assets/uploads"));
string pathString = System.IO.Path.Combine(orgDirectory.ToString(),"events");
var fileName1 = Path.GetFileName(file.FileName);
bool isExists = System.IO.Directory.Exists(pathString);
if(!isExists)
{
System.IO.Directory.CreateDirectory(pathString);
}
var path = string.Format("{0}\\{1}", pathString, file.FileName); //pathString + file.FileName;
file.SaveAs(path);
}
}
This issue could occur because of general security rules for the <input type="file" /> as you can't set a value for it. So I think the only thing you can do is a create separate view for the re-creating the image for the profile, and each time user sends a picture to you treat is a new one.

Addressing an images in View with its local path

How to display this image in an ASP.NET MVC project?
I've tried this, but it wouldn't work:
<img src="C:\BBBB\1.png" />
Any brilliant suggestion, please?
Thanks a lot!
I did something similar to this to display payroll stubs. I didn't want them accessible from within wwwroot.
See this article for serving an image from an mvc action.
ASP.NET MVC3: Image loading through controller
public ActionResult ShowImage(id)
{
var file = #"C:\BBB\"+id;
var ext = file.Split('.').Last();
return File(file, "image/"+ext, Path.GetFileName(file));
}
Call it like this:
<img src="#Url.Action("ShowImage",new { id="1.png" })" alt="1.png"/>
For a loop, you could do something like this in your existing view:
for (var i = 1; i < 10; i++ ) {
#Html.Partial("ShowIfExists", new {id=i.ToString()+".png" })
}
Create a new Razor View called _ShowIfExists.cshtml
<img src="#Url.Action("ShowImage",new { id=Model })" alt="1.png"/>
And add a corresponding action:
public ActionResult ShowIfExists(id)
if ( System.IO.File.Exists(#"C:\BBB\"+id) )
return PartialView("_ShowIfExists",null,id);
}
return new EmptyResult();
}
The image tag's src needs to point to where the image resides on a web server.
<img src="http://myserver.com/myimage.png" />
You need to reference images with relative address like this: ../images/1.png.
check this tutorial to start: W3schools Html Tutorial/img Tag
If you insist on displaying a local image, you should include the protocol, which in this case is file://:
<img src="file://C:/BBBB/1.png" />
This is not a good idea for real projects tho.

Create Hyperlinks from controller in asp.net MVC

I have a controller, which creates breadcrumbs as follows:
Software > Windows 7 > Outlook 2007
The code to create this is:
ViewBag.breadcrumbs = string.Join(" > ", cbh.Select(i => i.Title));
Is there a straightforward way of making the breadcrumbs hyperlinks, which would point to (i.ParentID) ie:
Software -> forum/index/12
Windows 7 -> forum/index/19
Outlook 2007 -> forum/index/23
Or should I just loop through cbh and manually build <a href=...> strings, and pass those to the view?
Thank you,
Mark
Your best bet is to put the required items into the model then loop through them.
Try something like this:
Model
public class Model
{
public struct BreadCrumb
{
public string Title;
public string Url;
}
public List<BreadCrumb> Breadcrumbs { get; set; }
}
View
#{ int index = 0; }
#foreach(var crumb in this.Model.Breadcrumbs)
{
#(crumb.Title)
if(index < this.Model.Breadcrumbs.Count - 1)
{
<span>></span>
}
index++;
}
Yes, you should build your breadcrumb links in the view. If it helps, you can create a BreadCrumbModel class (if you don't already have one).
ViewBag.breadcrumbs = cbh.Select(i => new BreadCrumbModel()
{
Id = i.Id,
Title = i.Title
});
#{
var printSeparator = false;
}
#foreach(BreadCrumbModel bc in ViewBag.breadcrumbs)
{
#if(printSeparator)
{
<span class="breadcrumb-separator"> > </span>
}
<span class="breadcrumb">
#Html.ActionLink(bc.Title, "index", "forum", new { id = bc.Id });
</span>
#{
printSeparator = true;
}
}
If you want to have breadcrumbs between different controllers and actions (not just forum / index), then add those as properties of your BreadCrumbModel.

Categories

Resources