我正在使用.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行
答案 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();
}
}