当通过控制器注入时,范围内的生命周期服务变成单例
Scoped lifetime services become singletons when injected through controllers
我在 .NET Core 应用程序中有一个控制器:
public FriendsController(IFriendRepository friendRepository)
{
this.friendRepository= friendRepository;
}
IFriendRepository 是一个通过 class:
实现的接口
public class FriendRepository : IFriendRepository {
...
}
在 Startup 中,我在 ConfigureServices() 中使用以下行进行设置:
services.AddScoped<IFriendRepository , FriendRepository >();
但是,当使用控制器时,FriendRepository 的生命周期设置为单例而不是作用域。我能够找到的原因是在这个页面上:
https://docs.microsoft.com/en-us/aspnet/core/fundamentals/dependency-injection?view=aspnetcore-3.1
在服务生命周期下,Scoped。它显示:
我不明白如何使用 Invoke 而不是构造函数。他们使用的示例是针对自定义中间件的,我至少不知道如何为构造函数解释它。
public class FriendRepository : IFriendRepository
{
private readonly ManagementDbContext dbContext;
public FriendRepository(ManagementDbContext dbContext)
{
this.dbContext = dbContext;
}
public void Add(Friend friend)
{
this.dbContext.Friends.Add(friend);
}
public void Remove(Friend friend)
{
this.dbContext.Remove(friend);
}
public void Update(Friend friend)
{
this.dbContext.Update(friend);
}
}
下面是FriendRepository里面的“GetFriends”:
public async Task<QueryResult<Friend>> GetFriendsAsync(FriendQuery queryObj)
{
var result = new QueryResult<Friend>();
var query = dbContext.Friends
.Include(c => c.Type)
.AsQueryable();
if(queryObj.TypeId.HasValue)
{
query = query.Where(c => c.Type.Id == queryObj.TypeId);
}
if(queryObj.Name != null && queryObj.Name.Length > 0)
{
query = query.Where(c => c.Name.Contains(queryObj.Name));
}
// todo add total price here
var columnsMap = new Dictionary<string, Expression<Func<Calculation, object>>>()
{
["id"] = c => c.Id,
["name"] = c => c.Name,
["type"] = c => c.Type,
["totalFriends"] = c => c.TotalFriends,
["createdTime"] = c => c.CreatedTime
};
query = query.ApplyOrdering(queryObj, columnsMap);
result.TotalItems = await query.CountAsync();
query = query.ApplyPaging(queryObj);
result.Items = await query.ToListAsync();
return result;
}
我解决了,我会先解释我的假设,因为修复可能非常局限于我的场景。
我在 3 个存储库中使用了所有 DBContext。它们都使用异步函数,但是它们都包含等待内部使用的任何异步函数的内部。
这个问题似乎只在我开始使用这些存储库后才会出现,就像我在控制器中直接访问 dbContext 之前一样。这让我想到了link中的问题,我也在问题中贴了一张图片:
https://docs.microsoft.com/en-us/aspnet/core/fundamentals/dependency-injection?view=aspnetcore-3.1
尽管它只指定了中间件,但我认为它值得一试,因为我想不出任何其他问题。
现在说说实际问题。我在 UserRepository 中的一个函数 GetUser() 是一个异步方法,即使错误似乎出现在 FriendRepository 方法中,但由于它们总是崩溃,结果证明 GetUser() 函数被使用了一次无需等待即可在 AddJwtBearer 下启动。
我原以为因为它内部有一个 await,所以不会产生问题。我也没有注意到这是一个问题,因为我非常专注于另一个存储库。我希望也许我错过了一些简单的东西,比如在中间件切换生命周期中通过构造函数进行依赖注入,而不管生命周期已经设置成什么。
对于以后的其他人,我最终做了两件事,这让我能够清楚地逐步调试我的应用程序。
我创建了一个 Logger static class,它允许我轻松地将文本保存到文件中。我用它来记录正在使用的函数、构造函数等。这让我可以确保我可以跟踪构造函数和函数被调用的次数、调用顺序以及哪些不会被调用。这是其他人的记录器:
public static class Logger
{
public static void Log(string text, string fileName)
{
string path = System.IO.Path.GetDirectoryName(Assembly.GetEntryAssembly().Location) + "/" + fileName;
bool done = false;
while (!done)
{
done = true;
try
{
FileStream fileStream = null;
fileStream = System.IO.File.Open(path, System.IO.File.Exists(path) ? FileMode.Append : FileMode.OpenOrCreate);
using (StreamWriter fs = new StreamWriter(fileStream))
{
fs.WriteLine(text);
};
fileStream.Close();
}
catch (IOException)
{
done = false;
}
}
}
public static void Log(string text)
{
Log(text, "logger.txt");
}
}
我向 DBContext 添加了一个字符串,每当我在任何函数中使用它时,我都会在使用它的 class 的名称之后添加函数的名称。所以如果我的 FriendsRepository 将在函数 GetTypes 中使用它,它看起来像:
myDbContext.methodUsing = "FriendsRepository>GetTypes()";
感谢@GuruStron 的耐心,并就如何一步一步地给我建议,向我解释中间件错误的想法没有立足之地,并向我建议如何进行调试。
我在 .NET Core 应用程序中有一个控制器:
public FriendsController(IFriendRepository friendRepository)
{
this.friendRepository= friendRepository;
}
IFriendRepository 是一个通过 class:
实现的接口public class FriendRepository : IFriendRepository {
...
}
在 Startup 中,我在 ConfigureServices() 中使用以下行进行设置:
services.AddScoped<IFriendRepository , FriendRepository >();
但是,当使用控制器时,FriendRepository 的生命周期设置为单例而不是作用域。我能够找到的原因是在这个页面上:
https://docs.microsoft.com/en-us/aspnet/core/fundamentals/dependency-injection?view=aspnetcore-3.1
在服务生命周期下,Scoped。它显示:
我不明白如何使用 Invoke 而不是构造函数。他们使用的示例是针对自定义中间件的,我至少不知道如何为构造函数解释它。
public class FriendRepository : IFriendRepository
{
private readonly ManagementDbContext dbContext;
public FriendRepository(ManagementDbContext dbContext)
{
this.dbContext = dbContext;
}
public void Add(Friend friend)
{
this.dbContext.Friends.Add(friend);
}
public void Remove(Friend friend)
{
this.dbContext.Remove(friend);
}
public void Update(Friend friend)
{
this.dbContext.Update(friend);
}
}
下面是FriendRepository里面的“GetFriends”:
public async Task<QueryResult<Friend>> GetFriendsAsync(FriendQuery queryObj)
{
var result = new QueryResult<Friend>();
var query = dbContext.Friends
.Include(c => c.Type)
.AsQueryable();
if(queryObj.TypeId.HasValue)
{
query = query.Where(c => c.Type.Id == queryObj.TypeId);
}
if(queryObj.Name != null && queryObj.Name.Length > 0)
{
query = query.Where(c => c.Name.Contains(queryObj.Name));
}
// todo add total price here
var columnsMap = new Dictionary<string, Expression<Func<Calculation, object>>>()
{
["id"] = c => c.Id,
["name"] = c => c.Name,
["type"] = c => c.Type,
["totalFriends"] = c => c.TotalFriends,
["createdTime"] = c => c.CreatedTime
};
query = query.ApplyOrdering(queryObj, columnsMap);
result.TotalItems = await query.CountAsync();
query = query.ApplyPaging(queryObj);
result.Items = await query.ToListAsync();
return result;
}
我解决了,我会先解释我的假设,因为修复可能非常局限于我的场景。
我在 3 个存储库中使用了所有 DBContext。它们都使用异步函数,但是它们都包含等待内部使用的任何异步函数的内部。 这个问题似乎只在我开始使用这些存储库后才会出现,就像我在控制器中直接访问 dbContext 之前一样。这让我想到了link中的问题,我也在问题中贴了一张图片:
https://docs.microsoft.com/en-us/aspnet/core/fundamentals/dependency-injection?view=aspnetcore-3.1
尽管它只指定了中间件,但我认为它值得一试,因为我想不出任何其他问题。
现在说说实际问题。我在 UserRepository 中的一个函数 GetUser() 是一个异步方法,即使错误似乎出现在 FriendRepository 方法中,但由于它们总是崩溃,结果证明 GetUser() 函数被使用了一次无需等待即可在 AddJwtBearer 下启动。
我原以为因为它内部有一个 await,所以不会产生问题。我也没有注意到这是一个问题,因为我非常专注于另一个存储库。我希望也许我错过了一些简单的东西,比如在中间件切换生命周期中通过构造函数进行依赖注入,而不管生命周期已经设置成什么。
对于以后的其他人,我最终做了两件事,这让我能够清楚地逐步调试我的应用程序。
我创建了一个 Logger static class,它允许我轻松地将文本保存到文件中。我用它来记录正在使用的函数、构造函数等。这让我可以确保我可以跟踪构造函数和函数被调用的次数、调用顺序以及哪些不会被调用。这是其他人的记录器:
public static class Logger { public static void Log(string text, string fileName) { string path = System.IO.Path.GetDirectoryName(Assembly.GetEntryAssembly().Location) + "/" + fileName; bool done = false; while (!done) { done = true; try { FileStream fileStream = null; fileStream = System.IO.File.Open(path, System.IO.File.Exists(path) ? FileMode.Append : FileMode.OpenOrCreate); using (StreamWriter fs = new StreamWriter(fileStream)) { fs.WriteLine(text); }; fileStream.Close(); } catch (IOException) { done = false; } } } public static void Log(string text) { Log(text, "logger.txt"); } }
我向 DBContext 添加了一个字符串,每当我在任何函数中使用它时,我都会在使用它的 class 的名称之后添加函数的名称。所以如果我的 FriendsRepository 将在函数 GetTypes 中使用它,它看起来像:
myDbContext.methodUsing = "FriendsRepository>GetTypes()";
感谢@GuruStron 的耐心,并就如何一步一步地给我建议,向我解释中间件错误的想法没有立足之地,并向我建议如何进行调试。