scaffolding a controller bound to a complex model in mvc 5 - c#

I have a model (A) consist of two other models (B - UltrasoundDTO & C - BloodTestDTO).
When I try Adding a controller through the MVC Controller with views, using Entity Framework option in VS2017 it creates a controller with the corresponding views though it binds only the properties of model A and not the properties of B & C. Is there a way to fix this or do I have to bind the rest on my own?
[Controller creation option ][1],
using System;
using System.Collections.Generic;
using System.ComponentModel.DataAnnotations;
using System.Text;
public class CheckUpDTO
{
public int Id { get; set; }
public int DayOfPeriod { get; set; }
[Required]
public UltrasoundDTO MyUltrasoundDTO { get; set; }
[Required]
public BloodTestDTO MyBloodTestDTO { get; set; }
}
one of the methods in the controller:
public async Task<IActionResult> Create([Bind("Id,DayOfPeriod")] CheckUpDTO checkUpDTO)
{
if (ModelState.IsValid)
{
_context.Add(checkUpDTO);
await _context.SaveChangesAsync();
return RedirectToAction("Index");
}
return View(checkUpDTO);
}
the view that corresponds to the method above:
#model DTOs.CheckUpDTO
#{
ViewData["Title"] = "Create";
}
<h2>Create</h2>
<form asp-action="Create">
<div class="form-horizontal">
<h4>CheckUpDTO</h4>
<hr />
<div asp-validation-summary="ModelOnly" class="text-danger"></div>
<div class="form-group">
<label asp-for="DayOfPeriod" class="col-md-2 control-label"></label>
<div class="col-md-10">
<input asp-for="DayOfPeriod" class="form-control" />
<span asp-validation-for="DayOfPeriod" class="text-danger"></span>
</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");}
}

Related

Data are not being set in the model ASP.Net mvc

I have a problem, where I have a form, and some of the data is not being set in the model and I don't know why or where to look.
My Model:
using System;
using System.Collections.Generic;
using System.ComponentModel.DataAnnotations;
using System.Linq;
using System.Threading.Tasks;
namespace VolunteerMngSystm.Models
{
public class Organisations
{
public int ID { get; set; }
[Required]
public string Organisation_name { get; set; }
[Required]
public string Industry { get; set; }
[Required]
public string Email { get; set; }
[Required]
public string OrganisationsID { get; set; }
}
}
The Email and OrganisationID are not being set.
My Controller Action method:
[HttpPost]
[ValidateAntiForgeryToken]
public async Task<IActionResult> OrgReg([Bind("Organisation_name,Industry,Email,OrganisationID")] Organisations organisations)
{
try
{
if (ModelState.IsValid)
{
_context.Add(organisations);
await _context.SaveChangesAsync();
return RedirectToAction(nameof(OrgHome));
}
}
catch (DbUpdateException e)
{
//Log the error (uncomment ex variable name and write a log.
ModelState.AddModelError("" + e, "Unable to save changes. " +
"Try again, and if the problem persists " +
"see your system administrator.");
}
return View(organisations);
}
My View:
#model VolunteerMngSystm.Models.Organisations;
#{
ViewData["Title"] = "Register";
}
<h1>Register</h1>
<h5>As Organisation</h5>
<hr />
<div class="row">
<div class="col-md-4">
<form asp-action="OrgReg">
<div asp-validation-summary="ModelOnly" class="text-danger"></div>
<div class="form-group">
<label asp-for="Organisation_name" class="control-label">Organisation Name</label>
<input asp-for="Organisation_name" class="form-control" />
<span asp-validation-for="Organisation_name" class="text-danger"></span>
</div>
<div class="form-group">
<label asp-for="Industry" class="control-label"></label>
<input asp-for="Industry" class="form-control" />
<span asp-validation-for="Industry" class="text-danger"></span>
</div>
<div class="form-group">
<label asp-for="Email" class="control-label"></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="OrganisationsID" class="control-label">Verification ID</label>
<input asp-for="OrganisationsID" type="file" accept="image/* " />
<span asp-validation-for="OrganisationsID" class="text-danger"></span>
</div>
<div class="form-group">
<input type="submit" value="Register" class="btn btn-primary" />
</div>
</form>
</div>
</div>
<div>
<a asp-action="Index">Back to List</a>
</div>
#section Scripts {
#{await Html.RenderPartialAsync("_ValidationScriptsPartial");}
}
Can anyone please advise me on where to look or how to fix this problem, please?
Since your action need AntiForgeryToken, add it to your form
<form asp-action="OrgReg">
<div asp-validation-summary="ModelOnly" class="text-danger"></div>
#Html.AntiForgeryToken()
or remove it from the action
also try to remove [Bind] from the action. You have a typo there and you don't need it since you are binding all properties any way.
[HttpPost]
[ValidateAntiForgeryToken]
public async Task<IActionResult> OrgReg( Organisations organisations)

