Skip to main content
A newer version of this page is available. .
All docs
V21.1

XPO Extensions for ASP.NET Core Dependency Injection

  • 5 minutes to read

XPO features extension methods for the standard IServiceCollection interface to register XPO services for the ASP.NET Core pipeline. This follows best practices for the platform and enables automatic management of the Data Layer and Session life cycles.

This article demonstrates how to use Dependency injection (DI) in XPO-based ASP.NET Core applications and describes corresponding XPO APIs.

Register the UnitOfWork Service

For Network Databases (Microsoft SQL Server, Oracle DB, PostgreSql)

Add the UnitOfWork service in the ConfigureServices method of the Startup class (declared in the Startup.cs file):

using DevExpress.Xpo.DB;
using Microsoft.Extensions.DependencyInjection;
// ...
public class Startup {
    public void ConfigureServices(IServiceCollection services) {
        services.AddXpoDefaultUnitOfWork(true, options =>
            options
                .UseConnectionString(Configuration.GetConnectionString("MSSqlServer"))
                // Remove this line if the database already exists.
                .UseAutoCreationOption(AutoCreateOption.DatabaseAndSchema) 
                // Pass all of your persistent object types to this method.
                .UseEntityTypes(new Type[] { typeof(User) })); 
    }
}

The code above makes XPO use a singletone ThreadSafeDataLayer instance with connection pooling.

If you do not need a thread-safe data layer and connection pooling with a network database, use the following code instead:

using Microsoft.Extensions.DependencyInjection;
// ...
public class Startup {
    public void ConfigureServices(IServiceCollection services) {
        services.AddXpoDefaultUnitOfWork(false, options =>
        options.UseConnectionString(Configuration.GetConnectionString("MSSqlServer"))
        .UseThreadSafeDataLayer(false)
        .UseConnectionPool(false));
    }
    // ...
}

You do not need to call the UseEntityTypes method to specify all persistent object types in this case.

For an Embedded Database (SQLite)

Add the UnitOfWork service in the Configure method of the Startup class declared in the Startup.cs file:

using DevExpress.Xpo.DB;
using Microsoft.Extensions.DependencyInjection;
// ...
public class Startup {
    public void ConfigureServices(IServiceCollection services) {
        services.AddXpoDefaultUnitOfWork(false, options =>
            options
            .UseConnectionString(Configuration.GetConnectionString("SQLite"))
            // Remove this line if the database already exists.
            .UseAutoCreationOption(AutoCreateOption.DatabaseAndSchema) 
            .UseConnectionPool(false)
            // Pass all of your persistent object types to this method.
            .UseEntityTypes(new Type[] { typeof(User) })); 
    }
    // ...
}

This code makes XPO use a singletone ThreadSafeDataLayer instance without connection pooling.

For an In-Memory Database

Add the UnitOfWork service in the Configure method of the Startup class declared in the Startup.cs file:

using Microsoft.Extensions.DependencyInjection;
// ...
public class Startup {
    public void ConfigureServices(IServiceCollection services) {
        services.AddXpoDefaultUnitOfWork(true, options =>
        options.UseInMemoryDataStore(true)
        .UseAutoCreationOption(DB.AutoCreateOption.DatabaseAndSchema)
        .UseThreadSafeDataLayerSchemaInitialization(true)
        .UseConnectionPool(false)
        .UseEntityTypes(new Type[] { typeof(User) })); // Pass all of your persistent object types to this method.
    }
}

Use the following code to specify a ReflectionDictionary instead of passing all your persistent object types to the UseEntityTypes method:

using Microsoft.Extensions.DependencyInjection;
// ...
public class Startup {
    public void ConfigureServices(IServiceCollection services) {
        services.AddXpoDefaultUnitOfWork(true, options =>
            options
                .UseConnectionString(Configuration.GetConnectionString("MSSqlServer"))
                .UseAutoCreationOption(DB.AutoCreateOption.SchemaAlreadyExists)
                .UseCustomDictionaryFactory(() => {
                    var dictionary = new ReflectionDictionary();
                    // Your persistent object types or another initialization code.
                    dictionary.GetDataStoreSchema(typeof(User));  
                    return dictionary; 
                })
        );
    }
}

