I am trying to connect my azure function to a local DB using Entity frameworkcore code 1st but I keep on getting this error when I try to add migrations,
Unable to resolve service for type 'Microsoft.EntityFrameworkCore.DbContextOptions
at Microsoft.Extensions.DependencyInjection.ActivatorUtilities.ConstructorMatcher.CreateInstance(IServiceProvider provider)
at Microsoft.Extensions.DependencyInjection.ActivatorUtilities.CreateInstance(IServiceProvider provider, Type instanceType, Object[] parameters)
at Microsoft.Extensions.DependencyInjection.ActivatorUtilities.GetServiceOrCreateInstance(IServiceProvider provider, Type type)
at Microsoft.EntityFrameworkCore.Design.Internal.DbContextOperations.<>c__DisplayClass13_4.b__13()
but I am using the same connection string i use for all my app, just a different DB
This is my context file
using Microsoft.EntityFrameworkCore;
using System;
using System.Collections.Generic;
using System.Text;
namespace FunctionApp36
{
class BookContext :DbContext
{
public BookContext(DbContextOptions<BookContext> options) : base(options)
{
}
public BookContext(DbContextOptions options) : base(options)
{
}
public BookContext() : base()
{
}
protected override void OnConfiguring(DbContextOptionsBuilder options) => options.UseSqlServer("Data Source=ABS\\SQLEXPRESS;Initial Catalog=Ba;Integrated Security=True");
}
}
and this is my startup file
using Microsoft.Azure.WebJobs;
using Microsoft.Azure.WebJobs.Hosting;
using System;
using System.Collections.Generic;
using System.Text;
using Microsoft.EntityFrameworkCore;
using Microsoft.Extensions.DependencyInjection;
using Microsoft.Extensions.Configuration;
using FunctionApp36;
[assembly: WebJobsStartup(typeof(StartUp))]
namespace FunctionApp36
{
public class StartUp : IWebJobsStartup
{
public void Configure(IWebJobsBuilder builder)
{
var config = new ConfigurationBuilder()
.AddJsonFile("local.settings.json", optional: true, reloadOnChange: true)
.AddEnvironmentVariables()
.Build();
builder.Services.AddDbContext<BookContext>(options1 =>
{
options1.UseSqlServer(
config["ConnectionStrings:DefaultConnection"],
builder =>
{
builder.EnableRetryOnFailure(5, TimeSpan.FromSeconds(10), null);
builder.CommandTimeout(10);
}
);
});
}
}
}
DbContextPool needs single public constructor.
You either need to use AddDbContext or AddDbContextPool, not both of them.
Check my Example below and try:
public partial class MyDbContext : DbContext
{
private readonly ... //Code
public MyDbContext(DbContextOptions<MyDbContext> options) : base(options)
{
//Code
}
}
For more information, please refer this MSFT documentation
Related
I have created an HTTP trigger-based .Net 6 Azure FunctionApp and trying to configure the database connection strings, other key values, and dependency injections for my service classes but, I don't know how to call my configure method of Startup.cs file from Program.cs main function. I am new to FunctionApp-based hosting.
I have tried with IHostBuilder like the following in the Program.cs file, but it says: "does not contain a definition for ConfigureWebHostDefaults" even used the namespace => using Microsoft.AspNetCore.Hosting;
public static void Main(string[] args)
{
var host = new HostBuilder().ConfigureFunctionsWorkerDefaults()
.Build();
host.Run();
}
public static IHostBuilder CreateHostBuilder(string[] args) =>
Host.CreateDefaultBuilder(args)
.ConfigureWebHostDefaults(webBuilder =>
{
webBuilder.UseStartup<Startup>();
});
My Startup.cs file,
[assembly: FunctionsStartup(typeof(Startup))]
namespace kpi
{
public class Startup : FunctionsStartup
{
private static IConfiguration _configuration = null;
public override void Configure(IFunctionsHostBuilder builder)
{
var serviceProvider = builder.Services.BuildServiceProvider();
_configuration = serviceProvider.GetRequiredService<IConfiguration>();
var appSettingsSection = _configuration.GetSection("AppSetting");
builder.Services.Configure<AppSetting>(appSettingsSection);
var appSettings = appSettingsSection.Get<AppSetting>();
RuntimeConfig.appsettings = appSettings;
var ConnectionString = RuntimeConfig.appsettings.AppDBConnection;
builder.Services.AddDbContext<ShardingDbContext>(options =>
options.UseSqlServer(ConnectionString), ServiceLifetime.Transient);
}
}
}
I have used the FunctionStartup assembly, I don't know where I did go wrong, Can anyone help me to configure my connection strings from Startup.cs file in .Net6 Function App project?
You can refer below code to fix your issue. For more details, please read official doc.
Guide for running C# Azure Functions in an isolated process
1. Startup.cs file
using System;
using System.Collections.Generic;
using System.IO;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
using Microsoft.Azure.Functions.Extensions.DependencyInjection;
using Microsoft.Extensions.Configuration;
using Microsoft.Extensions.DependencyInjection;
[assembly: FunctionsStartup(typeof(triggerFunc.Startup))]
namespace triggerFunc
{
public class Startup : FunctionsStartup
{
private static IConfiguration _configuration = null;
public override void ConfigureAppConfiguration(IFunctionsConfigurationBuilder builder)
{
var context = builder.GetContext();
// optional: customize your configuration sources
// here, we add appsettings.json files
// Note that these files are not automatically copied on build or publish.
//builder.ConfigurationBuilder
// .AddJsonFile(Path.Combine(context.ApplicationRootPath, "appsettings.json"), optional: true, reloadOnChange: false)
// .AddJsonFile(Path.Combine(context.ApplicationRootPath, $"appsettings.{context.EnvironmentName}.json"), optional: true, reloadOnChange: false);
}
public override void Configure(IFunctionsHostBuilder builder)
{
// get the configuration from the builder
//var configuration = builder.GetContext().Configuration;
var serviceProvider = builder.Services.BuildServiceProvider();
_configuration = serviceProvider.GetRequiredService<IConfiguration>();
var appSettingsSection = _configuration.GetSection("AppSetting");
builder.Services.Configure<AppSetting>(appSettingsSection);
var appSettings = appSettingsSection.Get<AppSetting>();
RuntimeConfig.appsettings = appSettings;
var ConnectionString = RuntimeConfig.appsettings.AppDBConnection;
builder.Services.AddDbContext<ShardingDbContext>(options =>
options.UseSqlServer(ConnectionString), ServiceLifetime.Transient);
}
}
}
2. Program.cs file
using Microsoft.Extensions.Configuration;
using Microsoft.Extensions.Hosting;
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
namespace triggerFunc
{
public class Program
{
public static async Task Main(string[] args)
{
var builder = Host
.CreateDefaultBuilder(args)
.ConfigureFunctionsWorkerDefaults()
.ConfigureAppConfiguration((hostingContext, configBuilder) =>
{
var env = hostingContext.HostingEnvironment;
;
})
.ConfigureServices((appBuilder, services) =>
{
var configuration = appBuilder.Configuration;
});
await builder.Build().RunAsync();
}
}
}
I just did override the function ConfigureAppConfiguration as below
public override void ConfigureAppConfiguration(IFunctionsConfigurationBuilder builder)
{
FunctionsHostBuilderContext context = builder.GetContext();
builder.ConfigurationBuilder
.AddJsonFile(Path.Combine(context.ApplicationRootPath, "local.settings.json"), optional: true, reloadOnChange: false)
.AddJsonFile(Path.Combine(context.ApplicationRootPath, $"local.settings.{context.EnvironmentName}.json"), optional: true, reloadOnChange: false)
.AddEnvironmentVariables();
}
It's working fine in my local without an isolated way or Program.cs file and I don't know whether this same code will work on a server or not.
My local.setings.json
{
"IsEncrypted": false,
"AppSettings": {
"AppDBConnection": "xyz....."
}
My Startup.cs file below and I can access the AppSettings section from my json file
public class Startup : FunctionsStartup
{
private static IConfiguration _configuration = null;
public override void Configure(IFunctionsHostBuilder builder)
{
//var connectionString = Environment.GetEnvironmentVariable("ConnectionStrings:DBConnection");
var serviceProvider = builder.Services.BuildServiceProvider();
_configuration = serviceProvider.GetRequiredService<IConfiguration>();
var appSettingsSection = _configuration.GetSection("AppSettings");
builder.Services.Configure<AppSettings>(appSettingsSection);
var appSettings = appSettingsSection.Get<AppSettings>();
RuntimeConfig.appsettings = appSettings;
var ConnectionString = RuntimeConfig.appsettings.AppDBConnection;
builder.Services.AddDbContext<ShardingDbContext>(options => options.UseSqlServer(ConnectionString), ServiceLifetime.Transient);
builder.Services.AddScoped<ITestService, TestService>();
}
public override void ConfigureAppConfiguration(IFunctionsConfigurationBuilder builder)
{
FunctionsHostBuilderContext context = builder.GetContext();
builder.ConfigurationBuilder
.AddJsonFile(Path.Combine(context.ApplicationRootPath, "local.settings.json"), optional: true, reloadOnChange: false)
.AddJsonFile(Path.Combine(context.ApplicationRootPath, $"local.settings.{context.EnvironmentName}.json"), optional: true, reloadOnChange: false)
.AddEnvironmentVariables();
}
}
I'm using .NET Core 2.2 and SignalR Core and I need to inject IHubContext<MyClass> via Simple Injector in my Webjob.
It works perfectly in my web app but when I'm trying to reach my service via web job, it's complaining about lacking injection of IHubContext<IHubContext<BroadcastHub>>
I need a way to register it via Simple Injector
This is my Configuration in Program.cs file in my Webjob
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());
}
}
}
This is my simplified Service that is using SignalR: (this is another project that webjob will use it
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;
}
}
this is my webjob that will call PatientService in another project
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);
}
}
}
and this is the process method that will call 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;
}
}
}
I need to register IHubContext<MyClass> in my webjob in program.cs but I'm not able to register it via the following ways:
hubContext = serviceProvider.GetService<IHubContext<BroadcastHub>>();
container.RegisterSingleton(hubContext);
or this way
container.Register<IHubContext<BroadcastHub>>(Lifestyle.Singleton);
Update 2019-12-02:
I was able to resolve IHubContext but now i'm receiving e new issue. this is my function class:
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);
}
}
}
and this is my progrm.cs class after all updates:
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());
}
}
}
Now I'm getting this error that it means the container inside the function class is not resolved:
fail: Host.Results[0]
System.InvalidOperationException: Unable to resolve service for type 'SimpleInjector.Container' while attempting to activate 'Gateway.WebJob.Functions'.
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, CancellationToken cancellationToken) in C:\projects\azure-webjobs-sdk-rqm4t\src\Microsoft.Azure.WebJobs.Host\Executors\FunctionExecutor.cs:line 117
I just tried this out myself, but as long as "auto cross wiring" is enabled in the Simple Injector integration (which is the default), you should be able to get IHubContext<T> implementations injected without having to do anything.
Here's an example startup class:
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?}");
});
}
}
And here's a hub context injected into a controller that is created by 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();
}
}
I'm trying to run test on the repository Controller 'PeoppleRepositoryController.cs.
I get the below error and I couldn't figure out what exactly it is complaining about.
Can anyone please explain what I need to do to fix this issue?
Microsoft.Extensions.DependencyInjection.ActivatorUtilities.GetService(IServiceProvider sp, Type type, Type requiredBy, bool isDefaultParameterRequired)
The full stack trace can be seen on the image below:
The controller is:
using System;
using System.Collections.Generic;
using System.Linq;
using System.Threading.Tasks;
using Microsoft.AspNetCore.Http;
using Microsoft.AspNetCore.Mvc;
using Microsoft.EntityFrameworkCore;
using Personkartotek.DAL;
using Personkartotek.Models;
using Personkartotek.Persistence;
namespace Personkartotek.Controllers
{
[Route("api/[controller]")]
[ApiController]
public class PeopleRepositoryController : ControllerBase
{
private readonly IUnitOfWork _uoWork;
public PeopleRepositoryController(IUnitOfWork uoWork)
{
_uoWork = uoWork;
}
// GET: api/PeopleRepository
[HttpGet]
public IEnumerable<Person> GetPersons()
{
return _uoWork._People.GetAll();
}
// GET: api/PeopleRepository/5
[HttpGet("{id}")]
public async Task<IActionResult> GetPerson([FromRoute] int id)
{
if (!ModelState.IsValid)
{
return BadRequest(ModelState);
}
var person = _uoWork._People.Get(id);
if (person == null)
{
return NotFound();
}
return Ok(person);
}
//GET: api/PeopleRepository/
[HttpGet("AtAdr/{id}")]
public IActionResult GetPersonsResidingAtAddress([FromRoute] int AddressId)
{
var ResidingPersons = _uoWork._People.GetAllPersonsById(AddressId);
return Ok(ResidingPersons);
}
// PUT: api/PeopleRepository/5
[HttpPut("{id}")]
public async Task<IActionResult> PutPerson([FromRoute] int id, [FromBody] Person person)
{
if (!ModelState.IsValid)
{
return BadRequest(ModelState);
}
if (id != person.PersonId)
{
return BadRequest();
}
if (!PersonExists(id))
{
return NotFound();
}
_uoWork._People.Put(person);
return NoContent();
}
// POST: api/PeopleRepository
[HttpPost]
public async Task<IActionResult> PostPerson([FromBody] Person person)
{
if (!ModelState.IsValid)
{
return BadRequest(ModelState);
}
_uoWork._People.Add(person);
_uoWork.Complete();
return CreatedAtAction("GetPerson", new { id = person.PersonId }, person);
}
// DELETE: api/PeopleRepository/5
[HttpDelete("{id}")]
public async Task<IActionResult> DeletePerson([FromRoute] int id)
{
if (!ModelState.IsValid) {
return BadRequest(ModelState);
}
var person = _uoWork._People.Get(id);
if (person == null) {
return NotFound();
}
_uoWork._People.Remove(person);
_uoWork.Complete();
return Ok(person);
}
private bool PersonExists(int id)
{
return _uoWork.Exist(id);
}
}
}
IUnitOfWork file:
using Personkartotek.DAL.IRepositories;
namespace Personkartotek.DAL
{
public interface IUnitOfWork : IDisposable
{
IPeopleRepository _People { get; }
int Complete();
bool Exist(int id);
}
}
My Startup.cs file set ups:
using System;
using System.Collections.Generic;
using System.Linq;
using System.Threading.Tasks;
using Microsoft.AspNetCore.Builder;
using Microsoft.AspNetCore.Hosting;
using Microsoft.AspNetCore.Http;
using Microsoft.AspNetCore.Mvc;
using Microsoft.EntityFrameworkCore;
using Microsoft.Extensions.Configuration;
using Microsoft.Extensions.DependencyInjection;
using Personkartotek.DAL;
using Personkartotek.Models.Context;
using Personkartotek.Persistence;
using Swashbuckle.AspNetCore.Swagger;
namespace Personkartotek
{
public class Startup
{
public Startup(IConfiguration configuration)
{
Configuration = configuration;
}
public IConfiguration Configuration { get; }
// This method gets called by the runtime. Use this method to add services to the container.
public void ConfigureServices(IServiceCollection services)
{
services.Configure<CookiePolicyOptions>(options =>
{
// This lambda determines whether user consent for non-essential cookies is needed for a given request.
options.CheckConsentNeeded = context => true;
options.MinimumSameSitePolicy = SameSiteMode.None;
});
services.AddDbContext<ModelsContext>(options =>
options.UseSqlServer(Configuration.GetConnectionString("PersonkartotekDB")));
services.AddMvc().SetCompatibilityVersion(CompatibilityVersion.Version_2_1);
}
// This method gets called by the runtime. Use this method to configure the HTTP request pipeline.
public void Configure(IApplicationBuilder app, IHostingEnvironment env)
{
if (env.IsDevelopment())
{
app.UseDeveloperExceptionPage();
}
else
{
app.UseExceptionHandler("/Home/Error");
}
app.UseStaticFiles();
app.UseCookiePolicy();
app.UseMvc(routes =>
{
routes.MapRoute(
name: "default",
template: "{controller=Home}/{action=Index}/{id?}");
});
}
}
}
It complaints because it doesn't know how to create an object of IUnitOfWork which is a dependency on your controller.
So to resolve the issue you need to instruct the framework on what implementation of IUnitOfWork you want to use. Typically you are doing it in your Startup.ConfigureServices method. For exmaple:
public class Startup
{
public void ConfigureServices(IServiceCollection services)
{
services.AddTransient<IUnitOfWork, UnitOfWorkImplementation>();
}
}
Where UnitOfWorkImplementation is a class that implement IUnitOfWork
I am trying to implement an InterceptAttribute which should intercept any method I add the attribute to. I have it working in a WebAPI solution, however, I cannot get it to work in an MVC 5 application. The code is the same in both projects. The following code is the attribute I created.
using Ninject;
using Ninject.Extensions.Interception;
using Ninject.Extensions.Interception.Attributes;
using Ninject.Extensions.Interception.Request;
namespace Questionnaire.Common.InterceptAttributes
{
public class InterceptCacheAttribute : InterceptAttribute
{
public double TimeOut { get; set; }
public override IInterceptor CreateInterceptor(IProxyRequest request)
{
var cacheInterceptor = request.Kernel.Get<CacheInterceptor>();
cacheInterceptor.TimeOut = TimeOut;
return cacheInterceptor;
}
}
}
The CacheInterceptor code is as follows:
using System;
using System.Text;
using Ninject;
using Ninject.Extensions.Interception;
using Ninject.Extensions.Interception.Request;
namespace Questionnaire.Common.Interceptors
{
public class CacheInterceptor : IInterceptor
{
[Inject]
public ICaching Cache { get; set; }
public double TimeOut { get; set; }
public void Intercept(IInvocation invocation)
{
var minutes = Cache.TimeOutMinutes;
if (Math.Abs(TimeOut - default(double)) > 0)
{
minutes = TimeOut;
}
invocation.ReturnValue = Cache.Get(GenerateCacheKey(invocation.Request), minutes, delegate
{
invocation.Proceed();
return invocation.ReturnValue;
});
}
private static string GenerateCacheKey(IProxyRequest request)
{
var sb = new StringBuilder(request.Method.Name).Append(".");
foreach (var argument in request.Arguments)
{
if (argument == null)
{
sb.Append("null");
}
else if (argument is string && argument.ToString().Length < 50)
{
sb.Append((string)argument);
}
else
{
sb.Append(argument.GetHashCode());
}
sb.Append(".");
}
sb.Remove(sb.Length - 1, 1);
return sb.ToString();
}
}
}
Finally I added the attribute to the following method.
using System.Configuration;
using Questionnaire.Common.InterceptAttributes;
namespace Questionnaire.Common.Utility
{
public class ConfigurationUtilities
{
[InterceptCache(TimeOut = 1440)]
public virtual string GetEnvironmentConnectionString(string name)
{
var connectionStringSettings = ConfigurationManager.ConnectionStrings[name + "_" + HostEnvironment];
return connectionStringSettings != null ? connectionStringSettings.ConnectionString : null;
}
}
}
Code execution never enters into the InterceptCacheAttribute class. I have put debug points within that class and the CacheInterceptor class and the debug points are never hit. The method the attribute is on executes just fine, but, I want it to be intercepted and that is not happening. I have the same code in a different project. That project is a WebAPI project which works great. The methods are intercepted and everything functions as it should. Can someone explain to me why I can't get it to work in the MVC 5 application? I would greatly appreciate it.
answer to BatteryBackupUnit's question:
The answer is I can't. The following is my NinjectWebCommon.cs class.
[assembly: WebActivatorEx.PreApplicationStartMethod(typeof(Mayo.Questionnaire.App_Start.NinjectWebCommon), "Start")]
[assembly: WebActivatorEx.ApplicationShutdownMethodAttribute(typeof(Mayo.Questionnaire.App_Start.NinjectWebCommon), "Stop")]
namespace Questionnaire.App_Start
{
using System;
using System.Web;
using System.Web.Http;
using System.Linq;
using ApplicationExtensions;
using Microsoft.Web.Infrastructure.DynamicModuleHelper;
using Ninject;
using Ninject.Web.Common;
public static class NinjectWebCommon
{
private static readonly Bootstrapper bootstrapper = new Bootstrapper();
public static void Start()
{
DynamicModuleUtility.RegisterModule(typeof(OnePerRequestHttpModule));
DynamicModuleUtility.RegisterModule(typeof(NinjectHttpModule));
bootstrapper.Initialize(CreateKernel);
}
public static void Stop()
{
bootstrapper.ShutDown();
}
private static IKernel CreateKernel()
{
var kernel = new StandardKernel();
try
{
kernel.Bind<Func<IKernel>>().ToMethod(ctx => () => new Bootstrapper().Kernel);
kernel.Bind<IHttpModule>().To<HttpApplicationInitializationHttpModule>();
GlobalConfiguration.Configuration.DependencyResolver = new NinjectDependencyResolver(kernel);
RegisterServices(kernel);
return kernel;
}
catch
{
kernel.Dispose();
throw;
}
}
private static void RegisterServices(IKernel kernel)
{
foreach (var module in from assembly in AppDomain.CurrentDomain.GetAssemblies()
select assembly.GetNinjectModules()
into modules
from module in modules
where !kernel.GetModules().Any(m => m.Name.Equals(module.Name))
select module)
{
kernel.Load(module);
}
}
}
}
Inside the RegisterServices method every assembly in the application is iterated over and any classes that inherit from NinjectModule are loaded. However, I can't verify that it is working because I can't debug it. I have tried, but, execution is never stopped within the class. I know that the class is being instantiated and that the modules are being loaded because I have bindings in those modules that are working, however, I can't verify it.
I am trying to create a WCF DataService using in-memory object graph. This means that the backend is not an Entity Framework store, but a bunch of objects that reside in memory.
I am trying to create a service operation called GetUsersByName that has a single parameter for name and returns the matching users as an IQueryable collection.
I followed the documentation and added the access rules for this operation
config.SetServiceOperationAccessRule("GetUsersByName", ServiceOperationRights.All);
But when the SetServiceOperationAccessRule method is called I receive an exception on the client:
System.AggregateException was unhandled.
Here is the full code for my console application
using System;
using System.ServiceModel;
using System.ServiceModel.Web;
using System.ServiceModel.Description;
using System.Data.Services;
using System.Data.Services.Common;
using System.Collections.Generic;
using System.Runtime.Serialization;
using System.Collections.ObjectModel;
using System.Linq;
using System.Web;
using System.Net.Http;
using System.Net;
using System.IO;
namespace WCF_OData
{
class Program
{
static void Main(string[] args)
{
string serviceAddress = "http://localhost:8080";
Uri[] uriArray = { new Uri(serviceAddress) };
Type serviceType = typeof(UserDataService);
using (var host = new DataServiceHost(serviceType, uriArray)) {
host.Open();
var client = new HttpClient() { BaseAddress = new Uri(serviceAddress) };
Console.WriteLine("Client received: {0}", client.GetStringAsync("Users?$format=json").Result);
HttpWebRequest request = (HttpWebRequest)WebRequest.Create("http://localhost:8080");
request.Method = "GET";
request.Accept = #"application/json";
using (HttpWebResponse response = (HttpWebResponse)request.GetResponse())
{
Console.WriteLine(response.StatusCode);
Console.WriteLine(response.ContentType);
Console.WriteLine((new StreamReader(response.GetResponseStream())).ReadToEnd());
}
Console.WriteLine("Press any key to stop service");
Console.ReadKey();
}
}
}
[EnableJsonSupport]
[ServiceBehavior(IncludeExceptionDetailInFaults = true)]
public class UserDataService : DataService<UserService> {
public static void InitializeService(DataServiceConfiguration config)
{
config.SetEntitySetAccessRule("Users", EntitySetRights.All);
config.SetServiceOperationAccessRule("GetUsersByName", ServiceOperationRights.All);
config.UseVerboseErrors = true;
config.DataServiceBehavior.MaxProtocolVersion = DataServiceProtocolVersion.V2;
}
}
public class UserService
{
private List<User> _List = new List<User>();
public UserService()
{
_List.Add(new User() { ID = 1, UserName = "John Doe" });
_List.Add(new User() { ID = 2, UserName = "Jane Doe" });
}
public IQueryable<User> Users
{
get
{
HttpContext x = HttpContext.Current;
return _List.AsQueryable<User>();
}
}
[OperationContract]
[WebGet(UriTemplate="GetUsersByName")]
public IQueryable<User> GetUsersByName(string name)
{
return new List<User>().AsQueryable();
}
}
[DataServiceKey("ID")]
public class User
{
public int ID { get; set; }
public string UserName { get; set; }
}
}
It looks like there are a few things going on here, so this may take a couple of iterations to work through. The first problem that should be fixed is the service operation. Service operations need to be declared on the class that inherits from DataService: "Service operations are methods added to the data service class that derives from DataService". Here's a sample:
using System.Data.Entity;
using System.Data.Services;
using System.Data.Services.Common;
using System.Linq;
using System.ServiceModel;
using System.ServiceModel.Web;
namespace Scratch.Web
{
[ServiceBehavior(IncludeExceptionDetailInFaults = true)]
public class ScratchService : DataService<ScratchEntityFrameworkContext>
{
static ScratchService()
{
Database.SetInitializer(new ScratchEntityFrameworkContextInitializer());
}
public static void InitializeService(DataServiceConfiguration config)
{
config.SetEntitySetAccessRule("*", EntitySetRights.All);
config.SetServiceOperationAccessRule("*", ServiceOperationRights.AllRead);
config.DataServiceBehavior.MaxProtocolVersion = DataServiceProtocolVersion.V3;
config.UseVerboseErrors = true;
}
[WebGet]
public IQueryable<Product> FuzzySearch(string idStartsWith)
{
var context = new ScratchEntityFrameworkContext();
return context.Products.ToList().Where(p => p.ID.ToString().StartsWith(idStartsWith)).AsQueryable();
}
}
}
You should then be able to call your service operation from a browser, with a URL format similar to the following: http://localhost:59803/ScratchService.svc/FuzzySearch()?idStartsWith='1'
Can we start by trying to get this functional in a browser and then see whether the AggregateException still happens?