LogoLogo
HomeNewsSupportVideos
  • Introduction
  • Getting Started
  • What's new in 4.0
    • Known Issues
    • .NET Core Designer
    • Managed Graphics
    • Fluent Markup
    • Markdown Support
    • Upgrade from 3.x
  • Releases
    • What's new in 4.0
    • What's new in 3.5
    • What's new in 3.2
      • View Builder
      • Validation Rules
      • Enhanced Font Support
      • Design-Time Debug
    • What's new in 3.1
    • What's new in 3.0
      • FAQs
      • Update Existing Projects
      • Multi Targeting
      • Visual Studio Designer
      • Referencing Assemblies
      • Docker Support
      • Troubleshooting
      • Deployment
    • What's new in 2.5
    • What's new in 2.2
    • What's new in 2.1
    • What's new in 2.0
    • Upgrade from 1.x
  • Getting Started
    • New Project
    • Templates
    • Troubleshooting
    • License Activation
    • FAQ
    • API
    • Hybrid
    • Deployment
    • Theme Builder
  • Concepts
    • Startup
    • Configuration
    • Load Balancing
    • Designer
    • Layouts
    • Client Profiles
    • Tab Order
    • Compression
    • Embedded Resources
    • Modal Workflow
    • Localization
    • RightToLeft
    • Background Tasks
    • Real Time Web Applications
    • JavaScript
    • JavaScript Object Model
    • Security
    • Synchronization
    • Session Management
    • Theming
    • Dependency Injection
    • Application Switches
    • Visual Studio Code
  • Controls & Components
    • General
      • Application
      • AutoSizing
      • AutoScroll
      • AutoScaling
      • Accessibility
      • Colors & Fonts
      • Embedded Tools
      • Events
      • Touch Events
      • Images
      • Labels
      • ToolTips
      • Data Binding
      • Common Properties
      • Custom Painting
      • Move & Resize
      • Drag & Drop
      • Validation
      • User Data
      • Responsive Properties
      • VB.NET Extensions
    • Common Dialogs
      • FolderBrowserDialog
      • ColorDialog
      • OpenFileDialog
      • SaveFileDialog
    • Editors
      • TextBox
        • TagTextBox
        • MaskedTextBox
        • TypedTextBox
      • DateTimePicker
      • MonthCalendar
      • TimeUpDown
      • DomainUpDown
      • NumericUpDown
      • TrackBar
    • Buttons
      • Button
      • SplitButton
      • CheckBox
      • RadioButton
    • Containers
      • Page
      • Form
      • Desktop
      • Panel
      • FlexLayoutPanel
      • FlowLayoutPanel
      • TableLayoutPanel
      • GroupBox
      • Accordion
      • TabControl
      • UserPopup
      • UserControl
      • ToolBar
      • StatusBar
      • SplitContainer
      • SlideBar
    • Lists & Grids
      • ComboBox
        • UserComboBox
        • TreeViewComboBox
        • ListViewComboBox
      • ListBox
        • CheckedListBox
      • TreeView
      • ListView
      • DataGridView
        • Column
        • TextBoxColumn
        • ButtonColumn
        • LinkColumn
        • ImageColumn
        • MaskedTextBoxColumn
        • DateTimePickerColumn
        • NumericUpDownColumn
        • CheckBoxColumn
        • ComboBoxColumn
      • DataRepeater
      • PropertyGrid
    • Extenders
      • Animation
      • ToolTip
      • ErrorProvider
      • Rotation
      • StyleSheet
      • JavaScript
    • Media
      • Audio
      • Video
      • FlashPlayer
    • Content
      • Label
      • LinkLabel
      • PictureBox
      • ScrollBars
      • Upload
      • AspNetPanel
      • ImageList
      • PdfViewer
      • ProgressBar
      • Spacer
      • Widget
      • WebBrowser
      • IFramePanel
      • HtmlPanel
      • Canvas
      • Shape
      • Line
    • Menus
      • MainMenu
      • MenuBar
      • MenuItem
      • LinkMenuItem
      • ContextMenu
    • Notifications
      • AlertBox
      • MessageBox
      • Toast
    • Other Components
      • Timer
      • BindingSource
      • BindingNavigator
      • DataSet
      • EventLog
      • MessageQueue
      • PerformanceCounter
Powered by GitBook
On this page
  • Registering Services
  • Using a Service
  • Service Injection
  • Generic Service Type
  • Alternative IServiceProvider
  • Services Lifetime

Was this helpful?

Export as PDF
  1. Concepts

Dependency Injection

Services and Dependency Injection in 3.1.

PreviousThemingNextApplication Switches

Last updated 3 months ago

Was this helpful?

Starting with Wisej.NET 3.1, we added full support for services and dependency injection. Like everything else in Wisej.NET, it's a lean, performant, and flexible implementation.

If you need something more complex, we also support switching our with any third-party implementation, including Microsoft's DI, Autofac, or others.

Our DI implementation is supported in both .NET 4.8 and .NET Core.

Registering Services

You can register services at any point in the application. Services are always registered globally - if a service type is registered more than once, subsequent definitions replace the existing definition.

A good place to initialize services is in the static Program constructor, though you can register services anywhere in your code.

