Read and use settings from appsettings.json in MVC 5 - c#

I have a MVC 5 project (framework 4.6.1), where I would like to load a POCO from appsettings.json.
My MVC app does not have a Startup.cs, starting point seems to be Global.asax.
I tried adding Owin to have a Startup.cs, but contrary to most articles I have found, Configuration seems to be a void method called during startup and not an IConfiguration as in net core.
This article pretty much attempts to do what I want, but also assumes that Configuration is an IConfiguration interface.

Ok here is what I ended up doing:
I wanted to load an object of class ScrumBan from my appsettings.json.
I declared this class
public class ChartConfiguration: IChartConfiguration
{
public Scrumban Scrumban { get; }
public ChartConfiguration()
{
var configuration = new ConfigurationBuilder()
.SetBasePath(AppDomain.CurrentDomain.BaseDirectory)
.AddJsonFile("appsettings.json", optional: false, reloadOnChange: true)
.Build();
Scrumban = new Scrumban();
configuration.GetSection("Scrumban").Bind(Scrumban);
}
}
The interface only exposes the ScrumBan object:
public interface IChartConfiguration
{
Scrumban Scrumban { get; }
}
Then i included Unity for Dependency Injection handling and registered my interface:
public static class IocExtensions
{
public static void BindInRequestScope<T1, T2>(this IUnityContainer container) where T2 : T1
{
container.RegisterType<T1, T2>(new HierarchicalLifetimeManager());
}
}
public class UnityMvc5
{
public static void Start()
{
var container = BuildUnityContainer();
DependencyResolver.SetResolver(new UnityDependencyResolver(container));
}
private static IUnityContainer BuildUnityContainer()
{
var container = new UnityContainer();
// register all your components with the container here
// it is NOT necessary to register your controllers
// Configuration object, one per request, ensure it is disposed
container.BindInRequestScope<IChartConfiguration, ChartConfiguration>();
return container;
}
}
Finally in Application_Start in Global.asax.cs I added the UnityMvc5.Start():
protected void Application_Start()
{
BundleConfig.RegisterBundles(BundleTable.Bundles);
AreaRegistration.RegisterAllAreas();
UnityMvc5.Start();
RouteConfig.RegisterRoutes(RouteTable.Routes);
}
With Unity in place, I can now change my Controller constructors to include my IChartConfiguration interface and store it for future reference, exactly as is common practice with ASP.NET Core.
I am not quite sure about the instantiation model BindInRequestScope, I could have chosen the singleton, but as far as I can tell, the ChartConfiguration constructor is not called per request anyway. Similarly I am not sure of the value of reloadOnChange, but is not crucial to my app.
Hope this helps someone in a situation like mine.

Related

SignalR Dependency Injection for ASP.NET Core v2.0 using Autofac

Is it possible to use dependency injection to inject dependencies into SignalR on ASP.NET Core v2.0?
Assuming the following hub and dependency:
public MyHub : Hub {
private readonly IMyDependency dependency;
public MyHub(IMyDependency dependency) {
this.dependency = dependency;
}
}
public void MyDependency : IDependency
{
public void MyMethod() {
Console.WriteLine("I'm a dependency!");
}
}
I've scoured a bit of the web and there isn't anything obvious out there. I found this tutorial which at first seemed quite promising until I realised it was for Microsoft.AspNetCore.SignalR.Server which didn't ship in the end.
At the moment I have the following setup using Autofac and it's not working:
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 IServiceProvider ConfigureServices(IServiceCollection services)
{
services.AddMvc();
services.AddSignalR();
// Configue Autofac
var containerBuilder = new ContainerBuilder();
containerBuilder.RegisterModule<MyModule>();
// Configure SignalR hubs for dependency injection
containerBuilder.RegisterSignalRHubs(typeof(Startup).GetTypeInfo().Assembly);
containerBuilder.Populate(services);
var container = containerBuilder.Build();
return new AutofacServiceProvider(container);
}
}
public static class AutoFacExtensions
{
public static IRegistrationBuilder<object, ScanningActivatorData, DynamicRegistrationStyle> RegisterSignalRHubs(this ContainerBuilder builder, params Assembly[] assemblies)
{
return builder.RegisterAssemblyTypes(assemblies)
.Where(t => typeof(IHub).IsAssignableFrom(t))
.ExternallyOwned();
}
}
public class MyModule : Module
{
protected override void Load(ContainerBuilder builder)
{
builder.RegisterType<MyDependency>().As<IMyDependency>();
}
}
It looks like the IHub interface doesn't exist anymore. I tried IHubContext<MyHub> in the hope that this might work with the latest version but sadly not.
When I have dependencies in my hub's constructor, the hub isn't created despite all of the dependencies registered with Autofac.
How can I achieve this with the lastest version 1.0.0.0-alpha2-final?
The example given in the question does work with version 1.0.0.0-alpha2-final of Microsoft.AspNetCore.SignalR with one slight tweak, use Hub rather than the now non-existent IHub.
public static class AutoFacExtensions
{
public static IRegistrationBuilder<object, ScanningActivatorData, DynamicRegistrationStyle> RegisterSignalRHubs(this ContainerBuilder builder, params Assembly[] assemblies)
{
// typeof(Hub), not typeof(IHub)
return builder.RegisterAssemblyTypes(assemblies)
.Where(t => typeof(Hub).IsAssignableFrom(t))
.ExternallyOwned();
}
}
Ensure that all of your dependencies are satisfied by assigning them to a controller. I'm not sure at this point how to troubleshoot broken dependencies when injecting into a SignalR hub with this method.

