How do I get access to INodeServices without dependency injection - c#

I'd like to run some node code from my c#. Microsoft.AspNetCore.NodeServices seems to be the way to do this job however the examples are all very similar and all involve putting
services.AddNodeServices();
in the configure services function and then DI adds the implementation of INodeServices to a controller. Like this
public class foo
{
private readonly INodeServices _nodeServices;
public foo(INodeServices nodeServices)
{
_nodeServices = nodeServices;
}
}
As I'm using this in a class library rather than a webapi how is DI going to work? Also how do I call the class from a unit test, what can I pass into the constructor? I'm sure I'm missing something obvious.

The concept of DI is that it can be used to resolve object graphs. That is, it doesn't just resolve dependencies of the Controller class, but dependencies of those dependencies, dependencies of those dependencies, etc.
To use INodeServices in your own library, you simply need to reference Microsoft.AspNetCore.NodeServices, then accept it as a constructor parameter.
public class MyServiceFromMyLibrary : IMyServiceFromMyLibrary
{
private readonly INodeServices nodeServices;
public MyServiceFromMyLibrary(INodeServices nodeServices)
{
this.nodeServices = nodeServices;
}
// ...
}
Then reference your library from the Web API project and inject your service into a controller.
public class FooController
{
private readonly IMyServiceFromMyLibrary myService;
public FooController(IMyServiceFromMyLibrary myService)
{
this.myService = myService;
}
}
DI takes care of putting the INodeServices instance into your class provided it is registered in your composition root, as follows.
services.AddNodeServices();
services.AddTransient<IMyServiceFromMyLibrary, MyServiceFromMyLibrary>();
If your end game is to create a reusable library rather than an application layer refer to DI Friendly Library for some techniques to make your library easier to use without the use of dependency injection.
Also how do I call the class from a unit test, what can I pass into the constructor?
For a unit test, you would just need to mock INodeServices. The simplest way is to use a mocking library, such as Moq.
var mock = new Mock<INodeServices>();
mock.Setup(ns => ns.InvokeAsync(It.IsAny<string>())).Returns(...);
var target = new MyServiceFromMyLibrary(mock.Object);
// .. Call a method on target and then assert the results
References:
Using Node Services in ASP.NET Core
Dependency injection in ASP.NET Core

Related

.NET Core - ILogger DI and Base Classes/Object Classes

I must be missing something on DI in .NET Core and I'd need your help.
I've been using DI successfully for my Service Classes, my Azure Client classes etc etc, but I can't understand how to get that working with my base classes (classes that just represent a basic object).
Let's say I have a vary simple class like
public class Person{
private readonly Ilogger<Person> logger;
public string name {get; set;}
public string lastname {get; set;}
public void LogYourName(){
logger.logInformation(this.name);
}
}
Also, let's say I have a HTTP rest API or another service that return as result an instance of Person.
How can I initiate ILogger in Person class without using DI?
The Microsoft Dependency Injection framework requires you to implement via the Constructor. You would need to do:
public class Person
{
private readonly ILogger logger;
public Person(ILogger logger) => this.logger = logger;
// Additional Code Here
}
When the object is constructed the framework will inject the logger instance for you. However, based on your above question- to avoid the the Dependency Injection would need to do:
var logger = services.GetService<ILogger>();
var person = new Person(logger);
The services would derive from IServiceProvider. I would need to see how you instantiate the IServiceCollection and populate your IServiceProvider. That would allow you to manually put the interface into the class while still using the Microsoft Dependency Injection framework.

access appsetting from data layer without creating instantiation with parameter

How can i access my "appsettings.js" values in Business/Data layer without creating instantiation in the constructor level.
I can access all values in the controller but i don't want to send to all my layers like passing constructor parameter.
I am trying to understand this post but i don't understand fully. can some one provide me some sample code with out creating instantiation
ASP.NET 5 DI app setting outside controller
Controller - Services - DBServices (without parameter constructor?)
appsetting.json
"DbSettings":{
"ConnectionString" : "TESTING Connection string here"
}
Controller:
public class TestController : ControllerBase
{
public TestController(IOptions<DbSettings> dbSettings)
{
_balService = new BALServices(dbSettings.Value); // passing parameter "dbsetting" to constructor which i don't want.
}
}
Startup.cs
services.Configure<DbSettings>(Configuration.GetSection("DbSettings"));
services.AddSingleton<IConfiguration>(Configuration);
Dbsettings.cs
public class DbSettings
{
public string ConnectionString { get; set; }
}
The framework isn’t really designed to allow you to do that. ASP.NET Core uses dependency injection and kind of forces you to follow it, since pretty much everything is inaccessible outside of the DI container. So whenever something depends on something, then it should make that dependency clear by expecting it in the constructor. That is the way it is designed.
That being said, you creating a new instance of BALServices isn’t really in the spirit of dependency injection either. If you want to use BALServices in the controller, then instead of creating an instance of it itself, the controller should just depend on that type.
So you would change the controller to look like this:
public class TestController : ControllerBase
{
private readonly BALServices _balService;
public TestController(BALServices balService)
{
_balService = balService;
}
}
Now, the controller does not need to worry about how it could possibly create that object. It just depends on it being there and letting someone else figure that out. And that’s exactly what dependency injection is about.
In order to make that work, of course you now need to adjust your BALServices to depend on those IOptions<DbSettings> instead:
public class BALServices
{
private readonly DbSettings _dbSettings;
public BALServices(IOptions<DbSettings> dbSettings)
{
_dbSettings = dbSettings.Value;
}
}
And then you only need to register this service in your Startup:
services.AddScoped<BALServices>();
And now you have TestController depend on the actual service it wants to use, and BALServices depend on the configuration it requires. And the DI container will automatically provide you with what you need.