static Program() {

  // Register an ILogger service implemented by MyLogger as a global shared singleton.
  Application.Services.AddService<ILogger, MyLogger>();
	
  // Register an IFileSystem service where the implementation is crated by the CreateFileSystemFactory method
  // and scope is set to be the session.
  Application.Services.AddService<IFileSystem>(CreateFileSystemFactory, ServiceLifetime.Session);
}

private static IFileSystem CreateFileSystemFactory(Type serviceType) {
  return new MyFileSystemImplementation();
}

The code above registers two services:

  1. An _ILogger_ implementation. Wisej.NET creates a MyLogger instance once (Global scope) on first use. This service is never disposed, even if it implements _IDisposable_, because it's registered with Shared lifetime as a singleton instance used by all sessions.

  2. An _IFileSystem_ service that delegates creation to the _CreateFileSystemFactory_ method with Session scope. Wisej.NET invokes _CreateFileSystemFactory_ on first request per session. The service instance is automatically disposed if it implements _IDisposable_ when the session ends.

Using a Service

Your code can request a service implementation in three ways:

  • Using _Application.Services.GetService<T>()_

  • Using the _[Inject]_ attribute on a property

  • Adding a service argument to the constructor of another service implementation

_Application.GetService<T>()_ returns the service implementation for the requested T type if it exists, or null.

The _[Inject]_ attribute works by default only on top-level UI containers: _Page_, _Form_, and _Desktop_ classes. When you add the _[Inject]_ attribute to a property (protected, private or public), Wisej.NET automatically resolves the service and assigns it during object construction.

public class MyFileSystemImplementation : IFileSystem {

  [Inject]
  private ILogger Logger {get; set;}
  
  [Inject(Required = true]
  protected IVolumeManager Logger {get; set;}
}

To use the _[Inject]_ attribute on any object, call _Application.Services.Inject(object)_.

Services created by Wisej.NET can receive instances of other services by declaring them in the constructor.

public class MyLoggerImplementationService : ILogger {
  public MyLoggerImplementationService(IFileSystem fileSystemService, ...) {
  
    // Wisej.NET resolves all the services in the constructor, if possible.
    // Unresolved services are simply set to null.
    
  }
}

Service Injection

Wisej.NET supports Dependency Injection through constructors and property injection.

Property injection works automatically for all top-level containers (Form, Page, Desktop) and system-created services. Constructor injection works for service creation.

Example MyFileSystemImplementation with property injection:

public class MyFileSystemImplementation : IFileSystem {

  [Inject]
  private ILogger Logger {get; set;}
	
  // Notes: The property can be protected, private or public.
  // If the service doesn't exist it will be null, unless the attribute is set to be required:
  // [Inject(Required=true)] in this case it throws an exception if the service is not available.
}

Constructor injection example (works only for system-created services):

Application.Services.AddService<IFileSystem, MyFileSystemImplementation>(ServiceLifetime.Session);
	
...

public class MyFileSystemImplementation : IFileSystem {
	
  public MyFileSystemImplementation(ILogger logger, more services...) {
	
    // This constructor receives all the services it declared, if available, or null.
		
    // Wisej.NET detects circular dependencies and throws an exception instead of crashing
    // the server with a StackOverflow.

  }
}

To inject properties programmatically:

Application.Services.Inject(object);

If the object declares any _[Inject]_ properties, they receive service instances according to their lifetime.

Generic Service Type

You can register generic types as services (starting from Wisej.NET 3.5.4) and request concrete service instances at runtime.

When requesting a service, Wisej.NET constructs or retrieves the correct instance of the generic type.

// Register generic service
Application.Services.AddService(typeof(DBConnection<>));

// Request service
var dbTrucks = Application.Services.GetService<DBConnection<Truck>>);
var dbEmployees = Application.Services.GetService<DBConnection<Employee>>);

Alternative IServiceProvider

// ASP.NET Core startup
public class Startup {
  public static void Main(string[] args) {
		
    var builder = WebApplication.CreateBuilder(new WebApplicationOptions
    {
      Args = args,
      WebRootPath = "./"
    });
	
    var app = builder.Build();

    // Register Microsoft's IServiceProvider with Wisej.NET.
    Application.Services.AddService<IServiceProvider>(app.Services);
	
    app.UseWisej();
    app.UseFileServer();
    app.Run();
  }
}

The line Application.AddService<IServiceProvider>(app.Services); registers Microsoft's IServiceProvider with Wisej.NET and replaces our IServiceProvider.

After this, _Application.Services.AddService<T>()_ is not supported - all services must be registered using Microsoft's DI.

_Application.Services.GetService<T>()_ and _[Inject]_ use the alternative IServiceProvider to resolve services. The IServiceProvider instance is registered as a global singleton by default but can be registered per session using a different ServiceLifetime option.

Services Lifetime

We support these service lifetimes:

  • Shared: The service instance is a singleton used by all sessions and threads

  • Session: The service instance is created per session and disposed (if _IDisposable_) when the session ends. Note that no other DI container supports session lifetime

  • Thread: The service instance is created per thread (roughly corresponding to browser requests) and disposed (if _IDisposable_) when thread code ends

  • Transient: The service instance is created on each request. It's never disposed - disposal responsibility (if _IDisposable_) lies with the caller

The default lifetime when registering a service is always _Shared_.

To use a different service manager, register another object.

IServiceProvider
IServiceProvider