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.
Related
I have following two model classes:
public partial class EmployeeInfo
{
public string LastName { get; set; } = null!;
public string FirstName { get; set; } = null!;
public virtual ICollection<EmergencyInfo> EmergencyInfos { get; } = new List<EmergencyInfo>();
}
public partial class EmergencyInfo
{
public string emailAddress { get; set; } = null!;
public string PhoneNumber { get; set; } = null!;
public virtual EmployeeInfo EmployeeInfo { get; set; } = null!;
}
My Razor view to create a new employee looks like this:
#model AckPackage.Models.EmployeeInfo
#{
ViewData["Title"] = "Create";
}
<div class="form-group row">
<div class="col-sm-4">
<label asp-for="LastName" class="control-label"></label>
<input asp-for="LastName" class="form-control input-lg" />
<span asp-validation-for="LastName" class="text-danger"></span>
</div>
<div class="col-sm-4">
<label asp-for="FirstName" class="control-label"></label>
<input asp-for="FirstName" class="form-control input-lg" />
<span asp-validation-for="FirstName" class="text-danger"></span>
</div>
</div>
Can I display the input box for emeregencyInfo, emailAddress and phone number in above view. I want to show both the input box for emailAddress and PhoneNumber in the same EmployeeInfo view so that users can input their information.
Any help will be highly appreciated.
You can create a compound class and pass it to the view as data model:
public class Info
{
public EmployeeInfo? Employee { get; set; }
public EmergencyInfo? Emergency { get; set; }
}
The view code:
#model Info;
#{
ViewData["Title"] = "Create";
}
<form method="post" asp-action="Create">
<div class="form-group row">
<div class="col-sm-4">
<label asp-for="#Model.Employee.LastName" class="control-label"></label>
<input asp-for="#Model.Employee.LastName" class="form-control input-lg" />
<span asp-validation-for="#Model.Employee.LastName" class="text-danger"></span>
</div>
...
<button type="submit">Save</button>
</form
On the controller side:
[HttpPost]
public IActionResult Create(Info data)
{
// Processing the entered data
....
return View(data);
}
Faced such peculiar problem. For a better understanding, I will try to describe in more detail.
I have two metod in ArticleController:
[HttpGet]
public async Task<IActionResult> Create()
{
var sources = await _sourceServices.GetSourceNameAndId();
var listSources = new List<SourceNameAndIdModel>();
foreach (var source in sources)
{
listSources.Add(_mapper.Map<SourceNameAndIdModel>(source));
}
var viewModel = new ArticleCreateViewModel()
{
SourceNameAndIdModels = listSources
};
return View(viewModel);
}
[HttpPost]
public async Task<IActionResult> Create(ArticleCreateViewModel viewModel)
{
await _articleService.CreateArticle(_mapper.Map<ArticleDTO>(viewModel));
return RedirectToAction("Index", "Article");
}
As you can see, in the Get-method, I get the names and ids of all Sources from the database via _sourceService in the form of IEnumerable :
public class SourceNameAndIdDTO
{
public Guid Id { get; set; }
public string Name { get; set; }
}
Next, I enumerate them in a foreach loop and add each SourceNameAndIdDTO object to the List listSources I created before:
public class SourceNameAndIdModel
{
public string Name { get; set; }
public Guid Id { get; set; }
}
Next, I create an instance of the ArticleCreateViewModel model, which I will use further in the View:
public class ArticleCreateViewModel
{
public Guid Id { get; set; } = Guid.NewGuid();
public string Title { get; set; }
public string Description { get; set; }
public string Body { get; set; }
public Guid SourceId { get; set; }
public DateTime CreationDate { get; set; }
public List<SourceNameAndIdModel> SourceNameAndIdModels { get; set; }
}
And I assign to the field public List SourceNameAndIdModels { get; set; } List listSources values:
var viewModel = new ArticleCreateViewModel()
{
SourceNameAndIdModels = listSources
};
You can see this in the controller code I posted above. Next, I send the viewModel to the View.
Code of my View:
#model ArticleCreateViewModel
<div class="container">
<h2>Edit article</h2>
<div class="row gx-5">
<form asp-controller="Article" asp-action="Create" asp-antiforgery="true" method="post">
<div>
<input type="hidden" asp-for="Id" />
<div class="mb-3">
<label class="col-sm-2 col-form-label" asp-for="Title"></label>
<input class="form-control" type="text" asp-for="Title">
</div>
<div class="mb-3">
<label class="col-sm-2 col-form-label" asp-for="Description"></label>
<textarea class="form-control" asp-for="Description"></textarea>
</div>
<div class="mb-3">
<label class="col-sm-2 col-form-label" asp-for="Body"></label>
<textarea class="form-control" asp-for="Body"></textarea>
</div>
<div class="dropdown">
<a class="btn btn-secondary dropdown-toggle" href="#" role="button" data-bs-toggle="dropdown" aria-expanded="false">
Source
</a>
<ul class="dropdown-menu">
#foreach (var item in #Model.SourceNameAndIdModels)
{
<li><select class="dropdown-item" asp-for="SourceId" asp-items="#item.Id">#item.Name</select></li>
}
</ul>
</div>
<div class="mb-3">
<label class="col-sm-2 col-form-label" asp-for="CreationDate"></label>
<input type="datetime-local" class="form-control" asp-for="CreationDate">
</div>
</div>
<button type="submit" class="btn btn-primary">Submit</button>
</form>
</div>
</div>
And finally, in this place of the code, in which I want to set the Source of the article I am creating, I have an error:
enter image description here
Can you please tell me how in my case to make friends with my code with dropdown on my request? What am I doing wrong?
Using asp-items in this way is incorrect.
The Select Tag Helper asp-items specifies the option elements
Details and example:
https://learn.microsoft.com/...netcore-6.0#the-select-tag-helper
I am creating page to create model and save it to DBS. Model contains some simple properties, and list of properties that are selected from dynamic array of checkboxes. So my idea is to load list of props from database (it works) show checkbox for each property (also works) wait for user to fill all simple forms and check all props he wants, and send it via POST to database.
I just cannot figure out how to add all checked props to list in model. I will apriciate any help.
Model:
public class MyModel
{
public Guid Id { get; set; }
public string SimpleProp1 { get; set; }
public string SimpleProp2 { get; set; }
public IEnumerable<Guid> Extras { get; set; }
}
public class Extra
{
public Guid Id { get; set; }
public string Name { get; set; }
}
Code in backend add.cshtml.cs
[Authorize]
public class AddModel : PageModel
{
private readonly DatabaseHelper databasehelper;
[BindProperty]
public List<Extra> ExtrasList { get; set; }
public AddModel(ApplicationDbContext context)
{
databasehelper = new DatabaseHelper(context);
}
public IActionResult OnGet()
{
ExtrasList = StaticLists.Extras;
return Page();
}
[BindProperty]
public MyModel Model { get; set; }
public IActionResult OnPostAsync()
{
if (!ModelState.IsValid)
{
return Page();
}
var result = database.AddToDbs(Model);
return RedirectToPage("./Overview/"+ result.ResponseGuid.ToString());
}
}
and frontend
#page
#model Pages.AddModel
#{
ViewData["Title"] = "Add";
}
<hr />
<div class="row">
<div class="col-md-4">
<form method="post">
<div asp-validation-summary="ModelOnly" class="text-danger"></div>
<br />
<input type="text" asp-for="Model.SimpleProp1" />
<br />
<input type="text" asp-for="Model.SimpleProp2" />
<br />
<div>
#foreach (var cb in Model.ExtrasList) {
<input name="ExtrasList" type="checkbox" value="#cb.Id" /> #cb.Name<br />
}
<br />
</div>
<!-- somewhere here I need to bind checkbox state to model -->
</form>
<form method="post">
<button>Submit</button>
</form>
</div>
</div>
<div>
<a asp-page="Index">Back to List</a>
</div>
#section Scripts {
#{await Html.RenderPartialAsync("_ValidationScriptsPartial");}
}
I know, that this code is not super eficient and it is not best way how to do that. I am just learning FE and whole razor page concept.
According to your razor page codes, I found you have used multiple form tag in your page.
You should remove the form tag which is outside the <button>Submit</button> and modify the checkbox's name to Model.Extras, then it will work well.
More details, you could refer to below view codes:
<div class="row">
<div class="col-md-4">
<form method="post">
<div asp-validation-summary="ModelOnly" class="text-danger"></div>
<br />
<input type="text" asp-for="Model.SimpleProp1" />
<br />
<input type="text" asp-for="Model.SimpleProp2" />
<br />
<div>
#foreach (var cb in Model.ExtrasList)
{
<input name="Model.Extras" type="checkbox" value="#cb.Id" /> #cb.Name<br />
}
<br />
</div>
<!-- somewhere here I need to bind checkbox state to model -->
<button>Submit</button>
</d>
</form>
</div>
</div>
Result:
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
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.