Show images from IQueryable in View - asp.net

I have a question about showing images loaded from a mysql database in a view.
In my database table "deliverables" I have "item_id", "deliverable_image" and "afstudeerrichting_id". "item_id" and "afstudeerrichting_id" are FK from other tables.
I want to show the images when afstudeerrichting_id = ..
Controller:
public ActionResult Index()
{
var model = repository.GetIdsOfImages(1);
return View(model.ToList());
}
public ActionResult ShowImage(int afstudeerrichtingid)
{
IQueryable<byte[]> data = repository.GetImages(afstudeerrichtingid);
var thedata = data.First();
return File(thedata, "image/png");
}
Repository (where I get the images):
public IQueryable<long> GetIdsOfImages(int afstudeerrichtingid)
{
return from deliverable in entities.deliverables
where deliverable.afstudeerichting_id.Equals(afstudeerrichtingid)
select deliverable.item_id;
}
public IQueryable<byte[]> GetImages(int afstudeerrichtingid)
{
return from deliverable in entities.deliverables
where deliverable.afstudeerichting_id.Equals(afstudeerrichtingid)
select deliverable.deliverable_image;
}
View:
#foreach(var imgID in Model.DeliverablesIDsList)
{
<img src="#Url.Action("ShowImage", "Deliverable", new { DeliverableID = imgID })" />
}
In my Viewmodel:
public List<long> DeliverablesIDsList { get; set; }
public int DeliverableID { get; set; }
Now I get the error:
The model item passed into the dictionary is of type 'System.Collections.Generic.List`1[System.Int64]', but this dictionary requires a model item of type 'GDMfrontEnd.Models.DeliverableViewModel'.
What should I change in my ViewModel? Or what am I doing wrong?

You can do that:
1) pass to the view a list of images' ids, and build list like this
#foreach(var imgId in model.ImgIdsList)
{
<img src="#Url.Action("ShowImage", "Deliverable", new { imageId = imgId })" />
}
2) in controller, which open this view, simply build a ImgIdsList (probably you need a GetIdsOfImagesWithAfstudeerichtingid(int afstudeerrichtingid), which would return a list of int)
3) you should your ShowImage method - not pass afstudeerrichtingid, but unique id of image; of course in this method you should method like GetImageById(int id).

Related

ASP.NET MVC ListBox does not show the selected list items