MVC Core - Passing ID to view and pre-selecting value in selectlist

First of all forgive me as I am new to MVC.
I have a view which shows server(s) related to a particular application. If none exist, or the user wants to add an additional application/server relationship, they click on "Create New". From this link, I would like the ApplicationID to be passed to the Create view, and the selectlist for Applications to default to the correct Application. Or alternatively, display the application name/id in a label. I would also like to pass the ApplicationId back when "Back to List" is selected.
Model:
using System;
using System.Collections.Generic;
using System.ComponentModel.DataAnnotations.Schema;
using System.Linq;
using System.Threading.Tasks;
namespace ApplicationPortfolio.Models
{
[Table("tblServerApp")]
public class ServerApp
{
public int ServerAppId { get; set; }
public int? ApplicationId { get; set; }
public int? ServerId { get; set; }
public virtual Application Application { get; set; }
public virtual Server Server { get; set; }
}
}
Controller:
// GET: ServerApps/Create
public IActionResult Create(int? id)
{
ViewData["ApplicationId"] = new SelectList(_context.Application, "ApplicationID", "Name", id);
ViewData["ServerId"] = new SelectList(_context.Server, "ServerId", "ServerName");
return View();
}
View:
#model ApplicationPortfolio.Models.ServerApp
#{
ViewData["Title"] = "Create";
Layout = "~/Views/Shared/_Layout.cshtml";
}
<h1>Create</h1>
<h4>ServerApp</h4>
<hr />
<div class="row">
<div class="col-md-4">
<form asp-action="Create">
<div asp-validation-summary="ModelOnly" class="text-danger"></div>
<div class="form-group">
<div class="form-group">
<label asp-for="ApplicationId" class="control-label"></label>
<select asp-for="ApplicationId" class="form-control" asp-items="ViewBag.ApplicationId"></select>
</div>
</div>
<div class="form-group">
<label asp-for="ServerId" class="control-label"></label>
<select asp-for="ServerId" class ="form-control" asp-items="ViewBag.ServerId"></select>
</div>
<div class="form-group">
<input type="submit" value="Create" class="btn btn-primary" />
</div>
</form>
</div>
</div>
<div>
<a asp-action="Index">Back to List</a>
</div>
#section Scripts {
#{await Html.RenderPartialAsync("_ValidationScriptsPartial");}
}
After my test,I found your problem may in your code:
ViewData["ApplicationId"] = new SelectList(_context.Application, "ApplicationID", "Name", id);
ApplicationID and Name should be same with the name in your Application model.
If your model is(example) :
public class Application
{
[Key]
public int ApplicationId { get; set; }
public string ApplicationName { get; set; }
public List<ServerApp> ServerApps { get; set; }
}
Your code should be(Please pay attention to whether the case and match) :
ViewData["ApplicationId"] = new SelectList(_context.Applications, "ApplicationId", "ApplicationName",id);
And if you want to pass the ApplicationId back to Index,you can try following code.
#model ServerApp
#{
ViewData["Title"] = "Create";
Layout = "~/Views/Shared/_Layout.cshtml";
}
<h4>ServerApp</h4>
<hr />
<div class="row">
<div class="col-md-4">
<form asp-action="Create">
<div asp-validation-summary="ModelOnly" class="text-danger"></div>
<div class="form-group">
<div class="form-group">
<label asp-for="ApplicationId" class="control-label"></label>
<select id="select" asp-for="ApplicationId" class="form-control" asp-items="ViewBag.ApplicationId"></select>
</div>
</div>
<div class="form-group">
<label asp-for="ServerId" class="control-label"></label>
<select asp-for="ServerId" class="form-control" asp-items="ViewBag.ServerId"></select>
</div>
<div class="form-group">
<input type="submit" value="Create" class="btn btn-primary" />
</div>
</form>
</div>
</div>
<div>
<button id="submit" class="btn btn-info">Back to List</button>
</div>
#section Scripts {
#{await Html.RenderPartialAsync("_ValidationScriptsPartial");}
<script>
$("#submit").click(function (e) {
e.preventDefault();
var e = document.getElementById("select");
var strUser = e.value;
window.location.href = "/home/index?id=" + strUser;
})
</script>
}
Test Result:

