ASP.Net 核心 - 尝试激活 *Controller 时无法解析 *Context 类型的服务

ASP.Net Core - Unable to resolve service for type *Context while attempting to activate *Controller

这里是新手。我觉得我已经接近理解了,但是大多数文章都围绕 Startup.cs 展开,而我没有。我被错误困住了:

InvalidOperationException: Unable to resolve service for type 'SFTP.Models.SFTPContext' while attempting to activate 'SFTP.Controllers.ClientInfsController'.

我错过了什么?

Program.cs

var builder = WebApplication.CreateBuilder(args);

// Add services to the container.
builder.Services.AddControllersWithViews();

var app = builder.Build();

// Configure the HTTP request pipeline.
if (!app.Environment.IsDevelopment())
{
    app.UseExceptionHandler("/Home/Error");
}
app.UseStaticFiles();

app.UseRouting();

app.UseAuthorization();

app.MapControllerRoute(
    name: "default",
    pattern: "{controller=Home}/{action=Index}/{id?}");

app.Run();

控制器 - HomeController.cs

using Microsoft.AspNetCore.Mvc;
using SFTP.Models;
using System.Diagnostics;

namespace SFTP.Controllers
{
    public class HomeController : Controller
    {
        private readonly ILogger<HomeController> _logger;

        public HomeController(ILogger<HomeController> logger)
        {
            _logger = logger;
        }

        public IActionResult Index()
        {
            return View();
        }

        public IActionResult Privacy()
        {
            return View();
        }

        [ResponseCache(Duration = 0, Location = ResponseCacheLocation.None, NoStore = true)]
        public IActionResult Error()
        {
            return View(new ErrorViewModel { RequestId = Activity.Current?.Id ?? HttpContext.TraceIdentifier });
        }
    }
}

控制器 - ClienInfsContoller.cs

#nullable disable
using System;
using System.Collections.Generic;
using System.Linq;
using System.Threading.Tasks;
using Microsoft.AspNetCore.Mvc;
using Microsoft.AspNetCore.Mvc.Rendering;
using Microsoft.EntityFrameworkCore;
using SFTP.Models;

namespace SFTP.Controllers
{
    public class ClientInfsController : Controller
    {
        private readonly SFTPContext _context;

        public ClientInfsController(SFTPContext context)
        {
            _context = context;
        }

        // GET: ClientInfs
        public async Task<IActionResult> Index()
        {
            return View(await _context.ClientInfs.ToListAsync());
        }

        // GET: ClientInfs/Details/5
        public async Task<IActionResult> Details(string id)
        {
            if (id == null)
            {
                return NotFound();
            }

            var clientInf = await _context.ClientInfs
                .FirstOrDefaultAsync(m => m.Limiters == id);
            if (clientInf == null)
            {
                return NotFound();
            }

            return View(clientInf);
        }

        // GET: ClientInfs/Create
        public IActionResult Create()
        {
            return View();
        }

        // POST: ClientInfs/Create
        // To protect from overposting attacks, enable the specific properties you want to bind to.
        // For more details, see http://go.microsoft.com/fwlink/?LinkId=317598.
        [HttpPost]
        [ValidateAntiForgeryToken]
        public async Task<IActionResult> Create([Bind("Client,Inpath,Outpath,Limiters")] ClientInf clientInf)
        {
            if (ModelState.IsValid)
            {
                _context.Add(clientInf);
                await _context.SaveChangesAsync();
                return RedirectToAction(nameof(Index));
            }
            return View(clientInf);
        }

        // GET: ClientInfs/Edit/5
        public async Task<IActionResult> Edit(string id)
        {
            if (id == null)
            {
                return NotFound();
            }

            var clientInf = await _context.ClientInfs.FindAsync(id);
            if (clientInf == null)
            {
                return NotFound();
            }
            return View(clientInf);
        }

        // POST: ClientInfs/Edit/5
        // To protect from overposting attacks, enable the specific properties you want to bind to.
        // For more details, see http://go.microsoft.com/fwlink/?LinkId=317598.
        [HttpPost]
        [ValidateAntiForgeryToken]
        public async Task<IActionResult> Edit(string id, [Bind("Client,Inpath,Outpath,Limiters")] ClientInf clientInf)
        {
            if (id != clientInf.Limiters)
            {
                return NotFound();
            }

            if (ModelState.IsValid)
            {
                try
                {
                    _context.Update(clientInf);
                    await _context.SaveChangesAsync();
                }
                catch (DbUpdateConcurrencyException)
                {
                    if (!ClientInfExists(clientInf.Limiters))
                    {
                        return NotFound();
                    }
                    else
                    {
                        throw;
                    }
                }
                return RedirectToAction(nameof(Index));
            }
            return View(clientInf);
        }

        // GET: ClientInfs/Delete/5
        public async Task<IActionResult> Delete(string id)
        {
            if (id == null)
            {
                return NotFound();
            }

            var clientInf = await _context.ClientInfs
                .FirstOrDefaultAsync(m => m.Limiters == id);
            if (clientInf == null)
            {
                return NotFound();
            }

            return View(clientInf);
        }

