Save file names in database after uploaded, using plupload and mvc3 - asp.net-mvc

I am trying to save the name of each individual file in a database after they have been uploaded. I have this code that successfully uploads the files.
$(function () {
$("#uploader").plupload({
// General settings
runtimes: 'silverlight,flash,html5',
url: '#Url.Content( "~/FileUploadChunks/UploadChunk" )',
max_file_size: '10mb',
chunk_size: '1mb',
unique_names: true,
// Flash settings
flash_swf_url: '/plupload/js/plupload.flash.swf',
// Silverlight settings
silverlight_xap_url: '/plupload/js/plupload.silverlight.xap'
});
});
This is the Controller
[HttpPost]
public ActionResult UploadChunk(int? chunk, int chunks, string name)
{
var fileUpload = Request.Files[0];
var uploadpath = Server.MapPath("~/App_Data/UploadedFiles");
chunk = chunk ?? 0;
using (var fs = new FileStream(Path.Combine(uploadpath, name), chunk == 0 ? FileMode.Create : FileMode.Append))
{
var buffer = new byte[fileUpload.InputStream.Length];
fileUpload.InputStream.Read(buffer, 0, buffer.Length);
fs.Write(buffer, 0, buffer.Length);
}
return Content("chunk uploaded", "text/plain");
}
Just to test, I tried something like this to try to capture the name and add them to a list to return to the view, but I cannot figure out how to print out the list in the view to see its contents.
[HttpPost]
public ActionResult UploadChunk(int? chunk, int chunks, string name)
{
var fileUpload = Request.Files[0];
var uploadpath = Server.MapPath("~/App_Data/UploadedFiles");
chunk = chunk ?? 0;
using (var fs = new FileStream(Path.Combine(uploadpath, name), chunk == 0 ? FileMode.Create : FileMode.Append))
{
var buffer = new byte[fileUpload.InputStream.Length];
fileUpload.InputStream.Read(buffer, 0, buffer.Length);
fs.Write(buffer, 0, buffer.Length);
}
List<string> list = new List<string>();
foreach (string inputTagName in Request.Files)
{
HttpPostedFileBase file1 = Request.Files[inputTagName];
if (file1.ContentLength > 0)
{
list.Add(file1.FileName);
}
}
ViewBag.List = list;
}
Ultimately I am just trying to loop through the names and save them in a database. Any help is appreciated. Thanks

You didn't give any information about you database, etc. for us to provide you with good help. However I'll give it a shot.
To answer your other question,
I tried something like this to try to capture the name and add them to
a list to return to the view, but I cannot figure out how to print out
the list in the view to see its contents.
In your view, something like this should show them:
#foreach (string fileName in ViewBag.List)
{
#fileName
<br />
}
Assuming your using Entity Framework Code Fist, to save the file name to your database you need to have a model.
public class UploadedFileName
{
public int Id { get; set; }
public string Name { get; set; }
}
then in your controller you can alter the foreach statement you used to something like this:
foreach (HttpPostedFile file in Request.Files)
{
if (file.ContentLength > 0)
{
UploadedFileName uploadedFile = new UploadedFileName();
uploadedFile.Name = file.FileName;
databaseContext.UploadedFileNames.Add(uploadedFile);
}
}
The HttpPostedFile above may need to be HttpPostedFileBase, if you have an error. And the databaseContext is your database context, usually it is db.

Related

MVC Form with Sitecore File Post through Form returns Null