How to use NLog in static class where everything else is wired with Autofac

My MVC app is wired with Autofac. I have also configured NLog which works as expected in my controller classes. My nLogger is registered as below:
var builder = new ContainerBuilder();
builder.RegisterGeneric(typeof(LoggerService<>))
.As(typeof(ILoggerService<>)).SingleInstance();
var container = builder.Build();
And the constructor of the ILoggerService is:
public LoggerService()
{
SourceClass = typeof (T).FullName;
Logger = LogManager.GetLogger(SourceClass);
}
Now I have also got many static helper classes that I use. For example:
public static class Helper
{
public static string GenerateQrBitmap(string secret, string issuer, string userEmail)
{
...
}
}
But I want to be able to use the logger in these Helper classes as well.
This is one of the reasons why static classes aren't great.
You have two options:
Make them not static (and register them with Autofac) and take
ILoggerService as a constructor parameter.
Change their methods
(e.g. GenerateQrBitmap) to take a ILoggerService as a parameter.
I'd suggest the former.
The alternative is to use the Service Locator pattern - and have Helper resolve directly against the container. I will not show you how to do this, since I don't recommend it. It makes the code harder to unit test, and it hides your dependencies. But if you Google Autofac Service Locator static class c# I'm sure you'll work it out.

Who instantiates the test class in a test class project?

I am writing some integration tests. I am using Dependency Injection with Windsor Castle.
I would like to resolve the test class using an inversion of control container. I do not think that resolve all my dependencies inside the test class is the solution for my case.
I would like to do what I have done inside the web api project. I implemented IHttpControllerActivator, which is an extension point to fully control controller's life-cycle. That is, we can define how a controller is instantiated.
I would like to do the same for the tests. But I do not understand which is the interface I have to implement. Can anyone help me?
I think I just need to know which is the corresponding IHttpControllerActivator for unit test.
EDIT
I have a web api project to test. The web api project resolves all the dependencies with WindsorCastle. Now I need to test the web api. This is what I am doing:
public voi MyTest_Ok()
{
//Arrange
var myController = new MyWebApiController();
var result = await myController.DoWork();
//Asserts
}
Obviously it does not work because I am not using castle windsor to resolve the controller and so I do not resolve any dependency from web api controller to bottom.
I think I could replace this line
var myController = new MyWebApiController();
with something like this
var myController = windsorContainer.Resolve<MyWebApiController>();
But this solution I think is wrong. I think it's better to resolve dependencies as happen inside the controller:
public class MyWebApiController : ApiController()
{
public InjectedDependency dep { get; set; }
public DoWork()
{
dep.DoWork();
}
}
I can do this because I have implemented a custom IHttpControllerActivator.
Answer is: your test framework does. As I know none of the common test frameworks allows you take control over creating your test classes.
More info about this here as well:
A .NET Unit Test without a parameterless constructor, to facilitate dependency injection
NUnit provide ParameterizedTestFixture -https://github.com/nunit/docs/wiki/TestFixtureData
So in theory as a dirty workaround you would be able to inject some dependencies trough constructor by this, but it wasn't designed for this purpose.
In general you have to go for service locator.

IoC and ASP.NET MVC Controllers

Should I do something along the lines of this? I'm thinking of all my controllers inheriting from BaseController. Does this break the design pattern of IoC? What else should I do instead?
public class BaseController: Controller
{
protected ICookieService CookieService {
get {
return ServiceResolver.Resolve<ICookieService>(new { HttpContext = HttpContext });
}
}
protected IDateTimeService DateTimeService {
get {
return ServiceResolver.Resolve<IDateTimeService>();
}
}
protected ISettingsService SettingsService {
get {
return ServiceResolver.Resolve<ISettingsService>();
}
}
}
It would be a lot simpler to go with constructor injection and have a controllerfactory inject it for you. If you can, don't use a service locator (your ServiceResolver ) if you can get away with constructor injection.
There's some info on it on Adding a controller factory to ASP MVC
The link shows how to do it with StructureMap and it looks like you're using Unity, but it should be straightforward to adapt.
I'm assuming that the protected interfaces you have are dependencies for the controller. Its possible to set up an IoC container to inject the dependencies for you. It can certainly be done with Castle Windsor. You would need to change you BaseController class to have a constructor with the required dependencies, as long as the IoC container knows about the other services it'll be able to inject them.
One of the principles behind Inversion of Control and Component-Driven Development is about using static service locators only when there is no other way (i.e.: in web service hosts or object data sources).
Technically speaking, using static service locators the base controller does not violate IoC, it just does not use it.
Check out existing integration between Autofac IoC container and ASP.NET MVC (other containers should be able to do that as well).

Categories

Resources