ASP.NET MVC List of attachments (from binary data) - c#

Using ASP.NET MVC and SQL Server 2016. I have attachments which stored as binary data in SQL Server.
Table with data looks like:
attachment_ID | attachment_GUID | attachment_data | attachment_name|
--------------|------------------|-----------------|----------------|
211 | A893C2Z1-4C0 | 0x255044462... | file1.doc |
212 | A893C2R5-4F0 | 0x255044455... | file5.pdf |
I need to display list of this attachments (names), as hyperlinks in html page. So if I click on attachment name it should start the downloading process.
Need help with an ASP.NET MVC controller.
I have controller which downloads a file directly:
using System;
using System.Data.SqlClient;
using System.IO;
using System.Web;
using System.Web.Mvc;
using System.Collections.Generic;
namespace Project.SERVER.Controllers
{
public class AttachmenttoHTMLController : Controller
{
#region View attachments
[HttpGet]
public ActionResult Get()
{
SqlConnection connection = Project.SERVER.Classes.INT_DataBase.getConnection();
SqlCommand command = new SqlCommand("SELECT * FROM AllAttachments WHERE document_GUID='F3A2AC32-D98D'", connection);
command.Dispose();
SqlDataAdapter sqlDtAdptr = new SqlDataAdapter(command);
System.Data.DataTable result = new System.Data.DataTable();
result.Dispose();
sqlDtAdptr.Fill(result);
sqlDtAdptr.Dispose();
connection.Dispose();
connection.Close();
if (result.Rows.Count > 0 && !System.Convert.IsDBNull(result.Rows[0]["attachment_data"]))
{
byte[] file = (byte[])result.Rows[0]["attachment_data"];
Response.ContentType = result.Rows[0]["attachment_contentType"].ToString();
return File(file, Response.ContentType, result.Rows[0]["attachment_fileName"].ToString());
}
else return new EmptyResult();
}
#endregion
}
}
What should I add to the code to achieve controller for attachment list with option to download when clicked?

You have to save first the binary data into Image Format into your directory project.
Use FileResult
HTML:
<div>
#Html.ActionLink("Download", "Download", "Home");
</div>
HomeController:
public FileResult Download()
{
String path = HostingEnvironment.ApplicationPhysicalPath + "Image\\Capture.PNG";
string fname= Path.GetFileName(path);
byte[] fileBytes = System.IO.File.ReadAllBytes(path);
string fileName = fname;
return File(fileBytes, System.Net.Mime.MediaTypeNames.Application.Octet, fileName);
}
Assuming that you have a list in your model
List<Attachment> lst = new List<Attachment>();
This list is the content of your data from your Database and saved the byte to imageformat into you project folder.
Your code from above should fall in here saved the byte with a filename even id.PNG or any. Adding lst.id and lst.filename for html purpose.
public class Attachment
{
public int id { get; set; }
public string filename { get; set; }
}
Your HTML looks like:
<table>
#{
if (Models.GetAttachment.lst.Count > 0)
{
for (int m = 0; m < Models.GetAttachment.lst.Count; m++)
{
<tr>
<td>
#Html.ActionLink("Download", "Download", new { id = Models.GetAttachment.lst.Coun[m].id })
</td>
</tr>
}
}
}
</table>
HomeController With id:
public FileResult Download(int?id)
{
String path = HostingEnvironment.ApplicationPhysicalPath + "Image\\Capture.PNG";
string fname= Path.GetFileName(path);
byte[] fileBytes = System.IO.File.ReadAllBytes(path);
string fileName = fname;
return File(fileBytes, System.Net.Mime.MediaTypeNames.Application.Octet, fileName);
}
the purpose of id to locate the file in your project directory for every user click.

Related

Display image in front end in ASP.NET MVC