For the possible duplicate, I already know how to preview my image before uploading it, my issue as detailed below is that when I submit the Form, the image is being received as null.
I am trying to submit a form to an MVC controller that should submit a model, a string, and an Image File,
I made sure that the input has the same name as the parameter within the controller
Following is the Form Initialization code
#using (Html.BeginRouteForm(Sitecore.Mvc.Configuration.MvcSettings.SitecoreRouteName,
new
{
calendar = System.Convert.ToString(Request.QueryString["calendar"]),
ID = System.Convert.ToString(Request.QueryString["id"])
},
FormMethod.Post, new { enctype = "multipart/form-data" }))
{
//Model Input
<input style="opacity: 0;" name="EventImage" type="file" accept="image/jpeg, image/jpg" id="ImageUpload" onchange="readURL(this);" />
}
And the Controller Header
[HttpPost]
[ValidateInput(false)]
public ActionResult AddEvent(Event model, string calendar, HttpPostedFileBase EventImage)
The EventImage Parameter is being returned null and I can't seem to figure out why.
I thought that the ID might be causing the problem so I changed the name attribute to ImageUpload as well as the Parameter within the controller but to no avail as the value is still null.
Additional Info: when a User uploads an image, I let them preview it in an Image box, could that be causing it?
Thanks,
Update:
Here is the code for the readURL function
function readURL(input) {
if (input.files && input.files[0]) {
var ImageCorrect = false;
var file = input.files[0];
var reader = new FileReader();
reader.onload = function (e) {
// Concatenate our HTML image info
var ext = file.name.match(/\.([^\.]+)$/)[1];
switch (ext) {
case 'jpg':
case 'jpeg':
case 'JPG':
case 'JPEG':
{
if ((Math.round(file.size / 1024)) > 500) {
alert('Image is too Large');
}
else {
var image = new Image();
image.src = e.target.result;
image.onload = function () {
var width = parseInt(image.width);
if (width <= 500) {
$('#previewImage').attr('src', e.target.result);
$('#previewImage').show();
}
else {
alert('Image width exceeds maximum width');
}
}
}
}
break;
default:
alert('Image type not allowed')
}
}
reader.readAsDataURL(input.files[0]);
}
}
If I understood your question right you are trying to submit a file from your form to your controller and you get null in the controller.
I did this before, check the following:
cshtml (you can add your attributes to event image like JS call...etc ):
<div class="form-group">
#Sitecore.Globalization.Translate.Text("EventImage")<br>
#Html.TextBoxFor(m => m.EventImage, new { type = "file" })
</div>
Model:
[Display(Name = "Event Image")]
public HttpPostedFileBase EventImage { get; set; }
Controller Signature:
[HttpPost]
[ValidateInput(false)]
public ActionResult AddEvent(Event model)
Catching the Image field:
if (model.EventImage != null && model.EventImage.ContentLength > 0)
{
var fileName = Path.GetFileName(model.EventImage.FileName);
var tempPath = Server.MapPath("~/Temp/uploads");
var path = Path.Combine(tempPath, fileName);
if (!Directory.Exists(tempPath))
Directory.CreateDirectory(tempPath);
model.EventImage.SaveAs(path);
Sitecore.Resources.Media.MediaCreatorOptions options = new Sitecore.Resources.Media.MediaCreatorOptions();
options.FileBased = false;
options.IncludeExtensionInItemName = false;
options.KeepExisting = false;
options.Versioned = false;
options.Destination = "/sitecore/media library/Images/" + ItemUtil.ProposeValidItemName(Path.GetFileName(path));
options.Database = Sitecore.Configuration.Factory.GetDatabase(MasterDatabase);
// Now create the file
Sitecore.Resources.Media.MediaCreator creator = new Sitecore.Resources.Media.MediaCreator();
MediaItem mediaItem = creator.CreateFromFile(path, options);
ImageField _eventImage = (ImageField)_event.Fields[EventImage];
_eventImage.MediaID = mediaItem.ID;
PublishItem(mediaItem);
}

Download file from link inside my webpage

I have Webpage with table of objects.
One of my object properties is the file path, this file is locate in the same network. What i want to do is wrap this file path under link (for example Download) and after the user will click on this link the file will download into the user machine.
so inside my table:
#foreach (var item in Model)
{
<tr>
<th width ="150"><p><b>Download</b></p></th>
<td width="1000">#item.fileName</td>
<td width="50">#item.fileSize</td>
<td bgcolor="#cccccc">#item.date<td>
</tr>
}
</table>
I created this download link:
<th width ="150"><p><b>Download</b></p></th>
I want this download link to wrap my file path and click on thie link will lean to my controller:
public FileResult Download(string file)
{
byte[] fileBytes = System.IO.File.ReadAllBytes(file);
}
What i need to add to my code in order to acheive that ?
Return FileContentResult from your action.
public FileResult Download(string file)
{
byte[] fileBytes = System.IO.File.ReadAllBytes(file);
var response = new FileContentResult(fileBytes, "application/octet-stream");
response.FileDownloadName = "loremIpsum.pdf";
return response;
}
And the download link,
Download
This link will make a get request to your Download action with parameter fileName.
EDIT: for not found files you can,
public ActionResult Download(string file)
{
if (!System.IO.File.Exists(file))
{
return HttpNotFound();
}
var fileBytes = System.IO.File.ReadAllBytes(file);
var response = new FileContentResult(fileBytes, "application/octet-stream")
{
FileDownloadName = "loremIpsum.pdf"
};
return response;
}
In the view, write:
Download
In the controller, write:
public FileResult DownloadFile(string file)
{
string filename = string.Empty;
Stream stream = ReturnFileStream(file, out filename); //here a backend method returns Stream
return File(stream, "application/force-download", filename);
}
This example works fine for me:
public ActionResult DownloadFile(string file="")
{
file = HostingEnvironment.MapPath("~"+file);
string contentType = "application/vnd.openxmlformats-officedocument.spreadsheetml.sheet";
var fileName = Path.GetFileName(file);
return File(file, contentType,fileName);
}
View:
< script >
function SaveImg()
{
var fileName = "/upload/orders/19_1_0.png";
window.location = "/basket/DownloadFile/?file=" + fileName;
}
< /script >
<img class="modal-content" id="modalImage" src="/upload/orders/19_1_0.png" onClick="SaveImg()">

