DEVKIT1014 - phuocle/Dynamics-Crm-DevKit GitHub Wiki
This analyzer detects subscription to AppDomain events within plugin or workflow activity classes. Plugin instances are cached and reused, so subscribing to AppDomain events can cause memory leaks and unexpected behavior.
When you subscribe to AppDomain events in plugins:
- Memory Leaks: Event handlers are never removed, causing memory to accumulate
- Multiple Subscriptions: Each plugin execution might add another subscription
- Unexpected Behavior: Event handlers from one execution might interfere with another
- Platform Instability: Can affect the entire AppDomain, not just your plugin
| Event | Risk |
|---|---|
UnhandledException |
High - affects global exception handling |
FirstChanceException |
High - catches all exceptions before handlers |
AssemblyResolve |
High - affects assembly loading |
TypeResolve |
Medium - affects type resolution |
ResourceResolve |
Medium - affects resource loading |
AssemblyLoad |
Medium - monitors assembly loading |
DomainUnload |
High - runs on domain shutdown |
ProcessExit |
High - runs on process exit |
public class BadPlugin : IPlugin
{
public void Execute(IServiceProvider serviceProvider)
{
// ❌ Memory leak - event handler never removed
AppDomain.CurrentDomain.UnhandledException += (s, e) =>
{
// Handle exception
};
// ❌ Multiple subscriptions per execution
AppDomain.CurrentDomain.AssemblyResolve += OnAssemblyResolve;
}
private Assembly OnAssemblyResolve(object sender, ResolveEventArgs e)
{
// Resolve assembly
return null;
}
}public class GoodPlugin : IPlugin
{
public void Execute(IServiceProvider serviceProvider)
{
var tracingService = (ITracingService)serviceProvider
.GetService(typeof(ITracingService));
try
{
// Do work
}
catch (Exception ex)
{
// ✅ Handle exceptions locally instead of using AppDomain events
tracingService.Trace("Error: {0}", ex.Message);
throw new InvalidPluginExecutionException(
"An error occurred", ex);
}
}
}- Remove AppDomain event subscriptions from plugin code
- Use try-catch blocks for exception handling
- Use ITracingService for logging
- Throw InvalidPluginExecutionException for errors
In rare cases where you need this (not recommended):
#pragma warning disable DEVKIT1014
AppDomain.CurrentDomain.UnhandledException += handler;
#pragma warning restore DEVKIT1014Or in .editorconfig:
[*.cs]
dotnet_diagnostic.DEVKIT1014.severity = noneWarning: Suppressing this rule is strongly discouraged as it can cause platform instability.
| Property | Value |
|---|---|
| Rule ID | DEVKIT1014 |
| Category | DynamicsCrm.DevKit |
| Severity | Error |
| Enabled by default | Yes |