MVC5 HTML ActionLink Throws CS1502 - asp.net-mvc

I've created a very simple view class in my MVC5 solution. It uses the Entity Framework and calls one of the controller class's actions. I want to output a list of VIN numbers as hyperlinks on my home page.
The view class syntax is as follows:
#{
ViewBag.Title = "Vehicle Inventory";
}
#model IEnumerable<TavernaMVC.Controllers.InventoryController>
<ul>
#foreach (var item in Model)
{
<li>#item</li>
}
</ul>
The error is as follows:
CS1502: The best overloaded method match for
'System.Tuple.Create<object,int>(object, int)' has some invalid arguments
How do I rectify my code so that each VIN's details are output in the view class? Alternatively, how would I simply output all the VIN values as hyperlinks?

First, you should not use your controller as model. What model class are you using? Since you're talking about VIN I will guess it can be called Car:
public class Car {
public int VIN { get; set; }
public string Details { get; set; }
}
In your controller you would then like to do something like:
public ActionResult Index() {
var cars = db.Cars.ToList();
return View(cars);
}
Then, define your view as:
#model IEnumerable<TavernaMVC.Models.Car>
#{
ViewBag.Title = "Vehicle Inventory";
}
<ul>
#foreach (var item in Model)
{
<li>#item.VIN</li>
}
</ul>

Your view looks correct if the TavernaMVC.Controllers.InventoryController class looks somewhat like:
public class TavernaMVC.Controllers.InventoryController
{
//VIN
public string VIN{get;set;}
//Url to Details
public URL Details{get;set;}
}
and you use this
<li>#item.VIN</li>
as the li line

Check for renamed Properties in the first line ...
I had this error after renaming a Property and using the AutoRefactoring in the Visual Studio which does not change the Properties in CSHTM files.

Related

Passing Data From View back to the HttpPost method in MVC

Alright so i want to pass data from the view back to Post Method in the controller.
The View :
#model IEnumerable< MvcMobile.Models.Trips>
<p>Time : #ViewBag.titi</p>
<p>ID :#ViewBag.iid </p>
<p>From : #ViewBag.From</p>
<p>To :#ViewBag.To </p>
Avaibliabe Trips :
#foreach (var item in Model)
{
if ( item.Time==ViewBag.titi)
{
<p>#item.TripID</p>
}
}
My HttpGet Method in the controller :
[HttpGet]
public ActionResult Book2(MvcMobile.Models.TicketsBooked tik)
{
ViewBag.titi = tik.Time;
ViewBag.iid = tik.TicketID;
ViewBag.from = tik.From;
ViewBag.To = tik.To;
var TripsList = db.Trips.ToList();
return View(TripsList);
}
In This case i cant use a dynamic object to pass variable since the model is IEnumerable
i want to pass one or two textBoxes back to the controller, how can i do that ?
an alternative question would be how can i do the same functionality in the view without making the model IEnumberable ?
and thanks alot.
You should read up on using view models. Basically it's best practice to only pass relevant data to the view. So instead on passing a model of IEnumerable you would have a view model with a property of IEnumerable plus the extra properties you want to post back to your controller.
So for example:
public class ViewModel
{
public IEnumerable<MvcMobile.Models.Trips> Trips { get; set; }
public string ExtraValue { get; set; }
}
and your view would be:
#foreach(var trip in Model.Trips)
{
<p>Do stuff</p>
}
#Html.TextBoxFor(m => m.ExtraValue)
Your post method would then accept a ViewModel.
[HttpPost]
public ActionResult Book2(ViewModel viewModel)
{
}
You can read up more on view models here or by searching Google / SO. There are many, many examples.

How to use Html.Action's RouteValueDictionary values in controller

