Giter Club home page Giter Club logo

nanoframework.dependencyinjection's Introduction

Quality Gate Status Reliability Rating License NuGet #yourfirstpr Discord

nanoFramework logo


Welcome to the .NET nanoFramework Dependency Injection Library repository

Provides Dependency Injection (DI) for Inversion of Control (IoC) between classes and their dependencies built for .NET nanoFramework.

Build status

Component Build Status NuGet Package
nanoFramework.DependencyInjection Build Status NuGet

Samples

Dependency Injection Samples

Dependency Injection Unit Tests

Dependency Injection Container

A Dependency Injection (DI) Container provides functionality and automates many of the tasks involved in Object Composition, Interception, and Lifetime Management. It's an engine that resolves and manages object graphs. These DI Containers depend on the static information compiled into all classes. Then using reflection they can analyze the requested class and figure out which Dependencies are required.

This API mirrors as close as possible the official .NET DependencyInjection. Exceptions are mainly derived from the lack of generics support in .NET nanoFramework.

The .NET nanoFramework Generic Host provides convenience methods for creating dependency injection (DI) application containers with preconfigured defaults.

Usage

Service Collection

Creating a dependency injection container required three basic components.

  • Object Composition - A object composition defining a set of objects to create and couple.
  • Registering Services - Define an instance of the ServiceCollection and register the object composition with a specific service lifetime.
  • Service Provider - Creating a service provider to retrieve the object.

Object Composition

Define an object composition to create and couple.

Note: You can not currently define your objects as 'struct' or include array type parameters (ie. byte[] bytes) as constructor parameters. Doing so will create a null execption when trying to activate object.

public class RootObject
{
    public int One { get; }
    
    public string Two { get; }

    public ServiceObject ServiceObject { get; protected set; }

    public RootObject(ServiceObject serviceObject)
    {
        ServiceObject = serviceObject;
    }

    // constructor with the most parameters will be used for activation
    public RootObject(ServiceObject serviceObject, int one, string two)
    {
        ServiceObject = serviceObject;
        One = one;
        Two = two;
    }
}

public class ServiceObject
{
    public string Three { get; set; }
}

Registering Services

Create a Service Collection and register singleton or transient type services to the collection.

var serviceProvider = new ServiceCollection()
    .AddSingleton(typeof(ServiceObject))
    .AddSingleton(typeof(RootObject))
    .BuildServiceProvider();

Service Provider

Create a Service Provider to access or update an object.

var service = (RootObject)serviceProvider.GetService(typeof(RootObject));
service.ServiceObject.Three = "3";

Create a scoped Service Provider providing convient access to crate and distroy scoped object.

var serviceProvider = new ServiceCollection()
    .AddScoped(typeof(typeof(ServiceObject))
    .BuildServiceProvider();

using (var scope = serviceProvider.CreateScope())
{
    var service = scope.ServiceProvider.GetServices(typeof(ServiceObject));
    service.ServiceObject.Three = "3";
}

Activator Utilities

An instance of an object can be created by calling its constructor with any dependencies resolved through the service provider. Automatically instantiate a type with constructor arguments provided from an IServiceProvider without having to register the type with the DI Container.

var instance = (RootObject)ActivatorUtilities.CreateInstance(
                        serviceProvider, typeof(RootObject), 1, "2"
                    );

Debug.WriteLine($"One: {instance.One}");
Debug.WriteLine($"Two: {instance.Two}");
Debug.WriteLine($"Three: {instance.ServiceObject.Three}");
Debug.WriteLine($"Name: {instance.ServiceObject.GetType().Name}");

Validate On Build

A check is performed to ensure that all services registered with the container can actually be created. This can be particularly useful during development to fail fast and allow developers to fix the issue. Validate on build is configured false by default.

var serviceProvider = new ServiceCollection()
    .AddSingleton(typeof(IServiceObject), typeof(ServiceObject))
    .BuildServiceProvider(new ServiceProviderOptions() { ValidateOnBuild = true });

Validate Scopes

A check verifying that scoped services never gets resolved from root provider. Validate on build is configured false by default.

var serviceProvider = new ServiceCollection()
    .AddSingleton(typeof(IServiceObject), typeof(ServiceObject))
    .BuildServiceProvider(new ServiceProviderOptions() { ValidateScopes = true });

Example Application Container

using System;
using System.Device.Gpio;
using System.Threading;

using nanoFramework.Logging.Debug;
using nanoFramework.DependencyInjection;

using Microsoft.Extensions.Logging;

nanoFramework.DiApplication
{
    public class Program
    {
        public static void Main()
        {
            var services = ConfigureServices();
            var application = (Application)services.GetRequiredService(typeof(Application));

            application.Run();
        }

        private static ServiceProvider ConfigureServices()
        {
            return new ServiceCollection()
                .AddSingleton(typeof(Application))
                .AddSingleton(typeof(IHardwareService), typeof(HardwareService))
                .AddSingleton(typeof(ILoggerFactory), typeof(DebugLoggerFactory))
                .BuildServiceProvider();
        }
    }

    internal class Application
    {
        private readonly ILogger _logger;
        private readonly IHardwareService _hardware;
        private readonly IServiceProvider _provider;

        public Application(
            IServiceProvider provider,
            IHardwareService hardware, 
            ILoggerFactory loggerFactory)
        {
            _provider = provider;
            _hardware = hardware;
            _logger = loggerFactory.CreateLogger(nameof(Application));

            _logger.LogInformation("Initializing application...");
        }

        public void Run()
        {
            var ledPin = 23; // Set pin number to blink 15=ESP32; 23=STM32

            _logger.LogInformation($"Started blinking led on pin {ledPin}.");
            _hardware.StartBlinking(ledPin);
        }
    }

    internal interface IHardwareService
    {
        public void StartBlinking(int ledPin) { }
    }

    internal class HardwareService : IHardwareService, IDisposable
    {
        private Thread _thread;
        private readonly ILogger _logger;
        private readonly GpioController _gpioController;

        public HardwareService()
        {
            _gpioController = new GpioController();

            var loggerFactory = new DebugLoggerFactory();
            _logger = loggerFactory.CreateLogger(nameof(HardwareService));
        }

        public HardwareService(ILoggerFactory loggerFactory)
        {
            _gpioController = new GpioController();
            _logger = loggerFactory.CreateLogger(nameof(HardwareService));
        }

        public void StartBlinking(int ledPin)
        {
            GpioPin led = _gpioController.OpenPin(ledPin, PinMode.Output);
            led.Write(PinValue.Low);

            _thread = new Thread(() =>
            {
                while (true)
                {
                    Thread.Sleep(2000);

                    led.Write(PinValue.High);
                    _logger.LogInformation("Led status: on");

                    Thread.Sleep(2000);

                    led.Write(PinValue.Low);
                    _logger.LogInformation("Led status: off");
                }
            });

            _thread.Start();
        }

        public void Dispose()
        {
            _gpioController.Dispose();
        }
    }
}

Feedback and documentation

For documentation, providing feedback, issues and finding out how to contribute please refer to the Home repo.

Join our Discord community here.

Credits

The list of contributors to this project can be found at CONTRIBUTORS.

License

The nanoFramework Class Libraries are licensed under the MIT license.

Code of Conduct

This project has adopted the code of conduct defined by the Contributor Covenant to clarify expected behaviour in our community. For more information see the .NET Foundation Code of Conduct.

.NET Foundation

This project is supported by the .NET Foundation.

nanoframework.dependencyinjection's People

Contributors

bytewizer avatar corycharlton avatar ellerbach avatar github-actions[bot] avatar jazzman55 avatar josesimoes avatar nfbot avatar

Stargazers

 avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar

Watchers

 avatar  avatar  avatar  avatar  avatar  avatar  avatar

Recommend Projects

  • React photo React

    A declarative, efficient, and flexible JavaScript library for building user interfaces.

  • Vue.js photo Vue.js

    ๐Ÿ–– Vue.js is a progressive, incrementally-adoptable JavaScript framework for building UI on the web.

  • Typescript photo Typescript

    TypeScript is a superset of JavaScript that compiles to clean JavaScript output.

  • TensorFlow photo TensorFlow

    An Open Source Machine Learning Framework for Everyone

  • Django photo Django

    The Web framework for perfectionists with deadlines.

  • D3 photo D3

    Bring data to life with SVG, Canvas and HTML. ๐Ÿ“Š๐Ÿ“ˆ๐ŸŽ‰

Recommend Topics

  • javascript

    JavaScript (JS) is a lightweight interpreted programming language with first-class functions.

  • web

    Some thing interesting about web. New door for the world.

  • server

    A server is a program made to process requests and deliver data to clients.

  • Machine learning

    Machine learning is a way of modeling and interpreting data that allows a piece of software to respond intelligently.

  • Game

    Some thing interesting about game, make everyone happy.

Recommend Org

  • Facebook photo Facebook

    We are working to build community through open source technology. NB: members must have two-factor auth.

  • Microsoft photo Microsoft

    Open source projects and samples from Microsoft.

  • Google photo Google

    Google โค๏ธ Open Source for everyone.

  • D3 photo D3

    Data-Driven Documents codes.