Umbraco CMS
CloudHeartcoreDXPMarketplace
14.latest
14.latest
  • Umbraco CMS Documentation
  • Legacy Documentation
    • Our Umbraco
    • GitHub
  • Release Notes
  • Contribute
  • Sustainability Best Practices
  • Fundamentals
    • Get to know Umbraco
    • Setup
      • Requirements
      • Installation
        • Install using .NET CLI
        • Running Umbraco in Docker using Docker Compose
        • Install using Visual Studio
        • Local IIS With Umbraco
        • Install using Visual Studio Code
        • Installing Nightly Builds
        • Running Umbraco on Linux/macOS
        • Unattended Installs
      • Upgrade your project
        • Version Specific Upgrades
          • Upgrade from Umbraco 8 to the latest version
          • Migrate content to Umbraco 8
          • Minor upgrades for Umbraco 8
          • Upgrade to Umbraco 7
          • Minor upgrades for Umbraco 7
      • Server setup
        • Running Umbraco On Azure Web Apps
        • Hosting Umbraco in IIS
        • File And Folder Permissions
        • Runtime Modes
        • Umbraco in Load Balanced Environments
          • Load Balancing Azure Web Apps
          • Standalone File System
          • Advanced Techniques With Flexible Load Balancing
          • Logging With Load Balancing
    • Backoffice
      • Sections
      • Property Editors
        • Built-in Property Editors
          • Checkbox List
          • Collection
          • Color Picker
          • Content Picker
          • Document Picker
          • DateTime
          • Date
          • Decimal
          • Email Address
          • Eye Dropper Color Picker
          • File Upload
          • Image Cropper
          • Label
          • Markdown Editor
          • Media Picker
          • Member Group Picker
          • Member Picker
          • Multi Url Picker
          • Repeatable Textstrings
          • Numeric
          • Radiobutton List
          • Slider
          • Tags
          • Textarea
          • Textbox
          • Toggle
          • User Picker
          • Block Editors
            • Block Grid
            • Block List
          • Dropdown
          • Rich Text Editor
            • Rich Text Editor Configuration
            • Rich Text Editor Styles
            • Rich Text Editor Plugins
            • Blocks in Rich Text Editor
      • Login
      • Document Blueprints
      • Sidebar
      • Log Viewer
      • Language Variants
      • Settings Dashboards
    • Data
      • Defining Content
        • Default Document Types
        • Document Type Localization
      • Creating Media
        • Default Data/Media Types
      • Members
      • Data Types
        • Default Data Types
      • Scheduled Publishing
      • Using Tabs
      • Users
      • Relations
      • Dictionary Items
      • Content Version Cleanup
    • Design
      • Templates
        • Basic Razor Syntax
        • Razor Cheatsheet
      • Rendering Content
      • Rendering Media
      • Partial Views
      • Stylesheets And JavaScript
    • Code
      • Service APIs
      • Subscribing To Notifications
      • Creating Forms
      • Debugging
        • Logging
      • Source Control
  • Implementation
    • Learn how Umbraco works
    • Routing
      • Controller & Action Selection
      • Execute Request
      • Request Pipeline
    • Custom Routing
      • Adding a hub with SignalR and Umbraco
    • Controllers
    • Data Persistence (CRUD)
    • Composing
    • Integration Testing
    • Nullable Reference Types
    • Services and Helpers
      • Circular Dependencies
    • Unit Testing
  • Customizing
    • Extend and customize the editing experience
    • Project Bellissima
    • Setup Your Development Environment
      • Vite Package Setup
    • Foundation
      • Working with Data
        • Repositories
        • Context API
        • Store
        • States
      • Contexts
        • Property Dataset Context
      • Umbraco Element
        • Controllers
          • Write your own controller
      • Sorting
      • Routes
      • Icons
      • Backoffice Localization
      • Terminology
    • Extension Overview
      • Extension Registry
        • Extension Registration
        • Extension Manifest
      • Extension Types
        • Menu
        • Header Apps
        • Icons
        • Modals
          • Confirm Dialog
          • Custom Modals
          • Route Registration
        • Bundle
        • Kind
        • Backoffice Entry Point
        • Extension Conditions
        • Dashboards
        • Entity Actions
        • Entity Bulk Actions
        • Entity Create Option Action
        • Trees
        • Global Context
        • Section Sidebar
        • Section View
        • Sections
        • Workspace Context
        • Workspace Views
        • Workspace Actions
        • Localization
      • Extension Kind
      • Extension Conditions
      • Custom Extension types
    • Sections & Trees
    • Searchable Trees (ISearchableTree)
    • Property Editors
      • Property Editors Composition
        • Property Editor Schema
        • Property Editor UI
      • Property Value Converters
      • Property Actions
      • Integrate Property Editors
      • Tracking References
      • Content Picker Value Converter Example
      • Property Dataset
      • Integrate Validaction
    • Workspaces
    • Umbraco Package
    • UI Library
  • Extending
    • Build on Umbraco functionality
    • Health Check
      • Health Check Guides
        • Click-Jacking Protection
        • Content Content Security Policy (CSP)
        • Content/MIME Sniffing Protection
        • Cross-site scripting Protection (X-XSS-Protection header)
        • Debug Compilation Mode
        • Excessive Headers
        • Fixed Application Url
        • Folder & File Permissions
        • HTTPS Configuration
        • Notification Email Settings
        • SMTP
        • Strict-Transport-Security Header
    • Language Files & Localization
      • .NET Localization
    • Backoffice Search
    • Creating a Custom Database Table
    • Embedded Media Providers
    • Custom File Systems (IFileSystem)
      • Using Azure Blob Storage for Media and ImageSharp Cache
    • Configuring Azure Key Vault
    • Packages
      • Creating a Package
      • Language file for packages
      • Listing a Package on the Umbraco Marketplace
      • Good practice and defaults
      • Packages on Umbraco Cloud
      • Installing and Uninstalling Packages
      • Maintaining packages
      • Create accessible Umbraco packages
      • Example Package Repository
  • Reference
    • Dive into the code
    • Configuration
      • Basic Authentication Settings
      • Connection strings settings
      • Content Dashboard Settings
      • Content Settings
      • Data Types Settings
      • Debug settings
      • Examine settings
      • Exception filter settings
      • FileSystemProviders Configuration
      • Global Settings
      • Health checks
      • Hosting settings
      • Imaging settings
      • Indexing settings
      • Install Default Data Settings
      • Logging settings
      • Maximum Upload Size Settings
      • Models builder settings
      • NuCache Settings
      • Package Migration
      • Plugins settings
      • Request handler settings
      • Runtime settings
      • Security Settings
      • Serilog settings
      • Type finder settings
      • Unattended
      • Web routing
    • Templating
      • Models Builder
        • Introduction
        • Configuration
        • Builder Modes
        • Understand and Extend
        • Using Interfaces
        • Tips and Tricks
      • Working with MVC
        • Working with MVC Views in Umbraco
        • View/Razor Examples
        • Using MVC Partial Views in Umbraco
        • Using View Components in Umbraco
        • Querying & Traversal
        • Creating Forms
      • Macros
    • Querying & Models
      • IMemberManager
      • IPublishedContentQuery
      • ITagQuery
      • UDI Identifiers
      • UmbracoContext helper
      • UmbracoHelper
      • IPublishedContent
        • IPublishedContent Collections
        • IPublishedContent IsHelpers
        • IPublishedContent Property Access & Extension Methods
    • Routing & Controllers
      • Custom MVC controllers (Umbraco Route Hijacking)
      • Custom MVC Routes
      • Custom Middleware
      • URL Rewrites in Umbraco
      • Special Property Type aliases for routing
      • URL Redirect Management
      • Routing in Umbraco
        • FindPublishedContentAndTemplate()
        • IContentFinder
        • Inbound request pipeline
        • Outbound request pipeline
        • Published Content Request Preparation
      • Surface controllers
        • Surface controller actions
      • Umbraco API Controllers
        • Porting old Umbraco API Controllers
    • Content Delivery API
      • Custom property editors support
      • Extension API for querying
      • Media Delivery API
      • Protected content in the Delivery API
      • Output caching
      • Property expansion and limiting
      • Additional preview environments support
    • Webhooks
      • Expanding Webhook Events
    • API versioning and OpenAPI
    • Searching
      • Examine
        • Examine Management
        • Examine Manager
        • Custom indexing
        • PDF indexes and multisearchers
        • Quick-start
    • Using Notifications
      • Notification Handler
      • CacheRefresher Notifications Example
      • ContentService Notifications Example
      • Creating And Publishing Notifications
      • Determining if an entity is new
      • MediaService Notifications Example
      • MemberService Notifications Example
      • Sending Allowed Children Notification
      • Umbraco Application Lifetime Notifications
      • EditorModel Notifications
        • Customizing the "Links" box
      • Hot vs. cold restarts
    • Inversion of Control / Dependency injection
    • Management
      • Using Umbraco services
        • Consent Service
        • Media Service
        • Relation Service
        • Content Service
        • Content Type Service
        • Localization Service
        • User Service
    • Plugins
      • Creating Resolvers
      • Finding types
    • Cache & Distributed Cache
      • Accessing the cache
      • ICacheRefresher
      • IServerMessenger
      • Getting/Adding/Updating/Inserting Into Cache
      • Examples
        • Working with caching
    • Response Caching
    • Security
      • API rate limiting
      • BackOfficeUserManager and Events
      • Cookies
      • Replacing the basic username/password check
      • External login providers
      • Locking of Users and password reset
      • Reset admin password
      • Umbraco Security Hardening
      • Umbraco Security Settings
      • Sensitive data
      • Sanitizing the Rich Text Editor
      • Setup Umbraco for a FIPS Compliant Server
      • HTTPS
      • Two-factor Authentication
      • Server-side file validation
    • Scheduling
    • Common Pitfalls & Anti-Patterns
    • API Documentation
    • Debugging with SourceLink
    • Language Variation
    • UmbracoMapper
    • Distributed Locks
    • Management API
      • Setup OAuth using Postman
    • Custom Swagger API
    • Umbraco Flavored Markdown
  • Tutorials
    • Overview
    • Creating a Basic Website
      • Getting Started
      • Document Types
      • Creating Your First Template
      • CSS and Images
      • Displaying the Document Type Properties
      • Creating a Master Template
      • Creating Pages and Using the Master Template
      • Setting the Navigation Menu
      • Articles and Article Items
      • Adding Language Variants
      • Conclusions
    • Creating your First Extension
    • Creating a Custom Dashboard
      • Adding localization to the dashboard
      • Adding functionality to the Dashboard
      • Using Umbraco UI library in the Dashboard
    • Creating a Property Editor
      • Adding configuration to a Property Editor
      • Integrating context with a Property Editor
      • Custom value conversion for rendering
      • Adding server-side validation
        • Default Property Editor Schema aliases
    • Creating a Multilingual Site
    • Add Google Authentication (Users)
    • Add Microsoft Entra ID authentication (Members)
    • Creating Custom Database Tables with Entity Framework
    • The Starter Kit
      • Lessons
        • Customize the Starter Kit
        • Add a Blog Post Publication Date
          • Add a Blog Post Publication Date
          • Add a Blog Post Publication Date
        • Add Open Graph
          • Add Open Graph - Step 1
          • Add Open Graph - Step 2
          • Add Open Graph - Step 3
          • Add Open Graph - Step 4
          • Add Open Graph - Summary
        • Ask For Help and Join the Community
    • Editor's Manual
      • Getting Started
        • Logging In and Out
        • Umbraco Interface
        • Creating, Saving and Publishing Content Options
        • Finding Content
        • Editing Existing Content
        • Sorting Pages
        • Moving a Page
        • Copying a Page
        • Deleting and Restoring Pages
      • Working with Rich Text Editor
      • Version Management
        • Comparing Versions
        • Rollback to a Previous Version
      • Media Management
        • Working with Folders
        • Working with Media Types
        • Cropping Images
      • Tips & Tricks
        • Refreshing the Tree View
        • Audit Trail
        • Notifications
        • Preview Pane Responsive View
        • Session Timeout
    • Multisite Setup
    • Member Registration and Login
    • Custom Views for Block List
    • Connecting Umbraco Forms and Zapier
    • Creating an XML Sitemap
    • Implement Custom Error Pages
    • Create a custom maintenance page
    • Creating a backoffice API
      • Documenting your controllers
      • Adding a custom Swagger document
      • Versioning your API
      • Polymorphic output in the Management API
      • Umbraco schema and operation IDs
      • Access policies
