This question already has answers here:
ASP.Net MVC: How to display a byte array image from model
(10 answers)
Closed 5 years ago.
I am trying to upload and retrieve image from SQL server database. I created model, Controller and view as below.
Viewmodel is very similiar to actual modal
CheckoutModel.cs
public class CheckOutViewModel
{
public int ID { get; set; }
public ApplicationUser CandidateId { get; set; }
[Required]
public byte[] Image { get; set; }
}
Also i created a controller to upload and display images with action methods namely index, create and retreive
Index method is used to display images , create method is used to upload and save image in database and retrieve method is used to query the image according to its id.
CheckOutController.cs
using Microsoft.AspNet.Identity;
using shanuMVCUserRoles.Repositories;
using shanuMVCUserRoles.ViewModels;
using System.Collections.Generic;
using System.IO;
using System.Linq;
using System.Web;
using System.Web.Mvc;
namespace shanuMVCUserRoles.Models
{
public class CheckOutController : Controller
{
private readonly ApplicationDbContext db;
public CheckOutController()
{
db = new ApplicationDbContext();
}
[Route("Index")]
[HttpGet]
public ActionResult Index()
{
var content = db.Checkouts.Select(s => new
{
s.ID,
s.CandidateId,
s.Image,
});
List<CheckOutViewModel> contentModel = content.Select(item => new CheckOutViewModel()
{
ID = item.ID,
CandidateId = item.CandidateId,
Image = item.Image,
}).ToList();
return View(contentModel);
}
public ActionResult RetrieveImage(int id)
{
byte[] cover = GetImageFromDataBase(id);
if (cover != null)
{
return File(cover, "image/jpg");
}
else
{
return null;
}
}
public byte[] GetImageFromDataBase(int Id)
{
var q = from temp in db.Checkouts where temp.ID == Id select temp.Image;
byte[] cover = q.First();
return cover;
}
// GET: CheckOut
[Authorize]
public ActionResult Create()
{
return View();
}
[Route("Create")]
[HttpPost]
public ActionResult Create(CheckOutViewModel model)
{
HttpPostedFileBase file = Request.Files["ImageData"];
CheckOutRepository service = new CheckOutRepository();
int i = service.UploadImageInDataBase(file, model);
if (i == 1)
{
return RedirectToAction("Index");
}
return View(model);
}
}
}
Then i created a repository folder to save images and fields in database and also a method for converted image to bytes.
CheckoutRepostiory.cs
public class CheckOutRepository
{
private readonly ApplicationDbContext db;
public CheckOutRepository()
{
db = new ApplicationDbContext();
}
public int UploadImageInDataBase(HttpPostedFileBase file, CheckOutViewModel contentViewModel)
{
contentViewModel.Image = ConvertToBytes(file);
var userId = HttpContext.Current.User.Identity.GetUserId();
var member = db.Users.Single(u => u.Id == userId);
var Content = new CheckOut
{
CandidateId = member,
Image = contentViewModel.Image
};
db.Checkouts.Add(Content);
int i = db.SaveChanges();
if (i == 1)
{
return 1;
}
else
{
return 0;
}
}
public byte[] ConvertToBytes(HttpPostedFileBase image)
{
byte[] imageBytes = null;
BinaryReader reader = new BinaryReader(image.InputStream);
imageBytes = reader.ReadBytes((int)image.ContentLength);
return imageBytes;
}
}
Also i created the index view and then i placed the image in image tag using the for each loop.
Index.cshtml
#foreach (var item in Model)
{
<tr>
<td>
<img src="/Content/RetrieveImage/#item.ID" alt="" height=100 width=200 />
</td>
</tr>
}
Something like this may work... if you have image bytes in your model object
#foreach (var item in Model)
{
<tr>
<td>
#{
var base64 = Convert.ToBase64String(item.Image);
var imgSrc = String.Format("data:image/gif;base64,{0}", base64);
}
<img src="#imgSrc" alt="" height=100 width=200 />
</td>
</tr>
}
or
<img src="data:image;base64,#System.Convert.ToBase64String(item.Image)" width="200" height="100"/>
hope it helps
I have one alternative solution:
Alter your database table to set a field as varchar2
and store your image as string path on it:
Then after you same change, you can do in your MODEL as well as where it is required.
public class CheckOutViewModel
{
public int ID { get; set; }
public ApplicationUser CandidateId { get; set; }
[Required]
public string Image { get; set; }
}
Related
Greetings i want to call a web api that returns a json string from From Controller and i want to map it on a class so i can save the data on the database.But i dont understand how to map each data on the json with the class.
I only get the message that is succeed.
my code is:
public ActionResult API()
{
var client = new WebClient();
var text = client.DownloadString("https://www.example.com/api/all-users?name=user%20&pass=password");
wclients wclients = JsonConvert.DeserializeObject<wclients>(text);
if (wclients.message == "success")
{
ViewBag.name = ("name = " + wclients.name);
}
return View();
}
my view is this:
#foreach (var item in ViewBag.name) {
<tr>
<td>
#item
</td>
</tr>
}
The Response from web api is:
{"status":true,"message":"success","data":[{"name":"test test","email":"senthil#nscript.in","phone":"1234567890","affiliated_id":null,"account":{"real":[{"login":"1001175","pass":"4pJccK8AUWw8"},{"login":"3001180","pass":"4AeCqasw7jX2"},{"login":"3001182","pass":"fS2tf6Gsej7C"}]
try the below code:
public ActionResult API()
{
var client = new WebClient();
var text = client.DownloadString("https://www.example.com/api/all-users?
name=user%20&pass=password");
var wclients = JsonConvert.DeserializeObject<dynamic>(text);
if (wclients.message == "success")
{
var data = wclients.data;
}
return View();
}
wclients.name will never contain anything because there is not a property called "name" at the top level of the JSON object structure.
To access the name property you would need to enumerate through the data array (which should exist as a property on the wclients class) and get the name from there.
Update
As per the example below:
public class wclients
{
public bool status { get; set; }
public string message { get; set; }
public IEnumerable<Account> data { get; set; }
}
public class Account
{
public string name { get; set; }
public string email { get; set; }
public string phone { get; set; }
}
public ActionResult API()
{
var client = new WebClient();
var text = client.DownloadString("https://www.example.com/api/all-users?name=user%20&pass=password");
wclients clients = JsonConvert.DeserializeObject<wclients>(text);
if (wclients.message == "success")
{
ViewBag.name = clients.data;
}
return View();
}
and in the view
#foreach (var item in ViewBag.name)
{
<tr>
<td>
#item.name
</td>
</tr>
}
The JSON must map directly to your C# class.
For example, if the JSON has the following:
"name":"test test",
"email":"senthil#nscript.in"
Then your class (eg Person.cs) must have the same properties:
public class Person{
public string name {get;set}
public string email {get;set}
}
Then you would do:
Person person = JsonConvert.DeserializeObject<Person>(json);
In your example, you probably need wclients.data
if (wclients.message == "success")
{
ViewBag.name = ("name = " + wclients.data.name);
}
Finally, the name wclients suggests there are multiple... in which case:
var names = new List<string>();
foreach(var client in wclients){
if (client.message == "success")
{
names.Add("name = " + client.data.name);
}
}
I have a model as shown below. The MenuItem model, which has different SQL queries (MenuItem.MenuSQLQuery).
I am executing these query agaist a progress DB and I want to display the result on the view. The return of the SQL query is IEnumerable dynamic (using dapper ORM).
Thanks for your time reading and appreciate any help.
Model
namespace Models.Menu
{
public class MenuItem
{
public int MenuItemId { get; set; }
public string MenuName { get; set; }
public string MenuCategory { get; set; }
public string MenuParent { get; set; }
public string MenuAction { get; set; }
public string MenuController { get; set; }
public string MenuSQLQuery { get; set; }
public string ResultColumnHeading { get; set; }
public string MenuRole { get; set;}
}
}
Controller
using Dapper;
using Microsoft.AspNet.Identity;
using System.Collections.Generic;
using System.Data;
using System.Data.Odbc;
using System.Linq;
using System.Web.Mvc;
using DataLayer;
using Models.Menu;
namespace Controllers
{
public class BrowseController : Controller
{
public ActionResult Index()
{
return View();
}
public ActionResult BrowseResult(int menuId)
{
ApplicationDbContext context = new ApplicationDbContext();
var odbcConnection = new OdbcConnection("DRIVER=Progress OpenEdge 10.2B Driver;****DIL=READ UNCOMMITTED");
// Open your connection
//ApplicationUser currentUser = context.Users.Where(u => u.UserName.Equals(UserName, StringComparison.CurrentCultureIgnoreCase)).FirstOrDefault();
var userid = User.Identity.GetUserId();
List<MenuUserAccess> menuAccess = context.MenuUserAccess.Where(m => m.MenuItemId == menuId).ToList();
var access = menuAccess.FirstOrDefault(o => o.MenuUserId == userid);
if (access != null)
{
odbcConnection.Open();
var menuitem = context.MenuItem.First(m => m.MenuItemId == menuId);
var browseResult = odbcConnection.Query(menuitem.MenuSQLQuery);
odbcConnection.Close();
odbcConnection.Dispose();
return View(browseResult);
}
else
{
return View();
}
}
}
}
This is the view I am using, but not getting any output.
#model IEnumerable<dynamic>
<div>
<h2>BrowseResult</h2>
#if (Model.Count() > 0)
{
ViewBag.Title = "BrowseResult";
WebGrid grid = new WebGrid(source: Model);
#grid.GetHtml()
}
else
{
<p> No Data Found</p>
}
<h2>End</h2>
</div>
You need something like this
#model IEnumerable<dynamic>
<div>
<h2>BrowseResult</h2>
#if (Model.Count() > 0)
{
ViewBag.Title = "BrowseResult";
foreach(dynamic item in Model)
{
<span>#item.MenuName</span>
}
}
else
{
<p> No Data Found</p>
}
<h2>End</h2>
</div>
Returns
name1 name2
There's an example with WebGrid in this link: https://www.w3schools.com/asp/webpages_webgrid.asp
I made it working.
This is my view code.
#model IEnumerable<dynamic>
<div>
#{
int i = 0;
}
<table class="table-striped">
<tr>
#foreach (KeyValuePair<string, object> kvp in Model.ElementAt(1))
{
// This will be the column heading
<td> <b> #kvp.Key </b></td>
}
</tr>
#foreach (var d in Model)
{
<tr>
#foreach (KeyValuePair<string, object> kvp in Model.ElementAt(i))
{
//This will be the row data
<td> #kvp.Value </td>
}
</tr>
i++;
}
</table>
</div>
I currently am pulling a list of url's from a view using Entity Framework 5 and MVC 5. I have the view populating all the links but I need each link to display their 'LinkState' names like in my model so it will output:
Alabama
Georgia
etc.
with the link attached to the LinkState. Instead of the view foreach loop saying State Link. I cant get my model/controlled to pull the correct information.
Repository:
public class LinkRepository
{
private readonly LinkLibrary _entities = new LinkLibrary ();
public LinkRepository()
{
_entities = new LinkLibrary ();
}
public List<LinkModels> RetrieveStateLink(string year)
{
return
_entities.vw_URLLibrary.Where(s => s.YEAR.Equals(year) && s.URL_TYPE.Equals("United States")).Select(m => new LinkModels()
{
UrlLink = m.LinkLocation
}).ToList();
}
}
Model
public class LinkModels
{
public string LinkYear { get; set; }
public string LinkState { get; set; }
public string UrlLink { get; set; }
public string LinkType { get; set; }
public List<string> ListOfUrls{ get; set; }
}
Controller
public ActionResult GetStateLinks()
{
var stateLink = new List<string>();
var model = rr.RetrieveStateLinks("2014").Select(m=> m.UrlLink).ToList();
foreach (var s in model)
{
stateLink.Add(s);
}
var rm = new LinkModels();
rm.ListOfUrls = stateLink;
return View(rm);
}
View
#foreach (var item in Model.StateLinkList)
{
<td>
State Link
</td>
}
Your issue is that you are returning a List of strings as opposed to a list of LinkModels. I updated the repository to return the url and link name
removed some unneccessary code in your controller and updated it to work with a list of LinkObjects. Then updated the view to display the info.
You will have to update your view #model List<LinkModels> instead of #model List<string>
public class LinkRepository
{
private readonly LinkLibrary _entities = new LinkLibrary ();
public LinkRepository()
{
_entities = new LinkLibrary ();
}
public List<LinkModels> RetrieveStateLink(string year)
{
return
_entities.vw_URLLibrary.Where(s => s.YEAR.Equals(year) && s.URL_TYPE.Equals("United States")).Select(m => new LinkModels()
{
LinkState = m.LinkState,
UrlLink = m.LinkLocation
}).ToList();
}
}
public ActionResult GetStateLinks()
{
var stateLink = new List<LinkModels>();
var model = rr.RetrieveStateLinks("2014");
return View(model);
}
#foreach (var item in Model)
{
<td>
#item.LinkState
</td>
}
Controller
public ActionResult GetStateLinks()
{
var model = rr.RetrieveStateLinks("2014");
return View(model);
}
View (change your view model to list of LinkModels)
#foreach (var item in Model)
{
<td>
#item.LinkState
</td>
}
I have a web application to upload image to database and to retreive them.
public class ImageGallery
{
[Key]
public int ImageID { get; set; }
public int ImageSize { get; set; }
public string FileName { get; set; }
public byte[] ImageData { get; set; }
[Required(ErrorMessage="Please select Image File")]
public HttpPostedFileBase file { get; set; }
}
and my database context class is something like this
public class MyDatabaseEntities : DbContext
{
public DbSet<ImageGallery> ImageGalleries { get; set; }
}
and here is my controller
public ActionResult Upload()
{
return View();
}
[HttpPost]
public ActionResult Upload(ImageGallery IG)
{
IG.FileName = IG.File.FileName;
IG.ImageSize = IG.File.ContentLength;
byte[] data = new byte[IG.File.ContentLength];
IG.File.InputStream.Read(data, 0, IG.File.ContentLength);
IG.ImageData = data;
using(MyDatabaseEntities dc = new MyDatabaseEntities())
{
dc.ImageGalleries.Add(IG);
dc.SaveChanges();
}
return RedirectToAction("Gallery");
}
now when i try to upload the image it giving me following error
EntityType 'HttpPostedFileBase' has no key defined. Define the key for this EntityType. HttpPostedFileBases: EntityType: EntitySet 'HttpPostedFileBases' is based on type 'HttpPostedFileBase' that has no keys defined.
I have seen one of question on stack overflow-----'HttpPostedFileBase' has no key defined. Define the key for this EntityType. I tried the solution but did not get any success.
I was following this blog for this purpose------
http://dotnetawesome.com/mvc/how-to-upload-image-to-database-and-show-in-view-without-image-handler
Try this
[NotMapped]
public HttpPostedFileBase File { get; set; }
This will not map to the database.
The error occurs because their is no datatype HttpPostedFileBase in your table
You cannot store HttpPostedFileBase in a database field (its a complex object containing multiple properties). You could exclude this using the [NotMapped] attribute, however your model and your view really have no relationship (your not including any inputs for the other properties of your model).
Instead your view can be just
#using (Html.BeginForm("Upload", "ImageGallery", FormMethod.Post, new { enctype = "multipart/form-data" }))
{
<input type="file" name="file" />
<input type = "submit" value="Upload" />
}
and change the POST method to
[HttpPost]
public ActionResult Upload(HttpPostedFileBase file)
{
if (file.ContentLength > 0) // check a file was selected
{
// Initialize a new instance of the data model and set its properties
ImageGallery model = new ImageGallery()
{
FileName = file.FileName,
ImageSize = file.ContentLength,
....
};
.... // save and redirect
}
else {
// add a model state error and return the view?
}
}
Simply try a new view model with properties like this-----
public class ImageViewModel
{
public int ImageID { get; set; }
public int ImageSize { get; set; }
public string FileName { get; set; }
public byte[] ImageData { get; set; }
public HttpPostedFileBase File { get; set; }
}
and change your controller like this-----
public ActionResult Upload(HttpPostedFileBase file)
{
ImageGallery IG = new ImageGallery();
IG.FileName = file.FileName;
IG.ImageSize = file.ContentLength;
byte[] data = new byte[file.ContentLength];
file.InputStream.Read(data, 0, file.ContentLength);
IG.ImageData = data;
var model = new ImageViewModel
{
FileName = file.FileName,
ImageSize = file.ContentLength,
ImageData = data,
File = file
};
using(MyDatabaseEntities dc = new MyDatabaseEntities())
{
dc.ImageGalleries.Add(IG);
dc.SaveChanges();
}
return View(model);
}
}
}
and change your view page like this------
#model Image.Models.ImageViewModel
<h2>Upload</h2>
#using (Html.BeginForm("Upload", "ImageGallery", FormMethod.Post, new { enctype = "multipart/form-data" }))
{
#Html.ValidationSummary(true)
<table>
<tr>
<td>Select File : </td>
<td>
#Html.TextBoxFor(Model => Model.File, new { type = "file" })
#Html.ValidationMessage("CustomError")
</td>
<td>
<input type="submit" value="Upload" />
</td>
</tr>
</table>
}
I am trying to populate an HTML table with data from a table in my database. The issue is simply that the HTML table is not getting populated with any data.
Here is the ViewModel:
public class TestViewModel
{
public string MatchedId { get; set; }
public string UnmatchedId { get; set; }
public string Auth { get; set; }
public DateTime CreditDate { get; set; }
public string CreditNumber { get; set; }
public decimal CreditAmount { get; set; }
public DateTime DeniedDate { get; set; }
public int DeniedReasonId { get; set; }
public string DeniedNotes { get; set; }
}
Controller Action:
[HttpPost]
public ActionResult UploadValidationTable(HttpPostedFileBase csvFile)
{
var inputFileDescription = new CsvFileDescription
{
SeparatorChar = ',',
FirstLineHasColumnNames = true
};
var cc = new CsvContext();
var filePath = uploadFile(csvFile.InputStream);
var model = cc.Read<Credit>(filePath, inputFileDescription);
try
{
var entity = new Entities();
//model here is the .csv, doesn't have anything to do with this issue
foreach (var item in model)
{
var tc = new TemporaryCsvUpload
{
Id = item.Id,
CreditAmount = item.CreditAmount,
CreditDate = item.CreditDate,
CreditNumber = item.CreditNumber,
DeniedDate = item.DeniedDate,
DeniedReasonId = item.DeniedReasonId,
DeniedNotes = item.DeniedNotes
};
entity.TemporaryCsvUploads.Add(tc);
}
entity.SaveChanges();
System.IO.File.Delete(filePath);
//This is where the database table is getting filled
entity.Database.ExecuteSqlCommand("Insert into CsvReport Select p.Id as MatchedId, case when p.Id is null then t.Id end as UnmatchedId, p.Auth,p.CreditDate, p.CreditNumber,p.CreditAmount, p.DeniedDate,p.DeniedReasonId, p.DeniedNotes from TemporaryCsvUpload t left join PermanentTable p on p.Id = t.Id;");
TempData["Success"] = "Updated Successfully";
}
catch (LINQtoCSVException)
{
TempData["Error"] = "Upload Error: Ensure you have the correct header fields and that the file is of .csv format.";
}
return View("Upload");
}
View:
#model IEnumerable<TestProject.TestViewModel>
#if (Model != null)
{
foreach (var item in Model.Where(x => x.IdMatched != null))
{
<tr>
<td>
#item.MatchedId
</td>
<td>
#item.Auth
</td>
<td>
#item.CreditDate
</td>
<td>
#item.CreditNumber
</td>
<td>
#item.CreditAmount
</td>
<td>
#item.DeniedDate
</td>
<td>
#item.DeniedReasonId
</td>
<td>
#item.DeniedNotes
</td>
</tr>
}
}
It's a little weird because I am populating the database with an SQL command. What am I missing here? Do I need to try and pass it through the controller action? Let me know if you need more information. Thanks!
Edit
I tried to pass the instance through, but I may still be doing it incorrectly:
var testModel = new TestViewModel();
return View("Upload", testModel);
Here is what its padding through:
public class TestViewModel
{
public IEnumerable<Test> Test { get; set; }
}
Made an answer so essentially the view doesn't know what to render you need to pass an actual filled model (in your case an IEnumerable to the view). This can be done using the method:
View("Upload", viewModelList);
Controller.View docs on MSDN
It looks like you are not adding any data to your view model.
If your view model is a collection of Test objects, you need to add some
Test objects to the collection.
var model = new TestViewModel()
{
Test = new List<Test>() { new Test(), new Test(), ... }
}
return View("Upload", model);