locked
[MVC] DbProvider issue with Sqlite 3.1 RRS feed

  • Question

  • User-1370514677 posted

    Hi everyone,

    I'm following the ASP.NET Core MVC tutorials to work with a database : https://docs.microsoft.com/en-us/aspnet/core/tutorials/first-mvc-app/working-with-sql?view=aspnetcore-3.1&tabs=visual-studio-code

    So I did the following :

    > dotnet add package Microsoft.EntityFrameworkCore.Sqlite --version3.1
    > dotnet add package Microsoft.EntityFrameworkCore.Design --version3.1

    Startup.cs

            public void ConfigureServices(IServiceCollection services)
            {
                services.AddControllersWithViews();
                services.AddDbContext<WebAppContext>(options =>
                    options.UseSqlite(Configuration.GetConnectionString("WebAppContext")));
            }

    appsettings.json

    {
      "Logging": {
        "LogLevel": {
          "Default": "Information",
          "Microsoft": "Warning",
          "Microsoft.Hosting.Lifetime": "Information"
        }
      },
      "AllowedHosts": "*",
      "ConnectionStrings": {
        "WebAppContext": "Data Source=database.db"
      }
    }
    

    WebAppContext

    using Microsoft.EntityFrameworkCore;
    using WebApp.Models;
    
    namespace WebApp.Data
    {
        public class WebAppContext : DbContext
        {
            public WebAppContext(DbContextOptions<WebAppContext> options) : base(options)
            {}
    
            public DbSet<Message> Message { get; set; }
        }
    }

    Message.cs

    using System;
    
    namespace WebApp.Models
    {
        public class Message
        {
            public int Id { get; set; }
            public string Title { get; set; }
            public string Content { get; set; }
        }
    }

    MessageController

    using Microsoft.AspNetCore.Mvc;
    using Microsoft.EntityFrameworkCore;
    using WebApp.Data;
    using WebApp.Models;
    using System;
    using System.Linq;
    
    namespace WebApp.Controllers
    {
        public class MessageController : Controller
        {
            private readonly WebAppContext _context;
    
            public MessageController(WebAppContext context)
            {
                _context = context;
            }
    
            [HttpPost]
            [ValidateAntiForgeryToken]
            public IActionResult PublishMessage()
            {
                var db = new WebAppContext(new DbContextOptions<WebAppContext>{});
    
                var new_message = new Message{ 
                    Title = Request.Form["Title"],
                    Content = Request.Form["Content"]
                };
    
                db.Add(new_message);
                db.SaveChanges();
    return RedirectToAction("Index", "Home"); } } }

    Index.cshtml

    @addTagHelper *, Microsoft.AspNetCore.Mvc.TagHelpers
    
    <!DOCTYPE html>
    <html lang="en">
        <head>
            <meta charset="utf-8">
            <title>WebApp</title>
        </head>
    
        <body>
            <form asp-controller="Message" asp-action="PublishMessage" method="POST">
                @model WebApp.Models.Message
                <label asp-for="Title">Title : </label>
                <br>
                <input name="Title" type="text">
                <br>
                <label asp-for="Content">Message : </label>
                <br>
                <input name="Content" type="text">
                <br>
                <input value="Publish" type="submit">
            </form>
        </body>
    </html>

    Yet after having configured everything :

    > dotnet ef migrations add InitialCreate // Create the migration table
    > dotnet ef database update // Create/Update the DB according to the migration schema

    And running my app then Clicking on the publish button, I get :

    InvalidOperationException: No database provider has been configured for this DbContext.

    Why ? I followed the offical tutorial and don't understand where I'm missing something.

    Thank you in advance for your help

    Saturday, December 19, 2020 10:20 AM

