Error when converting List to IEnumerable [duplicate] - asp.net-mvc-4

This question already has answers here:
The model item passed into the dictionary is of type .. but this dictionary requires a model item of type
(7 answers)
Closed 5 years ago.
I am trying to display the default index page for a model. But I get the below error.
The model item passed into the dictionary is of type
'System.Collections.Generic.List 1[System.Boolean]', but this
dictionary requires a model item of type
'System.Collections.Generic.IEnumerable`1[EDIWebsite.Models.Error_Details]'.
Controller
public ActionResult FindRelatedBols(string bolnumber)
{
if (bolnumber == null)
{
return new HttpStatusCodeResult(HttpStatusCode.BadRequest);
}
var error_Summaries = db.Error_Details.Select(r => r.BOL == bolnumber);
if (error_Summaries == null)
{
return HttpNotFound();
}
return PartialView("~/Views/Error_Details/Index.cshtml",error_Summaries.ToList());
}
View
#model IEnumerable<EDIWebsite.Models.Error_Details>
#{
ViewBag.Title = "Index";
}
<h2>Index</h2>
<p>
#Html.ActionLink("Create New", "Create")
</p>
<table class="table">
<tr>
<th>
#Html.DisplayNameFor(model => model.Source_System)
</th>
.
.
.
#Html.ActionLink("Edit", "Edit", new { /* id=item.PrimaryKey */ }) |
#Html.ActionLink("Details", "Details", new { /* id=item.PrimaryKey */ }) |
#Html.ActionLink("Delete", "Delete", new { /* id=item.PrimaryKey */ })
</td>
</tr>
}
</table>

The error is self explanatory. Your view is strongly typed to a collection of Error_Details objects.Your current code is generating IQueryable<bool> as the type of error_Summaries variable and you are later calling the ToList() on that, which will generate a list of boolean values(List<bool>).
Your view is expecting something(IEnumerable<Error_Details>) and your action method is passing something else(List<bool>), hence getting that type mismatch exception!
You need to pass a collection of Error_Details objects to the view. I assume you wanted to pass a filtered list of items which is has the same BOL value as your bolnumber parameter. You can use the LINQ Where method to do the filtering.
var items = db.Error_Details.Where(a=>a.BOL == bolnumber).ToList();
return PartialView("~/Views/Error_Details/Index.cshtml",items);
Assuming the BOL property on Error_Details class is of string type.

Related

Property values of the same type are updated incorrectly in Blazor

Background:
I wanted to achieve the following:
Keep a copy of the data context and use the copy for editing
So that I can reset the data context back to its unchanged state using an onclick event by doing copyValue = unchangedValue
Here is my attempt (it's been trimmed down in size to reduce noises but it has the same issue):
**index.razor**
#page "/"
#using SolutionName.Data
#using System.Reflection
<EditForm Model="Items2">
<table class="table">
<thead>
<tr>
<th>Summary</th>
</tr>
</thead>
<tbody>
#foreach (var i in Items2)
{
<tr #key="#i.GetHashCode()">
<InputText #bind-Value="i.Summary"></InputText>
</tr>
}
</tbody>
</table>
</EditForm>
//
//reflections for debuggings
//
#if (Items != null)
{
<p>
#foreach (var item in Items)
{
<span>#($"Items.{typeof(WeatherForecast).GetProperty(nameof(WeatherForecast.Summary)).Name}={typeof(WeatherForecast).GetProperty(nameof(WeatherForecast.Summary)).GetValue(item)}")</span>
}
</p>
}
#if (Items2 != null)
{
<p>
#foreach (var item in Items2)
{
<span>#($"Items2.{typeof(WeatherForecast).GetProperty(nameof(WeatherForecast.Summary)).Name}={typeof(WeatherForecast).GetProperty(nameof(WeatherForecast.Summary)).GetValue(item)}")</span>
}
</p>
}
#code{
List<WeatherForecast> Items = new List<WeatherForecast>();
List<WeatherForecast> Items2 = new List<WeatherForecast>();
protected override void OnInitialized()
{
Items = new List<WeatherForecast>()
{
new WeatherForecast()
{
Date = DateTime.Now,
Summary = "123",
TemperatureC = 1
}
};
Items2 = Items;
}
private void ResetItems2()
{
Items2 = Items;
}
}
As you can see, I am binding Items2, and not Items, to the <EditForm>.
However, updating the summary seems to update both Items2 and Items. I also noticed that this will not happen if Items and Items2 are of two different types (say that they have exactly the same properties, and I cast one to another...)
Two questions:
Why is Item updated in this case?
Is there a way to only update Items2 and not Items, while allowing Items and Items2 to be the same type?
Detailed steps to reproduce the issue:
Step 1. Initialized and render for the first time
Step 2. Change the value to 456 and then tab away
The expected result should be
Items.Summary=123 (not 456)
Items2.Summary=456
The issue is that you're using reference type assignment. When you assign Items to Items2, you actually assign a pointer to Itemss values. Both variable point to the same list of objects.
If it's applicable create a value type instead. Saving data in the local storage and then retrieving it is a viable solution.
This:
List<WeatherForecast> Items = new List<WeatherForecast>();
List<WeatherForecast> Items2 = new List<WeatherForecast>();
is superfluous. Code like this:
List<WeatherForecast> Items;
List<WeatherForecast> Items2;