In ASP.NET MVC, the image path is stored in the database and server folder (image) but not displayed on the front.
Images are shown like this:
I was trying to display the image on the front in ASP.NET MVC.
I also attached the code of the controller and view to display the image using the Entity Framework model
In my controller method:
[HttpPost]
public ActionResult Create(Personaltable p, Personal u)
{
try
{
// TODO: Add insert logic here
string filename = Path.GetFileNameWithoutExtension(u.AttachPicture.FileName);
string extension = Path.GetExtension(u.AttachPicture.FileName);
filename = filename + DateTime.Now.ToString("yymmssfff") + extension;
u.ImagePath = "~/Image/" + filename;
filename = Path.Combine(Server.MapPath("~/Image/"), filename);
u.AttachPicture.SaveAs(filename);
using (PersonaltableEntities entity = new PersonaltableEntities())
{
var t = new Personaltable()//Make Variable of Table
{
AttachPicture=SaveToPhysicalLocation(u.AttachPicture),
LastPayCertificate = SaveToPhysicalLocation(u.LastPayCertificate)
};
db.Personaltables.Add(t);
db.SaveChanges();
}
return RedirectToAction("Index");
}
catch()
{}
}
private string SaveToPhysicalLocation(HttpPostedFileBase file)
{
if (file.ContentLength > 0)
{
var fileName = Path.GetFileName(file.FileName);
var path = Path.Combine(Server.MapPath("~/App_Data"), fileName);
file.SaveAs(path);
return path;
}
return string.Empty;
}
This is the view Controller on which I only show the image uploaded by the user in a list form.
public ActionResult Index()
{
return View(db.Personaltables.ToList());
}
This is my view:
#foreach (var item in Model)
{
<tr> <td><img src="~/Image/" width="100",height="250"/></td></td>
}
You must write src="~/Image/#item.ImagePath"
#foreach (var item in Model)
{
<tr> <td><img src="~/Image/(????)" width="100",height="250"/></td></td>
}

Upload data with file