How rebind service in TestHost

I am preparing environment tests for my application. And I have problem how can i rebind earlier registred services in my startup class?.
I am using TestHost in my tests and this is how looks my base class
public abstract class IntegrationTestBase : IDisposable
{
private readonly TestServer _server;
public IntegrationTestBase()
{
var webHostBuilder = new WebHostBuilder()
.UseStartup<Startup>();
_server = new TestServer(webHostBuilder);
}
public HttpClient CreateClient()
{
return _server.CreateClient();
}
public virtual void Dispose()
{
_server.Dispose();
}
}
The way I've been handling overriding the registration for integration tests is:
Make the ConfigureServices method on your Startup class virtual.
Create a derived class of Startup: e.g: IntegrationTestStartup
Override ConfigureService like:
override ConfigureServices(IServiceCollection s)
{
base.ConfigureServices(s);
s.AddSingleton<IService, IMockService>();
}
Since the last registration you make of a service is the one provided by the DI container when a constructor injection happens, this works well.
In case you depend on IEnumerable<IService>, all components registered for that service will be resolved.
If you can't make your ConfigureServices from the Startup class virtual I assume using new would do the job since the WebHostBuilder creates an instance of the type passed to it.
Now you can build your WebHostBuilder with:
var webHostBuilder = new WebHostBuilder()
.UseStartup<IntegrationTestStartup>();
Does this help or could you be more specific what kind of 'rebind' do you need?

How to configure Unity container for AccountController in identity authentication [duplicate]

