【问题标题】:EF Core works with razor pages but not MVCEF Core 适用于剃须刀页面,但不适用于 MVC
【发布时间】:2021-04-19 01:21:21
【问题描述】:

所以我正在开发我的应用程序,出于某种原因,与 UserManager、RoleManager 和 SigninManager 相关的任何操作都无法在视图和控制器中工作。它告诉我它无法访问数据库。我猜这是一个上下文问题。迁移工作正常,我可以在身份系统之外的数据库中创建对象。如果我使用脚手架使用剃须刀页面覆盖身份验证/身份中的页面,则一切正常(注册、登录等)。当我尝试在对控制器的一个视图操作中检查角色作为测试时,它给了我以下错误:

Microsoft.EntityFrameworkCore.Database.Connection: Error: An error occurred using the connection to database 'DDDTemplate' on server '.'.

这是一个本地数据库设置,在 SQL 服务器上具有受信任的连接。

Startup.cs

public class Startup
{
    private readonly IWebHostEnvironment _env;
    public Startup(IConfiguration configuration, IWebHostEnvironment env)
    {
        Configuration = configuration;
        _env = env;
    }

    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.AddApplication();
        services.AddInfrastructure(Configuration);
        services.AddDatabaseDeveloperPageExceptionFilter();

        services.AddSingleton<ICurrentUserService, CurrentUserService>();

        services.AddHttpContextAccessor();

        services.AddControllersWithViews()
                .AddFluentValidation();

        //services.AddRazorPages();

        if (_env.IsDevelopment())
        {
            services.AddSingleton<IConsoleLogger, ConsoleLogger>();
            
        }
        else
        {
            services.AddSingleton<IConsoleLogger, NullConsoleLogger>();
        }
        
    }

    // This method gets called by the runtime. Use this method to configure the HTTP request pipeline.
    public void Configure(IApplicationBuilder app, IWebHostEnvironment env)
    {
        if (env.IsDevelopment())
        {
            app.UseDeveloperExceptionPage();
            app.UseMigrationsEndPoint();
        }
        else
        {
            app.UseExceptionHandler("/Home/Error");
            // The default HSTS value is 30 days. You may want to change this for production scenarios, see https://aka.ms/aspnetcore-hsts.
            app.UseHsts();
        }
        app.UseHttpsRedirection();
        app.UseStaticFiles();

        app.UseRouting();

        app.UseAuthentication();

        app.UseAuthorization();

        app.UseEndpoints(endpoints =>
        {
            Routes.Addroutes(endpoints);
        });
    }
}

Routes.cs

public static class Routes
{

    public static void Addroutes(IEndpointRouteBuilder endpoints)
    {
        endpoints.MapControllerRoute(
                name: "default",
                pattern: "{controller=Home}/{action=Index}/{id?}");
        //endpoints.MapRazorPages();
    }
}

appsettings.json

{
  "UseInMemoryDatabase": false,
  "ConnectionStrings": {
    "DefaultConnection": "Data Source=.;Initial Catalog=DDDTemplate;Integrated Security=True;MultipleActiveResultSets=true;"
  },
  "Logging": {
    "LogLevel": {
      "Default": "Information",
      "Microsoft": "Warning",
      "Microsoft.Hosting.Lifetime": "Information"
    }
  },
  "AllowedHosts": "*"
}

AccountController.cs

public class AccountController : Controller
{
    private readonly RoleManager<ApplicationRole> _roleManager;
    private readonly UserManager<ApplicationUser> _userManager;
    private readonly SignInManager<ApplicationUser> _signInManager;
    private readonly IIdentityService _identityService;

    public AccountController(RoleManager<ApplicationRole> RoleManager, UserManager<ApplicationUser> userManager, SignInManager<ApplicationUser> signInManager, IIdentityService identityService)
    {
        _roleManager = RoleManager;
        _userManager = userManager;
        _signInManager = signInManager;
        _identityService = identityService;
    }

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

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

    public IActionResult Login(string t)
    {
        return View();
    }

    [HttpPost]
    public void Register(RegisterViewModel userInfo)
    {

    }

    [HttpPost]
    public async void Login(LoginViewModel loginInfo)
    {
        try
        {

            bool x = await _roleManager.RoleExistsAsync("Admin");
            Console.WriteLine("test");

        }
        catch (Exception exception)
        {
           
        }
        
    }
}

Login.cshtml来自 Views/Account 文件夹

@model DDDTemplate.App.LoginViewModel
@using Microsoft.AspNetCore.Identity
@using DDDTemplate.Data.Identity
@inject SignInManager<ApplicationUser> SignInManager
@inject UserManager<ApplicationUser> UserManager
@inject RoleManager<ApplicationRole> RoleManager
@{
    ViewData["Title"] = "Login";
}
<div class="text-center">
    <h1 class="display-4">Register Account</h1>
    <form asp-controller="Account" asp-action="Login" method="post">
        <div asp-validation-summary="ModelOnly"></div>
        <div>
            <label asp-for="Username"></label>
            <input asp-for="Username" />
            <span asp-validation-for="Username"></span>
        </div>
        <div>
            <label asp-for="Password"></label>
            <input asp-for="Password" />
            <span asp-validation-for="Password"></span>
        </div>

        <div>
            <input type="submit" value="Login" />
        </div>
    </form>