        // POST: ClientInfs/Delete/5
        [HttpPost, ActionName("Delete")]
        [ValidateAntiForgeryToken]
        public async Task<IActionResult> DeleteConfirmed(string id)
        {
            var clientInf = await _context.ClientInfs.FindAsync(id);
            _context.ClientInfs.Remove(clientInf);
            await _context.SaveChangesAsync();
            return RedirectToAction(nameof(Index));
        }

        private bool ClientInfExists(string id)
        {
            return _context.ClientInfs.Any(e => e.Limiters == id);
        }
    }
}

型号 - SFTPContext.cs

using System;
using System.Collections.Generic;
using Microsoft.EntityFrameworkCore;
using Microsoft.EntityFrameworkCore.Metadata;
using SFTP.Models;

namespace SFTP.Models
{
    public partial class SFTPContext : DbContext
    {
        public SFTPContext()
        {
        }

        public SFTPContext(DbContextOptions<SFTPContext> options)
            : base(options)
        {
        }

        public virtual DbSet<ClientInf> ClientInfs { get; set; } = null!;
        public virtual DbSet<SftpFileTrack> SftpFileTracks { get; set; } = null!;

        protected override void OnConfiguring(DbContextOptionsBuilder optionsBuilder)
        {
            if (!optionsBuilder.IsConfigured)
            {
#warning To protect potentially sensitive information in your connection string, you should move it out of source code. You can avoid scaffolding the connection string by using the Name= syntax to read it from configuration - see https://go.microsoft.com/fwlink/?linkid=2131148. For more guidance on storing connection strings, see http://go.microsoft.com/fwlink/?LinkId=723263.
                optionsBuilder.UseSqlServer("Data Source=**********;Initial Catalog=SFTP;Integrated Security=True");
            }
        }

        protected override void OnModelCreating(ModelBuilder modelBuilder)
        {
            modelBuilder.Entity<ClientInf>(entity =>
            {
                entity.HasKey(e => e.Limiters)
                    .HasName("PK__Client_I__7EFD3A29C824FBB5");

                entity.ToTable("Client_Inf");

                entity.Property(e => e.Limiters)
                    .HasMaxLength(255)
                    .IsUnicode(false)
                    .HasColumnName("LIMITERS");

                entity.Property(e => e.Client)
                    .HasMaxLength(255)
                    .IsUnicode(false)
                    .HasColumnName("CLIENT");

                entity.Property(e => e.Inpath)
                    .HasMaxLength(255)
                    .IsUnicode(false)
                    .HasColumnName("INPATH");

                entity.Property(e => e.Outpath)
                    .HasMaxLength(255)
                    .IsUnicode(false)
                    .HasColumnName("OUTPATH");
            });

            modelBuilder.Entity<SftpFileTrack>(entity =>
            {
                entity.HasKey(e => e.Infile)
                    .HasName("PK__SFTP_Fil__3B2253A7C9D06D81");

                entity.ToTable("SFTP_FileTrack");

                entity.Property(e => e.Infile)
                    .HasMaxLength(255)
                    .IsUnicode(false)
                    .HasColumnName("INFILE");

                entity.Property(e => e.Client)
                    .HasMaxLength(255)
                    .IsUnicode(false);

                entity.Property(e => e.Infilepath)
                    .HasMaxLength(255)
                    .IsUnicode(false)
                    .HasColumnName("INFILEPath");

                entity.Property(e => e.Intime)
                    .HasColumnType("datetime")
                    .HasColumnName("INTime");

                entity.Property(e => e.IntimeConfirm)
                    .HasColumnType("datetime")
                    .HasColumnName("INTimeCONFIRM");

                entity.Property(e => e.Outfile)
                    .HasMaxLength(255)
                    .IsUnicode(false)
                    .HasColumnName("OUTFILE");

                entity.Property(e => e.Outfilepath)
                    .HasMaxLength(255)
                    .IsUnicode(false)
                    .HasColumnName("OUTFILEPath");

                entity.Property(e => e.Outtime)
                    .HasColumnType("datetime")
                    .HasColumnName("OUTTime");

                entity.Property(e => e.Status)
                    .HasMaxLength(50)
                    .IsUnicode(false)
                    .HasColumnName("STATUS");
            });

            OnModelCreatingPartial(modelBuilder);
        }

        partial void OnModelCreatingPartial(ModelBuilder modelBuilder);
    }
}

型号 - ClientInf.cs

using System;
using System.Collections.Generic;

namespace SFTP.Models
{
    public partial class ClientInf
    {
        public string? Client { get; set; }
        public string? Inpath { get; set; }
        public string? Outpath { get; set; }
        public string Limiters { get; set; } = null!;
    }
}

看起来你错过了注入 SFTPContext,这是 DbContext 到 DI 容器。

Program.cs

builder.Services.AddDbContext<SFTPContext>(options =>
   options.UseSqlServer(builder.Configuration.GetConnectionString(/* ConectionString key from appsettings.json */)));

参考

Dependency injection (services) - ASP.NET Core fundamentals | Microsoft Docs