Answers

  • User475983607 posted

    I cannot reproduce this issue.

    public class BloggingContext : DbContext
    {
        public DbSet<Blog> Blogs { get; set; }
        public DbSet<Post> Posts { get; set; }
    
        public BloggingContext(DbContextOptions<BloggingContext> options) : base(options)
        {
    
        }
    }
        public class Startup
        {
            public Startup(IConfiguration configuration)
            {
                Configuration = configuration;
            }
    
            public IConfiguration Configuration { get; }
    
            // This method gets called by the runtime. Use this method to add services to the container.
            public void ConfigureServices(IServiceCollection services)
            {
                services.AddRazorPages();
    
                services.AddDbContext<BloggingContext>(options => 
                options.UseSqlite(Configuration.GetConnectionString("BloggingContext")));
            }
      "ConnectionStrings": {
        "BloggingContext": "Data Source=blogging.db"
      }

    However, your controller does not follow standards.  You used constructor injection but do not use the Bdcontext and try to create another context in the Action.  The code will fail due to a missing connections string.  Also the Action should have an input model.  

    private readonly BloggingContext _bloggingContext;
    public HomeController(BloggingContext bloggingContext)
    {
        _bloggingContext = bloggingContext;
    }
    // GET: HomeController
    public ActionResult Index()
    {
        List<Blog> model = _bloggingContext.Blogs.ToList();
        return View(model);
    }

    • Marked as answer by Anonymous Thursday, October 7, 2021 12:00 AM
    Saturday, December 19, 2020 1:01 PM

All replies

  • User475983607 posted

    I cannot reproduce this issue.

    public class BloggingContext : DbContext
    {
        public DbSet<Blog> Blogs { get; set; }
        public DbSet<Post> Posts { get; set; }
    
        public BloggingContext(DbContextOptions<BloggingContext> options) : base(options)
        {
    
        }
    }
        public class Startup
        {
            public Startup(IConfiguration configuration)
            {
                Configuration = configuration;
            }
    
            public IConfiguration Configuration { get; }
    
            // This method gets called by the runtime. Use this method to add services to the container.
            public void ConfigureServices(IServiceCollection services)
            {
                services.AddRazorPages();
    
                services.AddDbContext<BloggingContext>(options => 
                options.UseSqlite(Configuration.GetConnectionString("BloggingContext")));
            }
      "ConnectionStrings": {
        "BloggingContext": "Data Source=blogging.db"
      }

    However, your controller does not follow standards.  You used constructor injection but do not use the Bdcontext and try to create another context in the Action.  The code will fail due to a missing connections string.  Also the Action should have an input model.  

    private readonly BloggingContext _bloggingContext;
    public HomeController(BloggingContext bloggingContext)
    {
        _bloggingContext = bloggingContext;
    }
    // GET: HomeController
    public ActionResult Index()
    {
        List<Blog> model = _bloggingContext.Blogs.ToList();
        return View(model);
    }

    • Marked as answer by Anonymous Thursday, October 7, 2021 12:00 AM
    Saturday, December 19, 2020 1:01 PM
  • User-1370514677 posted

    Hi @mgebhard,

    Thank you for your answer, you are right, I didn't follow the D.I I created, it now works !

    using Microsoft.AspNetCore.Mvc;
    using Microsoft.EntityFrameworkCore;
    using WebApp.Data;
    using WebApp.Models;
    using System;
    using System.Linq;
    
    namespace WebApp.Controllers
    {
        public class MessageController : Controller
        {
            private readonly WebAppContext _context;
    
            public MessageController(WebAppContext context)
            {
                _context = context;
            }
    
            [HttpPost]
            [ValidateAntiForgeryToken]
            public IActionResult PublishMessage()
            {
                var new_message = new Message{ 
                    Title = Request.Form["Title"],
                    Content = Request.Form["Content"]
                };
    
                _context.Add(new_message); // Using the _context object
                _context.SaveChanges(); // Using the _context object
    
                return RedirectToAction("Index", "Home");
            }
        }
    }

    To put it in a nutshell, with ASP.NET Core MVC one should use DB context this way for usage in a Controller :

     public class MessageController : Controller
        {
            private readonly WebAppContext _context;
    
            public MessageController(WebAppContext context)
            {
                _context = context;
            }

    public void MethodToUseDbContext()
    {
    // Code
    } }

    Saturday, December 19, 2020 2:32 PM
  • User475983607 posted

    You should also pass a model to the Action as illustrated in every beginning level MVC tutorial.

    Saturday, December 19, 2020 2:48 PM