使用简单注入器

时间:2019-11-29 22:09:11

标签: asp.net-core dependency-injection simple-injector asp.net-core-signalr

我正在使用.NET Core 2.2和SignalR Core,并且需要通过Webjob中的Simple Injector注入IHubContext<MyClass>

它在我的Web应用程序中完美运行,但是当我尝试通过网络工作来获得服务时,它抱怨缺少注入IHubContext<IHubContext<BroadcastHub>>

我需要一种通过简单注入器进行注册的方法

这是我的Webjob中Program.cs文件中的Configuration

using AutoMapper;
using Gateway.BLL.BaseClasses;
using Gateway.BLL.Config;
using Gateway.BLL.Services;
using Gateway.BLL.Services.Interfaces;
using Gateway.BLL.SignalR;
using Gateway.Model.MappingProfiles;
using Gateway.Repository;
using Gateway.Repository.Interfaces;
using Gateway.Repository.Repositories;
using Microsoft.AspNetCore.SignalR;
using Microsoft.AspNetCore.SignalR.Internal;
using Microsoft.Azure.WebJobs.Extensions.SignalRService;
using Microsoft.Azure.WebJobs.Host;
using Microsoft.EntityFrameworkCore;
using Microsoft.Extensions.Caching.Memory;
using Microsoft.Extensions.Configuration;
using Microsoft.Extensions.DependencyInjection;
using Microsoft.Extensions.Hosting;
using Microsoft.Extensions.Logging;
using SimpleInjector;
using System;
using System.IO;
using System.Net.Http;

namespace Gateway.WebJob
{
    class Program
    {
        private static void Main()
        {
            var container = new Container();

            DbContextOptionsBuilder ob = new DbContextOptionsBuilder();

            var config = new MapperConfiguration
                (cfg =>
            {
                cfg.AddProfile(new ModelMappingProfile());
            }
                );
            var mapper = config.CreateMapper();

            var loggerFactory = new LoggerFactory();

            ServiceCollection sr = new ServiceCollection();

            sr.AddSignalR();


            var serviceProvider = sr.AddHttpClient().BuildServiceProvider();
            var httpClientFactory = serviceProvider.GetService<IHttpClientFactory>();

            IConfigurationBuilder configurationBuilder = new ConfigurationBuilder();
            // Duplicate here any configuration sources you use.
            configurationBuilder.AddJsonFile("appsettings.json");
            IConfiguration configuration = configurationBuilder.Build();

            var medchartApiConfiguration = new MedchartApiConfiguration();
            configuration.Bind("MedchartApiConfiguration", medchartApiConfiguration);

            var serviceBusConfiguration = new ServiceBusConfiguration();
            configuration.Bind("ServiceBusConfiguration", serviceBusConfiguration);

            ob = ob.UseSqlServer(configuration["ConnectionString:GatewayDB"]);

            IMemoryCache memoryCache = new MemoryCache(new MemoryCacheOptions());

            ConfigureServices(sr);

            var builder = new HostBuilder();
            builder.ConfigureWebJobs(b =>
            {
                b.AddAzureStorageCoreServices();
                b.AddServiceBus(o =>
                {
                    o.MessageHandlerOptions.AutoComplete = true;
                    o.MessageHandlerOptions.MaxConcurrentCalls = 10;
                    o.ConnectionString = "Endpoint=sb://gatewayqueue.servicebus.windows.net/;SharedAccessKeyName=admin;SharedAccessKey=Wd2YwCEJT2g3q4ykvdOIU2251YD5FizCn5aCuumzdz4=";
                }).AddSignalR();
            });
            builder.ConfigureLogging((context, b) =>
            {
                b.AddConsole();
                string instrumentationKey = context.Configuration["APPINSIGHTS_INSTRUMENTATIONKEY"];
                if (!string.IsNullOrEmpty(instrumentationKey))
                {
                    b.AddApplicationInsightsWebJobs(o => o.InstrumentationKey = instrumentationKey);
                }
            });

            builder.ConfigureServices((hostContext, services) => {
                //services.AddHttpClient();
                //hostContext.Configuration.Bind("MedchartApiConfiguration", medchartApiConfiguration);
                //services.AddSingleton(medchartApiConfiguration);
                services.AddSingleton(container);
                services.AddScoped<JobActivator.ScopeDisposable>();
                services.AddScoped<IJobActivator, JobActivator>();
            });

            container.Register<IPatientService, PatientService>();
            container.Register<IPatientRepository, PatientRepository>();
            container.Register<IProviderService, ProviderService>();
            container.Register<IPatientGroupProviderRepository, PatientGroupProviderRepository>();
            container.Register<IPatientGroupRepository, PatientGroupRepository>();
            container.Register<IConsentRepository, ConsentRepository>();
            container.Register<IHttpClientWrapper, HttpClientWrapper>();
            container.Register<IMedchartService, MedchartService>();
            container.Register<IGroupRepository, GroupRepository>();
            container.Register<IReportRepository, ReportRepository>();
            container.Register<IProviderRepository, ProviderRepository>();
            container.RegisterSingleton(httpClientFactory);
            container.RegisterSingleton(memoryCache);
            container.RegisterSingleton(medchartApiConfiguration);
            container.RegisterSingleton(serviceBusConfiguration);
            container.Register<ILoggerFactory>(() => loggerFactory, Lifestyle.Singleton);
            container.RegisterSingleton(configuration);
            container.RegisterSingleton(typeof(ILogger<PatientRepository>), typeof(Logger<PatientRepository>));
            container.RegisterSingleton(typeof(ILogger<PatientService>), typeof(Logger<PatientService>));
            container.RegisterSingleton(typeof(ILogger<HttpClientWrapper>), typeof(Logger<HttpClientWrapper>));
            container.RegisterSingleton(typeof(ILogger<MedchartService>), typeof(Logger<MedchartService>));
            container.RegisterSingleton(typeof(ILogger<ProviderService>), typeof(Logger<ProviderService>));
            container.RegisterSingleton(typeof(ILogger<ProviderRepository>), typeof(Logger<ProviderRepository>));
            container.RegisterSingleton(typeof(ILogger<ReportRepository>), typeof(Logger<ReportRepository>));
            container.RegisterSingleton(mapper);
            container.Register<GatewayDBContext>(() => {
                var options = ob.Options;
                return new GatewayDBContext(options);
            });

            var host = builder.Build();
            using (host)
            {
                host.Run();
            }
        }

