Returning object details in the View based on the object ID ASP.net core MVC - entity-framework

I'm building online catalog for phones, I have two controller one for phone Catalog and second for phone's details.With catalog everything is fine, now my goal is to see phone details after clicking on the phone's name or photo in the catalog.I think that with phone's id, its easier to solve this task, also I use repository pattern.
This Catalog' s Controller:
public class PhonesCatalog : Controller
{
private readonly IPhoneRepository _repository;
public int PageSize = 6;
public PhonesCatalog(IPhoneRepository repository)
{
_repository = repository;
}
[HttpGet]
public IActionResult Catalog(int productPage = 1)
=> View(new ProductsListViewModel
{
Phones = _repository.Phones
.OrderBy(x => x.PhoneId)
.Skip((productPage -1) * PageSize)
.Take(PageSize),
PagingInfo = new PagingInfo
{
CurrentPage = productPage,
ItemsPrePage = PageSize,
TotalItems = _repository.Phones.Count()
}
});
}
The repository pattern:
public interface IPhoneRepository
{
IQueryable<Phone> Phones { get; }
Phone GetPhoneById(int id);
}
public class EfMobileStoreRepository : IPhoneRepository
{
private readonly MobileStoreCatalogContext _context;
public EfMobileStoreRepository(MobileStoreCatalogContext context)
{
_context = context;
}
public IQueryable<Phone> Phones => _context.Phones;
public Phone GetPhoneById(int id) => _context.Phones
.FirstOrDefault(p => p.PhoneId == id);
}
and here is Phone detail controller and view:
public class PhonesDetails : Controller
{
private readonly IPhoneRepository _repository;
public PhonesDetails(IPhoneRepository repository)
{
_repository = repository;
}
[HttpGet]
public IActionResult Details(int id)
{
return View(_repository.GetPhoneById(id));
}
}
#model Mobile_Store_Catalog_wandio.Models.Phone
<h4>Phone Details</h4>
<div class="row">
<p>#Model.PhoneName</p>
<p>#Model.Manufactor</p>
<p>#Model.OperationSystem</p>
<p>#Model.Processor</p>
<p>#Model.Memory</p>
<p>#Model.ScreenResolution</p>
<p>#Model.Size</p>
<p>#Model.Wight</p>
</div>
Here Catalog View:
#model ProductsListViewModel
<h1>Phone Catalog</h1>
<div class="container-fluid">
<div class="container-fluid">
<div class="row">
<div class="col-md-3 btn-group-vertical text-center">
Filter
Search
</div>
<div class=" row col-md-9">
#foreach (var p in Model.Phones)
{
<div class=" col-md-4 border border-dark">
<a href="#Url.Action("Details", "PhonesDetails")">
<img class="img-fluid" src="/Images/#p.ImageName"/>
</a>
<p class="text-center container">#p.PhoneName</p>
<p class="text-white text-center bg-success">#p.Price.ToString("C2")</p>
</div>
}
</div>
</div>
</div>
</div>
<div class="row">
<div page-model="#Model.PagingInfo" page-action="Catalog" page-classes-enabled="true"
page-class="btn" page-class-normal="btn-outline-dark"
page-class-selected="btn-primary" class="btn-group-toggle m-1 al">
</div>
</div>
and here is the ProductViewList code:
public class ProductsListViewModel
{
public IEnumerable<Phone> Phones { get; set; }
public PagingInfo PagingInfo { get; set; }
}
Problem is that when I'm clicking on the phone image,but it takes only first id of phone and returns its detail,it doesn't matter which image is clicked, but I need to return details by id, not only first id Phone detail.
What I'm doing wrong here, can anyone help me?

You can change your code like this:
<a asp-controller="PhonesDetails" asp-action="Details" asp-route-id="#p.Id">
<img class="img-fluid" src="/Images/#p.ImageName"/></a>

Related

How to update a MVC Form before Submit