asp.net mvc 4 with jquery-file-upload Request.Files.Count always 0

I'm currently use asp.net mvc 4 ,and use jquery-file-upload to upload images,if i initialize like this:
$('#fileupload').fileupload();
$('#fileupload').fileupload('option', {
//url: '/Admin/News/Create',
maxFileSize: 500000000,
acceptFileTypes: /(\.|\/)(gif|jpe?g|png)$/i,
maxNumberOfFiles: 1,
resizeMaxWidth: 1920,
resizeMaxHeight: 1200,
});
when select a image file,the image can preview in the borwser,but in the mvc Action Request.Files.Count is 0,that means no file uploaded.
And if i initialize like this:
//$('#fileupload').fileupload();
$('#fileupload').fileupload('option', {
//url: '/Admin/News/Create',
maxFileSize: 500000000,
acceptFileTypes: /(\.|\/)(gif|jpe?g|png)$/i,
maxNumberOfFiles: 1,
resizeMaxWidth: 1920,
resizeMaxHeight: 1200,
});
i can't preview the image ,but the mvc Action get the file,does anyone know why?
post code for controller:
[HttpPost]
[ValidateInput(false)]
public ActionResult Create(NewsViewModel model, FormCollection form)
{
if (ModelState.IsValid)
{
//....
// upload image
foreach (string file in Request.Files)
{
HttpPostedFileBase hpf = Request.Files[file] as HttpPostedFileBase;
if (hpf.ContentLength == 0)
continue;
string path = Path.Combine(Server.MapPath("~/Uploads/News/"),GUID.NewGuid()+ Path.GetExtension(hpf.FileName));
hpf.SaveAs(path);
data.ImagePath = path;
_iNewsService.UpdateNews(data);
}
}
}
i had same problem ,solved it with following :
[HttpPost]
[ValidateInput(false)]
public ActionResult Create(NewsViewModel model, FormCollection form)
{
var length = Request.ContentLength;
var bytes = new byte[length];
Request.InputStream.Read(bytes, 0, length);
//or for creating image from stream
Bitmap bmp = new Bitmap(Bitmap.FromStream(InputStream));
bmp.Save("some path");
}
hope this could help.

How to filter the image data in MVC4 using linq

