使用asp.net核心

时间:2018-05-18 11:30:10

标签: c# asp.net-mvc asp.net-core

我正在编写一个网络应用程序(asp.net core,mvc),目前我的所有代码都在控制器中。我想将其中的一部分移动到服务类中,以便重用代码,并稍微整理一下我的控制器类。

问题是,当我尝试这样做时,我不断收到错误'无法访问已处置的对象。'

似乎第二次尝试使用数据库访问类(DBcontext或userManager)时,会处理类(或其他内容)。

我的代码示例如下。为了简洁起见,我删除了一些位(删除的位几乎不相关)。

首先,控制器:

using System;
using System.Collections.Generic;
using System.Linq;
using System.Net;
using System.Threading.Tasks;
using Microsoft.AspNetCore.Http;
using Microsoft.AspNetCore.Mvc;
using MyProject.Data;
using MyProject.Models;
using Microsoft.AspNetCore.Identity;
using MyProject.Models.Api;
using Microsoft.AspNetCore.Identity;
using Microsoft.AspNetCore.Authentication.JwtBearer;
using Microsoft.AspNetCore.Authorization;
using Microsoft.Extensions.Configuration;
using MyProject.Services;

namespace MyProject.ApiControllers
{
    [Produces("application/json")]
    [Route("api/Migration")]
    public class MigrationController : Controller
    {
        private readonly ApplicationDbContext _context;
        private UserManager<ApplicationUser> _userManager;
        private RoleManager<IdentityRole> _roleManager;
        private IConfiguration _configuration;
        private InitialMigrationService _initialMigrationService;

        public MigrationController(ApplicationDbContext context, UserManager<ApplicationUser> userManager, RoleManager<IdentityRole> roleManager, IConfiguration configuration)
        {
            _context = context;
            _userManager = userManager;
            _roleManager = roleManager;
            _configuration = configuration;
            _initialMigrationService = new InitialMigrationService(userManager, roleManager, context, configuration);
        }

        [Authorize(AuthenticationSchemes = JwtBearerDefaults.AuthenticationScheme)]
        [HttpPost]
        [Route("GetDumpData")]
        public async Task<bool> GetDumpData([FromBody] ApiDataDumpInfo apiDataDumpInfo)
        {
            // I have removed some code here to download a file into dumpBytes (byte array). This works fine

            Models.InitialMigration.DataDump dataDump = Models.InitialMigration.DataDump.DeserialiseFromByteArray(dumpBytes);
            _initialMigrationService.MigrateDataDump(dataDump);
            return true;
        }

    }
}

服务类(和接口):

using System;
using System.Collections.Generic;
using System.Linq;
using System.Threading.Tasks;
using MyProject.Data;
using MyProject.Models;
using MyProject.Models.InitialMigration;
using Microsoft.AspNetCore.Identity;
using Microsoft.Extensions.Configuration;

namespace MyProject.Services
{
    public class InitialMigrationService : IInitialMigrationService
    {
        private UserManager<ApplicationUser> _userManager;
        private RoleManager<IdentityRole> _roleManager;
        private ApplicationDbContext _context;
        private IConfiguration _configuration;

        public InitialMigrationService(UserManager<ApplicationUser> userManager, RoleManager<IdentityRole> roleManager, ApplicationDbContext context, IConfiguration configuration)
        {
            _context = context;
            _userManager = userManager;
            _roleManager = roleManager;
            _configuration = configuration;
        }
        public bool MigrateDataDump(DataDump dump)
        {
            MigrateUserSetup(dump);
            return true;
        }
        private void MigrateUserSetup(DataDump dump)
        {
            dump.UserSetupList.ForEach(u => u.Accounts = true);
            dump.UserSetupList.ForEach(async delegate (DDUserSetup u)
            {
                if (string.IsNullOrEmpty(u.Email))
                    return;
                var swUser = _context.SoftwareUser
                    .SingleOrDefault(du => du.OldID == u.ID);
                if (swUser == null)
                {
                    _context.SoftwareUser.Add(new Models.SoftwareUser
                    {
                        Name = u.Name
                        // Have left out lots of other fields being copied over
                    });
                    _context.SaveChanges();
                    swUser = _context.SoftwareUser
                        .SingleOrDefault(du => du.OldID == u.ID);
                    string userID = await EnsureUser(u.Password, u.Email, swUser.ID);
                    await EnsureRole(userID, ConstantData.ConstUserRole);
                }
            });

        }
        private async Task<string> EnsureUser(string testUserPw, string userName, int? SoftwareUserId)
        {
            var user = await _userManager.FindByNameAsync(userName);
            IdentityResult result = null;
            if (user == null)
            {
                user = new ApplicationUser { UserName = userName, SoftwareUserID = SoftwareUserId, Email = userName };
                if (string.IsNullOrEmpty(testUserPw))
                    result = await _userManager.CreateAsync(user);
                else
                    result = await _userManager.CreateAsync(user, testUserPw); // This is the line I get the error on.
            }
            return user.Id;
        }
        private async Task<IdentityResult> EnsureRole(string uid, string role)
        {
            try
            {
                IdentityResult IR = null;

                if (!await _roleManager.RoleExistsAsync(role))
                {
                    IR = await _roleManager.CreateAsync(new IdentityRole(role));
                }

                var user = await _userManager.FindByIdAsync(uid);

                IR = await _userManager.AddToRoleAsync(user, role);

                return IR;
            }
            catch (Exception exc)
            {
                throw;
            }
        }
    }

    public interface IInitialMigrationService
    {
        bool MigrateDataDump(DataDump dump);
    }
}

有人可以告诉我我做错了什么吗?我已经搜索了一个具体的例子,说明这种事情是如何构建的,但除了使用界面之外无法找到(这似乎没什么帮助)。

感谢。

---编辑--- 根据Camilos的建议,我做了以下更改:

MigrationController now starts like this:

    public class MigrationController : Controller
    {
        private readonly ApplicationDbContext _context;
        private UserManager<ApplicationUser> _userManager;
        private RoleManager<IdentityRole> _roleManager;
        private IConfiguration _configuration;
        private IInitialMigrationService _initialMigrationService;

        public MigrationController(ApplicationDbContext context, UserManager<ApplicationUser> userManager, RoleManager<IdentityRole> roleManager, IConfiguration configuration, IInitialMigrationService initialMigrationService)
        {
            _context = context;
            _userManager = userManager;
            _roleManager = roleManager;
            _configuration = configuration;
            _initialMigrationService = initialMigrationService;
        }

并将此添加到Startup.ConfigureServices方法:

public void ConfigureServices(IServiceCollection services)
{
    services.AddScoped<IInitialMigrationService, InitialMigrationService>();

但我仍然得到同样的错误。

-----编辑2 ---- 我现在怀疑问题在于运行异步方法。似乎运行Asynch方法会在下次尝试使用它时将对象处理掉。

例如,在下面的块中(对于我的&#34; MigrateUserSetup&#34;方法),我改变了#34; SaveChanges&#34; to&#34; SaveChangesAsync&#34;,下次使用dbcontext时,我收到了错误信息:

private  void MigrateUserSetup(DataDump dump)
{
    dump.UserSetupList.ForEach(async delegate (DDUserSetup u)
    {
        if (string.IsNullOrEmpty(u.Email))
            return;
        var swUser = _context.SoftwareUser
            .SingleOrDefault(du => du.OldID == u.ID);
        if (swUser == null)
        {
            _context.SoftwareUser.Add(new Models.SoftwareUser
            {
                Name = u.Name,
                // Migrate a bunch of fields
            });
            await _context.SaveChangesAsync(); // This was previously just "SaveChanges()", not Async
            swUser = _context.SoftwareUser
                .SingleOrDefault(du => du.OldID == u.ID); // Now I get the disposed object error here
            string userID = await EnsureUserAsync(u.Password, u.Email, swUser.ID);
            await EnsureRole(userID, ConstantData.ConstUserRole);
        }
    });

}

----编辑3 ----

我终于开始工作了。我最终用'#34; ForEach&#34;替换了用户设置循环。对于&#34;对于&#34;循环,如下所示:

原创&#34; ForEach&#34;循环:

    dump.UserSetupList.ForEach(async delegate (DDUserSetup u)
    {

New&#34; For&#34;循环:

    for (int i = 0; i < dump.UserSetupList.Count; i++)
    {
        var u = dump.UserSetupList[i];

我不确定这是如何产生如此大的差异,或者这是否真的是一个理想的解决方案,但可能会给底层问题提供更多线索。

1 个答案:

答案 0 :(得分:2)

这一行:

_initialMigrationService = new InitialMigrationService(userManager, roleManager, context, configuration);

不正确。如果你查看那个构造函数中的所有前面的行,那里就不存在另一个new,并且有一个原因,称为依赖注入。

如果要创建自己的服务,请将它们注册到ASP.NET Core提供的DI容器中:

public
{
    ...

    services.AddScoped<IInitialMigrationService, InitialMigrationService>();

    ...
}

然后你要求为你创建的新服务实例

public MigrationController(ApplicationDbContext context, UserManager<ApplicationUser> userManager, RoleManager<IdentityRole> roleManager, IConfiguration configuration, IInitialMigrationService initialMigrationService)
{
    _context = context;
    _userManager = userManager;
    _roleManager = roleManager;
    _configuration = configuration;
    _initialMigrationService = initialMigrationService;
}

在一个不那么无关的说明中,请注意注入IConfiguration会导致大量的RAM浪费。您应该遵循配置/选项方法。