This question already has an answer here:
How to inject webapi AccountController in WebApi
(1 answer)
Closed 5 years ago.
My controller is like :
public class AccountController : ApiController
{
private const string LocalLoginProvider = "Local";
private ApplicationUserManager _userManager;
private readonly ApplicationRoleManager _roleManager;
public AccountController()
{
}
public AccountController(ApplicationUserManager userManager,
ISecureDataFormat<AuthenticationTicket> accessTokenFormat,
ApplicationRoleManager roleManager)
{
UserManager = userManager;
AccessTokenFormat = accessTokenFormat;
_roleManager = roleManager;
}
}
In UnityConfig.cs I try to configure like this way :
public static void RegisterTypes(IUnityContainer container)
{
// NOTE: To load from web.config uncomment the line below. Make sure to add a Microsoft.Practices.Unity.Configuration to the using statements.
// container.LoadConfiguration();
// TODO: Register your types here
container.RegisterType<AccountController>(new InjectionConstructor());
container.RegisterType<ApplicationUserManager>();
container.RegisterType<ApplicationRoleManager>();
container.RegisterType<ISecureDataFormat<AuthenticationTicket>, SecureDataFormat<AuthenticationTicket>>();
}
In WebApiConfig.cs :
public static class WebApiConfig
{
public static void Register(HttpConfiguration config)
{
var container = new UnityContainer();
UnityConfig.RegisterTypes(container);
//Set the unity container as the default dependency resolver
config.DependencyResolver = new UnityHierarchicalDependencyResolver(container);
}
}
And in Global.asax.cs :
public class WebApiApplication : System.Web.HttpApplication
{
protected void Application_Start()
{
GlobalConfiguration.Configure(WebApiConfig.Register); // At the beginning, register with HttpConfiguration
AreaRegistration.RegisterAllAreas();
FilterConfig.RegisterGlobalFilters(GlobalFilters.Filters);
RouteConfig.RegisterRoutes(RouteTable.Routes);
BundleConfig.RegisterBundles(BundleTable.Bundles);
}
}
But when i try to retrieve role using roleManager (var role = await _roleManager.FindByIdAsync(model.RoleId);) it says :
Object reference not set to an instance of an object.
I see there is a similar question here, but it can't solve my problem.
Based on how the code in the question looks I believe you are using Unity bootstrapper for ASP.NET Web API which should wire up a UnityDependencyResolver.
container.RegisterType<AccountController>(new InjectionConstructor());
This registers the AccountController and instructs Unity to use the paramterless constructor. This is why all of your dependencies are null. If you want to use the other constructor remove the AccountController registration and Unity will use the constructor with the most parameters. However if you do this then you will get a runtime error attempting to resolve the AccountController because ISecureDataFormat<> is not registered and Unity will not know how to map that interface to a concrete type.
If you register a mapping to SecureDataFormat<> then there are some additional dependencies that will need to be registered.
container.RegisterType(typeof(ISecureDataFormat<>), typeof(SecureDataFormat<>));
container.RegisterType<ITextEncoder, Base64UrlTextEncoder>()
container.RegisterType<IDataSerializer<AuthenticationTicket>, TicketSerializer>()
container.RegisterType<IDataProtector>(new ContainerControlledLifetimeManager(),
new InjectionFactory(c => new DpapiDataProtectionProvider().Create("App Name")));
Note that the above registrations are not tested. Not sure if you should configure OWIN with data protection (and perhaps get the protection provider from the OWIN config).
The following two registrations are not strictly required since Unity knows how to resolve a concrete type without a registration and no additional InjectionMembers are being provided (e.g. lifetime, parameters overrides etc.).
container.RegisterType<ApplicationUserManager>();
container.RegisterType<ApplicationRoleManager>();

Injecting Dependency programmatically asp.net core

