<MyClass> 使用简单注入器在 Web 作业中创建 IHubContext 的实例



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

它在我的网络应用程序中完美运行,但是当我尝试通过网络作业访问我的服务时,它抱怨缺乏注入IHubContext<IHubContext<BroadcastHub>>

我需要一种方法通过简单注射器注册它

这是我在程序.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;
}
}
}

我需要在程序中的 Web 作业中注册IHubContext<MyClass>.cs但我无法通过以下方式注册它:

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);
}
}
}

这是我在所有更新后的进度.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"的服务。 at Microsoft.Extensions.DependencyInjection.ActivatorUtilities.GetService(IServiceProvider sp, Type type, Type requiredBy, Boolean isDefaultParameterRequired( at lambda_method(Closure , IServiceProvider , Object[] ( at Microsoft.Azure.WebJobs.Host.Executors.DefaultJobActivator.CreateInstance[T](IServiceProvider serviceProvider( in C:\projects\azure-webjobs-sdk-rqm4t\src\Microsoft.Azure.WebJobs.Host\Executors\DefaultJobActivator.cs:line 37 at Microsoft.Azure.WebJobs.Host.Executors.FunctionInvoker'2.CreateInstance(IFunctionInstanceEx functionInstance( in C:\projects\azure-webjobs-sdk-rqm4t\src\Microsoft.Azure.WebJobs.Host\Executors\FunctionInvoker.cs:line 44 at Microsoft.Azure.WebJobs.Host.Executors.FunctionExecutor.ParameterHelper.Initialize(( in C:\projects\azure-webjobs-sdk-rqm4t\src\Microsoft.Azure.WebJobs.Host\Executors\FunctionExecutor.cs:line 846 at Microsoft.Azure.WebJobs.Host.Executors.FunctionExecutor.TryExecuteAsyncCore(IFunctionInstanceEx functionInstance, CancelToken cancelToken( in C:\projects\azure-webjobs-sdk-rqm4t\src\Microsoft.Azure.WebJobs.Host\Executors\FunctionExecutor.cs:line 117

我只是自己尝试过,但只要在简单注入器集成(这是默认值(中启用了"自动交叉布线",您应该能够注入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?}");
});
}
}

下面是注入到由简单注入器创建的控制器中的中心上下文:

public class HomeController : Controller
{
private readonly IHubContext<MyHub> context;
public HomeController(IHubContext<MyHub> context, Container container)
{
this.context = context;
}
public IActionResult Index()
{
return View();
}
}

最新更新