        private static IConfiguration Configuration { get; set; }
        private static void ConfigureServices(IServiceCollection services)
        {
            var environment = Environment.GetEnvironmentVariable("ASPNETCORE_ENVIRONMENT");

            Configuration = new ConfigurationBuilder()
                .SetBasePath(Directory.GetCurrentDirectory())
                .AddJsonFile("appsettings.json", optional: false, reloadOnChange: true)
                .AddJsonFile($"appsettings.{environment}.json", optional: true, reloadOnChange: true)
                .AddEnvironmentVariables()
                .Build();

            services.AddSingleton(Configuration);
            services.AddTransient<Functions, Functions>();
            services.AddLogging(builder => builder.AddConsole());
        }
    }
}

这是我使用SignalR的简化服务:(这是webjob将使用它的另一个项目

using Microsoft.AspNetCore.SignalR;
using Gateway.BLL.SignalR;

// namespace Gateway.BLL.Services
public class PatientService : HttpClientWrapper, IPatientService
{
    private readonly IHubContext<BroadcastHub> _hubContext;

    public PatientService(IHubContext<BroadcastHub> hubContext)
        : base(logger,httpClientFactory,medchartConfig)
    {
        _hubContext = hubContext;
    }

    public async Task<OutputHandler<IEnumerable<PatientEnrollmentParams>>>
        CreatePatientAsync(List<PatientEnrollmentParams> patients,
            CancellationToken ct)
    {
        var result = new OutputHandler<IEnumerable<PatientEnrollmentParams>>();
        await _hubContext.Clients.All.SendAsync("BroadcastMessage");
        return result;
    } 
}

这是我的网络作业,它将在另一个项目中调用PatientService

    using Gateway.BLL.Config;
using Gateway.BLL.Processors;
using Gateway.BLL.Queues;
using Gateway.BLL.Services;
using Gateway.Model.Queues;
using Microsoft.Azure.ServiceBus;
using Microsoft.Azure.WebJobs;
using Microsoft.Extensions.Configuration;
using Microsoft.Extensions.Logging;
using Newtonsoft.Json;
using SimpleInjector;
using System;
using System.Collections.Generic;
using System.Text;
using System.Threading.Tasks;

namespace Gateway.WebJob
{
    public class Functions
    {
        private Container _container;
        public Functions(Container container)
        {
            _container = container;
        }

        public async Task ProcessEnrollmentStatus([ServiceBusTrigger("%ServiceBusConfiguration:EnrollmentMessage:QueueName%")]string message, ILogger log)
        {
            var _patientService = _container.GetInstance<IPatientService>();
            GetEnrollmentStatusTaskProcessor processor = new GetEnrollmentStatusTaskProcessor(_patientService);
            EnrollmentStatusTask data = JsonConvert.DeserializeObject<EnrollmentStatusTask>(message);
            await processor.Process(data);
        }

        public async Task ProcessConsentRequestStatus([ServiceBusTrigger("%ServiceBusConfiguration:ConsentRequestMessage:QueueName%")]string message, ILogger log)
        {
            var _patientService = _container.GetInstance<IPatientService>();
            GetConsentRequestTaskProcessor processor = new GetConsentRequestTaskProcessor(_patientService);
            ConsentRequestTask data = JsonConvert.DeserializeObject<ConsentRequestTask>(message);
            await processor.Process(data);
        }
    }
}

这是将调用PatientService的处理方法:

    using Gateway.BLL.Services;
using Gateway.Model.Queues;
using System;
using System.Collections.Generic;
using System.Text;
using System.Threading.Tasks;

namespace Gateway.BLL.Processors
{
    public class GetEnrollmentStatusTaskProcessor :  IProcessor<EnrollmentStatusTask>
    {
        private IPatientService _patientService;

        public GetEnrollmentStatusTaskProcessor(IPatientService patientService)
        {
            _patientService = patientService;
        }

        public async Task<bool> Process(EnrollmentStatusTask data)
        {
            bool updated = await _patientService.UpdatePatientEnrollmentStatus(data.PatientId, data.PatientMedchartId.ToString(), data.GroupId);
            return updated;
        }
    }
}

我需要在{job.cs}​​中注册IHubContext<MyClass>,但无法通过以下方式注册它:

hubContext = serviceProvider.GetService<IHubContext<BroadcastHub>>();
container.RegisterSingleton(hubContext);

或这种方式

container.Register<IHubContext<BroadcastHub>>(Lifestyle.Singleton);

更新2019-12-02: 我能够解决IHubContext,但现在收到一个新问题。这是我的函数类:

    using Gateway.BLL.Config;
using Gateway.BLL.Processors;
using Gateway.BLL.Queues;
using Gateway.BLL.Services;
using Gateway.Model.Queues;
using Microsoft.Azure.ServiceBus;
using Microsoft.Azure.WebJobs;
using Microsoft.Extensions.Configuration;
using Microsoft.Extensions.Logging;
using Newtonsoft.Json;
using SimpleInjector;
using System;
using System.Collections.Generic;
using System.Text;
using System.Threading.Tasks;

namespace Gateway.WebJob
{
    public class Functions
    {
        private Container _container;
        public Functions(Container container)
        {
            _container = container;
        }

        public async Task ProcessEnrollmentStatus([ServiceBusTrigger("%ServiceBusConfiguration:EnrollmentMessage:QueueName%")]string message, ILogger log)
        {
            var _patientService = _container.GetInstance<IPatientService>();
            GetEnrollmentStatusTaskProcessor processor = new GetEnrollmentStatusTaskProcessor(_patientService);
            EnrollmentStatusTask data = JsonConvert.DeserializeObject<EnrollmentStatusTask>(message);
            await processor.Process(data);
        }

        public async Task ProcessConsentRequestStatus([ServiceBusTrigger("%ServiceBusConfiguration:ConsentRequestMessage:QueueName%")]string message, ILogger log)
        {
            var _patientService = _container.GetInstance<IPatientService>();
            GetConsentRequestTaskProcessor processor = new GetConsentRequestTaskProcessor(_patientService);
            ConsentRequestTask data = JsonConvert.DeserializeObject<ConsentRequestTask>(message);
            await processor.Process(data);
        }
    }
}

这是我所有更新后的progrm.cs类:

    using AutoMapper;
using Gateway.BLL.BaseClasses;
using Gateway.BLL.Config;
using Gateway.BLL.Services;
using Gateway.BLL.Services.Interfaces;
using Gateway.BLL.SignalR;
using Gateway.Model.MappingProfiles;
using Gateway.Repository;
using Gateway.Repository.Interfaces;
using Gateway.Repository.Repositories;
using Microsoft.AspNetCore.SignalR;
using Microsoft.AspNetCore.SignalR.Internal;
using Microsoft.Azure.WebJobs.Extensions.SignalRService;
using Microsoft.Azure.WebJobs.Host;
using Microsoft.EntityFrameworkCore;
using Microsoft.Extensions.Caching.Memory;
using Microsoft.Extensions.Configuration;
using Microsoft.Extensions.DependencyInjection;
using Microsoft.Extensions.Hosting;
using Microsoft.Extensions.Logging;
using SimpleInjector;
using System;
using System.IO;
using System.Net.Http;

namespace Gateway.WebJob
{
    class Program
    {
        private static void Main()
        {
            var container = new Container();

            DbContextOptionsBuilder ob = new DbContextOptionsBuilder();

            var config = new MapperConfiguration
                (cfg =>
            {
                cfg.AddProfile(new ModelMappingProfile());
            }
                );
            var mapper = config.CreateMapper();

            var loggerFactory = new LoggerFactory();

            ServiceCollection sr = new ServiceCollection();
            sr.AddLogging();
            sr.AddSignalR();

            sr.AddDbContextPool<GatewayDBContext>(options => { /*options */ });

            sr.AddSimpleInjector(container, options =>
             {
                 options.AddLogging();
                 //options.CrossWire<ILoggerFactory>();
             });

            sr.BuildServiceProvider(validateScopes: true).UseSimpleInjector(container);


            var serviceProvider = sr.AddHttpClient().BuildServiceProvider();
            var httpClientFactory = serviceProvider.GetService<IHttpClientFactory>();

            IConfigurationBuilder configurationBuilder = new ConfigurationBuilder();
            // Duplicate here any configuration sources you use.
            configurationBuilder.AddJsonFile("appsettings.json");
            IConfiguration configuration = configurationBuilder.Build();

            var medchartApiConfiguration = new MedchartApiConfiguration();
            configuration.Bind("MedchartApiConfiguration", medchartApiConfiguration);

            var serviceBusConfiguration = new ServiceBusConfiguration();
            configuration.Bind("ServiceBusConfiguration", serviceBusConfiguration);

            ob = ob.UseSqlServer(configuration["ConnectionString:GatewayDB"]);

            IMemoryCache memoryCache = new MemoryCache(new MemoryCacheOptions());

            ConfigureServices(sr);

            var builder = new HostBuilder();
            builder.ConfigureWebJobs(b =>
            {
                b.AddAzureStorageCoreServices();
                b.AddServiceBus(o =>
                {
                    o.MessageHandlerOptions.AutoComplete = true;
                    o.MessageHandlerOptions.MaxConcurrentCalls = 10;
                    o.ConnectionString = "Endpoint=sb://gatewayqueue.servicebus.windows.net/;SharedAccessKeyName=admin;SharedAccessKey=Wd2YwCEJT2g3q4ykvdOIU2251YD5FizCn5aCuumzdz4=";
                });
            });
            builder.ConfigureLogging((context, b) =>
            {
                b.AddConsole();
                b.Services.AddLogging();
                string instrumentationKey = context.Configuration["APPINSIGHTS_INSTRUMENTATIONKEY"];
                if (!string.IsNullOrEmpty(instrumentationKey))
                {
                    b.AddApplicationInsightsWebJobs(o => o.InstrumentationKey = instrumentationKey);
                }
            });

            builder.ConfigureServices((hostContext, services) =>
            {
                //services.AddHttpClient();
                //hostContext.Configuration.Bind("MedchartApiConfiguration", medchartApiConfiguration);
                //services.AddSingleton(medchartApiConfiguration);
                //services.AddSingleton(container);
                //services.AddScoped<JobActivator.ScopeDisposable>();
                //services.AddScoped<IJobActivator, JobActivator>();
            });

            container.Register<IPatientService, PatientService>();
            container.Register<IPatientRepository, PatientRepository>();
            container.Register<IProviderService, ProviderService>();
            container.Register<IPatientGroupProviderRepository, PatientGroupProviderRepository>();
            container.Register<IPatientGroupRepository, PatientGroupRepository>();
            container.Register<IConsentRepository, ConsentRepository>();
            container.Register<IHttpClientWrapper, HttpClientWrapper>();
            container.Register<IMedchartService, MedchartService>();
            container.Register<IGroupRepository, GroupRepository>();
            container.Register<IReportRepository, ReportRepository>();
            container.Register<IProviderRepository, ProviderRepository>();
            container.RegisterSingleton(httpClientFactory);
            container.RegisterSingleton(memoryCache);
            container.RegisterSingleton(medchartApiConfiguration);
            container.RegisterSingleton(serviceBusConfiguration);
            //container.Register<ILoggerFactory>(() => loggerFactory, Lifestyle.Singleton);
            container.RegisterSingleton(configuration);
            container.RegisterSingleton(typeof(ILogger<PatientRepository>), typeof(Logger<PatientRepository>));
            container.RegisterSingleton(typeof(ILogger<PatientService>), typeof(Logger<PatientService>));
            container.RegisterSingleton(typeof(ILogger<HttpClientWrapper>), typeof(Logger<HttpClientWrapper>));
            container.RegisterSingleton(typeof(ILogger<MedchartService>), typeof(Logger<MedchartService>));
            container.RegisterSingleton(typeof(ILogger<ProviderService>), typeof(Logger<ProviderService>));
            container.RegisterSingleton(typeof(ILogger<ProviderRepository>), typeof(Logger<ProviderRepository>));
            container.RegisterSingleton(typeof(ILogger<ReportRepository>), typeof(Logger<ReportRepository>));
            container.RegisterSingleton(mapper);
            //container.Register<GatewayDBContext>(() =>
            //{
            //    var options = ob.Options;
            //    return new GatewayDBContext(options);
            //});
            container.Verify();
            var host = builder.Build();
            using (host)
            {
                host.Run();
            }
        }

        private static IConfiguration Configuration { get; set; }
        private static void ConfigureServices(IServiceCollection services)
        {
            var environment = Environment.GetEnvironmentVariable("ASPNETCORE_ENVIRONMENT");

            Configuration = new ConfigurationBuilder()
                .SetBasePath(Directory.GetCurrentDirectory())
                .AddJsonFile("appsettings.json", optional: false, reloadOnChange: true)
                .AddJsonFile($"appsettings.{environment}.json", optional: true, reloadOnChange: true)
                .AddEnvironmentVariables()
                .Build();

            services.AddSingleton(Configuration);
            services.AddTransient<Functions, Functions>();
            services.AddLogging(builder => builder.AddConsole());
        }
    }
}

现在我收到此错误消息,这意味着函数类中的容器未解析:

fail: Host.Results[0]

System.InvalidOperationException:尝试激活“ Gateway.WebJob.Functions”时无法解析类型为“ SimpleInjector.Container”的服务。    在Microsoft.Extensions.DependencyInjection.ActivatorUtilities.GetService(IServiceProvider sp,Type type,Type requiredBy,Boolean isDefaultParameterRequired)    在lambda_method(Closure,IServiceProvider,Object [])    在C:\ projects \ azure-webjobs-sdk-rqm4t \ src \ Microsoft.Azure.WebJobs.Host \ Executors \ DefaultJobActivator.cs中的Microsoft.Azure.WebJobs.Host.Executors.DefaultJobActivator.CreateInstance [T](IServiceProvider serviceProvider) :第37行    在C. \ projects \ azure-webjobs-sdk-rqm4t \ src \ Microsoft.Azure.WebJobs.Host \ Executors \ FunctionInvoker.cs中的Microsoft.Azure.WebJobs.Host.Executors.FunctionInvoker`2.CreateInstance(IFunctionInstanceEx functionInstance) 44行    在C:\ projects \ azure-webjobs-sdk-rqm4t \ src \ Microsoft.Azure.WebJobs.Host \ Executors \ FunctionExecutor.cs:line 846中的Microsoft.Azure.WebJobs.Host.Executors.FunctionExecutor.ParameterHelper.Initialize()    在Microsoft.Azure.WebJobs.Host.Executors.FunctionExecutor.TryExecuteAsyncCore(IFunctionInstanceEx functionInstance,CancellationToken cancellingToken)在C:\ projects \ azure-webjobs-sdk-rqm4t \ src \ Microsoft.Azure.WebJobs.Host \ Executors \ FunctionExecutor.cs中:第117行

1 个答案:

答案 0 :(得分:0)

我自己尝试了一下,但是只要在Simple Injector集成中启用了“自动交叉布线”(这是默认设置),您就应该能够注入IHubContext<T>实现,而无需做任何东西。

这是一个示例启动类:

public class Startup
{
    private readonly Container container = new Container();
    public Startup(IConfiguration configuration) => Configuration = configuration;
    public IConfiguration Configuration { get; }

    public void ConfigureServices(IServiceCollection services)
    {
        // default asp stuff here

        // add signalr
        services.AddSignalR();

        // add simple injector (enables auto cross wiring)
        services.AddSimpleInjector(this.container, options =>
        {
            options.AddAspNetCore().AddControllerActivation();
        });
    }

    public void Configure(IApplicationBuilder app, IHostingEnvironment env)
    {
        app.UseSimpleInjector(container);

        app.UseCookiePolicy();

        app.UseMvc(routes =>
        {
            routes.MapRoute(
                name: "default",
                template: "{controller=Home}/{action=Index}/{id?}");
        });
    }
}

这是一个注入到由Simple Injector创建的控制器中的集线器上下文:

public class HomeController : Controller
{
    private readonly IHubContext<MyHub> context;

    public HomeController(IHubContext<MyHub> context, Container container)
    {
        this.context = context;
    }

    public IActionResult Index()
    {
        return View();
    }
}