I have to send the files along with some description about those to the server.
So as per above image, I want to upload a file and provide the description of file in a text box on right side of it. After clicking select files link, the user can select another file to upload and it will also have description text box. After clicking upload files, along with the file, description of it neet to upload to the server.
I am using plupload to do it. But it is just uploading file and not description.
Also, I am using MVC. So please suggest any solution to it or suggest any other javascript library which can fulfill my requirements.
Below is the MVC code,
public string Upload(List<HttpPostedFileBase> fileUploads,List<string> fileDescription)
{
int count = 0;
foreach (HttpPostedFileBase file in fileUploads)
{
byte[] fileData = new byte[file.ContentLength];
file.InputStream.Read(fileData, 0, file.ContentLength);
db.UploadedFiles.AddObject(new UploadedFile
{
FileDescription = fileDescription[count],
FileBinary = fileData,
FileName = file.FileName
});
count++;
}
db.SaveChanges();
return "Success";
}
Below is javascript code
var uploadFiles = [];
var descs = [];
var count = 0;
plupload.each(uploader.files, function (file) {
var id = file.id;
var fileUpload = file;
uploadFiles[count] = file;
descs[count] = $("#" + id + "_desc").val();
count++;
});
var da = { fileDescription: descs,fileUploads: uploader.files };
$.ajax({
url: '/LumosQC/Upload',
data: da,
method: 'POST',
}).done(function (data1) {
alert("Success");
}).error(function (a, b, c) {
console.log(a);
});
You can modify the route you use for uploading and use something like
...
[Route("upload/{description}")]
public HttpResponseMessage Upload(string description)
...
Or you can put description into cookie (but I would recomend to use the first approach it's cleaner)
function createCookie(name,value,days) {
var expires = "";
if (days) {
var date = new Date();
date.setTime(date.getTime() + (days*24*60*60*1000));
expires = "; expires=" + date.toUTCString();
}
document.cookie = name + "=" + value + expires + "; path=/";
}
createCookie('desciption', 'your description', 1)
and then
Request.Cookies["description"]
UPDATE
Now I see you need to upload multiple files, for that you can use the same approach with modified route
[Route("upload")]
public string Upload(List<HttpPostedFileBase> fileUploads, [FromUri] string[] fileDescription)
Create view model and use as parameter in action method,
ViewModel :
public class UploadViewModel
{
public List<string> FileDescriptions;
public List<HttpPostedFileBase> Files;
}
Action method :
public string Upload(UploadViewModel model)
{
// ....
}
that will bind the data correctly.

Retrive file name from database using HttpHandlers

I have database with EmpNo(Int) and EmpImage(Image) columns.
I am using HttpHandler to display the Images.
I am storing Images both in database and folder.
Now I want to change the names of Images in folder as names of EmpNo whose I didn't change while uploading.
So need to fetch the Images names from database to compare them with the Image names in the folder and rename them.
How can i fetch or extract the image names from the binary data that i get from database using generic handler.
I have attached the code In handler for reference.
using System;
using System.Web;
using System.Data;
using System.Data.SqlClient;
public class Lab_14___ImageFetchingHandler : IHttpHandler
{
public void ProcessRequest(HttpContext context)
{
SqlConnection vConn = new SqlConnection("server=localhost; database=Asp.netDemoWebsiteDatabase; Integrated Security = SSPI;");
vConn.Open();
String vQuery = "Select EmpImage from EmpImages where Empno=#id";
SqlCommand vComm = new SqlCommand(vQuery, vConn);
//Receive the Id from some Form
String vId = context.Request.QueryString["id"];
vComm.Parameters.AddWithValue("#id", vId);
SqlDataReader vDr = vComm.ExecuteReader();
while (vDr.Read())
{
context.Response.ContentType = "image/jpg";
context.Response.BinaryWrite((byte[])vDr["EmpImage"]);
[ Here I need the Images names to store in List or array.How?? ]
}
vConn.Close();
}
public bool IsReusable
{
get
{
return false;
}
}
}
Here are different ways to inspect image metadata.
Byte[] content = (Byte[])vDr["EmpImage"]
//Option 1
Image img = new Bitmap(new MemoryStream(content));
Encoding _Encoding = Encoding.UTF8;
var props = img.PropertyItems;
string propData;
foreach (var propertyItem in props)
{
propData = _Encoding.GetString(propertyItem.Value);
Debug.WriteLine("{0}[{1}]", propertyItem.Id, propData);
}
//option 2 - require reference of PresentationCore and WindowsBase and then using System.Windows.Media.Imaging
var imgFrame = BitmapFrame.Create(new MemoryStream(content));
var metadata = imgFrame.Metadata as BitmapMetadata;
//option 3 - require MetadataExtractor Nuget package
var mr = ImageMetadataReader.ReadMetadata(new MemoryStream(content));
foreach (var directory in mr)
{
foreach (var tag in directory.Tags)
{
Debug.WriteLine("{0} - {1} = {2}]", directory.Name, tag.Name, tag.Description);
}
}

Read single cell values from httppostedfilebase Excel File

I have an Excelfile that the client send to server as httppostedfilebase and I need to know how I can read values from this file.
[HttpPost]
public ActionResult ShowExcelFile(GetExcel model)
{
var file = model.Files[0];
FileInfo info = new FileInfo(file.FileName);
var fileName = Path.GetFullPath(file.FileName);
if (file != null && file.ContentLength > 0)
{
using (ExcelPackage package = new ExcelPackage(info))
{
//Read some cell value, how?
}
}
return View("ShowExcelFile");
}
My model:
public class GetExcel
{
public List<HttpPostedFileBase> Files { get; set; }
public GetExcel()
{
Files = new List<HttpPostedFileBase>();
}
}
My view:
#using (Html.BeginForm("ShowExcelFile", "ShowExcel", FormMethod.Post, new { enctype = "multipart/form-data" }))
{
#Html.TextBoxFor(m => m.Files, new { type = "file", name = "Files" })<br />
<input type="submit" value="Upload file" />
}
I really don't now how to do this, I have tried Excel Data Reader but it can't read formula values. I just wan't to read a cell value from this excelfile send from the client
Lets put this inside your controller action u will get the file:
[AcceptVerbs(HttpVerbs.Post)]
public JsonResult ShowExcelFile()
{
// For getting the file that is Uploadeded.
HttpPostedFileBase fileUpload = Request.Files["Files"];
byte[] data;
using (Stream inputStream = fileUpload.InputStream)
{
MemoryStream memoryStream = inputStream as MemoryStream;
if (memoryStream == null)
{
memoryStream = new MemoryStream();
inputStream.CopyTo(memoryStream);
data = memoryStream.ToArray();
return Json(data, JsonRequestBehavior.AllowGet);
}
}
return Json(new { }, JsonRequestBehavior.AllowGet);
}
As far as I understand you use EPPlus library. To get the value you need to write smth like that
public void Upload(HttpPostedFileBase file)
{
package.Load(file.InputStream);
var worksheet = package.Workbook.Worksheets.First();
var cellValue = worksheet.Cells[rowIndex, columnIndex].Value;
var formulaValue = worksheet.Cells[rowIndex, columnIndex].Formula;
}
There are a few prolems with the how the controller and view are implemented . For example, your ActionResult expects List<HttpPostedFileBase>, but the view is posting HttpPostedFileBase.
However, beyond that, inside using of package, try:
ExcelWorksheet worksheet = package.Workbook.Worksheets[1];
worksheet.Select(new ExcelAddress("A1")); //there is more than one way to set this
string cellVal = (string)worksheet.SelectedRange.Value;

I want to insert uploaded image in root directory images folder and its path to image column in database

how can i make an uploading image page via razor syntax (CSHTML) to simply upload file to /image root with increasing name like imgxxxyyy.jpg when the img part is fixed and xxx is the id of the inserting/updating product and yyy is the increasing number of image of that product and store the path to the imagpath column in my table ?
more i think about it and i research about it i get more confused .... please help me in this case .
It would be easier if you used Guids for filenames. So you could define a view model:
public class MyViewModel
{
[Required]
public HttpPostedFileBase File { get; set; }
}
a view containing a form where the user will be able to select a file to upload:
#model MyViewModel
#using (Html.BeginForm(null, null, FormMethod.Post, new { enctype = "multipart/form-data" }))
{
#Html.LabelFor(x => x.File)
#Html.TextBoxFor(x => x.File, new { type = "file" })
#Html.ValidationMessageFor(x => x.File)
<button type="submit">Upload</button>
}
and finally a controller to show the form and process the upload:
public class HomeController : Controller
{
public ActionResult Index()
{
return View(new MyViewModel());
}
[HttpPost]
public ActionResult Index(MyViewModel model)
{
if (model.File != null && model.File.ContentLength > 0)
{
var imageFolder = Server.MapPath("~/image");
var ext = Path.GetExtension(model.File.FileName);
var file = Path.ChangeExtension(Guid.NewGuid().ToString(), ext);
var fullPath = Path.Combine(imageFolder, file);
model.File.SaveAs(fullPath);
// Save the full path of the uploaded file
// in the database. Obviously this code should be externalized
// into a repository but for the purposes of this example
// I have left it in the controller
var connString = ConfigurationManager.ConnectionStrings["MyDb"].ConnectionString;
using (var conn = new SqlConnection(connString))
using (var cmd = conn.CreateCommand())
{
conn.Open();
cmd.CommandText = "INSERT INTO images VALUES (#path)";
cmd.Parameters.AddWithValue("#path", fullPath);
cmd.ExecuteNonQuery();
}
}
return View(model);
}
}

Categories

Resources