I want to make a form that user have to fill out it.
But I'm getting an error.
Model:
public UserReport Input;
[Key]
//[Required]
public string ReportID { get; set; }
[Required]
public string Description { get; set; }
[Required]
[DataType(DataType.DateTime)]
public string Date { get; set; }
Controller:
private ApplicationDbContext _userReport;
public UserReport Input;
public PageController(ApplicationDbContext userReport)
{
_userReport = userReport;
}
[HttpGet]
public IActionResult SendReport()
{
return View();
}
[Authorize]
[HttpPost]
public async Task<IActionResult> SendReport(UserReport userReport)
{
var user = new UserReport { Description = Input.Description, Date = Input.Date };
var r = await _userReport.AddAsync(user);
}
View:
#model UserReport
<div class="col-md-6">
<form id = "SendReport" method="post">
<div asp-validation-summary="All" class="text-danger"></div>
<div class="form-group">
<label asp-for="Input.Description"></label>
<input asp-for="Input.Description" class="form-control" />
<span asp-validation-for="Input.Description" class="text-danger"></span>
</div>
<div class="form-group">
<label asp-for="Input.Date"></label>
<input asp-for="Input.Date" class="form-control" />
<span asp-validation-for="Input.Date" class="text-danger"></span>
</div>
<button type = "submit" class="btn btn-primary">send report</button>
</form>
</div>
what is wrong with that?
It shows me this Error :System.NullReferenceException - Object reference not set to an instance of an object... who can help me to manage this error.
Show me where is my mistake please
I think you need to go back through the tutorials in the docs again. It doesn't seem like you really know what you're doing here. You've got a field named Input, which seems to be pulled from a Razor Page, but you're working in an MVC controller here. However, even that is off, because you'd typically see that as something like:
[BindProperty]
public UserReport Input { get; set; }
In a Razor Page. Here, it's not even a property, so even if this would normally do something, it wouldn't as a field, regardless.
The NullReferenceException comes because you reference this field, but never actually initialize it. Again, in a Razor Page (and if it was a property rather than a field), this would get filled with the post data (via BindProperty), but it doesn't work that way in a controller.
In your controller action, you've got a userReport param, so that is where the post data will go. However, since all the asp-for attributes in your view reference Input.Something, nothing will actually get bound to this param. This too seems to be pulled from a Razor Page, without considering that it only works this way in a Razor Page.
Long and short, it looks like you just copied code from other places, without actually understanding any of it or what it does, and cobbled it together into a controller and view. The whole thing is fundamentally broken top-down.
You have mixed with MVC and Razor Pages.
For MVC:
1.Model:
public class UserReport
{
[Key]
//[Required]
public string ReportID { get; set; }
[Required]
public string Description { get; set; }
[Required]
[DataType(DataType.DateTime)]
public string Date { get; set; }
}
2.SendReport.cshtml:
#model UserReport
<div class="col-md-6">
<form asp-action="SendReport" method="post">
<div asp-validation-summary="All" class="text-danger"></div>
<div class="form-group">
<label asp-for="Description"></label>
<input asp-for="Description" class="form-control" />
<span asp-validation-for="Description" class="text-danger"></span>
</div>
<div class="form-group">
<label asp-for="Date"></label>
<input asp-for="Date" class="form-control" />
<span asp-validation-for="Date" class="text-danger"></span>
</div>
<button type="submit" class="btn btn-primary">send report</button>
</form>
</div>
3.Controller:
public class UserReportsController : Controller
{
private readonly YourDbContext _context;
public UserReportsController(YourDbContext context)
{
_context = context;
}
public IActionResult SendReport()
{
return View();
}
[HttpPost]
public async Task<IActionResult> SendReport([Bind("ReportID,Description,Date")] UserReport userReport)
{
if (ModelState.IsValid)
{
_context.Add(userReport);
await _context.SaveChangesAsync();
return RedirectToAction(nameof(Index));
}
return View(userReport);
}
}
For Razor Pages:
1.Model:
public class UserReport
{
[Key]
//[Required]
public string ReportID { get; set; }
[Required]
public string Description { get; set; }
[Required]
[DataType(DataType.DateTime)]
public string Date { get; set; }
}
2.SendReport.cshtml:
#page
#model SendReportModel
<div class="col-md-6">
<form id="SendReport" method="post">
<div asp-validation-summary="All" class="text-danger"></div>
<div class="form-group">
<label asp-for="Input.Description"></label>
<input asp-for="Input.Description" class="form-control" />
<span asp-validation-for="Input.Description" class="text-danger"></span>
</div>
<div class="form-group">
<label asp-for="Input.Date"></label>
<input asp-for="Input.Date" class="form-control" />
<span asp-validation-for="Input.Date" class="text-danger"></span>
</div>
<button type="submit" class="btn btn-primary">send report</button>
</form>
</div>
3.SendReport.cshtml.cs:
public class SendReportModel : PageModel
{
private readonly YourDbContext _context;
public SendReportModel(YourDbContext context)
{
_context = context;
}
public IActionResult OnGet()
{
return Page();
}
[BindProperty]
public UserReport Input { get; set; }
public async Task<IActionResult> OnPostAsync()
{
if (!ModelState.IsValid)
{
return Page();
}
_context.UserReport.Add(Input);
await _context.SaveChangesAsync();
return RedirectToPage("./Index");
}
}
Reference:
Tutorial:Create a web app with ASP.NET Core MVC
Tutorial: Create a Razor Pages web app with ASP.NET Core
Related
I have two models:
public class Question
{
public int Id { get; set; }
public string Title { get; set; }
public int ClosedReasonId { get; set; }
public CloseReasonType CloseReasonType { get; set; }
}
public class CloseReasonType
{
public int Id { get; set; }
public string Name { get; set; }
public List<Question> Questions { get; set; }
}
I would like to create a view which has a form for adding questions and a dropdown for CloseReasonType.
#page
#model RazorPagesQuestion.Pages.Questions.CreateModel
#{
ViewData["Title"] = "Create";
}
<h1>Create</h1>
<h4>Question</h4>
<hr />
<div class="row">
<div class="col-md-4">
<form method="post">
<div asp-validation-summary="ModelOnly" class="text-danger"></div>
<div class="form-group">
<label asp-for="Question.Title" class="control-label"></label>
<input asp-for="Question.Title" class="form-control" />
<span asp-validation-for="Question.Title" class="text-danger"></span>
</div>
<div class="form-group">
<label asp-for="Question.CloseReasonType" class="control-label"></label>
<select asp-for="Question.CloseReasonType" class="form-control"
asp-items="Model.CloseReasonType">
</select>
<span asp-validation-for="Question.CloseReasonType" class="text-danger"></span>
</div>
<div class="form-group">
<input type="submit" value="Create" class="btn btn-primary" />
</div>
</form>
</div>
</div>
Of course when I just added asp-items="Model.CloseReasonType" to my select tag helper it didn't populate the dropdown with options. How can I populate the options?
I added this to my CreateModel class
[BindProperty]
public Question Question { get; set; }
[BindProperty]
public List<SelectListItem> CloseReasonType { get; }
All the examples I have seen show how to create the list out of hardcoded values.
The full class:
public class CreateModel : PageModel
{
private readonly RazorPagesQuestion.Data.RazorPagesQuestionContext _context;
public CreateModel(RazorPagesQuestion.Data.RazorPagesQuestionContext context)
{
_context = context;
}
public IActionResult OnGet()
{
return Page();
}
[BindProperty]
public Question Question { get; set; }
[BindProperty]
public List<SelectListItem> CloseReasonType { get; }
public async Task<IActionResult> OnPostAsync()
{
if (!ModelState.IsValid)
{
return Page();
}
_context.Question.Add(Question);
await _context.SaveChangesAsync();
return RedirectToPage("./Index");
}
}
You would need to populate the select list for it to display on the page
Assuming your DbContext has a CloseReasonTypes property
//...
private void loadCloseReasonTypes() {
CloseReasonTypes = new SelectList(_context.CloseReasonTypes, nameof(CloseReasonType.Id), nameof(CloseReasonType.Name));
}
public IActionResult OnGet() {
loadCloseReasonTypes();
return Page();
}
public SelectList CloseReasonTypes { get; set; }
[BindProperty]
public Question Question { get; set; }
//...
Update the view to bind to the relevant property on the model.
<div class="form-group">
<label asp-for="Question.CloseReasonId" class="control-label">Close Reason</label>
<select asp-for="Question.CloseReasonId" class="form-control"
asp-items="Model.CloseReasonTypes">
</select>
<span asp-validation-for="Question.CloseReasonId" class="text-danger"></span>
</div>
The list will also need to be repopulated if the post was not successful as the page will reload, clearing the select list.
public async Task<IActionResult> OnPostAsync() {
if (!ModelState.IsValid) {
loadCloseReasonTypes();
return Page();
}
_context.Question.Add(Question);
await _context.SaveChangesAsync();
return RedirectToPage("./Index");
}
I want to have a form on the webpage /create. This form contains : name, description and price. When filled in, it should send the data to the controller.
De controller does not receive the data and I don't know why.
I tried deleting the pages and recreate them, this did not work. I also tried #html.textlabelfor. this also did not work.
Here is my view code :
#using (Html.BeginForm("Create", "Beheer", FormMethod.Post))
{
<div class="form-group">
<label for="name">Name:</label>
<input type="text" class="form-control" placeholder="Fill article name" name="Naam">
</div>
<div class="form-group">
<label for="des">Description:</label>
<input type="text" class="form-control" placeholder="Fill in article description" name="Omschrijving">
</div>
<div class="form-group">
<label for="price">Price:</label>
<input type="number" class="form-control" placeholder="Fill in article price" name="Prijs">
</div>
<input type="submit" class="btn btn-default" value="submit" />
}
Here is my controller code:
[HttpPost]
public IActionResult Create(ArtikelModel artikelModel)
{
return View(artikelModel);
}
[HttpGet]
public IActionResult Create()
{
return View();
}
Here is my model :
public int Id { get; set; }
public string Naam { get; set; }
public string Omschrijving { get; set; }
public decimal Prijs { get; set; }
public byte[] Foto { get; set; }
public decimal Korting { get; set; }
public List<ReviewModel> Reviews { get; set; }
I expected the ArtikelModel to be filled with data the user put it.
Since you indicated that the controller method doesn't get called at all, the likely issue is the name of your controller as #LaljiDhameliya mentioned. So, since your view lists "Beheer" as the controller, due to ASP.NET MVC convention, your controller should be called "BeheerController" (you didn't include this bit of code in your question, so we can't see if that is the case)
Here is another issue I have faced in ASP.NET Core
Let say I have 2 Tables:
Accommodation
( ID, Name, LocationID)
Location
(ID, Address, Latitude, Longitude)
And I have a form:
Name:
Address:
Latitude:
Longitude:
Then when a button is clicked I want the value to be updated on both table and also MAP the LocationID to Accommodation table
How should I code it in EF Core? Like a proper way
You could try the following example I made :
Accommodation Model and Location Model
public class Accommodations
{
public int ID { get; set; }
public string Name { get; set; }
public int LocationID { get; set; }
[ForeignKey("LocationID")]
public Location Location { get; set; }
}
public class Location
{
public int ID { get; set; }
public string Address { get; set; }
//other stuff you want
}
DbSet two model in DbContext
public class MVCDbContext:DbContext
{
public MVCDbContext(DbContextOptions<MVCDbContext> options) : base(options)
{ }
public DbSet<Accommodations> Accommodations { get; set; }
public DbSet<Location> Location { get; set; }
}
The design of the view ,pay attention to the asp-for of the input tag
#model MVC2_1Test.Models.Accommodation.Accommodations
#{
ViewData["Title"] = "Accommondation";
}
<h2>Accommondation</h2>
<div class="row">
<div class="col-md-4">
<form id="form" class=".has-error" asp-action="CreateAccommodation">
<div asp-validation-summary="ModelOnly" class="text-danger"></div>
<div class="form-group ">
<label asp-for="Name" class="control-label"></label>
<input asp-for="Name" class="form-control" id="cusName" />
<span asp-validation-for="Name" class="text-danger"></span>
</div>
<div class="form-group">
<label asp-for="Location.Address" class="control-label"></label>
<input asp-for="Location.Address" class="form-control" id="age" />
<span asp-validation-for="Location.Address" class="text-danger"></span>
</div>
<div class="form-group">
<input type="submit" value="Create" class="btn btn-default" />
</div>
</form>
</div>
</div>
The action to update both table
[HttpPost]
[ValidateAntiForgeryToken]
public async Task<IActionResult> CreateAccommodation([FromForm]Accommodations accommodation)
{
if (ModelState.IsValid)
{
_context.Add(accommodation);
await _context.SaveChangesAsync();
return RedirectToAction(nameof(Index));
}
return View(accommodation);
}
My View is not seeing view model and give An expression tree may not contain a dynamic operation. When I look for this error most of people didnt used #model xxx on the view. But I used it
This is my User Controller page
public class UserController : Controller
{
private readonly DbManager _context;
public UserController(DbManager context)
{
_context = context;
}
[HttpGet]
public IActionResult Kayit()
{
UserViewModel vm = new UserViewModel();
return View(vm);
}
[HttpPost]
public async Task<IActionResult> KayitAsync([Bind("Isim,Soyad,DogumTarihi,KullaniciAdi,Sifre")]Kullanici k)
{
if (ModelState.IsValid)
{
_context.Kullanicilar.Add(k);
await _context.SaveChangesAsync();
return View("thanks");
}
return View("Index");
}
}
This is my User/Kayit View
#Model ArtSite.ViewModels.UserViewModel
<h2>Kayıt Sayfası</h2>
<div class="row">
<div class="col-md-4">
<form asp-controller="User" asp-action="Kayit" method="post">
<div asp-validation-summary="All"></div>
<div>
<label asp-for="Isim"></label>
<input asp-for="Isim" />
<span asp-validation-for="Isim"></span>
</div>
<div>
<label asp-for="Soyad"></label>
<input asp-for="Soyad" />
<span asp-validation-for="Soyad"></span>
</div>
<div>
<label asp-for="DogumTarihi"></label>
<input type="date" asp-for="DogumTarihi" />
<span asp-validation-for="DogumTarihi"></span>
</div>
<div>
<label asp-for="KullaniciAdi"></label>
<input asp-for="KullaniciAdi" />
<span asp-validation-for="KullaniciAdi"></span>
</div>
<div>
<label asp-for="Sifre"></label>
<input type="password" asp-for="Sifre" />
<span asp-validation-for="Sifre"></span>
</div>
<div>
<label asp-for="ConfirmSifre"></label>
<input type="password" asp-for="ConfirmSifre" />
<span asp-validation-for="ConfirmSifre"></span>
</div>
<div><input type="submit" value="Kayıt Ol" /></div>
</form>
</div>
</div>
And this is the View Model i used for View
namespace ArtSite.ViewModels
{
public class UserViewModel
{
[Required]
public string Isim { get; set; }
[Required]
public string Soyad { get; set; }
[Required,DataType(DataType.Date),Display(Name = "Doğum Tarihi")]
public DateTime DogumTarihi { get; set; }
[Required,MinLength(6),MaxLength(30),Display(Name ="Kullanıcı Adı")]
public string KullaniciAdi { get; set; }
[Required,DataType(DataType.Password), MinLength(6), MaxLength(30)]
[Display(Name ="Şifre")]
public string Sifre { get; set; }
[Required, DataType(DataType.Password), MinLength(6), MaxLength(30)]
[Compare("Password",ErrorMessage ="Şifreniz Uyuşmadı."),Display(Name ="Şifreyi Onayla")]
public string ConfirmSifre { get; set; }
}
}
So please help me to understand it.
You are confusing between #Model property and #model directive, as they both are different things and have different purpose too. You need to put #model to define the model for view.
#model ArtSite.ViewModels.UserViewModel
Also refer to this post (mvc uppercase Model vs lowercase model
) for more detailed understanding of these.
I have a View which uses a dynamic object to pull data from multiple models declared in the ViewModel. However, within the same model I am trying to take user input via a form. The data is correctly displayed for the 2 models which are also part of the dynamic object. But I am UNSUCCESSFUL getting the form input, because I keep getting the error that the dynamic object is not accessible.[And this is for the form only.]
Here is how the View looks like
#model dynamic
#using ActionAugerMVC.ViewModels
#addTagHelper "*,Microsoft.AspNetCore.Mvc.TagHelpers"
<div class="course__title">
#Model.item.PageTitle
</div>
<p class="course__desc">
#Html.Raw(Model.item.PageText)
</p>
<div class="event__price">
<h3>#Model.item.NoticeTitle</h3>
<p>#Model.item.NoticeNeedItem</p>
<button type="submit" class="btn btn-accent">
Get A Quote Now
</button>
</div>
<h3 class="course_desc__title">Other Services</h3>
<ul class="course_requirements__list multi-column">
#foreach (var link in Model.data)
{
<li><i class="ion-android-arrow-forward"></i> #Html.ActionLink((string)link.PageTitle, "Page", "Plumbing", new { id = link.ID, url = link.PageURL }) </li>
}
</ul>
<div class="sidebar__item">
<p class="subheading">Instant Quote Request</p>
<form class="register__form" role="form" asp-controller="Plumbing" asp-action="Page" method="post">
<div class="text-danger" asp-validation-summary="All"></div>
<div class="form-group">
<label class="sr-only">Full Name </label>
<input asp-for="#Model.quote.FullName" type="text" class="form-control" placeholder="Full name">
</div>
<div class="form-group">
<label class="sr-only">Your phone</label>
<input asp-for="#Model.quote.Phone" type="tel" class="form-control" placeholder="Your phone">
<span asp-validation-for="#Model.quote.Phone" class="text-danger"></span>
</div>
<div class="form-group">
<label class="sr-only">E-mail</label>
<input asp-for="#Model.quote.Email" type="email" class="form-control" placeholder="E-mail">
<span asp-validation-for="#Model.quote.Email" class="text-danger"></span>
</div>
<div class="form-group">
<label class="sr-only">Your Message</label>
<input asp-for="#Model.quote.Message" type="text" class="form-control" placeholder="Your Message">
</div>
<input type="submit" value="Get a Quote Now" class="btn btn-accent btn-block">
</form>
</div> <!-- .sidebar__item -->
And here is how the controller looks like :-
public class PlumbingController : Controller
{
private readonly ActionAugerDataContext actionAugerDbContext;
private readonly UnitOfWork unitOfWork;
private readonly PlumbingPageViewModel plumbingViewModel;
public PlumbingController(ActionAugerDataContext context)
{
actionAugerDbContext = context;
unitOfWork = new UnitOfWork(actionAugerDbContext);
plumbingViewModel = new PlumbingPageViewModel(unitOfWork);
}
// GET: /<controller>/
public IActionResult Index()
{
var data = plumbingViewModel.PlumbingContent;
return View(data);
}
[HttpGet]
[Route("plumbing/calgary-{url}")]
public IActionResult Page(int ID, string url)
{
dynamic Page = new ExpandoObject();
Page.item = unitOfWork.ContentRepository.GetById(ID);
Page.data = plumbingViewModel.PlumbingContent;
Page.cities = plumbingViewModel.Cities;
// Page.quote = plumbingViewModel.Quote;
return View(Page);
}
[HttpPost]
public IActionResult Page(Quote quote)
{
return View();
}
}
Here is the View Model :-
public class PlumbingPageViewModel
{
public IEnumerable<Content> PlumbingContent { get; set; }
public IEnumerable<Cities> Cities { get; set; }
public Quote Quote { get; set; }
public PlumbingPageViewModel(UnitOfWork unitOfWork)
{
PlumbingContent = unitOfWork.ContentRepository
.GetAll()
.Where(d => d.Section == "Plumbing")
.Where(c => c.City == "Calgary");
Cities = unitOfWork.CitiesRepository
.GetAll()
.Where(c => c.HomeCity == "Calgary");
}
}
And here is the model class for the form.
public class Quote
{
public int ID { get; set; }
public string FullName { get; set; }
public string Phone { get; set; }
public string Email { get; set; }
public string City { get; set; }
public string Message { get; set; }
}
you can't you use dynamic model ( #model dynamic) for building your form with HtmlHelper
If you want Post form you should specific model.
Hope you this will you.