I'm on a project with .Net Core and I'm using ASP Razor Pages. In my model, I have an OnGet which load all the data I need in my view.
public IList<Projet> Projets { get; set; }
public ActionResult OnGet()
{
Projets = _serviceSelect.getProjets();
return Page();
}
Then, in my OnPost which is activated when I submit my form.
<form method="post">
<div asp-validation-summary="All" class="text-danger"></div>
<input type="radio" value="1" asp-for="LoginData.TypeCompte" />choice<br />
Username: <input asp-for="LoginData.Username" /><br />
Password: <input asp-for="LoginData.Password" /><br />
Remember me: <input asp-for="LoginData.RememberMe" type="checkbox" /><br />
<input asp-page-handler="connexion" type="submit" value="Login" />
@Html.AntiForgeryToken()
</form>
I would like to display an error in my view, using my ModelState.
public ActionResult OnPostConnexion()
{
if (ModelState.IsValid)
{
// Do stuff
}
else
{
ModelState.AddModelError("", "username or password is blank");
return Page();
}
}
But, when I return Page(), It's like the model is reload and when I try to access to my data, my objects are null.
Object reference not set to an instance of an object.
@foreach (var item in Model.Projets)
How can I update my view without losing my data contain in the model ?
From the docs, "Razor Pages can make coding page-focused scenarios easier and more productive than using controllers and views." If your ASP.NET MVC app makes heavy use of views, you may want to consider migrating from actions and views to Razor Pages.
Property binding in Angular helps you set values for properties of HTML elements or directives. Use property binding to do things such as toggle button features, set paths programmatically, and share values between components.
Razor Pages focus on page-based scenarios for building web applications rather than using controllers and views like a traditional ASP.NET MVC application. Once the application receives an HTTP request, it moves through the middleware pipeline until it reaches a middleware component that can handle and process it.
I solved this issue by replacing return Page();
with return this.OnGet();
in public ActionResult OnPostConnexion()
That way any logic you have in the OnGet which populates PageModel properties gets reused.
So my full example looks like:
public IEnumerable<SelectListItem> CompanyListing { get; private set; }
public async Task<IActionResult> OnGet()
{
if (!string.IsNullOrEmpty(this.ErrorMessage))
{
this.ModelState.AddModelError(string.Empty, this.ErrorMessage);
}
this.CompanyListing = await this.PopulateCompanyList();
return this.Page();
}
public async Task<IActionResult> OnPostAsync()
{
if (!this.ModelState.IsValid)
{
// Something failed. Redisplay the form.
return await this.OnGet();
}
return this.RedirectToPage("/");
}
The reason you are getting an object reference error is because the Model.Projects has not been populated when returning the view and therefore cannot iterate in the foreach loop.
Based off your existing code, you could populate your model again before returning the page.
public ActionResult OnPostConnexion()
{
if (ModelState.IsValid)
{
// Do stuff
}
else
{
Projets = _serviceSelect.getProjets();
ModelState.AddModelError("", "username or password is blank");
return Page();
}
}
A better solution would be:
public ActionResult OnPostConnexion(viewModel model)
{
if (!ModelState.IsValid)
{
return View(model);
}
else
{
//do stuff
}
}
I faced the same issue and noone from suggested solution worked. I resolved it with simple usage of helping class that keeps the model for me. The solution is not elegant but effective :)
public interface ISessionHelper
{
void AddRenewItem(string key, object item);
object GetItem(string key);
}
public class SessionHelper : ISessionHelper
{
private readonly Dictionary<string, object> _sessionBag;
public SessionHelper()
{
_sessionBag = new Dictionary<string, object>();
}
public void AddRenewItem(string key, object item)
{
if (_sessionBag.Keys.Contains(key)) _sessionBag.Remove(key);
_sessionBag.Add(key, item);
}
public object GetItem(string key)
{
if (_sessionBag.Keys.Contains(key))
{
return _sessionBag[key];
}
return null;
}
}
In my get method I add an item to the dictionary:
public async Task<IActionResult> OnGetAsync(int? id)
{
...
_sessionHelper.AddRenewItem(this.ToString(), this);
...
}
In my post method I take the model back from the dictionary and assign required properties for the current model:
public async Task<IActionResult> OnPostApplyGuess(int itemId)
{
GameModel model = (GameModel) _sessionHelper.GetItem(this.ToString());
MyProp1= model.MyProp1;
MyProp2 = model.MyProp2 ;
MyProp3= model.MyProp3;
if (!ModelState.IsValid)
{
return Page();
}
return Page();
}
Do not forget to add the service as a Singleton:
services.AddSingleton<ISessionHelper, SessionHelper>();
I hope it helped to somebody :)
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With