我正在编写一个网络应用程序(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];
我不确定这是如何产生如此大的差异,或者这是否真的是一个理想的解决方案,但可能会给底层问题提供更多线索。
答案 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浪费。您应该遵循配置/选项方法。