Here i am using Html.Action to display a set of books in (Books.cshtml) partial page.
I am passing Route Dictionary values in action but I don't have any idea about how to get Route Dictionary values in Controller and also is it possible to get Route Dictionary values in Partial page("Books.cshtml").
Index.cshtml
#{RouteValueDictionary objRoute = new RouteValueDictionary();
objRoute.Add("Book1", "DavinciCode");
objRoute.Add("Book2", "Pirates");
objRoute.Add("Book3", "Ghost");
}
#Html.Action("Books", "Home", objRoute)
Books.cshtml(Partial Page)
<p style="color:Blue;">
The list of books are as folows
<p># Book items</p>
//Here I need to display list of books (i.e) routevalue Dictionary values
</p>
HomeController:
public ActionResult Books()
{
return PartialView();
}
I don't think using a RouteValueDictionary to store your model in is the best idea. You can use a model with your partial view too, you know.
I would make a model for the partial view, which represents the data you need, i.e. a list of Books. On the Book, you put the necessary data for each book, including the key needed to display the detail view of the book (i.e. an Id property):
public class Book
{
public int Id { get; internal set; }
public string Name { get; internal set; }
// ...
}
Then you make your partial view have a model of e.g. List<Book>, in Books.cshtml:
#model IList<Book>
<p style="color:Blue;">
The list of books are as follows:
<ul>
#foreach (var book in #Model)
{
#Html.ActionLink(book.Name, "BookDetails", new { id = book.Id })
}
</ul>
You should be able to access route data along the lines of:
ViewContext.RouteData.Values["controller"]
Try the below solution, Its working fine for me.
CONTROLLER :
public ActionResult Books()
{
Dictionary<int, string> books = new Dictionary<int, string>() {
{ 1, "ASP.NET MVC #" },
{ 2, "C#" },
{ 3, "Razor View" } };
return PartialView("Books", books);
}
PARTIAL VIEW :
#{
Layout = null;
}
#model Dictionary<int, string>
<h2>The list of books are as follows:</h2>
<ul>
#foreach (var book in #Model)
{
<li>#book.Value</li>
}
</ul>
IN VIEW ( Wherever you want to display the list of books)
#Html.Action("Books", "YOURCONTROLLERNAME")
They should appear as method arguments - you just have to declare the ones you're interested in:
public ActionResult Books(string Book1, string Book2, string Book3)
{
return PartialView();
}

Is it possible to have a generic Razor view to work with a generic model?

I'm working on a list generator using MVC.Net.
I have created ColumnInfo<T> and Report<T> classes as follows:
public class ColumnInfo<T>
{
public string Title{get;set;}
public Func<T,object> Projector{get;set;}
}
public class Report<T>
{
public IList<ColumnInfo<T>> Header{get;set;}
public IQueryable<T> Result{get;set;}
......
}
What I'd like to do is to create the header and the body of a Report by enumerating its Header in a partial view.
The question is : How to introduce my generic Report<T> to a Razor view?
Here's what I have in mind:
#foreach(var row in Model.Result)
{
<tr>
#foreach(var col in Model.Header)
{
<td>#col.Projector(row)</td>
}
</tr>
}
Possible solution is to use a dynamic as your generic type in your view:
#model Models.Report<dynamic>
Your controller also needs to set the type as dynamic:
public ActionResult Report()
{
var viewModel = new Report<dynamic>();
return View(viewModel);
}
Not sure if this solution suits your problem, but I've noticed it's not possible to just set: #model Models.Report<T>

The model item passed into the dictionary is of type 'System.Collections.Generic.List`1[System.Int32]'

