Tableau Migration SDK 6.0.0
  • Articles
  • Code Samples
  • Python API Reference
  • C# API Reference
Show / Hide Table of Contents
  • SDK Terminology
  • Features & Tableau REST API Versions
  • Configuration
    • Data Loading
    • Skipping Content Types
  • Dependency Injection
    • Custom Migration Services
  • Plan Validation
  • Logging
  • Hooks
    • Custom Hooks
    • Example Hook Use Cases
    • Python Hook Update from v3 to v4+
  • User Authentication
  • Custom View File
  • Troubleshooting

Custom Migration Services

Migration services provide an alternative path for dependency injection to customize Migration SDK behavior. Replacing most DI services is controlled through the application's IServiceProvider container, which typically does not change after application startup and is not easily available in all contexts. Migration services are those DI services that the Migration SDK obtains through the migration plan, which may or may not ultimately come from the IServiceProvider container. This allows migration services to be customized on a per-plan basis, and makes service customization easier in interoperability scenarios (e.g. Python).

Supported Migration Services

The services available to override through the migration services feature are listed in the plan builder's service collection. If the migration service is generic the open generic type is listed in the supported services list.

  • Python
  • C#

Supported migration services are available through the plan builder's services property.

plan_builder = MigrationPlanBuilder()
for service in plan_builder.services.supported_services:
	print(service.name) # Service name contains the 

Supported migration services are available through the plan builder's Services property.

var planBuilder = new MigrationPlanBuilder();
foreach(var service in planBuilder.Services.SupportedServices)
{
    Console.WriteLine(service.Name);
}

Overriding Migration Services

All migration services have default implementations provided by the Migration SDK. When a migration service is registered with the plan builder it will be used in place of the default implementation for that plan.

  • Python
  • C#

Override migration services on a per-plan basis through the plan builder's services property.

Migration Service Class

Like hooks, migration services are created by inheriting from a service base class.

from typing import TypeVar
from tableau_migration import (
    empty_pager,
    MigrationContentLoaderBase
)

TContent = TypeVar("T")

class EmptyMigrationContentLoader(MigrationContentLoaderBase[TContent]):
    def get_migration_content_pager(self, page_size: int):
        return empty_pager(TContent)

Registration

Migration services are then registered with the service builder for a given service type.

plan_builder.services.set(MigrationContentLoaderBase[IUser], EmptyMigrationContentLoader[IUser])

Override migration services on a per-plan basis through the plan builder's Services property.

Migration Service Class

Like hooks, migration services are created by implementing a service interface.

public class EmptyMigrationContentLoader<TContent> : IMigrationContentLoader<TContent>
    where TContent : IContentReference
{
    public IPager<TContent> GetMigrationContentPager(int pageSize)
        => new MemoryPager<TContent>([], pageSize);
}

Registration

A service factory is then registered with the service builder for a given service type. The service factory context includes the scoped IServiceProvider container for types available through application DI.

planBuilder.Services.Set<IMigrationContentLoader<IUser>>(MigrationServiceFactoryContext ctx => 
{
	return ctx.Services.GetRequiredService<EmptyMigrationContentLoader<IUser>>();
});

Generic Migration Services

Many migration services are generic, meaning they have type arguments. Normally these type arguments represent migrating content types, so that different migration service implementations can be used for different content types.

When a migration service overrides a closed generic type, meaning all type arguments are specified, that override will only be used for those type arguments.

Alternatively, a migration service can override the open generic type, meaning no type arguments are specified. Migration service overrides for open generic types are used when no other override is registered for the specific type arguments involved.

  • Python
  • C#
# Closed generic, only overrides IUser.
plan_builder.services.set(MigrationContentLoaderBase[IUser], EmptyMigrationContentLoader[IUser])

# Open generic, used for all types without a closed generic override.
plan_builder.services.set(MigrationContentLoaderBase, EmptyMigrationContentLoader) 

The service factory context includes the requested type arguments for service creation.

// Closed generic, only overrides IUser.
planBuilder.Services.Set<IMigrationContentLoader<IUser>>(MigrationServiceFactoryContext ctx => 
{
	return ctx.Services.GetRequiredService<EmptyMigrationContentLoader<IUser>>();
});

// Open generic, used for all types without a closed generic override.
planBuilder.Services.Set(typeof(IMigrationContentLoader<>), MigrationServiceFactoryContext ctx => 
{
	return ctx.Services.GetRequiredService(typeof(EmptyMigrationContentLoader<>).MakeGenericType(ctx.Type.GetGenericArguments()));
});
  • Edit this page
In this article