MVC Removing the need to pre-fix the Project Name in a model binding within a view

I have this model:
using System;
using System.ComponentModel.DataAnnotations;
namespace MVCProjectName.Models.Login
{
public class LoginViewModel
{
[Required]
[EmailAddress]
public string Email { get; set; }
[Required]
[DataType(DataType.Password)]
public string Password { get; set; }
[Display(Name = "Remember me")]
public bool RememberMe { get; set; }
}
}
I have this view:
#model MVCProjectName.Models.Login.LoginViewModel
#{
ViewBag.Title = "Login";
}
<h1>User Login</h1>
<div class="row">
<div class="col-md-12">
<form method="post">
<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">
<div class="checkbox">
<label asp-for="RememberMe">
<input asp-for="RememberMe" />
#Html.DisplayNameFor(m => m.RememberMe)
</label>
</div>
</div>
<button type="submit" class="btn btn-primary">Login</button>
</form>
</div>
</div>
Is there any way in which we can have the model binding reduced to just this:
#model Models.Login.LoginViewModel
Or this:
#model Login.LoginViewModel
Given that the LoginViewModel should be in the same namespace anyway, and that the Models folder is in the root. Can we reduce the #model statements above more via any means?
Add your project's namespace as a using statement into the \Views\_ViewImports.cshtml.
MS documentation here
I think you have two options:
1. Change the namespace of LoginViewModel itself
2. In your view, add #using MVCProjectName and then add #mode Models.Login.LoginViewModel
One other thing you might be able to try is if you have a layout page. You can do the using in that and then in any view that uses that layout page would just need to use the model name as I mentioned in option 2.

View post form return null?

I am having problems to return a model using a form.
The problem is when I submit the form, the values are null even though I've specified that returns a model
This is my controller
And this is my View that returns null.
#model MyEnglishDictionary.Models.Dictionary
#{
ViewData["Title"] = "Create";
}
<h2>Create</h2>
<form method="post" asp-action="Create">
<div class="p-4 border rounded">
<div asp-validation-summary="ModelOnly" class="text-danger"></div>
<div class="form-group row">
<div class="col-2">
<label asp-for="Word"></label>
</div>
<div class="col-5">
<input asp-for="Word" class="form-control" />
</div>
<span asp-validation-for="Word" class="text-danger"></span>
</div>
<div class="form-group row">
<div class="col-2">
<label asp-for="Meaning"></label>
</div>
<div class="col-5">
<input asp-for="Meaning" class="form-control" />
</div>
<span asp-validation-for="Meaning" class="text-danger"></span>
</div>
<div class="form-group row">
<div class="col-2">
<label asp-for="Pronunciation"></label>
</div>
<div class="col-5">
<input asp-for="Pronunciation" class="form-control" />
</div>
<span asp-validation-for="Pronunciation" class="text-danger"></span>
</div>
<br />
<div class="form-group">
<input type="submit" class="btn btn-primary" value="Create" />
<a asp-action="Index" class="btn btn-success">Back To List</a>
</div>
</div>
</form>
#section Scripts{
#{ await Html.RenderPartialAsync("_ValidationScriptsPartial"); }
}
EDIT
This is my Dictionary controller.
using System;
using System.Collections.Generic;
using System.Linq;
using System.Threading.Tasks;
using Microsoft.AspNetCore.Mvc;
using MyEnglishDictionary.Data;
using MyEnglishDictionary.Models;
namespace MyEnglishDictionary.Controllers
{
public class DictionaryController : Controller
{
private readonly ApplicationDbContext _db;
public DictionaryController(ApplicationDbContext db)
{
_db = db;
}
public IActionResult Index()
{
return View(_db.Dictionaries.ToList());
}
public IActionResult Create()
{
return View();
}
[HttpPost]
[ValidateAntiForgeryToken]
public async Task<IActionResult> Create(Models.Dictionary word)
{
if(!ModelState.IsValid)
{
return View(word);
}
_db.Add(word);
await _db.SaveChangesAsync();
return RedirectToAction(nameof(Index));
}
}
}
And this is my Dictionary model
using System;
using System.Collections.Generic;
using System.Linq;
using System.Threading.Tasks;
namespace MyEnglishDictionary.Models
{
public class Dictionary
{
[Key]
public int Id { get; set; }
[Required]
public string Word { get; set; }
[Required]
public string Meaning { get; set; }
[Required]
public string Pronunciation { get; set; }
public string Link { get; set; }
public DateTime Date { get; set; }
}
}
I am using Net Core 2.1, but I have some few projects that I use the same way to pass the form model from View to controller and they work.
You need to pay attention to the name of the parameter and fields.
For your issue, it is caused by that you defined a field which is Word and the parameter is word which caused the binding failed.
Try to change the public async Task<IActionResult> Create(Models.Dictionary word) to public async Task<IActionResult> Create(Models.Dictionary dictionary).
change the word parameter name to something else like _word, it seems like the compiler doesn't accept it as a parameter name in c#.
public async Task<IActionResult> Create(Models.Dictionary _word)
{
if(!ModelState.IsValid)
{
return View(_word);
}
_db.Add(_word);
await _db.SaveChangesAsync();
return RedirectToAction(nameof(Index));
}
btw, I didn't see it in the reserved keywords list
You have to bind the properties to your model. In your case:
public async Task<IActionResult> Create([Bind("Word, Meaning, Pronounciation")] Dictionary word)
Further reading:
Model Binding

