![](/img/trans.png)
[英]How to Setup Hangfire using Asp.Net 4.7 and DI with Microsoft.Extensions.DependencyInjection?
[英]Microsoft.Extensions.DependencyInjection: DI'd code runs fine on dotnet CLI / Rider default .NET profile, but crashes VS2022
許多用戶報告了在我們的一個 OSS 存儲庫中運行一個非常基本的示例項目的錯誤: https://github.com/akkado.net/Akka.Hosting/issues/179
示例代碼如下所示:
public interface IReplyGenerator
{
string Reply(object input);
}
public class DefaultReplyGenerator : IReplyGenerator
{
public string Reply(object input)
{
return input.ToString()!;
}
}
public class EchoActor : ReceiveActor
{
private readonly string _entityId;
private readonly IReplyGenerator _replyGenerator;
public EchoActor(string entityId, IReplyGenerator replyGenerator)
{
_entityId = entityId;
_replyGenerator = replyGenerator;
ReceiveAny(message => {
Sender.Tell($"{Self} rcv {_replyGenerator.Reply(message)}");
});
}
}
public class Program
{
private const int NumberOfShards = 5;
private static Option<(string, object)> ExtractEntityId(object message)
=> message switch {
string id => (id, id),
_ => Option<(string, object)>.None
};
private static string? ExtractShardId(object message)
=> message switch {
string id => (id.GetHashCode() % NumberOfShards).ToString(),
_ => null
};
public static void Main(params string[] args)
{
var builder = WebApplication.CreateBuilder(args);
builder.Services.AddScoped<IReplyGenerator, DefaultReplyGenerator>();
builder.Services.AddAkka("MyActorSystem", configurationBuilder =>
{
configurationBuilder
.WithRemoting(hostname: "localhost", port: 8110)
.WithClustering(new ClusterOptions{SeedNodes = new []{ "akka.tcp://MyActorSystem@localhost:8110", }})
.WithShardRegion<Echo>(
typeName: "myRegion",
entityPropsFactory: (_, _, resolver) =>
{
return s => resolver.Props<EchoActor>(s);
},
extractEntityId: ExtractEntityId,
extractShardId: ExtractShardId,
shardOptions: new ShardOptions());
});
var app = builder.Build();
app.MapGet("/", async (HttpContext context, IRequiredActor<Echo> echoActor) =>
{
var echo = echoActor.ActorRef;
var body = await echo.Ask<string>(
message: context.TraceIdentifier,
cancellationToken: context.RequestAborted)
.ConfigureAwait(false);
await context.Response.WriteAsync(body);
});
app.Run();
}
}
觸發失敗的關鍵行(只是有時:)在這里:
entityPropsFactory: (_, _, resolver) =>
{
return s => resolver.Props<EchoActor>(s);
},
resolver.Props<TActor>
方法是Akka.DependencyInjection的一部分,它在幕后執行以下操作(因此您可以確切地看到 Microsoft.Extensions.DependencyInjection 是如何被調用的:)
internal class ServiceProviderActorProducer : IIndirectActorProducer
{
private readonly IServiceProvider _provider;
private readonly object[] _args;
public ServiceProviderActorProducer(IServiceProvider provider, Type actorType, object[] args)
{
_provider = provider;
_args = args;
ActorType = actorType;
}
public ActorBase Produce()
{
return (ActorBase)ActivatorUtilities.CreateInstance(_provider, ActorType, _args);
}
public Type ActorType { get; }
public void Release(ActorBase actor)
{
// no-op
}
}
錯誤消息聽起來好像ActivatorUtilities
class 正在嘗試使用定義的類型沒有的 0 參數構造函數 - 因此出現錯誤。
奇怪的是:通過do.net run
或 Rider 2022.3 的默認“.NET 配置文件”啟動示例應用程序時,我們沒有看到此錯誤。 該錯誤僅在 VS2022 中運行或使用 Rider 2022.3 的“.NET 啟動配置文件”時發生,這在某種程度上有所不同。 您可以在此處查看我們的測試結果列表: https://github.com/akkado.net/Akka.Hosting/issues/179#issuecomment-1372320831
為什么這段代碼在一種配置下可以正常工作,而在另一種配置下卻不行?
所以我在 Twitter 上得到了我的問題的答案 - 顯然問題確實是我們在沒有任何范圍可言的環境中創建IReplyGenerator
作為范圍依賴項(Akka.NET 參與者沒有范圍):
builder.Services.AddScoped<IReplyGenerator, DefaultReplyGenerator>();
至於為什么這在某些環境 ( AS.NETCORE_ENVIRONMENT="Production"
) 中不是問題,但在其他環境 ( AS.NETCORE_ENVIRONMENT AS.NETCORE_ENVIRONMENT="Development"
) 中是問題 - 這是由於IServiceProvider
實現中的此設置: https:// learn.microsoft.com/en-us/do.net/api/microsoft.extensions.dependencyinjection.serviceprovideroptions.validatescopes
在開發環境中,此值設置為true
但在生產環境中它默認為false
- 因此在生產環境中即使沒有范圍也會創建這些資源,但在開發環境中會引發錯誤以嘗試警告開發人員沒有此“作用域”依賴項的IScope
。
錯誤消息根本沒有說清楚,但希望這個答案能幫助其他人。
感謝 https://twitter.com/chton/status/1611024413314400260解決這個問題。
聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.