Warning
This rule reports when a handler method's signature does not match the images registered with WithPreImage(), WithPostImage(), or AddImage(), and the generated PreImage/PostImage types don't exist yet. The handler method must accept parameters in a specific order: PreImage first (if registered), then PostImage (if registered).
This is a warning to allow the initial build to succeed so that the source generator can create the wrapper types. Once the types exist, this diagnostic escalates to XPC4003 (Error).
public class AccountPlugin : Plugin
{
public AccountPlugin()
{
// XPC4002: Handler method 'HandleUpdate' does not have expected signature.
// Expected parameters in order: PreImage
RegisterStep<Account, IAccountService>(
EventOperation.Update,
ExecutionStage.PostOperation,
nameof(IAccountService.HandleUpdate))
.WithPreImage(x => x.Name);
}
}
public interface IAccountService
{
void HandleUpdate(); // Missing PreImage parameter!
}public class AccountPlugin : Plugin
{
public AccountPlugin()
{
// XPC4002: Handler method 'HandleUpdate' does not have expected signature.
// Expected parameters in order: PostImage
RegisterStep<Account, IAccountService>(
EventOperation.Update,
ExecutionStage.PostOperation,
nameof(IAccountService.HandleUpdate))
.WithPostImage(x => x.Name);
}
}
public interface IAccountService
{
void HandleUpdate(); // Missing PostImage parameter!
}public class AccountPlugin : Plugin
{
public AccountPlugin()
{
// XPC4002: Handler method 'HandleUpdate' does not have expected signature.
// Expected parameters in order: PreImage, PostImage
RegisterStep<Account, IAccountService>(
EventOperation.Update,
ExecutionStage.PostOperation,
nameof(IAccountService.HandleUpdate))
.WithPreImage(x => x.Name)
.WithPostImage(x => x.AccountNumber);
}
}
public interface IAccountService
{
void HandleUpdate(PostImage post, PreImage pre); // Wrong order!
}Update the handler method signature to match the registered images:
public class AccountPlugin : Plugin
{
public AccountPlugin()
{
RegisterStep<Account, IAccountService>(
EventOperation.Update,
ExecutionStage.PostOperation,
nameof(IAccountService.HandleUpdate))
.WithPreImage(x => x.Name)
.WithPostImage(x => x.AccountNumber);
}
}
public interface IAccountService
{
// Correct order: PreImage first, then PostImage
void HandleUpdate(PreImage preImage, PostImage postImage);
}| Registered Images | Expected Signature |
|---|---|
| PreImage only | void Method(PreImage preImage) |
| PostImage only | void Method(PostImage postImage) |
| Both images | void Method(PreImage preImage, PostImage postImage) |
| No images | void Method() |
-
Type-safe code generation: The source generator creates strongly-typed
PreImageandPostImagewrapper classes that are injected into your handler method. If the signature doesn't match, the generated code won't compile or work correctly. -
Compile-time enforcement: This error prevents developers from accidentally ignoring registered images, which could lead to subtle bugs where image data is never used.
-
Clear contract: The handler signature explicitly declares what data the method expects, making the code more readable and maintainable.
Visual Studio and other IDEs supporting Roslyn analyzers will offer a code fix to update the method signature to match the registered images.
- XPC4002 (Warning): Reported when the generated types don't exist yet. This allows the initial build to succeed so the types can be generated.
- XPC4003 (Error): Reported when the generated types exist but the signature is still wrong. This prevents runtime failures.