Running this Index controller gives me errors, when I try to pass IEnumerable into Tempdata.
When debugging, TempData["ProductCategory"] seems to store expected data in Watch, but cannot render Html View after storing. However, the Html does show when I store a simple stirng.
public IActionResult Index()
{
// This gives me http error 500
//TempData["ProductCategory"] = productcategoryrepository.GetAllProductCategory();
// This works at least!
TempData["ProductCategory"] = "test";
//TempData.Keep();
return View();
}
public IEnumerable<ProductCategory> GetAllProductCategory()
{
return _context.ProductCategory.ToList();
}
Other Info:
public partial class ProductCategory
{
public ProductCategory()
{
Product = new HashSet<Product>();
}
public int ProductCategoryId { get; set; }
public string ProductCategoryName { get; set; }
public string ProductCategoryDescription { get; set; }
public virtual ICollection<Product> Product { get; set; }
}
public partial class Product
{
public int ProductId { get; set; }
public string ProductName { get; set; }
public string ProductDescription { get; set; }
public string ImageLocation { get; set; }
public int? ProductCategoryId { get; set; }
public virtual ProductCategory ProductCategory { get; set; }
}
To be able to store data in sessions or temp data, the type must be serializable. IEnumerable<T> cannot be serialized. Try a List<T> instead.
https://learn.microsoft.com/en-us/aspnet/core/fundamentals/app-state?view=aspnetcore-2.1
Related
I want to do an simply ASP .Net Core MVC APP.
I have two models:
public class Farming
{
[Key]
public int Id { get; set; }
public string Localization { get; set; }
public List<Animal> Animals { get; set; } //i want to get into it
public List<Worker> Workers { get; set; } //from cshtml file
}
public class Animal
{
[Key]
public int Id { get; set; }
public Species Species { get; set; }
public DateTime BirthDate { get; set; }
public bool Sex { get; set; }
public DateTime ImpregnationDate { get; set; }
}
public class Worker
{
[Key]
public int Id { get; set; }
public string FirstName { get; set; }
public string LastName { get; set; }
public string Position { get; set; }
public float Salary { get; set; }
public DateTime EmploymentDate { get; set; }
public DateTime EndOfEmploymentDate { get; set; }
}
I setting up my database, it works ok. In dbo.Animals (dbo.Workers works too) in SQL Object explorer everything works pretty fine:
What i want to do, is to get acces into List<Animal> Animals and list of Workers fromIndex.cshtml page genereted internally in ASP .Net Core MVC in another List.cshtml file. Controller is genereted by Scaffolding too.
My Index.cshtml (i short it a little)
#model IEnumerable<Farm.Models.Farming>
#{
ViewData["Title"] = "Index";
}
//foreach loop here with "item"
<a asp-action="List" asp-route-id="#item.Id">#Html.DisplayFor(modelItem => item.Localization)</a>
Method for going to List.cshtml from FarmingController.cs
public async Task<IActionResult> List(int? id)
{
if (id == null)
{
return NotFound();
}
var farming = await _context.Farms.FirstOrDefaultAsync(m => m.Id == id);
if (farming == null)
{
return NotFound();
}
return View(farming);
}
So, how to get acces into Models.Farming.Animal and Models.Farming.Worker from imported #SolutinName.Models.Farmin in List.cshtml?
EDIT1:
I tried to get acces to Animal in this way:
var animal = await _context.Animals.FirstOrDefaultAsync(a => a.FarmingId == id);
//i get `id` poperty from func `<IActionResult>` that i mentioned higher in this question
But i get information from Visual, that Animal dont have definition FarmingId (that is true, look at Animal model) but it exist in dbo.Animals. Im new in Core, any ideas?
EDIT2:
I edited database to this form, now it works better:
public class Farming
{
[Key]
public int Id { get; set; }
public string Localization { get; set; }
public List<Animal> Animals { get; set; }//
public List<Worker> Workers { get; set; }//
}
public class Animal
{
[Key]
public int Id { get; set; }
public DateTime BirthDate { get; set; }
public bool Sex { get; set; }
public DateTime ImpregnationDate { get; set; }
[ForeignKey("Farming")]
public int FarmingId { get; set; }
public Farming Farming { get; set; }
}
public class Worker //pracownik
{
[Key]
public int Id { get; set; }
public string FirstName { get; set; }
public string LastName { get; set; }
public string Position { get; set; }
public float Salary { get; set; }
public DateTime EmploymentDate { get; set; }
public DateTime EndOfEmploymentDate { get; set; }
[ForeignKey("Farming")]
public int FarmingId { get; set; }
public Farming Farming { get; set; }
}
Everything seems to be okay, however try to explicitly include the animals
Farm theFarm = _context.Farms.Include(f => f.Animals).Where(f => f.Id == farmId);
the object theFarm will contain all fields of the farm and also the list with animals. and farmId is the id of the farm you want to get.
use this to get all farms with their animals:
var theFarms = _context.Farms.Include(f => f.Animals).ToList();
I have been trying to make this happen for a few hours now.I have two models within my model folder called Models, i am trying to pull data from the model to display it in the view, i am aware of only one model statement can be applied to the view. So i have Created a ViewModels which contain the properties that i would like to reference in the view. now when i run the the application im getting a compilation Error which says:
"Compiler Error Message: CS0246: The type or namespace name 'Models' could not be found (are you missing a using directive or an assembly reference?)"
I would appreciate a bit of help of if there is any other way of doing it feel free to advice.
New ViewModel created
public class MainModelscs <T> where T :class
{
public StoreAudit StoreAudit { get; set; }
public StoreQuestions StoreQuestions { get; set; }
public List<string> StoreWindow { get; set; }
public IPagedList<T> IndexList { get; set; }
}
ViewMode PROPERTIES inside my view,
#model PopMarketing.ViewModel.MainModelscs<PopMarketing.Models>
Model 1
public class StoreQuestions
{
[DatabaseGenerated(DatabaseGeneratedOption.Identity)]
[Key]
public int ReviewId { get; set; }
public int AuditId { get; set; }
public int QuestionOne { get; set; }
public string QuestionTwo { get; set; }
public string QuestionThree { get; set; }
public string QuestionFour { get; set; }
}
Model 2
[Key]
[Column(Order = 1)]
public int AuditId { get; set; }
public string Date { get; set; }
public int StoreNumber { get; set; }
public string StoreName { get; set; }
public string Address { get; set; }
public string Manager { get; set; }
Controller Method
public class AuditController : Controller
{
private PopMarketingContext db = new PopMarketingContext();
//
// GET: /Audit/
private const string PASSWORD = "MarchJava2016";
public ActionResult Index(string searchString)
{
int number;
int check;
bool result = Int32.TryParse(searchString, out number);
if (result)
{
check = Convert.ToInt32(searchString);
var shops = from s in db.StoreAudit
select s;
if (!String.IsNullOrEmpty(searchString))
{
shops = shops.Where(s => s.StoreName.ToUpper().Contains(searchString.ToUpper()) ||
s.StoreNumber.Equals(check));
}
return View(shops.ToList());
}
else
{
var shops = from s in db.StoreAudit
select s;
if (!String.IsNullOrEmpty(searchString))
{
shops = shops.Where(s => s.StoreName.ToUpper().Contains(searchString.ToUpper()));
}
return View(shops.ToList());
}
}
Jaimin is correct, in #model you pass the class you want to use as model, not the directory or namespace of the class.
As for using viewmodels correctly:
Let's say I have two classes:
class Student
{
public string name;
public string mentor;
}
class Teacher
{
public string name;
public string salary;
}
And i want to have a view show both their names. I can create a viewmodel like this:
class StudentAndTeacherVM
{
public Teacher teacher;
public Student student;
}
The controller would look like this:
public ActionResult Index()
{
var student = new Student();
*fill student*
var teacher = new Teacher();
*fill teacher*
var model = new PersonVM();
model.teacher = teacher;
model.student = student;
return view(model);
}
Now you can reach them in the view by:
#Model.student.name
#Model.teacher.name
Or if I want to be as efficient as possible, I could also just put in the names into the VM.
controller:
public ActionResult Index()
{
var student = new Student();
*fill student*
var teacher = new Teacher();
*fill teacher*
var model = new PersonVM();
model.teacherName = teacher.name;
model.studentName= student.name;
return view(model);
}
View:
class StudentAndTeacherVM
{
public string teacherName;
public string studentName;
}
Create instance of MainModelscs in your action
. . .
i.e. MainModelscs <string> Obj = new MainModelscs <string> ;
. . .
Then pass this to the view.
return View(Obj);
Now in your view,
#model PopMarketing.ViewModel.MainModelscs<string>
(take T as your model name not the namespace!)
Sorry, i got much late than i said. But here is how you can join two tables, map them to a model and pass to the view. The first one of the class whose properties correspond to the comments table of the database.
public class Comments
{
public int ID { get; set; }
public string CommentText { get; set; }
public string Username { get; set; }
public int Upvote { get; set; }
public int Downvote { get; set; }
public int InappropriateFlags { get; set; }
public int PostId { get; set; }
public string ControllerName { get; set; }
public int ReplyTo { get; set; }
public bool replied { get; set; }
}
Now another user profiles table which is needed to be joined with the comments table.
public class UserProfile
{
public int ID { get; set; }
public string Username { get; set; }
public string DisplayName { get; set; }
public int Reputation { get; set; }
public DateTime DateOfRegistration { get; set; }
public int Money { get; set; }
public string ImageUrl { get; set; }
public string FirstName { get; set; }
public string LastName { get; set; }
public string Country { get; set; }
public string State { get; set; }
public string City { get; set; }
public string Location { get; set; }
public int? PostalCode { get; set; }
public int ProfileViews { get; set; }
public string AboutMe { get; set; }
}
Now the much needed model for handling the join of these two tables. I haven't included all the properties of both tables as i didn't need them in the view, but you can ofcourse include them. In that case, don't forget to update your data access query also.
public class CommentUserProfileJoin
{
public int ID { get; set; }
public string CommentText { get; set; }
public string Username { get; set; }
public string DisplayName { get; set; }
public int Upvote { get; set; }
public int Downvote { get; set; }
public int InappropriateFlags { get; set; }
public int PostId { get; set; }
public string ControllerName { get; set; }
public int ReplyTo { get; set; }
public bool replied { get; set; }
public int UserProfileId { get; set; }
}
I am using dapper ORM. So this is the data access code that creates a join and maps it to the join table written above.
public IEnumerable<CommentUserProfileJoin > GetComments(int postId, string controllerName, int replyTo)
{
IEnumerable<CommentUserProfileJoin> comments;
const string query = "Select c.[id], c.[CommentText], c.[Username], c.[Upvote], c.[Downvote], c.[InappropriateFlags], c.[PostId], c.[ControllerName], c.[ReplyTo], c.[replied], u.[id] as UserProfileId, u.displayname from Main.Comments c LEFT JOIN Profile.UserProfiles u on c.username = u.username where c.PostId = #postId and c.ControllerName = #contName and c.ReplyTo = #ReplyTo order by ID desc";
comments = conObj.Query<CommentUserProfileJoin>(query, new { postId = postId, contName = controllerName, ReplyTo = replyTo });
return comments;
}
so now i have the model for the join of two tables, i can use it in any view like this
#model IEnumerable<DataAccessLayer.Models.CommentUserProfileJoin>
Hope this helps you. Also, unintentionally, i may not have followed best practices. I will be glad if someone can notify them through comments. Thanks
this is how the controller looks like
public ActionResult Edit()
{
return View();
}
[HttpPost]
public ActionResult Edit(Car _car)
{
if (ModelState.IsValid)
{
entities.Entry(_car).State = EntityState.Modified;
entities.SaveChanges();
RedirectToAction("Stock");
}
return View(_car);
}
the page itself is pretty much the "Edit" template with just a different redirect at the bottom.
this is the Car class
public partial class Car
{
public Car()
{
this.Orders = new HashSet<Order>();
}
public int CarID { get; set; }
public string Manufacturer { get; set; }
public string Model { get; set; }
public decimal Daily_Cost { get; set; }
public decimal Late_Fee { get; set; }
public int Year { get; set; }
public string Gear { get; set; }
public int Mileage { get; set; }
public bool Available { get; set; }
public string Registration { get; set; }
public int Location { get; set; }
public string Picture { get; set; }
public virtual Branch Branch { get; set; }
public virtual ICollection<Order> Orders { get; set; }
}
I'm not exactly sure what's causing the ModelState to be invalid but when I look at the object at runtime the only thing I see that I think is wrong, is Branch is null.
Branch is in a relationship in the db with Location. Location is foreign key and Branch is primary key (in the DB it's BranchID but I don't think that's relevant)
I have these models:
public class Condominium
{
public int CondominiumID { get; set; }
public int BatchID { get; set; }
public string Name { get; set; }
public bool LiveInCondominium { get; set; }
public string Phone { get; set; }
public string Email { get; set; }
public Batch Batch { get; set; }
public List<Employee> Employees { get; set; }
}
public class Employee
{
public int EmployeeID { get; set; }
public int CityID { get; set; }
public string UserID { get; set; }
public Condominium CondominiumID { get; set; }
public string Name { get; set; }
public string Address { get; set; }
public string ZipCode { get; set; }
public string Contact { get; set; }
public string Phone { get; set; }
public string Email { get; set; }
public City City { get; set; }
public Condominium Condominium { get; set; }
}
I need to create Employee objects dynamically and put them into a list and when I make a post request the object Condominium contains a list with Employee objects. I don't have any idea how I can make the view for this.
I suggest that you build View models for each view, in this case you would build a model that contains a property that holds a list of employees. You would then simple fill the model and return it to the view.
Here is some pseudo code:
Controller
public ActionResult Index()
{
var viewModel = new ViewModel()
{
Employees = BuildListOfEmployees() // Method that gets/builds a list of employees, expected return type List<Employee>
};
return View(viewModel);
}
class ViewModel
{
public List<Employee> Employees { get; set; }
}
View
#model YourNamespace.ViewModel
<ul>
#foreach (var employee in Model)
{
<li>employee.Name</li>
}
</ul>
Typically this information is stored in a database and you just pass the IDs as URL parameters. The HTTP request handler will take the parameter(s) and look up the information it needs from the database.
Your object structure looks pretty flat so they would translate easily to Tables in a relational database.
Trying to figure out checkboxlists to implement in a few areas of our system. We have a table, tblJobs. This has a "AllocatedTo" property, which links to the UserID of "tblGlobalUsers". What we want is to be able to select multiple users, iterate through and insert a database record for each user selected to allocate the job to them.
I've tried following some other questions people asked on here, such as Asp.Net MVC4 Display CheckboxList and some other guides, but just getting nowhere with it unfortunately.
Will provide the code that anyone wants, or more information if needed.
Many thanks
Edit:
Have followed the link Stephen provided and attempted to update my viewmodel and controller as required. My viewmodel is now:
public class JobCreateViewModel
{
public string JobTitle { get; set; }
public string Description { get; set; }
public int InventoryID { get; set; }
public int ReportedBy { get; set; }
public int Priority { get; set; }
public int JobType { get; set; }
public int UserID { get; set; }
public string NetworkLogin { get; set; }
public bool IsSelected { get; set; }
public virtual tblGlobalUser GlobalUserAllocated { get; set; }
public virtual tblGlobalUser GlobalUserReportedBy { get; set; }
public virtual tblInventory InventoryHardware { get; set; }
public virtual tblJobType TypeJob { get; set; }
public virtual tblJobPriority JobsPriority { get; set; }
}
public class JobsAllocateViewModel
{
public JobsAllocateViewModel()
{
AllocatedTo = new List<JobCreateViewModel>();
}
public int UserID { get; set; }
public string NetworkLogin { get; set; }
public List<JobCreateViewModel> AllocatedTo { get; set; }
}
And the controller is:
public ActionResult Create()
{
return View();
}
[HttpPost]
[ValidateAntiForgeryToken]
public ActionResult Create(JobCreateViewModel viewModel)
{
JobsAllocateViewModel model = new JobsAllocateViewModel();
if(ModelState.IsValid)
{
JobsContext.tblJobs.Add(new tblJob
{
JobTitle = viewModel.JobTitle,
JobDescription = viewModel.Description,
InventoryID = viewModel.InventoryHardware.InventoryID,
ReportedBy = viewModel.GlobalUserReportedBy.UserID,
AllocatedTo = model.AllocatedTo,
Priority = viewModel.JobsPriority.PriorityID,
JobType = viewModel.TypeJob.TypeID
});
JobsContext.SaveChanges();
return RedirectToAction("Index");
}
return View(viewModel);
}
Getting an error of "Cannot convert type systems.collections.generic.list to int" on AllocatedTo = model.AllocatedTo,