ASP.Net MVC 4
I am trying to populate a list of Countries (data from Country table in DB) in a dropdownlist. I get the following error:
The model item passed into the dictionary is of type
System.Collections.Generic.List`1[System.Int32]', but this dictionary requires a model item of type 'BIReport.Models.Country'.
I am new to ASP.Net MVC and I don't understand that error. What I feel is what Index method is returning doesn't match with the model that I am using in the View.
Model::
namespace BIReport.Models
{
public partial class Country
{
public int Country_ID { get; set; }
public string Country_Name { get; set; }
public string Country_Code { get; set; }
public string Country_Acronym { get; set; }
}
}
Controller::
public class HomeController : Controller
{
private CorpCostEntities _context;
public HomeController()
{
_context = new CorpCostEntities();
}
//
// GET: /Home/
public ActionResult Index()
{
var countries = _context.Countries.Select(arg => arg.Country_ID).ToList();
ViewData["Country_ID"] = new SelectList(countries);
return View(countries);
}
}
View::
#model BIReport.Models.Country
<label>
Country #Html.DropDownListFor(model => model.Country_ID, ViewData["Country_ID"] as SelectList)
</label>
Where am I going wrong?
You are selecting CountryIDs, therefore you will have a list of integers passed into the view.
I think you really want something like this:
public ActionResult Index()
{
var countries = _context.Countries.ToList();
ViewData["Country_ID"] = new SelectList(countries, "Country_ID", "Country_Name");
return View();
}
I'm not really sure why you have single country as a model for your view.
Update:
I'm still not sure why the model is a country, if you are just going to post the ID of the selected country you don't necessarily need a model at all (or just have an integer). This will be just fine though:
View
#model MvcApplication1.Models.Country
#Html.DropDownListFor(m => m.Country_ID, ViewData["Country_ID"] as SelectList)
the problem is in line 1 of your view. change it like this :
#model IEnumerable<BIReport.Models.Country>
also there is no need to pass the model to view if you already did it by :
ViewData["Country_ID"] = new SelectList(countries);
When you say #model BIReport.Models.Country it means your view is expecting a model consisting single country details. On the contrary you need a list of countries to be displayed in the drop-down list. Hence you should tell the view to look for a list of country details instead.
Therefore #model IEnumerable.

EditorTemplate for collection property not used when calling EditorForModel (custom object template)

I am aware that complex types are not usually rendered when using EditorForModel but I am using a custom object template that does not do the check and calls Html.Editor for every property including complex types.
Unfortunately, whilst I can see the correct TemplateHint value for the property within the object template, the Editor call doesn't seem to use it and the built in collection template is used instead.
My object template is basically this:
#foreach (var property in ViewData.ModelMetadata.Properties.Where(x => x.ShowForEdit))
{
#Html.Editor(property.PropertyName)
}
If I force the use of the template by passing the name to the Editor call then the ModelMetadata is empty in the template.
Is this a bug / are there any workarounds?
Some more info:
So my view model contains the following:
[ACustomAttribute("Something")]
public IEnumerable<int> SelectedOptions { get; set; }
The attribute implements IMetadataAware and adds some stuff to the AdditionalValues Collection of the ModelMetadata as well as setting the TemplateHint. I can read this data from the object template but not from my custom template.
#foreach (var property in ViewData.ModelMetadata.Properties.Where(x => x.ShowForEdit))
{
if (!string.IsNullOrEmpty(property.TemplateHint))
{
#Html.Editor(property.PropertyName, property.TemplateHint)
}
else
{
#Html.Editor(property.PropertyName)
}
}
But please note that if you don't rely on the established conventions for resolving templates for complex collection types (a.k.a ~/Views/Shared/EditorTemplates/NameOfTheTypeOfCollectionElements.cshtml) and have used an UIHint on your collection property:
[UIHint("FooBar")]
public IEnumerable<FooViewModel> Foos { get; set; }
then the ~/Views/Shared/EditorTemplates/FooBar.cshtml editor template must be strongly typed to IEnumerable<FooViewModel> and not FooViewModel. So be careful, if this is your case, it's up to you to loop inside this custom template if you want to get to individual items of the collection. It will no longer be ASP.NET MVC that will automatically loop for you and invoke the editor template for each element.
UPDATE:
Still can't repro your issue.
Custom attribute:
public class ACustomAttribute : Attribute, IMetadataAware
{
private readonly string _templateHint;
public ACustomAttribute(string templateHint)
{
_templateHint = templateHint;
}
public void OnMetadataCreated(ModelMetadata metadata)
{
metadata.AdditionalValues["foo"] = "bar";
metadata.TemplateHint = _templateHint;
}
}
Model:
public class MyViewModel
{
[ACustom("Something")]
public IEnumerable<int> Foos { get; set; }
}
Controller:
public class HomeController : Controller
{
public ActionResult Index()
{
var model = new MyViewModel
{
Foos = Enumerable.Range(1, 5)
};
return View(model);
}
}
View (~/Views/Home/Index.cshtml):
#model MyViewModel
#using (Html.BeginForm())
{
#Html.EditorForModel()
}
Editor template for the object type (~/Views/Shared/EditorTemplates/Object.cshtml):
#foreach (var property in ViewData.ModelMetadata.Properties.Where(x => x.ShowForEdit))
{
if (!string.IsNullOrEmpty(property.TemplateHint))
{
#Html.Editor(property.PropertyName, property.TemplateHint)
}
else
{
#Html.Editor(property.PropertyName)
}
}
Custom editor template (~/Views/Shared/EditorTemplates/Something.cshtml):
#model IEnumerable<int>
<h3>
#ViewData.ModelMetadata.AdditionalValues["foo"]
</h3>
#foreach (var item in Model)
{
<div>
#item
</div>
}
Result:
So as you can see the additional metadata we added is shown in the template.

Resources