</div>

在服务配置期间调用的引用项目的依赖注入文件中

public static IServiceCollection AddInfrastructure(this IServiceCollection services, IConfiguration configuration)
{
    services.AddDbContext<ApplicationDbContext>(options =>
        options.UseSqlServer(
            configuration.GetConnectionString("DefaultConnection"),
            b =>
                b.MigrationsAssembly(typeof(ApplicationDbContext).Assembly.FullName)
        )
    );

    services
        .AddIdentity<ApplicationUser,ApplicationRole>()
        .AddEntityFrameworkStores<ApplicationDbContext>()
        .AddDefaultUI()
        .AddDefaultTokenProviders(); ;

    services.AddScoped<IApplicationDbContext>(provider => provider.GetService<ApplicationDbContext>());

    services.AddScoped<IDomainEventService, DomainEventService>();

    services.AddTransient<IDateTime, DateTimeService>();
    services.AddTransient<IIdentityService, IdentityService>();
    services.AddTransient<ICsvFileBuilder, CsvFileBuilder>();

    services.AddAuthorization();

    return services;
}

ApplicationDBContext.cs

public class ApplicationDbContext : IdentityDbContext<ApplicationUser, ApplicationRole, int>, IApplicationDbContext
{

    private IDomainEventService _domainEventService {get;}
    public ApplicationDbContext(DbContextOptions<ApplicationDbContext> options, IDomainEventService domainEventService) : base(options)
    {
        _domainEventService = domainEventService;
    }

    protected override void OnModelCreating(ModelBuilder builder)
    {
        base.OnModelCreating(builder);

        builder.ApplyConfigurationsFromAssembly(Assembly.GetAssembly(typeof(ApplicationDbContext)));
        
    }

    public DbSet<TodoItem> TodoItems { get; set; }

    public DbSet<TodoList> TodoLists { get; set; }

    public override async Task<int> SaveChangesAsync(CancellationToken cancellationToken = new CancellationToken())
    {
        foreach (Microsoft.EntityFrameworkCore.ChangeTracking.EntityEntry<AuditableEntity> entry in ChangeTracker.Entries<AuditableEntity>())
        {
            switch (entry.State)
            {
                case EntityState.Added:
                    entry.Entity.CreatedBy = _currentUserService.;
                    entry.Entity.Created = _dateTime.Now;
                    break;

                case EntityState.Modified:
                    entry.Entity.LastModifiedBy = _currentUserService.UserId;
                    entry.Entity.LastModified = _dateTime.Now;
                    break;
            }
        }

        var result = await base.SaveChangesAsync(cancellationToken);

        await DispatchEvents();

        return result;
    }

    private async Task DispatchEvents()
    {
        while (true)
        {
            var domainEventEntity = ChangeTracker.Entries<IHasDomainEvent>()
                .Select(x => x.Entity.DomainEvents)
                .SelectMany(x => x)
                .Where(domainEvent => !domainEvent.IsPublished)
                .FirstOrDefault();
            if (domainEventEntity == null) break;

            domainEventEntity.IsPublished = true;
            await _domainEventService.Publish(domainEventEntity);
        }
    }
}

【问题讨论】:

  • 要检查的一件事是应用程序池正在运行的用户帐户,就好像它在 IIS 中运行一样。
  • @StevePy 如果我可以使用其他无身份模型执行 CRUD,那会是一个问题吗?它们都使用相同的数据库上下文。
  • 嗨@ObieMD5,有任何详细的错误信息吗?根据您的描述,脚手架的身份剃须刀页面(如注册和登录)运行良好,众所周知,这些页面也使用了UserManager或RoleManager,请检查它们是否有不同之处?另外,在Account Login 页面(index.cshtml),我觉得SignInManager、UserManager 或SignInManager 不需要添加inject,尝试去掉。而在Account控制器中,有一个IIdentityService,不确定问题是否与它有关。你可以检查一下。

标签: c# entity-framework asp.net-core asp.net-core-5.0


【解决方案1】:

我发现问题是我从一个有任务的异步函数返回 void。只有某些情况是可以接受的,这不是其中之一。所以在 AccountController.cs 我更改了以下内容以返回 Task 而不是 void 并且一切正常:

    [HttpPost]
    public async Task Login(LoginViewModel loginInfo)
    {
        try
        {

            bool x = await _roleManager.RoleExistsAsync("Admin");
            Console.WriteLine("test");

        }
        catch (Exception exception)
        {
           
        }
        
    }

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 2019-01-19
    • 1970-01-01
    • 1970-01-01
    • 2020-11-06
    • 2019-05-04
    • 2017-10-03
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多