Dependency injection IOption class library - c#

I have a class library where I want to access a Connectionstring from appsettings.json.
appsettings.json :
"DatabaseSettings": {
"ConnectionString": "Server=.;Database=Test;Trusted_Connection=True;"
},
In startup.cs I have the following code:
public void ConfigureServices(IServiceCollection services)
{
services.Configure<DatabaseSettings>(Configuration.GetSection("DatabaseSettings"));
services.AddOptions();
services.AddTransient<IConnectionOption, Class1>();
}
And in class library
IConnectionOption.cs
public interface IConnectionOption
{
void ReadValue();
}
Class1.cs
public class Class1 : IConnectionOption
{
private readonly DatabaseSettings test;
public Class1(IOptions<DatabaseSettings> dbOptions)
{
test = dbOptions.Value;
}
public void ReadValue()
{
var r = test;
}
}
Now from index.cshtml I want to Invoke the class Library Class1
public class IndexModel : PageModel
{
public void OnGet()
{
Class1 test = new Class1();
test.ReadValue();
}
}
But of course that doesnt work since there are no Constructor taking zero parameters, I don´t think I should add IOptions as an parameter. But how do I invoke the class library to read the connectionstring? (When I get this to work I will of course read data and return instead of the connectionstring). I have looked at several examples including net core 2.1 Dependency injection
But I don´t understand how to use the class library directly, Is it necessary to use an controller ?!

If DatabaseSettings is accessible to the class library, there really is not much need for tightly coupling Class1 library to IOptions, which is more framework related.
Ideally Class1 can explicitly depend on DatabaseSettings via explicit constructor injection
public class Class1 : IConnectionOption {
private readonly DatabaseSettings test;
public Class1(DatabaseSettings settings) {
test = settings;
}
public void ReadValue() {
var r = test;
//...
}
}
then in Startup, the dependency can be extract from configuration and registered with the DI container
public void ConfigureServices(IServiceCollection services) {
var settings = Configuration.GetSection("DatabaseSettings").Get<DatabaseSettings>();
services.AddSingleton<DatabaseSettings>(settings);
services.AddTransient<IConnectionOption, Class1>();
}
That way when ever Class1 is resolved, the container will know how to inject the DatabaseSettings dependency.
Another option could have also been to use the factory delegate
public void ConfigureServices(IServiceCollection services) {
var settings = Configuration.GetSection("DatabaseSettings").Get<DatabaseSettings>();
services.AddTransient<IConnectionOption, Class1>(_ => new Class1(settings));
}
That way, when the IndexModel depends on IConnectionOption for injection.
public class IndexModel : PageModel {
private readonly IConnectionOption connectionOption;
public IndexModel(IConnectionOption iConnectionOption) {
connectionOption = iConnectionOption;
}
public void OnGet() {
connectionOption.ReadValue();
//...
}
}
the proper dependency will be injected when the page model is initialized.