Use Multiple Databases in One Application

Since the DI client cannot configure dependencies, create multiple dependencies to support multiple databases. XPO allows you to create multiple UnitOfWork descendants and use the AddXpoCustomSession<TSession> method to register them:

public class Db1UnitOfWork :UnitOfWork {
    public Db1UnitOfWork(IDataLayer dataLayer, params IDisposable[] disposeOnDisconnect) : base(dataLayer, disposeOnDisconnect) { }
}
public class Db2UnitOfWork : UnitOfWork {
    public Db2UnitOfWork(IDataLayer dataLayer, params IDisposable[] disposeOnDisconnect) : base(dataLayer, disposeOnDisconnect) { }
}

services.AddXpoCustomSession<Db1UnitOfWork>(true, options =>
    options
        .UseConnectionString(Configuration.GetConnectionString("DB1"))
        .UseAutoCreationOption(AutoCreateOption.None)
        .UseEntityTypes(new Type[] { /* entity types for DB1 */ })
);
services.AddXpoCustomSession<Db2UnitOfWork>(true, options =>
    options
        .UseConnectionString(Configuration.GetConnectionString("DB2"))
        .UseAutoCreationOption(AutoCreateOption.None)
        .UseEntityTypes(new Type[] { /* entity types for DB2 */ })
);

Examples of Accessing XPO Services

In an ASP.NET Core application, you can access an XPO UnitOfWork in the following ways:

  • Use the HttpContext.RequestServices object in the ASP.NET Core application. HttpContext is available in controllers, Middleware services, etc.:

    public class HomeController : Controller {
        public IActionResult Index() {
            UnitOfWork uow = HttpContext.RequestServices.GetService<UnitOfWork>();
            //  ...
        }
    }
    
  • Use the Dependency Injection in a Controller constructor:

    public class HomeController : Controller {
        public HomeController(UnitOfWork uow) {
            // ...
        }
        // ...
    }
    
  • Use the ApplicationServices property of the IApplicationBuilder object passed to the Configure method of the Startup class:

    public class Startup {
        public void ConfigureServices(IServiceCollection services) {
            services.AddXpoDefaultUnitOfWork(/* ... */);
        }
        public void Configure(IApplicationBuilder app) {
            IServiceCollection services = app.ApplicationServices;
            using(var scope = services.GetService<IServiceScopeFactory>().CreateScope()) {
            UnitOfWork uow = scope.ServiceProvider.GetService<UnitOfWork>();
            // ...
            }
        }
    }
    
  • Use a custom Middleware service’s Invoke method:

    public class Startup {
        public void ConfigureServices(IServiceCollection services) {
            services.AddXpoDefaultUnitOfWork(...);
        }
        public void Configure(IApplicationBuilder app) {
            // ...
            app.UseMiddleware<MyMiddleware>();
            // ...
        }
    }
    public class MyMiddleware {
        public MyMiddleware(RequestDelegate next) {
            // ...
        }
        public async Task Invoke(HttpContext context, UnitOfWork uow) {
            // ...
        }
    }
    

Extension Methods List

The XpoServiceCollectionExtensions class exposes the following IServiceCollection extension methods:

  • AddXpoDefaultDataLayer - adds the IDataLayer service.
  • AddXpoDefaultObjectLayer - adds the IObjectLayer service.
  • AddXpoDefaultUnitOfWork - adds the UnitOfWork service.
  • AddXpoDefaultSession - adds the Session service.
  • AddXpoCustomSession<TSession> - adds a custom session service. A generic parameter is a custom Session descendant type.

Limitations

  • AddXpoDefaultUnitOfWork and other XPO extension methods for DI are not available in XPO for the full .NET Framework.

    For the full .NET Framework + ASP.NET Core, you can manually initialize the data layer as described in the following article (see the XpoHelper class): How to use XPO in an ASP.NET (Web) application.

  • Consider the settings compatibility when you register an XPO service: