Использование класса обслуживания с ядром asp.net - PullRequest
0 голосов
/ 18 мая 2018

Я пишу веб-приложение (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 объект удаляется в следующий раз, когда я пытаюсь его использовать.

Например, в блоке ниже (для моего метода "MigrateUserSetup") я изменил "SaveChanges" на "SaveChangesAsync"", и в следующий раз при использовании 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 ----

Я наконец заработал.Я закончил тем, что заменил цикл настройки пользователя из цикла «ForEach» на цикл «for», как показано ниже:

Оригинальный цикл «ForEach»:

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

Новый цикл «For»:

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

Я не уверен, как это имеет такое большое значение, или действительно ли это желаемое решение, но может дать немного больше подсказки относительно основной проблемы.

1 Ответ

0 голосов
/ 18 мая 2018

Эта строка:

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

неверна.Если вы посмотрите на все предыдущие строки в этом конструкторе, там нет другого new, и есть причина для этого, называемая Dependency Injection.

Когда вы хотите создать свои собственные сервисы, вы регистрируете ихна контейнере DI, который обеспечивает ASP.NET Core:

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 может привести к огромным потерям ОЗУ.Вместо этого вы должны следовать подходам Конфигурация / Опции.

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...