You are using Dependency Injection but only halfway. This is what you are missing:
Register the service in the container (I'm going to assume a better name for Class1):
services.AddScoped<IConnectionOption, DatabaseConnectionOption>();
Make the page receive the service:
public class IndexModel : PageModel
{
private readonly IConnectionOption _IConnectionOption;
public IndexModel(IConnectionOption iConnectionOption)
{
_IConnectionOption = iConnectionOption;
}
public void OnGet()
{
_IConnectionOption.ReadValue();
}
}

Related

Derived Class How to inject ?

ASP.Net Core Web API
Does the parent class have no empty constructor
derived class Autofac injection ?
If the injection class is added after the parameter, it cannot be used
public class A
{
public A(string e1,string e2){}
}
public class B:A
{
private readonly IProductService _productService;
public B(IProductService productService):base(string e1,string e2)
{
_productService = productService
}
public void test()
{
_productService.AddProduct("");
}
}
AutoFac has no problem configuring
_productService exception occurred
You should try it like this:
public B(IProductService productService, string e1,string e2):base(e1,e2)
{
_productService = productService
}
And then configure Autofac like this for this class registration:
builder.Register(c => new B(c.Resolve<IProductService>(), "e1_val","e2_val"));
If the B class will implement an interface at some point you can use it like this also:
builder.RegisterType<B>().As<IB>()
.WithParameter("e1", "e1value")
.WithParameter("e2", "e2value");
Keep in mind that you have a lot of flexibility with Autofac, please check their documentation at: Autofac Parameters Register for even more information.

C# Dependency injection duplicating

I'm making an ASP.NET Core Razor Pages web application. In my application I use the following code:
public class MyClass
{
private readonly ApplicationDbContext _dbContext;
private readonly ICalendarService _calendarService;
public MyClass(ApplicationDbContext dbContext, ICalendarService calendarService)
{
_dbContext = dbContext;
_calendarService = calendarService;
}
public void MyFunction()
{
// here I need to use _dbContext and _calendarService
}
But when I use this class I need to do the following:
public class MySecondClass
{
private ImportIntoCalendar ImportHintSchedule;
public MySecondClass()
{
MyClass= new MyClass(_dbContext, _calendarService);
}
// Do something with variable ImportHintSchedule
ImportHintschedule.Function()
}
Everytime I need to add the dbcontext and the calendarservice into the parameters. So both need to be available in the other class. This feels like I'm doing something stupid, like I'm duplicating the same step. Does anybody know a better way to do this. Or is this just fine?
Edit:
I have this line in my startup.cs
services.AddScoped<ICalendarService, CalendarService>();
In your ConfigureServices you can add the IOC scopes.
For example, something like this. I don't know all of your code so the is just an example.
services.AddScoped<ICalendarService, CalendarService>();
services.AddScoped<IApplicationDbContext, ApplicationDbContext>();
You can also add singletons if that meets your needs as well.
Here is an example singleton call I use in my application
services.AddSingleton<IRepository<BaseItem>>(x => new Repository<BaseItem>(Configuration["MongoConnection:DefaultConnection"]));
I would suggest to create an Interface of your class, something like:
public interface IMyClass {
void MyFunction();
}
Then, implement that in your class:
public class MyClass : IMyClass {
private readonly ApplicationDbContext _dbContext;
private readonly ICalendarService _calendarService;
public MyClass(ApplicationDbContext dbContext, ICalendarService calendarService)
{
_dbContext = dbContext;
_calendarService = calendarService;
}
public void MyFunction()
{
// here I need to use _dbContext and _calendarService
}
}
And the add that to injector:
public void ConfigureServices(IServiceCollection services)
{
// existing code
services.AddTransient<IMyClass, MyClass>();
}
and finally use IMyClass in Controller constructor.
public class MyController:Controller
{
private IMyInterface _myClass;
public MyController(IMyInterface myclass) {
_myClass = myClass;
}
public IActionResult MyAction() {
_myClass.MyFunction();
return View();
}
}

asp.net core dependency passing dependencies along

I'm trying to inject a dependency into a class used internally in a controller,
I have
//Startup.cs
public void ConfigureServices(IServiceCollection services){
services.AddMvc();//IDocumentService is a WCF service from our legacy stack
services.AddScoped(typeof(IDocumentService),typeof(DocumentServiceClient));
}
//Controller.cs
[Route("api/eci/test/[action]")]
public class Controller{
private IDocumentService injectedDocService;
public Controller(IDocumentService client){
injectedDocService=client;
}
[HttpPost({"id"})]
public void ingestedDocs(string id){
new Logic(injectedDocService).ingest(id);
}
}
//Logic.cs
public class Logic{
private IDocumentService injectedDocServiceActualTarget;
public Logic(IDocumentService injected2){
injectedDocServiceActualTarget=injected2;
}
public void injest(string id){
injectedDocServiceActualTarget.doWork(id);
}
}
It seems a little redundant to have it injected to the target class's parent. Is this the right way of doing things?
You need to register the Logic, then inject it to the controller. DocumentService will be injected to the Logic then.
The idea behind dependency injection is to implement the IoC (inversion of control) principle. In your example, it is only partial, since you explicitly instantiate Logic in your controller. If you want to do the dependency inversion properly - all your dependencies need to be passed as constructor parameters.
You should abstract the Logic behind an interface, only exposing the members that are to be used by dependents.
public interface ILogic {
void injest(string id);
}
Have the Logic class derive from the abstraction.
//Logic.cs
public class Logic : ILogic {
private readonly IDocumentService injectedDocServiceActualTarget;
public Logic(IDocumentService injected2) {
this.injectedDocServiceActualTarget=injected2;
}
public void injest(string id) {
injectedDocServiceActualTarget.doWork(id);
}
}
The Controller should now only explicitly depend on the ILogic interface
//Controller.cs
[Route("api/eci/test/[action]")]
public class Controller {
private readonly ILogic service;
public Controller(ILogic service) {
this.service = service;
}
[HttpPost({"id"})]
public void ingestedDocs(string id) {
service.ingest(id);
}
}
With that the last thing to do is to register all dependencies with the service collection.
//Startup.cs
public void ConfigureServices(IServiceCollection services){
services.AddMvc();
services.AddScoped<IDocumentService, DocumentServiceClient>();
services.AddScoped<ILogic, Logic>();
}
So now when the controller is called all dependencies will be resolved and injected into their respective dependents.

How do i get values from appsettings.json to BusinessLayer(my helper class) MVC 6

My controller which returns user details by calling an API intern
public class HomeController : Controller
{
public ActionResult AccountDetails(int userId)
{
return this.Content(new WebHelperService().GetAccountDetails(userId)), "application/json");
}
}
Here is my WebHelperService which is in Business Layer, where i need to get value from appsettings.json
public class WebHelperService
{
private string url = null;
public WebHelperService()
{
//url = ConfigurationManager.ConnectionString["ExternalApiUrl"].ToString();
// ConfigurationManager is not available in .net core.
//So How do i read ExternalApiUrl from appsettings.josn,Which is the best way
}
public string GetAccountDetails(int userId)
{
return WebCall("{'userId':" + userId + "}");
}
private string WebCall(string data)
{
WebRequest request = WebRequest.Create(url);
// get the data from url and returns it
}
}
Do I need to carry settings all the way from controller in mvc6?
Reference : learn.microsoft.com/en-us/aspnet/core/mvc/con..)
Let's forget for a moment your particular use case and just talk about settings in .net core in general. Importantly, I think you are trying to access the raw AppSettings from your class, but what you actually want to do is DI them into your class. So let's do that.
Consider you have a appSettings.json that resembles something like below :
{
"myConfiguration": {
"myProperty": true
}
}
Now you need to create a POCO to hold these settings. Something like so :
public class MyConfiguration
{
public bool MyProperty { get; set; }
}
In your startup.cs you should have a method called "ConfigureServices". In there you are going to place a call to "configure" your settings like so.
public void ConfigureServices(IServiceCollection services)
{
services.Configure<MyConfiguration>(Configuration.GetSection("myConfiguration"));
}
And so now you want to inject that settings object into a class. Let's call it MyClass for now. It would look like the following :
public class MyClass : IMyClass
{
private readonly MyConfiguration _myConfiguration;
public MyClass(IOptions<MyConfiguration> myConfiguration)
{
_myConfiguration = myConfiguration.Value;
}
}
Now you have access to your configuration!
Bonus!
Instead you can make your ConfigureServices method look like the following :
public void ConfigureServices(IServiceCollection services)
{
//services.Configure<MyConfiguration>(Configuration.GetSection("myConfiguration"));
services.AddSingleton(Configuration.GetSection("myConfiguration").Get<MyConfiguration>());
}
What this now does is bind your services onto an actual class, not the IOptions object.
Now when you inject it into your class, you instead inject the POCO settings class, not IOptions. Like so :
public class MyClass : IMyClass
{
private readonly MyConfiguration _myConfiguration;
public MyClass(MyConfiguration myConfiguration)
{
_myConfiguration = myConfiguration;
}
}
For further reading :
http://dotnetcoretutorials.com/2016/12/26/custom-configuration-sections-asp-net-core/
https://learn.microsoft.com/en-us/aspnet/core/fundamentals/configuration

