StructureMap .Net核心Windows服务嵌套容器

问题描述 投票:6回答:1

有很多文章讨论如何使用ASP.NET Core的Structure Map,但谈论控制台应用程序或Windows服务并不是很多。 ASP.Net Core中的默认行为是StructureMap为每个HTTPRequest创建一个嵌套容器,以便每个HTTP请求只对实例化一个具体类。

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

我的Windows服务是在Timer上设置的,每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");
    }
}
c# dependency-injection windows-services .net-core structuremap
1个回答
3
投票

CreateScope命名空间中有IServiceProvider的扩展方法Microsoft.Extensions.DependencyInjection。它的作用是解决当前DI容器的特殊接口(IServiceScopeFactory),它负责创建新的作用域,并使用该工厂创建新的作用域。 StructureMap注册了这个接口的实现,所以当你调用CreateScope时 - StructureMap会创建嵌套容器。样品用法:

using (var scope = _serviceProvider.CreateScope()) {
    // use scope.ServiceProvider, not _serviceProvider to resolve instance
    var service = scope.ServiceProvider.GetService<IUpgradeOpportunityService>‌​();
}
© www.soinside.com 2019 - 2024. All rights reserved.