Powered by GitBook
On this page
  • Registering dependencies
  • Choosing a strategy for registering dependencies
  • Registering dependencies in the Program.cs file
  • Registering dependencies in a composer
  • Registering dependencies in bundles
  • Service lifetime
  • Injecting dependencies
  • Injecting dependencies into a class
  • Injecting dependencies into a View or Template
  • Other things you can inject
  • UmbracoHelper
  • ExamineManager
  • ILogger
  • Using DI in Services and Helpers
Edit on GitHub
Export as PDF
  1. Reference

Inversion of Control / Dependency injection

Inversion of Control/Dependency Injection in Umbraco

PreviousHot vs. cold restartsNextManagement

Last updated 7 months ago

Umbraco supports dependency injection out of the box using the . This means that working with dependencies in Umbraco is similar to working with them in ASP.NET Core.

IUmbracoBuilder is a Umbraco-specific abstraction on top of the IServiceCollection. Its purpose is to aid in adding and replacing Umbraco-specific services, such as notification handlers, filesystems, server role accessors, and so on. You can access the IServiceCollection directly to add custom services through the Services property. See below for a concrete example:

IUmbracoBuilder.Services

Registering dependencies

There are different strategies for registering your dependencies and not one strategy is better than the other.

In this article, we will cover the following three strategies:

Which strategy to choose depends on the scenario requiring dependency registration.

Choosing a strategy for registering dependencies

Are you ? You can choose whichever strategy you prefer working with.

Are you and do not have access to the Program.cs file? In this case, you have the option to register the dependencies in a composer.

Are you in a situation where you need to ? You can bundle your dependencies in custom extension methods and register them in a single call.

Registering dependencies in the Program.cs file

When working with your Umbraco site, dependencies can be registered within the Program.cs file.

In the example below, a custom notification handler is added to the CreateUmbracoBuilder() builder chain:

Program.cs
builder.CreateUmbracoBuilder()
    .AddBackOffice()
    .AddWebsite()
    .AddDeliveryApi()
    .AddComposers()
    // When you need to add something Umbraco-specific, do it in the "AddUmbraco" builder chain, using the IUmbracoBuilder extension methods.
    .AddNotificationHandler<ContentTypeSavedNotification, ContentTypeSavedHandler>()
    .Build();

Registering dependencies in a composer

Below is an example of a composer using the Services property of the IUmbracoBuilder:

MyComposer.cs
using IOCDocs.NotificationHandlers;
using IOCDocs.Services;
using Microsoft.Extensions.DependencyInjection;
using Umbraco.Cms.Core.Composing;
using Umbraco.Cms.Core.DependencyInjection;
using Umbraco.Cms.Core.Notifications;

namespace IOCDocs;

public class MyComposer : IComposer
{
    public void Compose(IUmbracoBuilder builder)
    {
        builder.AddNotificationHandler<ContentTypeSavedNotification, ContentTypeSavedHandler>();
        builder.Services.AddSingleton<IFooBar, Foobar>();
    }
}

To access the IUmbracoBuilder, you need to add Umbraco.Cms.Core.DependencyInjection and Microsoft.Extensions.DependencyInjection as using statements when registering your services. This, in turn, will also give you access to the IUmbracoBuilder extension methods as well as the Microsoft IServiceProvider.

Registering dependencies in bundles

Depending on your scenario, you may have a lot of dependencies you need to register. In this case, your Program.cs or Composer can become cluttered and hard to manage.

You can manage multiple services in one place by creating your custom extension methods for the IUmbracoBuilder. This way you can bundle similar dependencies in extension methods and register them all in a single call.

In the following code sample two dependencies, RegisterCustomNotificationHandlers and RegisterCustomServices are bundled together in a custom AddCustomServices extension method.

MyCustomBuilderExtensions.cs
using IOCDocs.NotificationHandlers;
using IOCDocs.Services;
using Microsoft.Extensions.DependencyInjection;
using Umbraco.Cms.Core.DependencyInjection;
using Umbraco.Cms.Core.Notifications;

namespace IOCDocs;

public static class MyCustomBuilderExtensions
{
    // The first dependency is registered
    public static IUmbracoBuilder RegisterCustomNotificationHandlers(this IUmbracoBuilder builder)
    {
        builder.AddNotificationHandler<ContentTypeSavedNotification, ContentTypeSavedHandler>();
        {...}
        return builder;
    }

    // The second dependency is registered
    public static IUmbracoBuilder RegisterCustomServices(this IUmbracoBuilder builder)
    {
        builder.Services.AddSingleton<IFooBar, Foobar>();
        {...}
        return builder;
    }

    // The two dependencies are bundled together
    public static IUmbracoBuilder AddCustomServices(this IUmbracoBuilder builder)
    {
        builder.RegisterCustomNotificationHandlers();
        builder.RegisterCustomServices();
        return builder;
    }
}

It is not required to have an interface registering your dependencies:

services.AddSingleton<Foobar>();

With the dependencies bundled together, you can call the AddCustomServices method in either the Program.cs file or your composer:

Program.cs
builder.CreateUmbracoBuilder()
    .AddBackOffice()
    .AddWebsite()
    .AddDeliveryApi()
    .AddComposers()
    // Register all custom dependencies in one go using the custom extension method
    .AddCustomServices()
    .Build();
MyComposer.cs
using Umbraco.Cms.Core.Composing;
using Umbraco.Cms.Core.DependencyInjection;

namespace IOCDocs;

public class MyComposer : IComposer
{
    public void Compose(IUmbracoBuilder builder)
    {
        // Register all custom dependencies in one go using the custom extension method
        builder.AddCustomServices();
    }
}

Service lifetime

During registration of your dependencies, you have to define the lifetime of your service:

IServiceCollection.AddTransient<TService, TImplementing>();
IServiceCollection.AddScoped<TService, TImplementing>();
IServiceCollection.AddSingleton<TService, TImplementing>();

There are three possible lifetimes:

Name
Lifetime
Description

Transient

Creates a new instance

A new instance will be created each time it's injected.

Scoped

One unique instance per web request (connection)

Scoped services are disposed of at the end of the request. Be careful not to resolve a scoped service from a singleton, as it may lead to an incorrect state in subsequent requests.

Singleton

One unique instance for the whole web application

The single instance will be shared across all web requests.

Injecting dependencies

Once you have registered the dependencies inject them into your project where needed.

Injecting dependencies into a class

If you need to inject your service into a controller or another service, you will do so through the class.

FooController.cs
using IOCDocs.Services;
using Microsoft.AspNetCore.Mvc;

namespace IOCDocs.Controllers;

[ApiController]
[Route("/umbraco/api/foo")]
public class FooController : Controller
{
    private readonly IFooBar _fooBar;

    public FooController(IFooBar fooBar)
    {
        _fooBar = fooBar;
    }

    [HttpGet("foo")]
    public string Foo()
    {
        var bar = _fooBar.Foo();
        return bar;
    }
}

If you place a breakpoint on var bar = _foobar.Foo(), open /Umbraco/Api/foo/foo in your browser and inspect the variable, you'll see that the value is bar. This is what you would expect as all the Foobar.Foo() method does is to return Bar as a string:

Foobar.cs
namespace IOCDocs.Services;

public class Foobar : IFooBar
{
    public string Foo() => "Bar";
}

Injecting dependencies into a View or Template

In some cases you might need to use services within your templates or view files. Services can be injected directly into your views using the @inject keyword. This means that you can inject the Foobar from above into a view like shown below:

Home.cshtml
@using Umbraco.Cms.Web.Common.PublishedModels;
@inherits Umbraco.Cms.Web.Common.Views.UmbracoViewPage<ContentModels.Home>
@using ContentModels = Umbraco.Cms.Web.Common.PublishedModels;

@* Add a using statement for the namespace of the service *@
@using IOCDocs.Services
@* Inject the service *@
@inject IFooBar _fooBar

@{
 Layout = null;
}

<h1>@_fooBar.Foo()</h1>

When loading a page using the template above, you will see the "Bar" heading which is retrieved from the service.

To use the service a using statement for the namespace of the service needs to be added.

Other things you can inject

In this section, you can find examples of what you can inject when working with Umbraco.

UmbracoHelper

The UmbracoHelper is a scoped service, which means you can only use it in services that are also scoped or transient. To get the UmbracoHelper you must inject IUmbracoHelperAccessor and use that to resolve it:

MyCustomScopedService.cs
using System.Collections.Generic;
using Umbraco.Cms.Core.Models.PublishedContent;
using Umbraco.Cms.Web.Common;

namespace IOCDocs.Services;

// This service must be scoped
public class MyCustomScopedService
{
    private readonly IUmbracoHelperAccessor _umbracoHelperAccessor;

    public MyCustomScopedService(IUmbracoHelperAccessor umbracoHelperAccessor)
    {
        _umbracoHelperAccessor = umbracoHelperAccessor;
    }
    
    public IEnumerable<IPublishedContent> GetContentAtRoot()
    {
        // Try and get the Umbraco helper
        var success = _umbracoHelperAccessor.TryGetUmbracoHelper(out var umbracoHelper);
        if (success is false)
        {
            // Failed to get UmbracoHelper, probably because it was accessed outside of a scoped/transient service.
            return null;
        }

        public IEnumerable<IPublishedContent> GetContentAtRoot()
        {
            // Try and get the Umbraco helper
            var success = _umbracoHelperAccessor.TryGetUmbracoHelper(out var umbracoHelper);
            if (success is false)
            {
                // Failed to get UmbracoHelper, probably because it was accessed outside of a scoped/transient service.
                return null;
            }

            // We got Umbraco helper, now we can do something with it.
            return umbracoHelper.ContentAtRoot();
        }
    }
}

ExamineManager

SearchService.cs
using System;
using System.Collections.Generic;
using Examine;
using Umbraco.Cms.Core;
using Umbraco.Cms.Core.Models.PublishedContent;
using Umbraco.Cms.Core.Web;
using Umbraco.Cms.Infrastructure.Examine;
using Umbraco.Extensions;

namespace IOCDocs.Services;

// This service must be scoped.
public class SearchService : ISearchService
{
    private readonly IExamineManager _examineManager;
    private readonly IUmbracoContextAccessor _umbracoContextAccessor;

    public SearchService(IExamineManager examineManager, IUmbracoContextAccessor umbracoContextAccessor)
    {
        _examineManager = examineManager;
        _umbracoContextAccessor = umbracoContextAccessor;
    }

    public IEnumerable<PublishedSearchResult> Search(string searchTerm)
    {
        if (_examineManager.TryGetIndex(Constants.UmbracoIndexes.ExternalIndexName, out var index) is false)
        {
            throw new InvalidOperationException($"No index found by name {Constants.UmbracoIndexes.ExternalIndexName}");
        }

        if (!(index is IUmbracoIndex umbracoIndex))
        {
            if (_examineManager.TryGetIndex(Constants.UmbracoIndexes.ExternalIndexName, out var index) is false)
            {
                throw new InvalidOperationException($"No index found by name {Constants.UmbracoIndexes.ExternalIndexName}");
            }

            if (!(index is IUmbracoIndex umbracoIndex))
            {
                throw new InvalidOperationException("Could not cast");
            }

            // Do stuff with the index
            if (_umbracoContextAccessor.TryGetUmbracoContext(out var umbracoContext) is false)
            {
                throw new InvalidOperationException("Could not get Umbraco context");
            }

            return umbracoIndex.Searcher.Search(searchTerm).ToPublishedSearchResults(umbracoContext.PublishedSnapshot.Content);
        }
        
        // Do stuff with the index
        if (_umbracoContextAccessor.TryGetUmbracoContext(out var umbracoContext) is false)
        {
            throw new InvalidOperationException("Could not get Umbraco context");
        }

        return umbracoIndex.Searcher.Search(searchTerm).ToPublishedSearchResults(umbracoContext.PublishedSnapshot.Content);
    }
}

ILogger

Foobar.cs
using System;
using Microsoft.Extensions.Logging;

namespace IOCDocs.Services;

public class Foobar : IFooBar
{
    private readonly ILogger<Foobar> _logger;

    public Foobar(ILogger<Foobar> logger)
    {
        _logger = logger;
    }

    public void Foo()
    {
        _logger.LogInformation("Method Foo called at {DateTime}", DateTime.UtcNow);
    }
}

Using DI in Services and Helpers

You will also find information about creating custom services and helpers to inject and use in your Umbraco project.

Learn more about the uses of the Program.cs file in .

When working with packages, you do not have access to the Program.cs file. Instead, you can use a to register your dependencies.

For more information, read the official .

Using the UmbracoHelper is only possible when there is an instance of the UmbracoContext. .

.

In the , you can find more examples of using dependency injection and gaining access to the different services and helpers.

the official ASP.NET Core Fundamentals documentation
composer
Microsoft documentation on dependency injections
Read more about the UmbracoHelper
You can read more in the implementation article about services
Read more about the ExamineManager in the Searching articles
Read more about logging in the debugging section
Services and Helpers documentation
ASP.NET Core built-in dependency injection
Registering dependencies in the Program.cs file
Registering dependencies in a composer
Registering dependencies in bundles
working directly on your site
building a package
register more than a few dependencies