How to display images in MVC4 from database.
Step 1:
In my code, retrieve the data and place in array class.
public class ImageTable
{
public string ImageId { get; set; }
public string CategoryId { get; set; }
public byte[] Image { get; set; }
}
public class DataAcceess
{
public ImageTable[] GetImages()
{
ImageTable[] Images = null;
SqlConnection Conn = new SqlConnection("Data Source=;Initial Catalog=;UserID=;Password=;");
Conn.Open();
//SqlCommand Cmd = new SqlCommand("Select [Product ID],ImageView1 From Cpecial_Image_tbl", Conn);
SqlCommand Cmd = new SqlCommand("Select b.[Category ID],a.[Product ID], a.[ImageView1] from Cpecial_Image_tbl as a inner join [Cpecial_Product_tbl] as b ON a.[Product ID]=b.[Product ID]", Conn);
SqlDataReader Reader = Cmd.ExecuteReader();
DataTable dt = new DataTable();
dt.Load(Reader);
Images = new ImageTable[dt.Rows.Count];
int i = 0;
foreach (DataRow Dr in dt.Rows)
{
Images[i] = new ImageTable()
{
ImageId = (string)Dr["Product ID"],
CategoryId = (string)Dr["Category ID"],
Image = (byte[])Dr["ImageView1"]
};
i = i + 1;
}
Conn.Close();
return Images;
}
Step 2: In controller retreive the image value assign, it in byte array and return to the view like this.
public ActionResult Index(string id)
{
// var image = db.Categories.First(m => m.CategoryID == id).Picture;
DataAcceess objContext = new DataAcceess();
//byte[] Image = (from a in Images select a.Image.ToArray());
byte[] a;
foreach (var item in objContext.GetImages())
{
a = item.Image;
return File(a, "Image/jpg");
}
return View();
}
Step 3: I added the tag in view like this
this will show only one image.
I want to show all the the images, and also manipulate the image with respect to the Filters
(sorting ascending , desending with catagoryId) like in shopping cart.
Could any one give me the solution?
You have to retrieve every Image separately.
A return statement ends the function where you are.
Personally I would save the images on the file system and paths to them in a ImageUrl annotated model property.
You can then just make a DisplayFor because the images will be a property of your Model.
If you save your image in a Database. The database will get big and slow.

Read image from database and display in view

I'm trying to convert an older ASP.NET application to MVC (I am just learning MVC). and I have a need to display an image in a Gridview. The image itself is stored in a SQL Server table as datatype image. The code that was used previously is below. Can someone suggest an approach using MVC? I was thinking of creating a partial page that I could embed in a standard view, but not sure if that is the right design to implement.
Thanks is advance!
` string sqlText = "SELECT * FROM Images WHERE img_pk = " + id;
SqlConnection connection = new SqlConnection(ConfigurationManager.ConnectionStrings["LocalSqlServer"].ConnectionString);
SqlCommand command = new SqlCommand(sqlText, connection);
connection.Open();
SqlDataReader dr = command.ExecuteReader();
if (dr.Read())
{
//Response.Write("test");
Response.BinaryWrite((byte[])dr["img_data"]);
}
connection.Close();
}
Then it can be referenced using this image tag:
<asp:Image Height="73" Width="80" ID="Image1" ImageAlign="Middle" ImageUrl='<%#"viewimage.aspx?id=" + Eval("ImageId") %>' runat="server"/></a></td>
The first thing is to forget about GridView in an ASP.NET MVC application. Server side controls, postbacks, viewstate, events, ... all those are notions that no longer exists.
In ASP.NET MVC you work with Models, Controllers and Views.
So you could write a controller action which will fetch the image from the database and serve it:
public class ImagesController: Controller
{
public ActionResult Index(int id)
{
string sqlText = "SELECT img_data FROM Images WHERE img_pk = #id";
using (var conn = new SqlConnection(ConfigurationManager.ConnectionStrings["LocalSqlServer"].ConnectionString))
using (var command = conn.CreateCommand())
{
conn.Open();
command.CommandText = sqlText;
command.Parameters.AddWithValue("#id", id);
using (var reader = command.ExecuteReader())
{
if (!reader.Read())
{
return HttpNotFound();
}
var data = GetBytes(reader, reader.GetOrdinal("img_data"));
return File(data, "image/jpg");
}
}
}
private byte[] GetBytes(IDataReader reader, int columnIndex)
{
const int CHUNK_SIZE = 2 * 1024;
byte[] buffer = new byte[CHUNK_SIZE];
long bytesRead;
long fieldOffset = 0;
using (var stream = new MemoryStream())
{
while ((bytesRead = reader.GetBytes(columnIndex, fieldOffset, buffer, 0, buffer.Length)) > 0)
{
byte[] actualRead = new byte[bytesRead];
Buffer.BlockCopy(buffer, 0, actualRead, 0, (int)bytesRead);
stream.Write(actualRead, 0, actualRead.Length);
fieldOffset += bytesRead;
}
return stream.ToArray();
}
}
}
and then in your view simply:
<img src="#Url.Action("Index", "Images", new { id = "123" })" alt="" />
Now of course all this controller action is nice and dandy, but you should really abstract all data access into a repository:
public interface IImagesRepository
{
byte[] GetImageData(int id);
}
then implement this method for the data provider you are using:
public class ImagesRepositorySql: IImagesRepository
{
public byte[] GetImageData(int id)
{
// you already know what to do here.
throw new NotImplementedException();
}
}
Finally you will have your controller become database agnostic. Layers in your application are now weakly coupled between them which would allow you to reuse and unit test them in isolation:
public class ImagesController: Controller
{
private readonly IImagesRepository _repository;
public ImagesController(IImagesRepository repository)
{
_repository = repository;
}
public ActionResult Index(int id)
{
var data = _repository.GetImageData(id);
return File(data, "image/jpg");
}
}
and the last part would be to configure your favorite DI framework to inject the proper implementation of the repository into the controller.

Resources