Editor method of HtmlHelper class doesn't work with collections

In my view I have a model with a property Details of type List. The collection has 3 elements. Now I need to edit this list in a view.
If I use Html.EditorFor method passing the expression everything works correctly, But if I use Html.Editor method, the binding fails. By "fails" I mean that MVC uses the string editor for all fields (even if they are numbers) passing null as a model.
// this works correctly
#for (var i = 0; i < Model.Details.Count; i++)
{
<li>
#Html.EditorFor(m => m.Details[i].Name)
#Html.EditorFor(m => m.Details[i].Age)
</li>
}
// this doesn't work
#for (var i = 0; i < Model.Details.Count; i++)
{
<li>
#Html.Editor("Details[" + i +"].Name")
#Html.Editor("Details[" + i +"].Age")
</li>
}
I'm using ASP.NET Core 3.0 and didn't test this code against previous versions. For several reasons, I cannot use the EditorFor method so I'm stuck with this problem.
Any ideas?
Editor() HTML Helper method is for simple type view and EditorFor() HTML Helper method is for strongly type view to generate HTML elements based on the data type of the model object’s property.
The definition of Html.Editor:
// Summary:
// Returns HTML markup for the expression, using an editor template. The template
// is found using the expression's Microsoft.AspNetCore.Mvc.ModelBinding.ModelMetadata.
//
// Parameters:
// htmlHelper:
// The Microsoft.AspNetCore.Mvc.Rendering.IHtmlHelper instance this method extends.
//
// expression:
// Expression name, relative to the current model. May identify a single property
// or an System.Object that contains the properties to edit.
//
// Returns:
// A new Microsoft.AspNetCore.Html.IHtmlContent containing the <input> element(s).
//
// Remarks:
// For example the default System.Object editor template includes <label> and <input>
// elements for each property in the expression's value.
// Example expressions include string.Empty which identifies the current model and
// "prop" which identifies the current model's "prop" property.
// Custom templates are found under a EditorTemplates folder. The folder name is
// case-sensitive on case-sensitive file systems.
public static IHtmlContent Editor(this IHtmlHelper htmlHelper, string expression);
You could identify a single property for the expression of Editor Tag Helper like below :
#model MVC3_0.Models.Detail
<table>
<tr>
<td>Id</td>
<td>#Html.Editor("Id")</td>
</tr>
<tr>
<td>Name</td>
<td>#Html.Editor("Name")</td>
</tr>
<tr>
<td>Age</td>
<td>#Html.Editor("Age")</td>
</tr>
</table>
public IActionResult Index()
{
var model = new Detail { Id = 1, Name = "jack", Age = 12 };
return View(model);
}
Result:
There is a workaround that you could use TextBox or input instead
#for (var i = 0; i < Model.Details.Count; i++)
{
<li>
#Html.TextBox("Details[" + i + "].Name", Model.Details[i].Name, new { htmlAttributes = new { #class = "text-field" } })
#Html.TextBox("Details[" + i + "].Age", Model.Details[i].Age, new { htmlAttributes = new { #class = "text-field" } })
</li>
}
// input tag helper
#for (var i = 0; i < Model.Details.Count; i++)
{
<li>
<input asp-for="#Model.Details[i].Name" />
<input asp-for="#Model.Details[i].Age" />
</li>
}