So i have 2 Viewbags, they each have a list of values from a database table, the first Viewbag have all possible values of a database column, while the other have only the values corresponding to the selected value in the first Viewbag.
I have the logic for the search.
but i need to have the form update after selecting one value, since they both need to be in the same form, it is not searching for the second value.
OBS:i am only using the controllers, and cshtml views, not razor pages.
Here is a simple demo how to create cascading selectlist in asp.net core mvc:
Model:
public class Category
{
public int Id { get; set; }
public string Name { get; set; }
}
public class SubCategory
{
public int Id { get; set; }
public int CategoryId { get; set; }
public string SubCategoryName { get; set; }
}
View(Index.cshtml):
<div>
<div style="float:left;width:40%">
<form id="form">
<div class="form-group row">
<label>Category Name</label>
<div class="col-12">
<select id="CategoryId" class="custom-select mr-sm-2"
asp-items="#(new SelectList( #ViewBag.Category,"Id","Name"))">
<option value="">Please Select</option>
</select>
</div>
</div>
<div class="form-group row">
<label>SubCategory Name</label>
<div class="col-12">
<select id="SubCategoryId" class="custom-select mr-sm-2"
asp-items="#(new SelectList(string.Empty,"Id","SubCategoryName"))">
<option value="">Please Select</option>
</select>
</div>
</div>
<div>
<input type="button" value="Search" />
</div>
</form>
</div>
</div>
#section Scripts
{
<script>
$(function () {
$('#CategoryId').change(function () {
var data = $("#CategoryId").val();
$.ajax({
url: '/Home/GetSubCategory?CategoryId=' + data,
type: 'Get',
success: function (data) {
var items = "";
$.each(data, function (i, item) {
items += "<option value='" + item.value + "'>" + item.text + "</option>";
});
$('#SubCategoryId').html(items);
}
})
});
})
</script>
}
Controller:
public class HomeController : Controller
{
private readonly MvcProj3Context _context;
public HomeController(MvcProj3Context context)
{
_context = context;
}
public IActionResult Index()
{
ViewBag.Category = _context.Category.ToList();
return View();
}
public JsonResult GetSubCategory(int CategoryId)
{
ViewBag.SubCategory = (from m in _context.SubCategory
where m.CategoryId == CategoryId
select m).ToList();
return Json(new SelectList(ViewBag.SubCategory, "Id", "SubCategoryName"));
}
}
Result:
The problem is, that the .cshtml file is completely rendered before its send to your browser. Therefore you cannot change it with C# code after its sent to the browser.
You could use blazor if you want to do it with c#, or you could do it with javascript.

Need walk-through of how to create a user and assign a role to it in one form (ASP.NET Core MVC 3+)

Using ASP.NET Core MVC 3.1.
Added security using the identity scaffolding.
Created default groups following the instructions from eShopOnWeb (https://github.com/dotnet-architecture/eShopOnWeb/blob/master/src/Infrastructure/Identity/AppIdentityDbContextSeed.cs)
Able to seed the database and create
3 groups: Admins, Managers, Users
3 users: Admin, Manager, User
assign the user to respective group.
I need instructions on how to accomplish assigning the roles to users from the User Management form (MVC pattern) at the time when I create a user or need to edit the roles for the users. Also I need MVC pattern not Razor pages like here https://github.com/bhrugen/Uplift/blob/master/Uplift/Areas/Identity/Pages/Account/Register.cshtml.cs
I presume I need to create the ViewModel which would include entries from dbo.AspNetUsers, dbo.AspNetRoles, dbo.AspNetUserRoles for that but not sure what exactly I need and how to perform.
Here is the desired functionality of the form
Here is a simple working demo , you could refer to
Models
public class ApplicationUser: IdentityUser
{
public DateTime BirthDate { get; set; }
public string City { get; set; }
public string Country { get; set; }
}
public class RegisterVM
{
[Required]
[EmailAddress]
[Display(Name = "Email")]
public string Email { get; set; }
[Required]
[StringLength(100, ErrorMessage = "The {0} must be at least {2} and at max {1} characters long.", MinimumLength = 6)]
[DataType(DataType.Password)]
[Display(Name = "Password")]
public string Password { get; set; }
[Display(Name = "Birth date")]
public DateTime BirthDate { get; set; }
public string City { get; set; }
public string Country { get; set; }
[Display(Name ="Management role")]
public string role { get; set; }
public List<IdentityRole> RoleList { get; set; }
}
DbContext
public class ApplicationDbContext : IdentityDbContext<ApplicationUser, IdentityRole, string>
{
public ApplicationDbContext(DbContextOptions<ApplicationDbContext> options)
: base(options)
{
}
public DbSet<ApplicationUser> ApplicationUser { get; set; }
}
Register view
#model MVC3_1Identity.Models.ViewModels.RegisterVM
<div class="row">
<div class="col-md-4">
<form method="post">
<h4>Create a new account.</h4>
<hr />
<div asp-validation-summary="All" class="text-danger"></div>
<div class="form-group">
<label asp-for="Email"></label>
<input asp-for="Email" class="form-control" />
<span asp-validation-for="Email" class="text-danger"></span>
</div>
<div class="form-group">
<label asp-for="Password"></label>
<input asp-for="Password" class="form-control" />
<span asp-validation-for="Password" class="text-danger"></span>
</div>
<div class="form-group">
<label asp-for="BirthDate"></label>
<input asp-for="BirthDate" class="form-control" />
<span asp-validation-for="BirthDate" class="text-danger"></span>
</div>
<div class="form-group">
<label asp-for="City"></label>
<input asp-for="City" class="form-control" />
<span asp-validation-for="City" class="text-danger"></span>
</div>
<div class="form-group">
<label asp-for="Country"></label>
<input asp-for="Country" class="form-control" />
<span asp-validation-for="Country" class="text-danger"></span>
</div>
<div class="custom-checkbox">
<label asp-for="role"></label>
#for (var i = 0; i < Model.RoleList.Count; i++)
{
<input asp-for="role" type="radio" value="#Model.RoleList[i].Name" />
<label asp-for="#Model.RoleList[i].Name">#Model.RoleList[i].Name</label>
}
<span asp-validation-for="role" class="text-danger"></span>
</div>
<button type="submit" class="btn btn-primary">Register</button>
</form>
</div>
</div>
#section Scripts {
<partial name="_ValidationScriptsPartial" />
}
Controller
public IActionResult Register()
{
var model = new RegisterVM();
model.RoleList = _roleManager.Roles.ToList();
return View(model);
}
[HttpPost]
public async Task<IActionResult> Register(RegisterVM model)
{
if (ModelState.IsValid)
{
var user = new ApplicationUser
{
UserName = model.Email,
Email = model.Email,
BirthDate=model.BirthDate,
City=model.City,
Country =model.Country,
};
var result = await _userManager.CreateAsync(user, model.Password);
if (result.Succeeded)
{
_userManager.AddToRoleAsync(user,model.role).Wait();
_logger.LogInformation("User created a new account with password and role.");
// other logic you want
}
foreach (var error in result.Errors)
{
ModelState.AddModelError(string.Empty, error.Description);
}
}
return View();
}
Startup.cs
public void ConfigureServices(IServiceCollection services)
{
services.AddDbContext<ApplicationDbContext>(options =>
options.UseSqlServer(
Configuration.GetConnectionString("DefaultConnection")));
services.AddIdentity<ApplicationUser ,IdentityRole>()
.AddEntityFrameworkStores<ApplicationDbContext>();
services.AddControllersWithViews();
services.AddRazorPages();
}
Result:

Use of View Components with forms

I am trying to learn the correct usage of View Components in ASP.NET Core MVC, so I have the following example: The idea is to render a view with Movie details, and inside of it, the ReviewViewComponent holding a 10-star movie rating widget.
Inside of the View Component's View is a form with radio buttons. The form action name is passed to the View Component (either Create or Edit, depending on if the user already gave a rating). Depending on the received action name, the form inside the View Component will either call the Create or the Edit method inside of the ReviewsController.
This all works until I reach the return call inside of ReviewsController. I would like to be able to return the View Component there and simply render the return result inside the div with id="now-showing-details-rating-div" in Details using AJAX. This works with Partial Views (code commented out in the ReviewsController's Edit method), but it seems it doesn't work with View Components (it just renders the View Component's View as a completely new View, even though I call the AJAX on the form the same way I would if it were in a Partial View).
Am I actually misusing the View Component concept here? In the sense of rendering a portion of a View after form submit, is it actually better to just use Partial Views?
Ajax snippet
$.ajax({
type: "POST",
url: requestUrl,
data: form.serialize(),
success: function (data) {
$("#" + divZaRezultat).html(data);
}
});
ViewModels:
public class MovieDetailsVM
{
public string Title { get; set; }
public int Id { get; set; }
public int Year { get; set; }
public string Actors { get; set; }
public string Country { get; set; }
public string Directors { get; set; }
public int Duration { get; set; }
public string VideoLink { get; set; }
public string AverageRating { get; set; }
public string NumberOfReviews { get; set; }
public ReviewIndexVM CurrentUserReview { get; set; }
}
public class ReviewIndexVM
{
public int ReviewId { get; set; }
public int Rating { get; set; }
public MasterModel User { get; set; }
public MasterModel Movie { get; set; }
}
ViewComponent
public class ReviewViewComponent : ViewComponent
{
public async Task<IViewComponentResult> InvokeAsync(string methodName, ReviewIndexVM review)
{
ViewBag.Method = methodName;
return View(review);
}
}
ViewComponent Default View
#model Cinema.DTO.ViewModels.Reviews.ReviewIndexVM
#{
ViewData["Title"] = "Default";
}
<form asp-controller="Reviews" asp-action="#ViewBag.Method">
<input asp-for="ReviewId" hidden />
<input asp-for="Movie.Id" hidden />
<input asp-for="User.Id" hidden />
<div class="rating form-group">
#for (int i = 10; i > 0; i--)
{
<input asp-for="Rating" type="radio" value="#i" id="#($"rating-star-{i}")" onclick="this.form.submit();" class="form-control rating-star"><label class="rating-star-label" for="#($"rating-star-{i}")"></label>
}
</div>
</form>
Views:
#model Cinema.DTO.ViewModels.Movies.MovieDetailsVM
#using Microsoft.AspNetCore.Identity
#using Cinema.Domain.Entities.Identity
#inject SignInManager<ApplicationUser> SignInManager
#inject UserManager<ApplicationUser> UserManager
#{
ViewData["Title"] = "Details";
Layout = "~/Views/Shared/_Layout.cshtml";
bool first = true;
DateTime currentDate = DateTime.Now;
}
<section>
<div class="container">
<div class="content-wrap">
<div class="row">
<h1 class="h2">#Html.DisplayFor(model => model.Title)</h1>
</div>
<div class="row">
<div class="col-md-4">
<img id="movie-poster" class="pull-left" src="~/img/movie-poster.png" />
</div>
<div class="col-md-8">
<ul class="list-unstyled movie-info">
<li>
<span>#Html.DisplayNameFor(model => model.Title)</span>
#Html.DisplayFor(model => model.Title)
</li>
<li>
<span>#Html.DisplayNameFor(model => model.Year)</span>
#Html.DisplayFor(model => model.Year)
</li>
<li>
<span>#Html.DisplayNameFor(model => model.Actors)</span>
#Html.DisplayFor(model => model.Actors)
</li>
<li>
<span>#Html.DisplayNameFor(model => model.Country)</span>
#Html.DisplayFor(model => model.Country)
</li>
<li>
<span>#Html.DisplayNameFor(model => model.Directors)</span>
#Html.DisplayFor(model => model.Directors)
</li>
<li>
<span>#Html.DisplayNameFor(model => model.Duration)</span>
#Html.DisplayFor(model => model.Duration)
</li>
#*<li>
<span>#Html.DisplayNameFor(model => model.GenreMovies)</span>
#Html.DisplayFor(model => model.GenreMovies)
</li>*#
<li>
<span>#Html.DisplayNameFor(model => model.VideoLink)</span>
#Html.DisplayFor(model => model.VideoLink)
</li>
</ul>
Average rating <span class="badge">#Model.AverageRating</span>
<hr />
<div asp-authorize asp-roles="#Roles.User">
Your rating:
<div id="now-showing-details-rating-div">
#if (#Model.CurrentUserReview.ReviewId == 0)
{
#await Component.InvokeAsync("Review", new { methodName = "Create", review = #Model.CurrentUserReview })
}
else
{
#await Component.InvokeAsync("Review", new { methodName = "Edit", review = #Model.CurrentUserReview })
}
</div>
</div>
</div>
</div>
</div>
</section>
#section Scripts {
$(document).ready(function () {
$('.rating-star-label').mouseover(function () {
$('.rating-star').prop('checked', false);
});
});
</script>
}
ReviewsController
[HttpGet]
[Authorize(Roles = Roles.User)]
public async Task<IActionResult> Edit(int reviewId)
{
Review review = await _unit.Reviews.GetAsync(reviewId);
var authorizationResult = await _authorizationService.AuthorizeAsync(User, review, OperationRequirements.Update);
if (authorizationResult.Succeeded)
{
ReviewUpdateVM model = review.ToUpdateVM();
return PartialView(model);
}
else if (User.Identity.IsAuthenticated)
{
return new ForbidResult();
}
else
{
return new ChallengeResult();
}
}
[Authorize(Roles = Roles.User)]
public async Task<IActionResult> Edit(ReviewIndexVM model)
{
Review review = model.Create();
var authorizationResult = await _authorizationService.AuthorizeAsync(User, review, OperationRequirements.Update);
if (authorizationResult.Succeeded)
{
await _unit.Reviews.UpdateAsync(review, model.ReviewId);
await _unit.SaveAsync();
return ViewComponent("Review");
//return Redirect("/Reviews/Details?reviewId=" + review.Id);
}
else if (User.Identity.IsAuthenticated)
{
return new ForbidResult();
}
else
{
return new ChallengeResult();
}
}
}
else if (User.Identity.IsAuthenticated)
{
return new ForbidResult();
}
else
{
return new ChallengeResult();
}
}
Here is a working demo:
Details.cshtml:
#model MovieDetailsVM
#{
ViewData["Title"] = "Details";
Layout = "~/Views/Shared/_Layout.cshtml";
bool first = true;
DateTime currentDate = DateTime.Now;
}
<section>
<div class="container">
<div class="content-wrap">
<div class="row">
<h1 class="h2">#Html.DisplayFor(model => model.Title)</h1>
</div>
<div class="row">
<div class="col-md-8">
<ul class="list-unstyled movie-info">
<li>
<span>#Html.DisplayNameFor(model => model.Title)</span>
#Html.DisplayFor(model => model.Title)
</li>
<li>
<span>#Html.DisplayNameFor(model => model.Year)</span>
#Html.DisplayFor(model => model.Year)
</li>
<li>
<span>#Html.DisplayNameFor(model => model.Actors)</span>
#Html.DisplayFor(model => model.Actors)
</li>
<li>
<span>#Html.DisplayNameFor(model => model.Country)</span>
#Html.DisplayFor(model => model.Country)
</li>
<li>
<span>#Html.DisplayNameFor(model => model.Directors)</span>
#Html.DisplayFor(model => model.Directors)
</li>
<li>
<span>#Html.DisplayNameFor(model => model.Duration)</span>
#Html.DisplayFor(model => model.Duration)
</li>
#*<li>
<span>#Html.DisplayNameFor(model => model.GenreMovies)</span>
#Html.DisplayFor(model => model.GenreMovies)
</li>*#
<li>
<span>#Html.DisplayNameFor(model => model.VideoLink)</span>
#Html.DisplayFor(model => model.VideoLink)
</li>
</ul>
Average rating <span class="badge">#Model.AverageRating</span>
<hr />
<div>
Your rating:
<div id="now-showing-details-rating-div">
#if (#Model.CurrentUserReview == null)
{
#await Component.InvokeAsync("Review", new { methodName = "Create", review = #Model.CurrentUserReview })
}
else
{
#await Component.InvokeAsync("Review", new { methodName = "Edit", review = #Model.CurrentUserReview })
}
</div>
</div>
</div>
</div>
</div>
</div>
</section>
Ajax in Details.cshtml:
#section Scripts {
<script>
$(document).ready(function () {
$('.rating-star-label').mouseover(function () {
$('.rating-star').prop('checked', false);
});
});
function Update() {
$.ajax({
type: "POST",
url: "/Reviews/Edit/#Model.CurrentUserReview.ReviewId",
data: $("form").serialize(),
success: function (data) {
$("#now-showing-details-rating-div").html(data);
}
});
}
</script>
}
Components/Review/Default.cshtml:
#model ReviewIndexVM
#{
ViewData["Title"] = "Default";
}
<form asp-controller="Reviews" asp-action="#ViewBag.Method">
<input asp-for="ReviewId" hidden />
<input asp-for="Movie.Id" hidden />
<input asp-for="User.Id" hidden />
<div class="rating form-group">
#for (int i = 10; i > 0; i--)
{
<input asp-for="Rating" type="radio" value="#i" id="#($"rating-star-{i}")" onclick="Update();" class="form-control rating-star"><label class="rating-star-label" for="#($"rating-star-{i}")"></label>
}
</div>
</form>
Controller:
public class ReviewsController : Controller
{
private readonly Component2_2Context _context;
public ReviewsController(Component2_2Context context)
{
_context = context;
}
// GET: Reviews/Details/5
public async Task<IActionResult> Details(int? id)
{
var reviewIndexVM = await _context.MovieDetailsVM
.Include(m => m.CurrentUserReview)
.FirstOrDefaultAsync(m => m.Id == id);
return View(reviewIndexVM);
}
// GET: Reviews/Edit/5
public async Task<IActionResult> Edit(int? id)
{
if (id == null)
{
return NotFound();
}
var reviewIndexVM = await _context.ReviewIndexVM.FindAsync(id);
if (reviewIndexVM == null)
{
return NotFound();
}
return View(reviewIndexVM);
}
// POST: Reviews/Edit/5
[HttpPost]
[ValidateAntiForgeryToken]
public async Task<IActionResult> Edit(int id, [Bind("ReviewId,Rating")] ReviewIndexVM reviewIndexVM)
{
if (id != reviewIndexVM.ReviewId)
{
return NotFound();
}
if (ModelState.IsValid)
{
_context.Update(reviewIndexVM);
await _context.SaveChangesAsync();
return ViewComponent("Review");
}
return new ChallengeResult();
}
ViewComponent:
public class ReviewViewComponent : ViewComponent
{
public async Task<IViewComponentResult> InvokeAsync(string methodName, ReviewIndexVM review)
{
ViewBag.Method = methodName;
return View(review);
}
}
Result:

How to View data from a different table and Insert data in to another table from one view page using Asp.net core MVC?

Scenario
I am going to create a simple interface to insert donations from students using Asp.net Core MVC and EF. According to the App, before entering donation I have to display student information (from Student table) by using student's Admission number (Add_No).
Then I have to insert donation data using the same view but using a different submit button to the table Welfare.
Problem:
I tried it as following ways as shown in my code blocks. Insertion is successful. But I couldn't show student info on the screen even though I retrieve them.
Code for View.cshtml
#model Student_Management.Models.Welfare
#{
ViewData["Title"] = "Wcreate";
Layout = "~/Views/Shared/_Layout.cshtml";
}
<h4 align="center">Welfare Donation Entry Form</h4>
<hr />
<table>
<tr>
<td>
#using (Html.BeginForm("getStudentInfo", "Payments", FormMethod.Post))
{
<div class="form-group">
<label asp-for="Add_No" class="control-label"></label>
<input asp-for="Add_No" class="form-control" id="t1" name="A" />
<span asp-validation-for="Add_No" class="text-danger"></span>
</div>
<div class="form-group">
<input type="submit" value="getStudentInfo" class="btn btn-primary" id="btngetStudentInfo" />
</div>
}
</td>
<td>
<ul>
#if (ViewBag.students != null)
{
#foreach (var std in ViewBag.students)
{
<li>
#std
</li>
}
}
</ul>
</td>
</tr>
</table>
Code for Controller
public class PaymentsController : Controller
{
private readonly ConnectionString _context;
public PaymentsController(ConnectionString context)
{
_context = context;
}
public IActionResult Wcreate(Welfare welfare, string A)
{
int maxR_No = _context.Welfare.Max(p => p.R_No);
maxR_No = maxR_No + 1;
welfare.R_No = maxR_No;
if (ModelState.IsValid)
{
_context.Add(welfare);
_context.SaveChanges();
ModelState.Clear();
}
return View();
}
public ActionResult getStudentInfo(string A)
{
var items = _context.Students.Where(x => x.Add_No == A)
.Select(x => new
{
P1 = x.F_Name,
P2 = x.Class + "-" + x.ClassNo
});//.ToList();
ViewData["students"] = items;
return RedirectToAction("Wcreate");
}
namespace Student_Management.Models
{
public class Welfare
{
[Key]
[DatabaseGenerated(DatabaseGeneratedOption.Identity)]
public int R_No { get; set; }
[Required]
public string Add_No { get; set; }
[Required]
public string Grade { get; set; }
[Required]
public string STClassNo { get; set; }
[Required]
public string Month { get; set; }
[Required]
public string Year { get; set; }
[Required]
public string Rs { get; set; }
[Required]
[DataType(DataType.Date)]
public DateTime Date { get; set; }
public string cmt { get; set; }
As hint given by Jasen, I modified my action method and view as follows.
<td>
#using (Html.BeginForm("getStudentInfo", "Payments", FormMethod.Post))
{
<div class="form-group">
<label asp-for="Add_No" class="control-label"></label>
<input asp-for="Add_No" class="form-control" id="t1" name="A" />
<span asp-validation-for="Add_No" class="text-danger"></span>
</div>
<div class="form-group">
<input type="submit" value="getStudentInfo" class="btn btn-primary" id="btngetStudentInfo" />
</div>
}
</td>
<p>#TempData["info"]</p>
<p>#(TempData["info2"] +"-" + TempData["info3"])</p>
Action method
public ActionResult getStudentInfo(string A)
{
var items = _context.Students.Where(x => x.Add_No == A)
.Select(x => new
{
P1 = x.F_Name,
P2 = x.Class,
p3=x.ClassNo
}).ToList();
TempData["info"] = items[0].P1;
TempData["info2"] = items[0].P2;
TempData["info3"] = items[0].p3;
return RedirectToAction("Wcreate");
}

Asp Net Core - Entity Framework - ViewBag - Related Data - CRUD

I am creating a simple Location and Country relationship and i have been able to link the to tables and i am able to pull the related data, the issue is that when i try post the form the database does not update with the ID of the country.
When monitoring the POST action via Firefox Developer tools i can see the ID of the country is being posted.
LocationsController
public class LocationsController : Controller
{
private readonly DataContext _context;
public LocationsController(DataContext context)
{
_context = context;
}
// DropDown: Populate the Dropdown lists
private void PopulateCountryDropDownList(object selectedCountry = null)
{
var countriesQuery = from c in _context.Countries
orderby c.CountryID
select c;
ViewBag.CountryID = new SelectList(countriesQuery.AsNoTracking(), "CountryID", "Title");
}
// GET: Locations/Create
public IActionResult Create()
{
PopulateCountryDropDownList();
return View();
}
// POST: Locations/Create
// To protect from overposting attacks, please enable the specific properties you want to bind to, for
// more details see http://go.microsoft.com/fwlink/?LinkId=317598.
[HttpPost]
[ValidateAntiForgeryToken]
public async Task<IActionResult> Create(Location location)
{
if (ModelState.IsValid)
{
_context.Add(location);
await _context.SaveChangesAsync();
return RedirectToAction("Index");
}
return View(location);
}
}
Location
using System.ComponentModel.DataAnnotations;
namespace RaceCaribbean.Models
{
public class Location
{
public int LocationID { get; set; }
public string Title { get; set; }
public Country Country { get; set; }
}
}
Country
using System.ComponentModel.DataAnnotations;
namespace RaceCaribbean.Models
{
public class Country
{
public int CountryID { get; set; }
[Required]
public string Title { get; set; }
[Required]
public string Code { get; set; }
}
}
Create.cshtml
#model RaceCaribbean.Models.Location
#{
ViewData["Title"] = "Create";
}
<h2>Create</h2>
<form asp-action="Create">
<div class="form-horizontal">
<h4>Location</h4>
<hr />
<div asp-validation-summary="ModelOnly" class="text-danger"></div>
<div class="form-group">
<label asp-for="Title" class="col-md-2 control-label"></label>
<div class="col-md-10">
<input asp-for="Title" class="form-control" />
<span asp-validation-for="Title" class="text-danger"></span>
</div>
</div>
<div class="form-group">
<label asp-for="Country" class="col-md-2 control-label"></label>
<div class="col-md-10">
<select asp-for="Country" class="form-control" asp-items="ViewBag.CountryID">
<option selected="selected" value="">-- Select Country --</option>
</select>
<span asp-validation-for="Country" class="text-danger" />
</div>
</div>
<div class="form-group">
<div class="col-md-offset-2 col-md-10">
<input type="submit" value="Create" class="btn btn-default" />
</div>
</div>
</div>
</form>
<div>
<a asp-action="Index">Back to List</a>
</div>
#section Scripts {
#{await Html.RenderPartialAsync("_ValidationScriptsPartial");}
}