StructureMap .Net Core Windows Service 嵌套容器



有很多文章在谈论如何将结构映射与 ASP.NET Core一起使用,但没有多少文章谈论控制台应用程序或Windows服务。 ASP.Net Core 中的默认行为是 StructureMap 为每个 HTTPRequest 创建一个嵌套容器,以便每个 HTTP 请求仅实例化一次具体类。

我正在使用PeterKottas.DotNetCore.WindowsService nuget包创建一个.Net Core Windows服务。 我使用这篇文章设置了结构图:https://andrewlock.net/using-dependency-injection-in-a-net-core-console-application/

我的 Windows 服务在计时器上设置,每 X 秒执行一次操作。我希望这些操作中的每一个都使用类似于 ASP.NET 执行的嵌套容器。 换句话说,我希望为轮询传递 #1 创建的所有内容在轮询传递完成后被处理掉。 当轮询传递 #2 开始时,我希望实例化对象的所有新实例。 但是,在单个轮询传递的范围内,我只想创建每个对象的一个实例。

正确的方法是什么?

这是我的程序类

public class Program
{
public static ILoggerFactory LoggerFactory;
public static IConfigurationRoot Configuration;
static void Main(string[] args)
{
var applicationBaseDirectory = AppContext.BaseDirectory;
string environment = Environment.GetEnvironmentVariable("ASPNETCORE_ENVIRONMENT");
if (string.IsNullOrWhiteSpace(environment))
throw new ArgumentNullException("Environment not found in ASPNETCORE_ENVIRONMENT");
ConfigureApplication(applicationBaseDirectory, environment);
var serviceCollection = ConfigureServices();
var serviceProvider = ConfigureIoC(serviceCollection);
ConfigureLogging(serviceProvider);
var logger = LoggerFactory.CreateLogger<Program>();
logger.LogInformation("Starting Application");
ServiceRunner<IWindowsService>.Run(config =>
{
var applicationName = typeof(Program).Namespace;
config.SetName($"{applicationName}");
config.SetDisplayName($"{applicationName}");
config.SetDescription($"Service that matches Previous Buyers to Vehicles In Inventory to Fine Upgrade Opportunities.");
config.Service(serviceConfig =>
{
serviceConfig.ServiceFactory((extraArgs, microServiceController) =>
{
return serviceProvider.GetService<IWindowsService>();
});
serviceConfig.OnStart((service, extraArgs) =>
{
logger.LogInformation($"Service {applicationName} started.");
service.Start();
});
serviceConfig.OnStop((service =>
{
logger.LogInformation($"Service {applicationName} stopped.");
service.Stop();
}));
serviceConfig.OnError(error =>
{
logger.LogError($"Service {applicationName} encountered an error with the following exception:n {error.Message}");
});
});
});
}
private static void ConfigureApplication(string applicationBaseDirectory, string environment)
{
Directory.SetCurrentDirectory(AppDomain.CurrentDomain.BaseDirectory);
var builder = new ConfigurationBuilder()
.SetBasePath(applicationBaseDirectory)
.AddJsonFile("appsettings.json")
.AddJsonFile($"appsettings.{environment}.json", optional: true)
.AddEnvironmentVariables();
Configuration = builder.Build();
}
private static IServiceCollection ConfigureServices()
{
var serviceCollection = new ServiceCollection().AddLogging().AddOptions();
serviceCollection.AddDbContext<JandLReportingContext>(options => options.UseSqlServer(Configuration.GetConnectionString("JandLReporting")), ServiceLifetime.Transient);
//serviceCollection.AddDbContext<JLMIDBContext>(options => options.UseSqlServer(Configuration.GetConnectionString("JLMIDB")), ServiceLifetime.Scoped);
serviceCollection.Configure<TimerSettings>(Configuration.GetSection("TimerSettings"));
serviceCollection.Configure<AppSettings>(Configuration.GetSection("AppSettings"));
return serviceCollection;
}
private static IServiceProvider ConfigureIoC(IServiceCollection serviceCollection)
{
//Setup StructureMap
var container = new Container();
container.Configure(config =>
{
config.Scan(scan =>
{
scan.AssemblyContainingType(typeof(Program));
scan.AssembliesFromApplicationBaseDirectory();
scan.AssembliesAndExecutablesFromApplicationBaseDirectory();
scan.WithDefaultConventions();
});
config.Populate(serviceCollection);
});
return container.GetInstance<IServiceProvider>();
}
private static void ConfigureLogging(IServiceProvider serviceProvider)
{
LoggerFactory = serviceProvider.GetService<ILoggerFactory>()
.AddConsole(Configuration.GetSection("Logging"))
.AddFile(Configuration.GetSection("Logging"))
.AddDebug();
}
}

这是我的WindowsService类:

public class WindowsService : MicroService, IWindowsService
{
private readonly ILogger _logger;
private readonly IServiceProvider _serviceProvider;
private readonly TimerSettings _timerSettings;
public WindowsService(ILogger<WindowsService> logger, IServiceProvider serviceProvider, IOptions<TimerSettings> timerSettings)
{
_logger = logger;
_serviceProvider = serviceProvider;
_timerSettings = timerSettings.Value;
}
public void Start()
{
StartBase();
Timers.Start("ServiceTimer", GetTimerInterval(), async () =>
{
await PollingPassAsyc();
},
(error) =>
{
_logger.LogCritical($"Exception while starting the service: {error}n");
});
}
private async Task PollingPassAsyc()
{
using (var upgradeOpportunityService = _serviceProvider.GetService<IUpgradeOpportunityService>())
{
await upgradeOpportunityService.FindUpgradeOpportunitiesAsync();
}
}
private int GetTimerInterval()
{
return _timerSettings.IntervalMinutes * 60 * 1000;
}
public void Stop()
{
StopBase();
_logger.LogInformation($"Service has stopped");
}
}

命名空间中有用于IServiceProviderMicrosoft.Extensions.DependencyInjection扩展方法CreateScope。它的作用是从当前负责创建新作用域的当前 DI 容器中解析特殊接口 (IServiceScopeFactory),并使用此工厂创建新作用域。StructureMap 寄存了此接口的实现,因此当您调用CreateScope- StructureMap 时,它将创建嵌套容器。示例用法:

using (var scope = _serviceProvider.CreateScope()) {
// use scope.ServiceProvider, not _serviceProvider to resolve instance
var service = scope.ServiceProvider.GetService<IUpgradeOpportunityService>‌​();
}

最新更新