How to pass records from one view to another view?

I have a table of records and a submit button.
How do I pass those records from one view to another view while clicking the Submit Button?
Thanks in advance!
You have a table of records (from where are you getting those records?)
I'm guessing
In your controller:
public ActionResult Index()
{
ModelTemp = model = new ModelTemp();
model.listRecord = new List<ModelTempB>();
return view(model);
}
In your view:
#for (int x = 0; x < Model.listRecord .Count; x++)
{
<tr>
<td>
#Html.DisplayFor(modelItem => Model.listRecord[x].Someproperty)
<br/>
#Html.HiddenFor(modelItem => Model.listRecord[x].Someproperty)
</td>
</tr>
}
In your controller for Post:
[HttpPost]
public ActionResult Confirmation(ModelTemp model)
{
//now you can access the list of records
return view();
}
easiest way would be put a hidden input within the form same as submit button, serialize your records to json string on client or server depending on your situation. you can access the form collection and deserialize records from string in other controller.

Adding a record to the database based on input passed from a link on another form MVC 4

I have been using ASP.NET MVC 4 for a while but I have not yet come across a situation where i need to insert a value into the database from a scaffolded Create view which is based on a value passed from another view. I have tried to infer from the Edit view to try and modify my code to work but I have run into a snag. I got an error similar to this post. Here is my code from the view passing the value
#Html.ActionLink("Allocate", "Create", "Allocation", new { id=item.requestID}, null)
this is from the list of requests already in the database from the Index view
here is my code on the controller that is trying to force the Create method to use the ID passed from the link above
public ActionResult Create(int id = 0)
{
Request request = db.Requests.Find(id);
ViewBag.requestID = new SelectList(db.Requests, "requestID", "requestID", request.requestID);
return View(request);
}
then here is the posting code to the db
[HttpPost]
[ValidateAntiForgeryToken]
public ActionResult Create(Allocation allocation)
{
if (ModelState.IsValid)
{
db.Allocations.Add(allocation);
db.SaveChanges();
return RedirectToAction("Index");
}
ViewBag.requestID = new SelectList(db.Requests, "requestID", "requestID", allocation.requestID);
return View(allocation);
}
Basically what I am trying to do is allocate funds to a request made where by the allocation is entered into the db based on the request id. I am trying to prevent the user from choosing the request id from a drop down list. When I run this i get an error
The model item passed into the dictionary is of type 'System.Data.Entity.DynamicProxies.Request_A52006F7570E0448EE323CB36858E4D13EED0BAD958340B32FF166708545DA8C', but this dictionary requires a model item of type 'BudgetAllocation.Models.Allocation'.
If theres anyone out there who can help me out with this please do as soon as you can. I appreciate all the effort offred!!!!!
//EDIT
Here is my Create view
#model BudgetAllocation.Models.Allocation
#{
ViewBag.Title = "Create";
}
<h2>Create</h2>
#using (Html.BeginForm()) {
#Html.AntiForgeryToken()
#Html.ValidationSummary(true)
<fieldset>
<legend>Allocation</legend>
#Html.HiddenFor(model => model.requestID)
<div class="editor-label">
#Html.LabelFor(model => model.allocAmount, "Amount")
</div>
<div class="editor-field">
#Html.EditorFor(model => model.allocAmount)
#Html.ValidationMessageFor(model => model.allocAmount)
</div>
<p>
<input type="submit" value="Allocate" />
</p>
</fieldset>
}
<div>
#Html.ActionLink("Back to List", "Index")
</div>
#section Scripts {
#Scripts.Render("~/bundles/jqueryval")
}
The problem is your view id strongly typed with BudgetAllocation.Models.Allocation while in get action of Create you are passing object of type BudgetAllocation.Models.Request thats why you are getting the exception.
You have to pass object of type BudgetAllocation.Models.Allocation in Create get action as well because you view is strongly typed to it.
public ActionResult Create(int id = 0)
{
Request request = db.Requests.Find(id);
return View(request) // <-------------- here is the mistake
}
it should return allocation object, something like this, it is just an example may be you need to do some other thing instead of selecting:
public ActionResult Create(int id = 0)
{
Allocation allocation = db.Allocations.Find(x=>x.requestID == id);
ViewBag.requestID = new SelectList(db.Requests, "requestID", "requestID", request.requestID);
return View(allocation);
}
UPDATE:
you simply need to do like this not return allocaiton object return simply View:
public ActionResult Create(int id = 0)
{
ViewBag.requestID = new SelectList(db.Requests, "requestID", "requestID", request.requestID);
return View();
}

