Skip to content

Commit 099d18a

Browse files
committed
REFACTOR: Use the ExtendedTracingService in LocalPluginContext
1 parent 5725390 commit 099d18a

File tree

11 files changed

+77
-46
lines changed

11 files changed

+77
-46
lines changed

XrmPluginCore.Tests/LocalPluginContextTests.cs

Lines changed: 19 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -1,9 +1,10 @@
1+
using XrmPluginCore.Extensions;
12
using XrmPluginCore.Tests.Helpers;
23
using FluentAssertions;
3-
using Microsoft.Xrm.Sdk;
44
using NSubstitute;
55
using System;
66
using Xunit;
7+
using Microsoft.Extensions.DependencyInjection;
78

89
namespace XrmPluginCore.Tests
910
{
@@ -14,13 +15,16 @@ public void Constructor_ValidServiceProvider_ShouldInitializeCorrectly()
1415
{
1516
// Arrange
1617
var mockProvider = new MockServiceProvider();
18+
var serviceProvider = mockProvider.ServiceProvider.BuildServiceProvider(services => services);
19+
var tracingService = serviceProvider.GetService<IExtendedTracingService>();
1720

1821
// Act
19-
var context = new LocalPluginContext(mockProvider.ServiceProvider);
22+
var context = new LocalPluginContext(serviceProvider);
2023

2124
// Assert
2225
context.PluginExecutionContext.Should().Be(mockProvider.PluginExecutionContext);
23-
context.TracingService.Should().Be(mockProvider.TracingService);
26+
tracingService.Should().NotBeNull();
27+
context.TracingService.Should().Be(tracingService);
2428
context.OrganizationService.Should().Be(mockProvider.OrganizationService);
2529
context.OrganizationAdminService.Should().Be(mockProvider.OrganizationAdminService);
2630
}
@@ -37,7 +41,8 @@ public void Trace_ValidMessage_ShouldCallTracingService()
3741
{
3842
// Arrange
3943
var mockProvider = new MockServiceProvider();
40-
var context = new LocalPluginContext(mockProvider.ServiceProvider);
44+
var serviceProvider = mockProvider.ServiceProvider.BuildServiceProvider(services => services);
45+
var context = new LocalPluginContext(serviceProvider);
4146
var testMessage = "Test trace message";
4247

4348
// Act
@@ -56,7 +61,8 @@ public void Trace_NullMessage_ShouldNotCallTracingService()
5661
{
5762
// Arrange
5863
var mockProvider = new MockServiceProvider();
59-
var context = new LocalPluginContext(mockProvider.ServiceProvider);
64+
var serviceProvider = mockProvider.ServiceProvider.BuildServiceProvider(services => services);
65+
var context = new LocalPluginContext(serviceProvider);
6066

6167
// Act
6268
context.Trace(null);
@@ -70,7 +76,8 @@ public void Trace_EmptyMessage_ShouldNotCallTracingService()
7076
{
7177
// Arrange
7278
var mockProvider = new MockServiceProvider();
73-
var context = new LocalPluginContext(mockProvider.ServiceProvider);
79+
var serviceProvider = mockProvider.ServiceProvider.BuildServiceProvider(services => services);
80+
var context = new LocalPluginContext(serviceProvider);
7481

7582
// Act
7683
context.Trace("");
@@ -84,7 +91,8 @@ public void Trace_WhitespaceMessage_ShouldNotCallTracingService()
8491
{
8592
// Arrange
8693
var mockProvider = new MockServiceProvider();
87-
var context = new LocalPluginContext(mockProvider.ServiceProvider);
94+
var serviceProvider = mockProvider.ServiceProvider.BuildServiceProvider(services => services);
95+
var context = new LocalPluginContext(serviceProvider);
8896

8997
// Act
9098
context.Trace(" ");
@@ -100,9 +108,10 @@ public void OrganizationService_ShouldUseUserId()
100108
var mockProvider = new MockServiceProvider();
101109
var userId = Guid.NewGuid();
102110
mockProvider.PluginExecutionContext.UserId.Returns(userId);
111+
var serviceProvider = mockProvider.ServiceProvider.BuildServiceProvider(services => services);
103112

104113
// Act
105-
var context = new LocalPluginContext(mockProvider.ServiceProvider);
114+
var context = new LocalPluginContext(serviceProvider);
106115

107116
// Assert
108117
mockProvider.OrganizationServiceFactory.Received(1).CreateOrganizationService(userId);
@@ -113,9 +122,10 @@ public void OrganizationAdminService_ShouldUseNullUserId()
113122
{
114123
// Arrange
115124
var mockProvider = new MockServiceProvider();
125+
var serviceProvider = mockProvider.ServiceProvider.BuildServiceProvider(services => services);
116126

117127
// Act
118-
var context = new LocalPluginContext(mockProvider.ServiceProvider);
128+
var context = new LocalPluginContext(serviceProvider);
119129

120130
// Assert
121131
mockProvider.OrganizationServiceFactory.Received(1).CreateOrganizationService(null);

XrmPluginCore.Tests/PluginTests.cs

Lines changed: 15 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -258,7 +258,9 @@ public void GetEntity_ValidTarget_ShouldReturnEntity()
258258
{
259259
// Arrange
260260
var mockProvider = new MockServiceProvider();
261-
var context = new LocalPluginContext(mockProvider.ServiceProvider);
261+
262+
var serviceProvider = mockProvider.ServiceProvider.BuildServiceProvider(services => services);
263+
var context = new LocalPluginContext(serviceProvider);
262264
var account = new Entity("account") { Id = Guid.NewGuid() };
263265

264266
var inputParameters = new ParameterCollection { { "Target", account } };
@@ -273,7 +275,9 @@ public void GetEntity_NoTarget_ShouldReturnNull()
273275
{
274276
// Arrange
275277
var mockProvider = new MockServiceProvider();
276-
var context = new LocalPluginContext(mockProvider.ServiceProvider);
278+
279+
var serviceProvider = mockProvider.ServiceProvider.BuildServiceProvider(services => services);
280+
var context = new LocalPluginContext(serviceProvider);
277281
var inputParameters = new ParameterCollection();
278282
mockProvider.SetupInputParameters(inputParameters);
279283

@@ -289,7 +293,9 @@ public void GetEntity_WrongEntityType_ShouldReturnNull()
289293
{
290294
// Arrange
291295
var mockProvider = new MockServiceProvider();
292-
var context = new LocalPluginContext(mockProvider.ServiceProvider);
296+
297+
var serviceProvider = mockProvider.ServiceProvider.BuildServiceProvider(services => services);
298+
var context = new LocalPluginContext(serviceProvider);
293299
var contact = new Entity("contact") { Id = Guid.NewGuid() };
294300

295301
var inputParameters = new ParameterCollection { { "Target", contact } };
@@ -307,7 +313,9 @@ public void GetPreImage_ValidImage_ShouldReturnEntity()
307313
{
308314
// Arrange
309315
var mockProvider = new MockServiceProvider();
310-
var context = new LocalPluginContext(mockProvider.ServiceProvider);
316+
317+
var serviceProvider = mockProvider.ServiceProvider.BuildServiceProvider(services => services);
318+
var context = new LocalPluginContext(serviceProvider);
311319
var account = new Entity("account") { Id = Guid.NewGuid() };
312320

313321
var preImages = new EntityImageCollection { { "PreImage", account } };
@@ -322,7 +330,9 @@ public void GetPostImage_ValidImage_ShouldReturnEntity()
322330
{
323331
// Arrange
324332
var mockProvider = new MockServiceProvider();
325-
var context = new LocalPluginContext(mockProvider.ServiceProvider);
333+
334+
var serviceProvider = mockProvider.ServiceProvider.BuildServiceProvider(services => services);
335+
var context = new LocalPluginContext(serviceProvider);
326336
var account = new Entity("account") { Id = Guid.NewGuid() };
327337

328338
var postImages = new EntityImageCollection { { "PostImage", account } };

XrmPluginCore.Tests/TestPlugins/TestPlugins.cs

Lines changed: 0 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,6 @@
11
using XrmPluginCore.Enums;
22
using Microsoft.Xrm.Sdk;
33
using System;
4-
using XrmPluginCore;
54

65
namespace XrmPluginCore.Tests.TestPlugins
76
{

XrmPluginCore/CHANGELOG.md

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,3 +1,6 @@
1+
### v1.0.1-preview.1 - 2 October 2025
2+
* Refactor: Merge CustomAPI into Plugin base class for simplicity
3+
14
### v1.0.0 - 30 September 2025
25
* Add: Support for XrmBedrock style plugins by wrapping the LocalPluginContext in IServiceProvider
36
* Add: IPluginExecutionContext extension methods to simplify getting the target and image data

XrmPluginCore/CustomApis/CustomApiRegistration.cs

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -4,13 +4,13 @@ namespace XrmPluginCore.CustomApis
44
{
55
internal class CustomApiRegistration
66
{
7-
public CustomApiRegistration(CustomApiConfigBuilder customApiConfig, Action<IServiceProvider> action)
7+
public CustomApiRegistration(CustomApiConfigBuilder customApiConfig, Action<IExtendedServiceProvider> action)
88
{
99
ConfigBuilder = customApiConfig;
1010
Action = action;
1111
}
1212
public CustomApiConfigBuilder ConfigBuilder { get; set; }
1313

14-
public Action<IServiceProvider> Action { get; set; }
14+
public Action<IExtendedServiceProvider> Action { get; set; }
1515
}
1616
}
Lines changed: 16 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,16 @@
1+
using System;
2+
3+
namespace XrmPluginCore
4+
{
5+
public class ExtendedServiceProvider : IExtendedServiceProvider
6+
{
7+
private readonly IServiceProvider _wrappedServiceProvider;
8+
9+
public ExtendedServiceProvider(IServiceProvider wrappedServiceProvider)
10+
{
11+
_wrappedServiceProvider = wrappedServiceProvider;
12+
}
13+
14+
public object GetService(Type serviceType) => _wrappedServiceProvider.GetService(serviceType);
15+
}
16+
}

XrmPluginCore/Extensions/ServiceProviderExtensions.cs

Lines changed: 4 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -5,9 +5,9 @@
55

66
namespace XrmPluginCore.Extensions
77
{
8-
internal static class ServiceProviderExtensions
8+
public static class ServiceProviderExtensions
99
{
10-
public static ServiceProvider BuildServiceProvider(this IServiceProvider serviceProvider, Func<IServiceCollection, IServiceCollection> onBeforeBuild)
10+
public static ExtendedServiceProvider BuildServiceProvider(this IServiceProvider serviceProvider, Func<IServiceCollection, IServiceCollection> onBeforeBuild)
1111
{
1212
// Get services of the ServiceProvider
1313
var tracingService = serviceProvider.GetService<ITracingService>() ?? throw new Exception("Unable to get Tracing service");
@@ -35,7 +35,8 @@ public static ServiceProvider BuildServiceProvider(this IServiceProvider service
3535
services = onBeforeBuild(services);
3636

3737
// Build the service provider
38-
return services.BuildServiceProvider();
38+
var localServiceProvider = services.BuildServiceProvider();
39+
return new ExtendedServiceProvider(localServiceProvider);
3940
}
4041

4142
public static void Trace(this IServiceProvider serviceProvider, string message)
Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,8 @@
1+
using System;
2+
3+
namespace XrmPluginCore
4+
{
5+
public interface IExtendedServiceProvider : IServiceProvider
6+
{
7+
}
8+
}

XrmPluginCore/LocalPluginContext.cs

Lines changed: 4 additions & 20 deletions
Original file line numberDiff line numberDiff line change
@@ -14,9 +14,9 @@ public class LocalPluginContext
1414

1515
public IPluginExecutionContext PluginExecutionContext { get; }
1616

17-
public ITracingService TracingService { get; }
17+
public IExtendedTracingService TracingService { get; }
1818

19-
public LocalPluginContext(IServiceProvider serviceProvider)
19+
public LocalPluginContext(IExtendedServiceProvider serviceProvider)
2020
{
2121
if (serviceProvider == null)
2222
{
@@ -27,7 +27,7 @@ public LocalPluginContext(IServiceProvider serviceProvider)
2727
PluginExecutionContext = serviceProvider.GetService<IPluginExecutionContext>();
2828

2929
// Obtain the tracing service from the service provider.
30-
TracingService = serviceProvider.GetService<ITracingService>();
30+
TracingService = serviceProvider.GetService<IExtendedTracingService>();
3131

3232
// Obtain the Organization Service factory service from the service provider
3333
var factory = serviceProvider.GetService<IOrganizationServiceFactory>();
@@ -41,23 +41,7 @@ public LocalPluginContext(IServiceProvider serviceProvider)
4141

4242
public void Trace(string message)
4343
{
44-
if (string.IsNullOrWhiteSpace(message) || TracingService == null)
45-
{
46-
return;
47-
}
48-
49-
if (PluginExecutionContext == null)
50-
{
51-
TracingService.Trace(message);
52-
}
53-
else
54-
{
55-
TracingService.Trace(
56-
"{0}, Correlation Id: {1}, Initiating User: {2}",
57-
message,
58-
PluginExecutionContext.CorrelationId,
59-
PluginExecutionContext.InitiatingUserId);
60-
}
44+
TracingService?.Trace(message, PluginExecutionContext);
6145
}
6246
}
6347
}

XrmPluginCore/Plugin.cs

Lines changed: 4 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -159,7 +159,7 @@ protected PluginStepConfigBuilder<TEntity> RegisterStep<TEntity, TService>(
159159
/// <param name="action">The action to execute</param>
160160
/// <returns>The <see cref="PluginStepConfigBuilder{T}"/> to register filters and images</returns>
161161
protected PluginStepConfigBuilder<T> RegisterStep<T>(
162-
EventOperation eventOperation, ExecutionStage executionStage, Action<IServiceProvider> action)
162+
EventOperation eventOperation, ExecutionStage executionStage, Action<IExtendedServiceProvider> action)
163163
where T : Entity
164164
{
165165
var builder = new PluginStepConfigBuilder<T>(eventOperation, executionStage);
@@ -198,7 +198,7 @@ protected CustomApiConfigBuilder RegisterAPI<TService>(string name, Action<TServ
198198
/// </para>
199199
/// </summary>
200200
/// <exception cref="InvalidOperationException">If called multiple times in the same class</exception>
201-
protected CustomApiConfigBuilder RegisterAPI(string name, Action<IServiceProvider> action)
201+
protected CustomApiConfigBuilder RegisterAPI(string name, Action<IExtendedServiceProvider> action)
202202
{
203203
if (RegisteredCustomApi != null)
204204
{
@@ -219,14 +219,14 @@ protected PluginStepConfigBuilder<MessageEntity> RegisterPluginStep(
219219
}
220220

221221
protected PluginStepConfigBuilder<MessageEntity> RegisterStep(
222-
string pluginMessage, EventOperation eventOperation, ExecutionStage executionStage, Action<IServiceProvider> action)
222+
string pluginMessage, EventOperation eventOperation, ExecutionStage executionStage, Action<IExtendedServiceProvider> action)
223223
{
224224
var builder = new PluginStepConfigBuilder<MessageEntity>(pluginMessage, eventOperation, executionStage);
225225
RegisteredPluginSteps.Add(new PluginStepRegistration(builder, action));
226226
return builder;
227227
}
228228

229-
private Action<IServiceProvider> GetAction(IPluginExecutionContext context)
229+
private Action<IExtendedServiceProvider> GetAction(IPluginExecutionContext context)
230230
{
231231
// Iterate over all of the expected registered events to ensure that the plugin
232232
// has been invoked by an expected event

0 commit comments

Comments
 (0)