AspNet Core 1.1 Inject IOptions into a class - asp.net-core

I am using the Options pattern in my AspNet Core 1.1 application. Everything is set according to the documentation:
public Startup(IHostingEnvironment env)
{
var builder = new ConfigurationBuilder()
.SetBasePath(env.ContentRootPath)
.AddJsonFile("appsettings.json", optional: false, reloadOnChange: true)
.AddJsonFile($"appsettings.{env.EnvironmentName}.json", optional: true)
.AddEnvironmentVariables();
Configuration = builder.Build();
}
public void ConfigureServices(IServiceCollection services)
{
...
services.Configure<AppOptions>(Configuration);
...
}
I would like to inject the AppOptions class into a service that I am creating:
public class MyService
{
private readonly AppOptions options;
public MyService(IOptions<AppOptions> optionsAssesor)
{
options = optionsAssesor.Value;
}
...
}
My questions is: when I try to create an instance of the MyService class like:
MyService svc = new MyService();
I am getting an error saying that There is no argument given that corresponds to the required formal parameter optionsAssesor How can I take advantage of the DI and inject the AppOptions into my service?
I am kind of new to .NET Core so I am guessing I am missing something simple, but I cannot figure out what.
Thank you.

I am assuming that Service (MyService) is within scope of ASP.net core project.
You have to do following Thing.
public void ConfigureServices(IServiceCollection services)
{
services.AddScoped<MyService>();
... other things
}
Now Suppose that you are using your service ( or you want to use your service some controller then you have to do
public class HomeController : Controller
{
private MyService _myService = null;
public HomeController(MyService service)
{
_myService = service;
}
// now you can use _myService in your controller method.
}
Every thing like you have to go through Dependency.
Update 1
Now suppose you want to use it in another class then you can do like this.
For example another class is MyClass1.
public class MyClass1
{
private MyService _myService = null;
public MyClass1(MyService service)
{
_myService = service;
}
}
Now if I am thinking correct then if you are using ASP.net core then MyClass1 one way or other it will use by Controller. You have to register dependency for this.
services.AddScoped<MyClass1>(); // This should be in your ConfigureServices.

It depends on where you are trying to get an instance of MyService from. Basically you need to get a reference to the services collection (and register MyService in DI as well in startup), build a service provider, and then get the service. This will allow DI to construct an instance of MyService and pass it in an instance of AppOptions.
For example:
var provider = serviceCollection.BuildServiceProvider();
var myService = provider.GetService<MyService>();
That being said, in most places in ASP.NET Core you don't need to do this and are better off getting an instance of MyService through the Controller / Middleware constructor without having to build a Service Provider on your own.
You should look at the Microsoft Docs on Dependency Injection in ASP.NET core to further understand the different Service Lifetimes.

Related

Service Injected on startup is null in Extension Service Configuration aspnet core

Service Injected on startup is null in Extension Service Configuration ASP.NET Core
We have one service for userservice to save user profiles and it is injected as scoped on startup.
In our extension, we add another service for students as singleton to insert update delete users' transactions. We want student info from userservice but in our student service it showing null.
In Startup.
services.AddMemoryCache();
services.AddSingleton<ITempDataProvider, CookieTempDataProvider>();
services.TryAddSingleton<IHttpContextAccessor, HttpContextAccessor>();
services.AddScoped<IUserService, UserService>();
In Extension
public void Execute(IServiceCollection serviceCollection, IServiceProvider serviceProvider)
{
serviceCollection.AddMvc();
serviceCollection.AddSingleton<IStudenService, StudenService>();
}
In Student Service
public class StudentSerivce : IStudentSerivce
{
private readonly IUserService _userService;
public StudentSerivce(IUserService userService)
{
_userService = userService; // is null
}
}
You could try this:
public StudentService(IServiceProvider services)
{
Services = services;
}
public IServiceProvider Services { get; }
public void SomeMethod()
{
using (var scope = Services.CreateScope())
{
var userService = scope.ServiceProvider.GetRequiredService<IUserService>();
// Do Something
}
}
It would probably be better to make them both scoped or both singletons (then it would work without manually creating a scope).
It's dangerous to resolve a scoped service from a singleton. It may cause the service to have incorrect state when processing subsequent requests.
Reference: Dependency injection in ASP.NET Core

Simplified approach to IOptions<T>

I am trying to get a .NET Framework class library in line with an ASP.NET Core 2.1 application while using builtin DI mechanism. Now, I created a config class and added appropriate section to appsettings.json:
services.Configure<MyConfig>(Configuration.GetSection("MyConfiguration"));
services.AddScoped<MyService>();
In class lib:
public class MyService
{
private readonly MyConfig _config;
public MyService(IOptions<MyConfig> config)
{
_config = config.Value;
}
}
However, in order to build this classlib I have to add Microsoft.Extensions.Options NuGet package. The problem is that package carries a hell of a lot of dependencies which seem rather excessive to add just for the sake of one interface.
So, the question ultimately is, "is there another approach I can take to configure a DI service located in .NET Framework class library which is not dependency heavy?
Check this article written by Filip Wojcieszyn.
https://www.strathweb.com/2016/09/strongly-typed-configuration-in-asp-net-core-without-ioptionst/
You add extension method:
public static class ServiceCollectionExtensions
{
public static TConfig ConfigurePOCO<TConfig>(this IServiceCollection services, IConfiguration configuration) where TConfig : class, new()
{
if (services == null) throw new ArgumentNullException(nameof(services));
if (configuration == null) throw new ArgumentNullException(nameof(configuration));
var config = new TConfig();
configuration.Bind(config);
services.AddSingleton(config);
return config;
}
}
Apply it in configuration:
public void ConfigureServices(IServiceCollection services)
{
services.AddMvc();
services.ConfigurePOCO<MySettings>(Configuration.GetSection("MySettings"));
}
And then use it:
public class DummyService
{
public DummyService(MySettings settings)
{
//do stuff
}
}
I bumped into this problem a little while ago, if you can even call it a problem really. I think we all tend to get a little shell-shocked when we see a dependency list like that. But as #Tseng mentioned, it's really not a big deal to include a bunch of extra tiny assemblies (they'll be included in the bin already anyways by virtue of a reference in another project). But I will admit it's annoying to have to include them just for the options interface.
How I solved it was by resolving the service dependency in startup.cs and adjust the service's constructor accordingly:
services.AddTransient<MyService>(Configuration.GetConfiguration("MyConfiguration"));
If you don't care about whatever IOptions provides you, why not just inject IConfiguration into your service?
public class MyService
{
private readonly IConfiguration _config;
public MyService(IConfiguration config)
{
_config = config;
}
public void DoSomething()
{
var value = _config["SomeKey"];
// doing something
}
}

How to pass IOptions through Dependency injection to another Project

I have a WebApplication targetting .net core.
I have also created a Class Library targetting .net core as well.
I am creating a Users Repository following this Dapper tutorial Here
It would be nice to be able to provide the option that was injected in start up of the WebApplication into the project that will be the data access layer.
Here is the code for the Users Repository in a separate project.
class UsersRepository
{
private readonly MyOptions _options;
private string connectionString;
public UsersRepository(IOptions iopt/// insert Option here )
{
_options = iopt.Value;
connectionString = _options.connString;
}
public IDbConnection Connection
{
get
{
return new SqlConnection(connectionString);
}
}
The WebApplication Project Startup looks as follows.
public class Startup
{
public void ConfigureServices(IServiceCollection services)
{
services.AddOptions();
services.Configure<MyOptions>(Configuration);
services.AddMvc();
}
and of course MyOptions is a class in the web application that has only one property connString
One possible design is to make a new interface for your repository configuration inside your class library, and have your MyOptions type implement that interface.
For example, in your class library you can do the following:
public interface IRepositoryConfig
{
string ConnectionString { get; }
}
public class UserRepository
{
public UserRepository(IRepositoryConfig config)
{
// setup
}
}
And in your WebAPI Startup class you can wire this up as follows:
public void ConfigureServices(IServiceCollection services)
{
services.AddOptions();
services.Configure<MyOptions>(Configuration);
services.AddMvc();
services.AddScoped<IRepositoryConfig>(s =>
s.GetService<IOptions<MyOptions>>().Value
);
services.AddScoped<UserRepository>();
}
Doing this will allow you to use the Asp.Net Core configuration/options framework without having to reference any Asp.Net DLLs in your class library directly.

Autofac inject into ValidationAttribute on WebApi and OWIN

There's a few posts on SO relating to the work around for allowing autofac injections with ValidationAttribute 's (Asp.Net MVC3: Set custom IServiceProvider in ValidationContext so validators can resolve services) but I'm using OWIN and WebApi so I'm not sure if this is possible?
All other dependency injection is working fine.
DependencyResolver isn't populated in OWIN and I remember reading a difference in how OWIN handles injections for the validation requests. Does anyone know if Autofac, OWIN, WebApi and ValidationAttribute 's are possible? And, with specific examples?
You need to register the Autofac middleware and then you need to extend it to the WebApi. Now you can use the Autofac resolution inside the OWIN middleware.
// Register the Autofac middleware FIRST.
app.UseAutofacMiddleware(container);
// extend the autofac scope to the web api
app.UseAutofacWebApi(HttpConfiguration);
After this, WebApi and OWIN middleware will share the same resolution context, and you can do whatever you want.
For the ValidationAttribute thing you can, for example, do something like this:
public class AppStartup
{
public void Configuration(IAppBuilder app)
{
// Get your HttpConfiguration. In OWIN, you'll create one
// rather than using GlobalConfiguration.
var config = new HttpConfiguration();
//Set builder
var builder = new ContainerBuilder();
//IoC container build
var container = builder.Build();
app.UseAutofacMiddleware(container);
app.UseAutofacWebApi(HttpConfiguration);
WebApiConfig.Register(HttpConfiguration);
app.UseWebApi(HttpConfiguration);
}
}
and then
public override bool IsValid(object value)
{
var dependencyResolver = (AutofacWebApiDependencyResolver)GlobalConfiguration.Configuration.DependencyResolver;
using (var lifetimeScope= dependencyResolver.BeginScope())
{
var foo = lifetimeScope.Resolve<Foo>();
// use foo
}
}

Ninject for Asp.net Web API

I got this error when using Ninject with Web API, but it works with MVC Controller:
Type 'App.Web.Controllers.ProductController' does not have a default constructor
NinjectControllerFactory :
public class NinjectControllerFactory : DefaultControllerFactory
{
private IKernel ninjectKernel;
public NinjectControllerFactory()
{
ninjectKernel = new StandardKernel();
AddBindings();
}
protected override IController GetControllerInstance(RequestContext requestContext, Type controllerType)
{
return controllerType == null ? null : (IController)ninjectKernel.Get(controllerType);
}
public void AddBindings()
{
ninjectKernel.Bind<IProductRepository>().To<EFProductRepository>();
}
}
Global.asax.cs :
BundleConfig.RegisterBundles(BundleTable.Bundles);
ControllerBuilder.Current.SetControllerFactory(new NinjectControllerFactory());
ProductController :
public class ProductController : ApiController
{
private IProductRepository repository;
public ProductController(IProductRepository ProducteRepository)
{
this.repository = ProductRepository;
}
public IEnumerable<Product> GetAllProducts()
{
return repository.Products.AsEnumerable();
}
}
You have overriden the DefaultControllerFactory. But this is used to instantiate ASP.NET MVC controllers (one deriving from System.Web.Mvc.Controller). It has strictly nothing to do with ASP.NET Web API controllers (the ones deriving from System.Web.Http.ApiController).
So basically what you have done here is dependency injection into ASP.NET MVC. If you want to use this for the Web API you may take a look at the following guides:
http://www.strathweb.com/2012/05/using-ninject-with-the-latest-asp-net-web-api-source/
http://www.peterprovost.org/blog/2012/06/19/adding-ninject-to-web-api/
You should use the latest Ninject Web API package, which solves these problems already. See here: http://nuget.org/packages/Ninject.Web.WebApi.WebHost/
You need to set DependencyResolver property of the HttpConfiguration. What you have done was for ASP.NET MVC and not ASP.NET Web API.
So get the NuGet package and set DependencyResolver:
var kernel = new StandardKernel();
// use kernel to register your dependencies
var dependencyResolver = new NInjectResolver(kernel);
config.DependencyResolver = dependencyResolver; // config is an instance of HttpConfiguration based on your hosting scenario