Error
This rule reports when LocalPluginContext is used as the TService type argument in RegisterStep<TEntity, TService>(). This causes a runtime exception because LocalPluginContext is not registered in the DI container. At runtime, the plugin will call sp.GetRequiredService<LocalPluginContext>(), which throws InvalidOperationException.
This typically happens when migrating from the legacy RegisterPluginStep<T> API and mistakenly using RegisterStep<TEntity, LocalPluginContext> instead of the correct DI-based approach.
public class ContactPlugin : Plugin
{
public ContactPlugin()
{
// XPC3004: LocalPluginContext is not in DI — causes runtime exception
RegisterStep<Contact, LocalPluginContext>(
EventOperation.Update,
ExecutionStage.PostOperation,
Execute);
}
private void Execute(LocalPluginContext context) { }
}Use RegisterPluginStep<T> which correctly wraps the LocalPluginContext:
public class ContactPlugin : Plugin
{
public ContactPlugin()
{
RegisterPluginStep<Contact>(
EventOperation.Update,
ExecutionStage.PostOperation,
Execute);
}
private void Execute(LocalPluginContext context) { }
}Migrate to a DI-registered service type for full dependency injection support:
public class ContactPlugin : Plugin
{
public ContactPlugin()
{
RegisterStep<Contact, IContactService>(
EventOperation.Update,
ExecutionStage.PostOperation,
nameof(IContactService.HandleUpdate));
}
protected override IServiceCollection OnBeforeBuildServiceProvider(IServiceCollection services)
{
return services.AddScoped<IContactService, ContactService>();
}
}
public interface IContactService
{
void HandleUpdate();
}RegisterStep<TEntity, TService> calls sp.GetRequiredService<TService>() at runtime. LocalPluginContext is constructed manually (not registered in the DI container), so this call throws InvalidOperationException. The exception is then caught and re-thrown as InvalidPluginExecutionException, masking the original cause.
Yes — the code fix rewrites RegisterStep<TEntity, LocalPluginContext>(...) to RegisterPluginStep<TEntity>(...).
- XPC3001: Prefer nameof over string literal for handler method
RegisterPluginStep<T>(legacy API, acceptsAction<LocalPluginContext>)