Data not passing from to Controller using view model [duplicate]

This question already has answers here:
Asp.Net MVC: Why is my view passing NULL models back to my controller?
(2 answers)
Closed 5 years ago.
I'm new to c# and asp.net MVC and i'm working on a small project. I'm having an error on a create view using a view model. Whats happening is that after I complete the form when I submit it the data I populated isn't being received by the controller. Below is the code for my view, for my create on the controller and a view of the ModelView i'm using
//Controllers
// GET: Producto/Create
public ActionResult Create()
{
return View(ProductoViewModel.CargarListas());
}
// POST: Producto/Create
[HttpPost]
[ValidateAntiForgeryToken]
public ActionResult Create(ProductoViewModel producto)
{
Producto aux = producto.Producto;
aux.IdRecetaPreferida = producto.IdRecetaPreferida;
if (aux.Guardar())
{
return RedirectToAction(nameof(Index));
}
return View();
}
/*
* My view model im using on the view
*/
public class ProductoViewModel
{
public Producto Producto {get;set;}
[Display(Name = "Receta")]
public long IdRecetaPreferida { get; set; }
public Receta Receta { get; set; }
public List<Receta> Recetas { get; set; }
public ProductoViewModel()
{
this.Recetas = new List<Receta>();
this.Receta = new Receta();
}
public static ProductoViewModel CargarListas()
{
ProductoViewModel productoViewModel = new ProductoViewModel()
{
Recetas = Receta.TraerTodos()
};
return productoViewModel;
}
}
//My create view
#model WebApp.ViewModels.ProductoViewModel
<h2>Ingresar Producto</h2>
<hr />
<div class="row">
<div class="col-md-12">
<form asp-action="Create">
<div asp-validation-summary="ModelOnly" class="text-danger"></div>
<div class="form-group row">
<label asp-for="Producto.Nombre" class="col-sm-2 col-form-label"></label>
<div class="col-sm-10">
<input asp-for="Producto.Nombre" class="form-control" placeholder="Nombre Producto" />
<span asp-validation-for="Producto.Nombre" class="text-danger"></span>
</div>
</div>
<div class="form-group row">
<label asp-for="Producto.Descripcion" class="col-sm-2 col-form-label"></label>
<div class="col-sm-10">
<input asp-for="Producto.Descripcion" class="form-control" placeholder="Una rica descripcion del producto" />
<span asp-validation-for="Producto.Descripcion" class="text-danger"></span>
</div>
</div>
<div class="form-group row">
<label asp-for="IdRecetaPreferida" class="col-sm-2 col-form-label"></label>
<div class="col-sm-10">
#Html.DropDownListFor(m => m.IdRecetaPreferida, new SelectList(Model.Recetas, "Id", "Nombre"), new { #class = "custom-select" })
</div>
</div>
<div class="form-group">
<input type="submit" value="Create" class="btn btn-primary" />
<a asp-action="Index">Volver</a>
</div>
</form>
</div>
</div>
If could point out my error would appreciate it. Below is a screenshot of the variable being debugged
I believe you forgot to specify that the form should send a POST request instead of a GET (default).
<form asp-action="Create" method="post">
Or you can remove the HttpPost attribute from the Create method.

Categories