I read somewhere on the ASP .NET Core documentation that I don’t need to worry about how an instance of my database context will be passed to other controller and model classes as dependency injection will automatically do that for me, I declared a Database Context property in the Page’s model class and then required an instance of the Database Context in the constructor of the model.
However when I try to access the Database Context object from the razor page associated with the model then I get an error that my Database Context is not set to an instance of an object.
The controllers do not throw this error however despite implementing the same declare database context object as property and require it in the constructor.
Why is my database context null when I try to access it from the Model property of the razor page and why is it not null when I access it from the controller?
// this property is accessed from the route
var id = Model.Id;
// use the id to get all the info about this question
var title = Model.dbctx.Posts.FirstOrDefault(x => x.Id == id).Title;
// the dbctx reference above is returning null
The code above is at the top of the razor page.
Here is how the model for that razor page looks like
public class QuestionViewModel:PageModel
{
// get the id from the route
[FromRoute]
public int Id { get; set; }
// the database context property
public Dbctx dbctx { get; set; }
// require an object in the constructor
public QuestionViewModel(Dbctx ctx)
{
dbctx = ctx;
}
}
I use the same logic as the above in my controllers, the only difference is that I use private fields on my controllers and then pass the Dbctx
reference to them via the constructors of the respective controllers.
How can I resolve this?
Update:
I do not know if it’s the query that is returning null but I redirect to this page after a new post object has been posted to database. I then call databaseContext.SaveChanges() to make sure that the insert query was a success. I then grab the id of the last question that was inserted into database and then redirect to the QuestionView page as per the logic in this controller.
public IActionResult HandleNewPost(string Title, string Body, string Tags){
//split the tags based on the space
var tags = Tags.Split(' ');
var tagList = new List<Tag>();
tags.ToList().ForEach(tag=>tagList.Add(new Tag(tag)));
//get the time the post was authored
var creationTime = DateTime.Now;
var postedBy = HttpContext.Session.GetString("email");
var post = new Post{
Title = Title,
Body = Body,
PostedBy = postedBy,
Tags = tagList,
Upvotes = 0,
Downvotes = 0
};
//post the object to database
_dbctx.Posts.Add(post);
_dbctx.SaveChanges();
//get the of the last post ans redirect to QuestionView page
if(_dbctx.Posts.OrderBy(x=>x.Id).LastOrDefualt()!=null){
var id = _dbctx.Posts.OrderBy(x=>x.Id).LastOrDefault().Id;
return RedirectToPage("/QuestionView",new []{id});
}else{
//some custom code
}
}
It is really weird that the error message starts with a different solution name. The name of my current solution is InputHandling, there is another solution though on repos called ASPLearner the QuestionView page is in the Page folder of my current solution but the error stack begins with this line.
ASPLearner.Pages.Pages_QuestionView.ExecuteAsync() in QuestionView.cshtml
7.var title = Model.dbctx.Posts.FirstOrDefault(x=>x.Id==id).Title
Is Visual Studio confused and could this be the source of the error?
2
Answers
@Dai provided an eye opener about properly using the Property Injection but didn't mention anything about assigning to the Model property from the controller's IAction method. To resolve this error then you need to declare a database context object property in the model then in the action method of your controller that redirects to the Page, assign to that property the database context object being use by the controller.
This method may help you:
https://github.com/dotnet/EntityFramework.Docs/blob/main/entity-framework/core/dbcontext-configuration/index.md
Configure DBContext via AddDbContext
Add new constructor to your DBContext class
Inject context to your controllers