skip to Main Content

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


  1. Chosen as BEST ANSWER

    @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.

    //in your controller IAction method
    public IActionResult HandleNewPost(){
      //create a new model for that page
      var model = new QuestionViewModel();
     //assign to the property
      model.dbctx = _dbctx;
     //redirect and do stuff 
    }
    

  2. This method may help you:

    https://github.com/dotnet/EntityFramework.Docs/blob/main/entity-framework/core/dbcontext-configuration/index.md

    Configure DBContext via AddDbContext

    public void ConfigureServices(IServiceCollection services)
    {
        services.AddDbContext<BloggingContext>(options => options.UseSqlite("Data Source=blog.db"));
    }
    

    Add new constructor to your DBContext class

    public class BloggingContext : DbContext
    {
        public BloggingContext(DbContextOptions<BloggingContext> options)
          :base(options)
        { }
    
        public DbSet<Blog> Blogs { get; set; }
    }
    

    Inject context to your controllers

    public class MyController
    {
        private readonly BloggingContext _context;
    
        public MyController(BloggingContext context)
        {
          _context = context;
        }
    
        ...
    }
    
    Login or Signup to reply.
Please signup or login to give your own answer.
Back To Top
Search