【问题标题】:ASP.NET Unable to resolve service for type, while attempting to activate controllerASP.NET 在尝试激活控制器时无法解析服务类型
【发布时间】:2020-10-15 00:53:02
【问题描述】:

虽然我知道关于这个主题还有其他问题,但我很难理解答案,并希望有人能指导我了解 DbContext 的工作原理,因为我觉得我可能在不应该创建第二个上下文时创建了第二个上下文.

所以,当我在自学更多关于 .NET Core 的知识时,我正在努力将一个旧学校项目转变为一个 .NET 项目,这是一个简单的牙医办公室 Web 应用程序,用户可以在其中注册约会、查看他们的约会等。我正在跟随 this tutorial 添加其他用户属性,而不仅仅是用户名和电子邮件,因为我在创建约会时试图获取当前用户。

在我使用默认 IdentityUI 添加此自定义属性之前,我让我的项目在用户可以注册和登录的地方工作,使用他们的“用户名”创建一个基本约会,选择一个日期和时间,一旦创建,他们的约会将以基本形式显示表格格式。我的下一步是添加自定义用户属性,以便根据他们的真实姓名而不是默认为他们的电子邮件的用户名显示。

按照教程,我不确定我是否误解了,但我创建了一个新的 Context 和 IdentityUser,它们都可以正常工作,但它破坏了我的“约会”页面,给了我:

InvalidOperationException:尝试激活“WelchDentistry.Controllers.AppointmentsController”时无法解析“Microsoft.AspNetCore.Identity.UserManager`1[Microsoft.AspNetCore.Identity.IdentityUser]”类型的服务。** 错误。

这是我的 ConfigureServices 方法,因为我认为这是注册 2 个不同上下文的问题。

    public void ConfigureServices(IServiceCollection services)
    {
        
        /*
        services.AddDbContext<ApplicationDbContext>(options =>
            options.UseSqlServer(
                Configuration.GetConnectionString("DefaultConnection")));
                */
                
        /*
        services.AddDefaultIdentity<IdentityUser>(options => options.SignIn.RequireConfirmedAccount = true)
            .AddEntityFrameworkStores<ApplicationDbContext>();
            */

            
        services.AddControllersWithViews();
        services.AddRazorPages();
        services.AddMvc();
    }

这是原始上下文

命名空间 WelchDentistry.Data
{
    公共类 ApplicationDbContext : IdentityDbContext
    {
        公共 ApplicationDbContext(DbContextOptions 选项)
            :基础(选项)
        {
        }
        公共 DbSet 约会 { 获取;放; }
    }
}

这是我的约会控制器

namespace WelchDentistry.Controllers
{
    public class AppointmentsController : Controller
    {
        private readonly ApplicationDbContext _context;
        private readonly UserManager<IdentityUser> _userManager;


        public AppointmentsController(ApplicationDbContext context, UserManager<IdentityUser> userManager)
        {
            _context = context;
            _userManager = userManager;
        }
            

        // GET: Appointments
        public async Task<IActionResult> Index()
        {
            var user = await _userManager.GetUserAsync(HttpContext.User);

            return View(await _context.Appointment.ToListAsync());
        }

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

            var appointment = await _context.Appointment
                .FirstOrDefaultAsync(m => m.ID == id);
            if (appointment == null)
            {
                return NotFound();
            }

            return View(appointment);
        }

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

        // POST: Appointments/Create
        // To protect from overposting attacks, please 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("ID, CustomerName, AppointmentTime,CustomerDoctor")] Appointment appointment)
        {
            if (ModelState.IsValid)
            {
                _context.Add(appointment);
                await _context.SaveChangesAsync();
                return RedirectToAction(nameof(Index));
            }
            return View(appointment);
        }

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

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

        // POST: Appointments/Edit/5
        // To protect from overposting attacks, please 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(int id, [Bind("ID,CustomerName,AppointmentTime,CustomerDoctor")] Appointment appointment)
        {
            if (id != appointment.ID)
            {
                return NotFound();
            }

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

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

            var appointment = await _context.Appointment
                .FirstOrDefaultAsync(m => m.ID == id);
            if (appointment == null)
            {
                return NotFound();
            }

            return View(appointment);
        }

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

        private bool AppointmentExists(int id)
        {
            return _context.Appointment.Any(e => e.ID == id);
        }
    }
}

如果需要更多代码,请询问或者您可以查看my Github

感谢所有的帮助,因为我仍然迷失在其中的大部分内容上,但正在慢慢学习。

【问题讨论】:

    标签: asp.net dependency-injection asp.net-identity


    【解决方案1】:

    首先在您的身份区域中删除您的 IdentityHostingStartup 文件。

    然后将您的数据库上下文更改为此(您应该介绍您的 User 类):

    public class ApplicationDbContext : IdentityDbContext<WelchDentistryUser, IdentityRole, string>
    {
        public ApplicationDbContext(DbContextOptions<ApplicationDbContext> options)
            : base(options)
        {
        }
    
        public DbSet<Models.Appointment> Appointment { get; set; }
    }
    

    并将此代码添加到您的启动文件中。

            services.AddIdentity<WelchDentistryUser, IdentityRole>()
                .AddEntityFrameworkStores<ApplicationDbContext>()
                .AddDefaultTokenProviders();
    

    最后你应该在控制器中使用你的自定义用户类。

    public class AppointmentsController : Controller
    {
        private readonly ApplicationDbContext _context;
        private readonly UserManager<WelchDentistryUser> _userManager;
    
    
        public AppointmentsController(ApplicationDbContext context, UserManager<WelchDentistryUser> userManager)
        {
            _context = context;
            _userManager = userManager;
        }
    

    }

    【讨论】:

    • 如果我可以问一个后续问题,删除 IdentityHostingStartup 文件的目的是什么,就好像我理解正确,正在注册我们的服务,我知道它是 Startup 中已有内容的副本文件,只是想更好地理解。那么,编辑我现有的上下文是否意味着我需要删除新创建的上下文?
    • 使用 IdentityHostingStartup 你注册依赖两次,所以你得到错误。您应该在 Startup 或 IdentityHostingStartup 中注册您的身份依赖项。这是你的选择。
    • 真的很感激!项目恢复工作!那么,通过向默认用户添加自定义属性来创建新上下文是否不正确?我是否可以使用现有的 DbContext 完成此操作,或者我仍然执行了正确的步骤?
    • 向用户添加自定义属性很好,但不需要添加新的 DbContext,您可以使用现有的 DbContext。
    • 所以创建自定义用户类很好,但我不需要新的上下文,明白了。感谢您的所有帮助。
    猜你喜欢
    • 1970-01-01
    • 2020-08-21
    • 2022-09-24
    • 2022-01-26
    • 1970-01-01
    • 2018-04-06
    • 1970-01-01
    • 2023-01-13
    相关资源
    最近更新 更多