I'm just starting with Asp.net core Dependency Injection, and my concept could be inaccurate. This docs.asp.net post explains how to inject context to a controller. I have little confusion regarding injection, in testing perspective. Assume we have following scenario:
public interface ITasksRepository
{
public void Create();
}
//This is fake implementation, using fake DbContext for testing purpose
public class TasksRepositoryFake : ITasksRepository
{
public void Create()
{
FakeDbContext.Add(sometask);
//logic;
}
}
//This is actual implementation, using actual DbContext
public class TasksRepository : ITasksRepository
{
public void Create()
{
DbContext.Add(someTask);
//logic;
}
}
Now in order to inject context in controller, we design it as:
public class TasksController : Controller
{
public ITasksRepository TaskItems { get; set; }
public TodoController(ITaskRepository taskItems)
{
TaskItems = taskItems;
}
//other logic
}
What asp.net core provides as builtin feature is, we can register the dependency injection in startup class as follows:
public void ConfigureServices(IServiceCollection services)
{
// Add framework services.
services.AddMvc();
services.AddSingleton<ITasksRepository, TasksRepositoryFake>();
}
According to this logic, my TaskRepositoryFake will be injected to the controller. So far, everything is clear. My questions/confusions regarding this are as follows:
Questions:
How can I use this builtin DI feature to inject the context using some logic? May be programatically, or configuration based, or environment based? (for example, always inject fake context, when using 'test' environment? etc.)
Is it even possible? If we always have to change this manually in StartUp class, then how does this builtin DI feature serve us? Because we could have simply done that in controller, without this feature.
First to answer your question: Yes, you can inject the dependency programmatically. By using factories, as is always the case with injecting dependencies based on run-time values. The AddSingleton has an overload which takes an implementationfactory and so a basic example for your use case looks like:
public class Startup
{
public bool IsTesting { get; }
public Startup(IHostingEnvironment env)
{
IsTesting = env.EnvironmentName == "Testing";
}
// This method gets called by the runtime. Use this method to add services to the container.
// For more information on how to configure your application, visit http://go.microsoft.com/fwlink/?LinkID=398940
public void ConfigureServices(IServiceCollection services)
{
services.AddSingleton<ISomeRepository>(sp => IsTesting ? (ISomeRepository)new SomeRepository() : (ISomeRepository) new FakesomeRepository());
}
// This method gets called by the runtime. Use this method to configure the HTTP request pipeline.
public void Configure(IApplicationBuilder app, ISomeRepository someRepository)
{
app.UseIISPlatformHandler();
app.Run(async (context) =>
{
await context.Response.WriteAsync($"Hello World from {nameof(someRepository)}!");
});
}
// Entry point for the application.
public static void Main(string[] args) => WebApplication.Run<Startup>(args);
}
The concerning line of code for your TasksRepository would look like:
services.AddSingleton<ITaskRepository>(sp => isTesting?(ITasksRepository)new TasksRepositoryFake(): (ITasksRespository)new TasksRepository() );
Even better would be to put it in a factory (again with my example):
services.AddSingleton<ISomeRepository>(sp => SomeRepositoryFactory.CreatSomeRepository(IsTesting));
I hope you see how this helps you setting it up config based, environment based, or however you want.
I you are interested I wrote more about DI based on run-time values via abstract factories here.
Having said that, with unit tests I would simply inject my fakes in the classes that are under test. Unit tests are there to still prove to yourself and your co-workers that the code still does as intended.
And with integration tests I would make a special StartUp class with all my fakes and give it to the test host as ASP.NET Core allows you to do. You can read more about the test host here: https://docs.asp.net/en/latest/testing/integration-testing.html
Hope this helps.
Update Added cast to interface because the ternary conditional has no way of telling. Plus added some basic samples.
You can inject your dependencies configuration based, or environment based, or both.
Option 1 : Environment Based
public IHostingEnvironment env{ get; set; }
public Startup(IHostingEnvironment env)
{
this.env = env;
}
public void ConfigureServices(IServiceCollection services)
{
if (env.IsDevelopment())
{
// register other fake dependencies
services.AddSingleton<ITasksRepository, TasksRepositoryFake>();
}
else
{
// register other real dependencies
services.AddSingleton<ITasksRepository, TasksRepository>();
}
}
Option 2 : Configuration Based
public IConfigurationRoot Configuration { get; set; }
public Startup()
{
var builder = new ConfigurationBuilder()
.SetBasePath(env.ContentRootPath)
.AddJsonFile("appsettings.json", optional: true, reloadOnChange: true)
.AddJsonFile($"appsettings.{env.EnvironmentName}.json", optional: true)
.AddEnvironmentVariables();
Configuration = builder.Build();
}
public void ConfigureServices(IServiceCollection services)
{
var isFakeMode= Configuration["ServiceRegistrationMode"] == "Fake";
if (isFakeMode)
{
// register other fake dependencies
services.AddSingleton<ITasksRepository, TasksRepositoryFake>();
}
else
{
// register other real dependencies
services.AddSingleton<ITasksRepository, TasksRepository>();
}
}
Option 3 : Environment Based + Configuration Based
public IConfigurationRoot Configuration { get; set; }
public IHostingEnvironment env{ get; set; }
public Startup(IHostingEnvironment env)
{
this.env = env;
var builder = new ConfigurationBuilder()
.SetBasePath(env.ContentRootPath)
.AddJsonFile("appsettings.json", optional: true, reloadOnChange: true)
.AddJsonFile($"appsettings.{env.EnvironmentName}.json", optional: true)
.AddEnvironmentVariables();
Configuration = builder.Build();
}
public void ConfigureServices(IServiceCollection services)
{
var isFakeMode = Configuration["ServiceRegistrationMode"] == "Fake";
if (env.IsDevelopment() && isFakeMode)
{
// register other fake dependencies
services.AddSingleton<ITasksRepository, TasksRepositoryFake>();
}
else
{
// register other real dependencies
services.AddSingleton<ITasksRepository, TasksRepository>();
}
}