I am in a big trouble. I read 4 stackoverflow question and one blogpost. I have tried 5 different approach to view the selected items in a multiple selectlist.
I have no success.
The multiple selectlist is generated, but it does not select the items. I have no more idea.
Model:
public class EditableModel
{
public IList<Company> SelectedCompanies { get; set; }
public IList<SelectListItem> SelectListCompanies { get; set; }
}
Controller:
public ActionResult Edit(int id)
{
var service = _serviceDAL.GetEditableModel(id);
if (service!= null)
{
service.SelectListCompanies = GetSelectListCompanies(service.SelectedCompanies);
return View(service);
}
}
private IList<SelectListItem> GetSelectListCompanies(IList<Company> selectedCompanies)
{
List<SelectListItem> items = new List<SelectListItem>();
foreach (Companycompany in _companyService.GetCompanies())
{
items.Add(new SelectListItem
{
Value = company.CompanyId.ToString(),
Text = company.Name,
Selected = selectedCompanies.Any(x => x.CompanyId == company.CompanyId)
});
}
return items;
}
View
#Html.ListBox("SelectedCompanies", Model.SelectListCompanies, Model.SelectedCompanies.Select(x => x.CompanyId.ToString()) )
And nothing. The items in the select list is not selected...
I have tried this Multiselect, the same result, or this one as the current solution.
You cannot bind a <select multiple> to a collection of complex objects. It binds to, and posts back an array of simple values (the values of the selected options).
Your SelectedCompanies property needs to be IEnumerable<int> (assuming the CompanyId of Company is also int). Note also the Selected property of SelectListItem is ignored when binding to a property.
Your also using the same collection for the selected Companies and the list of all Companies which makes no sense. Your SelectListCompanies should be generated from your table of Company.
Model
public class MyViewModel
{
public IEnumerable<int> SelectedCompanies { get; set; }
public IEnumerable<SelectListItem> SelectListCompanies { get; set; }
}
Base on your current code for EditableModel, your code should be
public ActionResult Edit(int id)
{
var service = _serviceDAL.GetEditableModel(id);
....
MyViewModel model = new MyViewModel
{
SelectedCompanies = service.SelectedCompanies.Select(x => x.CompanyId),
SelectListCompanies = GetSelectListCompanies()
};
return View(model);
private IEnumerable<SelectListItem> GetSelectListCompanies()
{
var all companies = ... // call method to get all Companies
return companies.Select(x => new SelectListItem
{
Value = x.CompanyId.ToString(),
Text = x.Name
});
}
However, it look like you should be modifying your EditableModel and the GetEditableModel() code to return the correct data in the first place.

Multiple models in same view in asp.net mvc 4

I'm using asp.net mvc 4 & Entity Framework 6 to make a website where after user login, the table records will show & the ID of the user will show as Session. But when I run, after login, I get this error, Object reference not set to an instance of an object. I've made a custom model where two DbSet from seperate EF6 models are attached. My code is below,
Custom Model
public class MkistatVsUserLogin
{
public sample_1 sample_1 { get; set; } //Login Model
public IEnumerable<mkistat> mkistats { get; set; } //Table Model
}
Controller
[HttpPost]
public ActionResult Login(sample_1 id)
{
if (ModelState.IsValid)
{
var uservar = db.sample_1.Where(a => a.boid.Equals(id.boid)).FirstOrDefault();
if (uservar != null)
{
Session["UserBOID"] = uservar.boid.ToString();
return RedirectToAction("UserLogin");
}
}
var mkimodel = new MkistatVsUserLogin { mkistats = dsedb.mkistats.ToList() };
return View(id);
return View(mkimodel);
}
View
#model ABCoLtd.Models.MkistatVsUserLogin
#if (Session["UserBOID"] != null)
{
<li>Welcome, <b>#Session["UserBOID"].ToString()</b></li>
}
<a class="btn btn-default" href="#Url.Action("UserLogout", "Home")">Log Out</a>
#foreach (var item in Model.mkistats)
{
<tr>
<td>
#Html.DisplayFor(modelItem => item.MKISTAT_ID)
</td>
<td>
#Html.DisplayFor(modelItem => item.MKISTAT_PHONE_NO)
</td>
</tr>
}
Is there something wrong with my code? If it is then please give me a solution. All I want is to use both models at the same view where user login model will be used in Session & table model to list all the records.
Remove bellow line
return View(id);
and in your return View line also mention View or ActionMethod name
return View("ViewName",mkimodel)
In your action method, Use Session to pass ID
Session["UserID"] = id;
You can use the same in your View as :
<html>
-----Your CODE
<body>
------Your CODE
#Session["UserID"]
------Your CODE
</body>
</html>
You can create a ViewModel to handle :
namespace ABCoLtd.ViewModels
{
public class LoginVM
{
public MkistatVsUserLogin MkistatVsUserLogin {get;set;}
public int Id {get;set;}
}
}
and in action pass this way:
var mkimodel = new MkistatVsUserLogin { mkistats = dsedb.mkistats.ToList() };
LoginVM vm = new LoginVM();
vm.MkistatVsUserLogin = mkimodel ;
vm.Id = id;
return View(vm );
and in View set model to LoginVM:
#model ABCoLtd.ViewModels.LoginVM
UPDATE:
you already have a viewmodel didnt noticed that, you just need to do this:
var mkimodel = new MkistatVsUserLogin
{
mkistats = dsedb.mkistats.ToList(),
sample_1 = id
};
return View(nkimodel);
After login you are directly redirecting your user to an action and that action you have not mentioned here.And that action whose view you have shown is an strongly typed view which expects a list of MkistatVsUserLogin. But, I think you are not passing that list, so Model property of view will remain null and that will be causing an error of object reference. Please check this issue.
I got it. I just made another method in controller for viewing table with user session.
[HttpPost]
public ActionResult Login(sample_1 id)
{
if (ModelState.IsValid)
{
var uservar = db.sample_1.Where(a => a.boid.Equals(id.boid)).FirstOrDefault();
if (uservar != null)
{
Session["UserBOID"] = uservar.boid.ToString();
return RedirectToAction("UserLogin");
}
}
return View(id);
}
public ActionResult UserLogin()
{
if(Session["UserBOID"] != null)
{
var mkimodel = new MkistatVsUserLogin { mkistats = dsedb.mkistats.ToList() };
return View(mkimodel);
}
else
{
return RedirectToAction("Login");
}
}

Two CheckBoxList

Model selects from a database list of products to their categories. On the form you want to display CheckBoxList with a list of categories and another with a list of items in this one (or more) category. Immediately after selecting the category list of products to be updated. How can this be implemented?
Thanks in advance.
I normally use below approach when dealing with checkboxes check whether it helps you.
Model:
namespace GateApplication.Models
{
public class Gate
{
public string PreprationRequired { get; set; }
public List<CheckBoxes> lstPreprationRequired{ get; set; }
public string[] CategoryIds { get; set; }
}
public class CheckBoxes
{
public int ID { get; set; }
public string Value { get; set; }
public string Text { get; set; }
public bool Checked { get; set; }
}
}
Controller:
Load CheckBox Value:
public ActionResult Create()
{
List<CheckBoxes> lstchk = new List<CheckBoxes>()
{
new CheckBoxes {Text="coduit", Value="coduit" },
new CheckBoxes {Text="safety", Value="safety" },
new CheckBoxes {Text="power", Value="power" },
new CheckBoxes {Text="access", Value="access" }
};
var model = new Gate
{
lstPreprationRequired=lstchk
};
return View(model);
}
View:
#foreach (var item in Model.lstPreprationRequired)
{
<input type="checkbox" id="#item.Value" name="CategoryIds" value="#item.Text"/>
<label for="optionId">#item.Text</label>
<br />
}
Now your view shold have list of checkboxes. Now saving CheckBox values to the database.
[HttpPost]
public ActionResult Create(Gate ViewModel,FormCollection collection)
{
try
{
Gate gate = new Gate();
if (ModelState.IsValid)
{
gate.PreprationRequired = Request.Form["CategoryIds"];// here you'll get a string containing a list of checked values of the checkbox list separated by commas
if (string.IsNullOrEmpty(gate.PreprationRequired))//this is used when no checkbox is checked
gate.PreprationRequired = "None,None";
Save();//Save to database
return RedirectToAction("Index");
}
else
{
return View();
}
}
catch
{
return View();
}
}
Now you have below kind of string in your database
safety,power,access
Now fetch the selected values and display the view.
public ActionResult Edit(int id)
{
List<CheckBoxes> lstchk = new List<CheckBoxes>()
{
new CheckBoxes {Text="coduit", Value="coduit" },
new CheckBoxes {Text="safety", Value="safety" },
new CheckBoxes {Text="power", Value="power" },
new CheckBoxes {Text="access", Value="access" }
};
var model = new Gate
{
lstPreprationRequired =lstchk,
CategoryIds = "safety,power,access".Split(',')//here get your comma separated list from database and assign it to the CategoryIds string array, i have used sample text for the values
};
return View(model);
}
View:
#foreach (var item in Model.lstPreprationRequired)
{
<input type="checkbox" id="#item.Value" name="CategoryIds" value=#item.Text"
#foreach (var c in Model.CategoryIds)
{
if(c == item.Value)
{
<text> checked="checked"</text>
}
}
<label for="optionId">#item.Text></label>
}
Let me know if this does not help you.

Error loading images from database

I have a question about showing images loaded from a mysql database in an Index view.
In my database table "deliverables" I have "item_id", "deliverable_image" and "afstudeerrichting_id". "item_id" and "afstudeerrichting_id" are FK from other tables.
I want to show the images when afstudeerrichting_id = ..
Controller:
public ActionResult Index()
{
var model = repository.GetIdsOfImages(1);
return View(model.ToList());
}
public ActionResult ShowImage(int id)
{
IQueryable<byte[]> data = repository.GetImages(id);
byte[] firstimage = data.First();
return File(firstimage, "image/png");
}
Repository:
public IQueryable<long> GetIdsOfImages(int afstudeerrichtingid)
{
return from deliverable in entities.deliverables
where deliverable.afstudeerichting_id.Equals(afstudeerrichtingid)
select deliverable.item_id;
}
public IQueryable<byte[]> GetImages(int itemID)
{
return from deliverable in entities.deliverables
where deliverable.item_id.Equals(itemID)
select deliverable.deliverable_image;
}
View:
#foreach(var imgID in Model.DeliverablesIDsList)
{
<img src="#Url.Action("ShowImage", "Deliverable", new { DeliverableID = imgID })" />
}
In my Viewmodel I have:
public List<long> DeliverablesIDsList { get; set; }
public int DeliverableID { get; set; }
But now I always get this error:
he model item passed into the dictionary is of type 'System.Collections.Generic.List`1[System.Int64]', but this dictionary requires a model item of type 'GDMfrontEnd.Models.DeliverableViewModel'.
Does someone knows what I'm doing wrong?
you're sending to the view a list of int64 repository.GetIdsOfImages(1).ToList() and the view requires a DeliverableViewModel, so you must create a model and put the list into the model and send it to the view
the action should looks like:
public ActionResult Index()
{
var model = repository.GetIdsOfImages(1);
DeliverableViewModel model = new DeliverableViewModel()
model.DeliverablesIDsList = repository.GetIdsOfImages(1).ToList();
return View(model); //send to the view a model type of DeliverableViewModel
}
now with ActionResult ShowImage, the action expect id parmeter and you're sending DeliverableID, so change de var name
public ActionResult ShowImage(int DeliverableID)
{
IQueryable<byte[]> data = repository.GetImages(DeliverableID);
byte[] firstimage = data.First();
return File(firstimage, "image/png");
}

MVC Model State Validation fails on Listbox

I have a simple model which uses a multi select listbox for a many-many EF relationship.
On my Create action, I'm getting the error
The parameter conversion from type 'System.String' to type 'MyProject.Models.Location' failed because no type converter can convert between these types.
I have 2 models, an Article and a Location:
Article.cs
namespace MyProject.Models
{
public class Article
{
public Article()
{
Locations = new List<Location>();
}
[Key]
public int ArticleID { get; set; }
[Required(ErrorMessage = "Article Title is required.")]
[MaxLength(200, ErrorMessage = "Article Title cannot be longer than 200 characters.")]
public string Title { get; set; }
public virtual ICollection<Location> Locations { get; set; }
}
Location.cs:
namespace MyProject.Models
{
public class Location
{
[Key]
public int LocationID { get; set; }
[Required(ErrorMessage = "Location Name is required.")]
[MaxLength(100, ErrorMessage = "Location Name cannot be longer than 100 characters.")]
public string Name { get; set; }
public virtual ICollection<Article> Articles { get; set; }
}
}
I have a ViewModel:
namespace MyProject.ViewModels
{
public class ArticleFormViewModel
{
public Article article { get; set; }
public virtual List<Location> Locations { get; set; }
public ArticleFormViewModel(Article _article, List<Location> _locations)
{
article = _article;
Locations = _locations;
}
}
}
create.cshtml:
#model MyProject.ViewModels.ArticleFormViewModel
<h2>Create</h2>
#using (Html.BeginForm()) {
#Html.AntiForgeryToken()
#Html.ValidationSummary(true)
<fieldset>
<legend>Article</legend>
<div class="editor-label">
#Html.LabelFor(model => model.article.Title)
</div>
<div class="editor-field">
#Html.EditorFor(model => model.article.Title)
#Html.ValidationMessageFor(model => model.article.Title)
</div>
<h3>Locations</h3>
#Html.ListBoxFor(m=>m.article.Locations,new MultiSelectList(Model.Locations,"LocationID","Name"))
<p>
<input type="submit" value="Create" />
</p>
</fieldset>
}
Finally my controller actions:
// GET: /Article/Create
public ActionResult Create()
{
var article = new Article();
var AllLocations = from l in db.Locations
select l;
ArticleFormViewModel viewModel = new ArticleFormViewModel(article, AllLocations.ToList());
return View(viewModel);
}
//
// POST: /Article/Create
[HttpPost]
[ValidateAntiForgeryToken]
public ActionResult Create(Article article)
{
var errors = ModelState.Values.SelectMany(v => v.Errors);
if (ModelState.IsValid)
{
var locations = Request.Form["article.Locations"];
if (locations != null)
{
var locationIDs = locations.Split(',');
foreach (var locationID in locationIDs)
{
int id = int.Parse(locationID);
Location location = db.Locations.Where(l => l.LocationID == id).First();
article.Locations.Add(location);
}
}
db.Articles.Add(article);
db.SaveChanges();
return RedirectToAction("Index");
}
var AllLocations = from l in db.Locations
select l;
ArticleFormViewModel viewModel = new ArticleFormViewModel(article, AllLocations.ToList());
return View(viewModel);
}
This all works relatively well, my Locations listbox is populated properly:
If I do not select a Location then my model is saved properly. If I select one or more locations then my Model.IsValid check fails with the exception
The parameter conversion from type 'System.String' to type 'MyProject.Models.Location' failed because no type converter can convert between these types.
However if I remove the ModelState.IsValid check then despite the error my values are all correctly saved into the database - just that I lose validation for things such as the model title.
Hope someone can help!
Unless you create a type converter, you cannot directly bind the results of your list box directly to a complex object like that. The reason lies in the fact that MVC can only deal with posted HTTP values, which in this case are an array of strings that contain the selected ID's. Those strings do not directly map to your Locations object (ie the number 1 cannot be directly converted to a Locations object with an ID of 1).
Your best bet is to have a list of location ID's in your View Model of type string or int to accept the posted values, then in your post method create the Location objects and fill them with the correct ID's.
FYI, the reason your code works is because you are bypassing the model binding and going directly to the Request.Form collection. You will notice that the bound Article object will not have any Location objects.
EDIT:
I don't even see how your code would work even without this problem. Your ArticleFormViewModel does not have a parameterless constructor, so that will fail in model binding (unless you have a custom model binder).
In any event, what you want to do is this (note, you will have to populate SelectedLocationIDs if you want them to be selected when the view is rendered):
public class ArticleFormViewModel
{
...
List<int> SelectedLocationIDs { get; set; }
...
}
Then, in your view you have:
#Html.ListBoxFor(m=>m.SelectedLocationIDs,
new MultiSelectList(Model.Locations,"LocationID","Name"))
In your Post method, instead of the code that calls Request.Form, you have something like this:
foreach(var locationID in article.SelectedLocationIDs) {
... // look up your locations and add them to the model
}

Resources