Cascade Drop down list

I am trying to create a cascading drop down list, and I am getting an error.
This contains what I am try to do with in my controller class:
public ActionResult Create()
{
ViewBag.Status = new SelectList(db.pjt_Statuses, "pjt_Status_ID", "StatusName");
ViewBag.CategoryID = new SelectList(db.pjt_Categories, "pjt_Category_ID", "CatName");
return View();
}
public ActionResult SubCategory(int id)
{
var SubCategory = from s in db.pjt_SubCategories
where s.CategoryID == id
select s;
return Json(SubCategory.ToList());
}
// POST: /Project/Create
[HttpPost]
public ActionResult Create(pjt_Projects pjt_projects)
{
if (ModelState.IsValid)
{
pjt_projects.CreationDate = DateTime.Now;
db.pjt_Projects.Add(pjt_projects);
db.SaveChanges();
return RedirectToAction("Index");
}
ViewBag.Status = new SelectList(db.pjt_Statuses, "pjt_Status_ID", "StatusName", pjt_projects.Status);
ViewBag.CategoryID = new SelectList(db.pjt_Categories, "pjt_Category_ID", "CatName", pjt_projects.CategoryID);
return View(pjt_projects);
}
View
This shows what I am try to do on the front end. I am getting a error with the bold line in my view code below. The error I am getting is:
There is no ViewData item of type IEnumerable<SelectListItem> that has the key pjt_SubCat_ID.
Code:
<div class="span3 offset1">
#Html.LabelFor(model => model.CategoryID, "Category")
#Html.DropDownList("CategoryID", String.Empty)#*, null, new { #onchange = "FetchSubCategories();" })*#
<br />
#Html.ValidationMessageFor(model => model.CategoryID)
</div>
<div class="span3 offset1">
<label>Sub Category</label>
#Html.DropDownList("pjt_SubCat_ID", String.Empty)
<br />
#Html.ValidationMessageFor(model => model.SubCategoryID)
</div>
Can someone advise me what is going wrong here?
The problem is that the engine is trying to get the SelectList from the viewbag and it cannot find it. I am guessing that you want the Dropdown to display the items you have stored in the viewbag under "pjt_SubCat_ID" but you are not adding that item to the viewbag anywhere in the code that you have listed in your question.
If that is supposed to be the data returned from the SubCategory() method, you will not find that data in the viewbag and you should have a javascript that calls this method on the click event of the original SelectList (category id one) and binds the returned data to the subcategory one.