Inject dependencies in a WebAPI with Unity

I have a WebAPI controller that (should) looks like this:
public class MyController : ApiController
{
private IRepository repository;
public MyController(IRepository repository)
{
this.repository = repositor;
}
// REST implementations
}
WebApiConfig is configured like that:
public static class WebApiConfig
{
public static void Register(HttpConfiguration config)
{
// Unity configuration
var container = new UnityContainer();
container
.RegisterType<IRepository , CustomRepository>();
config.DependencyResolver = new UnityResolver(container);
// Web API routes
// CORS
}
}
then in Global.asax.cs I have something like:
public class WebApiApplication : System.Web.HttpApplication
{
protected void Application_Start()
{
GlobalConfiguration.Configure(WebApiConfig.Register);
}
// CORS
protected void Application_BeginRequest(object sender, EventArgs e)
{
// some CORS config
}
}
and finally I have a Startup.cs:
[assembly: OwinStartup(typeof(Path.To.Startup))]
namespace ZeroCode.ConfigurazioneServizio.Web.Api
{
public class Startup
{
public void Configuration(IAppBuilder app)
{
new Mapping().Bootstrap();
}
}
}
To me everything looks ok, the code builds and I can launch the controller but as soon I make a request I get error cause parameterless constructor isn't present.
So I've added the default constructor but this will instantiate the controller so IRepository will never be injected.
I've searched for a possible solution. One of them tried to implement IHttpControllerActivator and so i've realized something like this:
public class UnityHttpControllerActivator : IHttpControllerActivator
{
private IUnityContainer _container;
public UnityHttpControllerActivator(IUnityContainer container)
{
_container = container;
}
public IHttpController Create(System.Net.Http.HttpRequestMessage request, HttpControllerDescriptor controllerDescriptor, Type controllerType)
{
return (IHttpController)_container.Resolve(controllerType);
}
}
At this point I've modified the WebApiConfig.cs inserting this line
config.Services.Replace(typeof(IHttpControllerActivator), new UnityHttpControllerActivator(container));
right after the config.DependencyResolver but this doesn't resolve the issue and exception is raised inside the Create method. I don't know what else I can do.
There's a nice little Nuget Package - Unity.Webapi. If you add that, you can simply plug in your container into your HttpConfiguration
public static void Register(HttpConfiguration config)
{
// Unity configuration
var container = new UnityContainer();
container.RegisterType<IRepository , CustomRepository>();
config.DependencyResolver = new UnityResolver(container);
//this
config.DependencyResolver = new UnityDependencyResolver(container);
// Web API routes
// CORS
}
Then you can bypass the extra class and web.config changes.
The first answer states to add Unity.WebApi. It is correct. After adding this package use it as is described in this link Using Unity.Mvc5 and Unity.WebApi together in a project. I did like this and my problem was solved.
With version 5 or higher for unity, you will have to add the Unity.AspNet.WebApi NuGet package. Then you can simply follow the instructions in the NuGet package to register your types and register your dependency resolver like the below:
using Unity.AspNet.WebApi;
config.DependencyResolver = new UnityDependencyResolver(container);
Link to NuGet package: https://github.com/unitycontainer/aspnet-webapi
You need to set up Unity as the dependency resolver for WebAPI.
Add the following NuGet package to your project: https://www.nuget.org/packages/Unity.WebAPI/
And then configure WebAPI to use the right resolver adding the following to your WebApiConfig.cs
GlobalConfiguration.Configuration.DependencyResolver = new UnityDependencyResolver(container);
This is 3 step process :
Register
Resolve
Link resolver to GlobalConfiguration
It appears you have not added resolving code and neither does above solutions.
Add this line before attaching DependencyResolver to GlobalConfiguration.
DependencyResolver.SetResolver(new UnityDependencyResolver(container));
I had the same problem. For me the solution to this exact error was that all other controllers constructors also was loaded at request time.
And one of them had not a valid parameter in the constructor. It was not registered with Unity.
So I got the resolution fail from Unity.
But after fixing that other controller everything worked fin.

Categories