Dependency Injection of configuration class into static Document DB repository (VS2015 DNX project)

I have a base Document DB repository in the infrastructure layer of my solution. I based this repository on this GitHub project, which is a static class that is utilized by my other domain model repositories.
In my API layer I have config.json files that are environment specific. I would like to use dependency injection to be able to use my configuration class that reads the DocumentDB settings defined in the API layer in the deeper Infrastructure layer. This StackOverflow answer details how to use DI with an API controller, however I can't figure out how to use DI in this case, as a static class, I don't have a constructor. Is it possible to use DI with my static repository? If not, how should I read config settings into the infrastructure layer?
My ConfigurationOptions class (in Infrastructure layer):
public class ConfigurationOptions
{
public string EndpointUri { get; set; }
}
My DocumentDbRepository class (in Infrastructure layer):
public static class DocumentDbRepository<T>
{
// I want to read these strings from my config.json files
private static string EndpointUri { get; } = ConfigurationOptions.EndpointUri;
//...
private static Document GetDocument(string id)
{
return Client.CreateDocumentQuery(Collection.DocumentsLink)
.Where(d => d.Id == id)
.AsEnumerable()
.FirstOrDefault();
}
}
Part of my Startup class (in my API layer)
public class Startup
{
public IConfiguration Configuration { get; set; }
public void ConfigureServices(IServiceCollection services)
{
services.Configure<ConfigurationOptions>(options =>
options.EndpointUri = Configuration.Get("EndpointUri"));
// ...
}
// ...
}
I believe you are almost there.
The first step you have to take is almost done.
in your startup.cs, you have
services.Configure<ConfigurationOptions>(options =>
options.EndpointUri = Configuration.Get("EndpointUri"));
you can just call
services.Configure<ConfigurationOptions>(Configuration);
the services will map the EndpointUri attribute of your class. With this step 1 is done.
Now, following the post you linked, you can send your configurationOptions to the controller like:
public class SomeController
{
private string _endpointUrl;
public SomeController(IOptions<ConfigurationOptions> options)
{
_endpointUrl = options.Options.EndpointUri;
}
}
but, from what i assume, you want to have the EndpointUri in the DocumentDbRepository. You can do that in 2 ways:
1 --------------------------------------------------
You can create a constructor in your DocumentDbRepository to receive the EndpointUri and call it in your controller like such:
public class SomeController
{
private DocumentDbRepository _documentDbRepositoy
public SomeController(IOptions<ConfigurationOptions> options)
{
_documentDbRepositoy = new DocumentDbRepository (options.Options.EndpointUri);
}
}
2 ---------------------------------------------------
You can inject the DocumentDbRepository to all your controllers. For that i suggest that you create an interface IDocumentDbRepository and then configure it at startup making it a singleton or scoped or trasiend (for more info, see this link)
To do so, lets start with your DocumentDbRepository
public static class DocumentDbRepository<T> : IDocumentDbRepository<T>
{
private string EndpointUri { get; private set;}
public DocumentDbRepository(IOptions<ConfigurationOptions> options){
EndpointUri = options.Options.EndpointUri;
}
//...
}
then, at startup.cs you set it as singleton (in this example)
public void ConfigureServices(IServiceCollection services){
services.Configure<ConfigurationOptions(Configuration);
services.AddSingleton<IDocumentDbRepository, DocumentDbRepository>();
// ...
}
by doing this, if your controllers have a dependency on a IDocumentDbRepository, the singleton will be provided:
public class SomeController
{
private DocumentDbRepository _documentDbRepositoy
public SomeController(IDocumentDbRepository documentDbRepository)
{
_documentDbRepositoy = documentDbRepository
}
}

Categories