Skip to content

Commit 855dc28

Browse files
authored
Remove documentation references to MEF (#1525)
1 parent 9442735 commit 855dc28

File tree

3 files changed

+85
-45
lines changed

3 files changed

+85
-45
lines changed

.github/copilot-instructions.md

Lines changed: 18 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -25,7 +25,7 @@ All new detectors start as **IDefaultOffComponentDetector** (must be explicitly
2525
1. **DefaultOff** → 2. **IExperimentalDetector** (enabled but output not captured) → 3. **Default** (fully integrated)
2626

2727
### Dependency Injection
28-
All services auto-register via `ServiceCollectionExtensions.AddComponentDetection()` in Orchestrator. Detectors are discovered at runtime via `[Export]` attribute.
28+
All services register via `ServiceCollectionExtensions.AddComponentDetection()` in Orchestrator using standard .NET DI. Detectors use constructor injection for dependencies.
2929

3030
## Creating a New Detector
3131

@@ -37,9 +37,18 @@ All services auto-register via `ServiceCollectionExtensions.AddComponentDetectio
3737

3838
2. **Implement Detector**:
3939
```csharp
40-
[Export]
4140
public class YourDetector : FileComponentDetector, IDefaultOffComponentDetector
4241
{
42+
public YourDetector(
43+
IComponentStreamEnumerableFactory componentStreamEnumerableFactory,
44+
IObservableDirectoryWalkerFactory walkerFactory,
45+
ILogger<YourDetector> logger)
46+
{
47+
this.ComponentStreamEnumerableFactory = componentStreamEnumerableFactory;
48+
this.Scanner = walkerFactory;
49+
this.Logger = logger;
50+
}
51+
4352
public override string Id => "YourEcosystem";
4453
public override IEnumerable<string> Categories => [DetectorClass.YourCategory];
4554
public override IEnumerable<ComponentType> SupportedComponentTypes => [ComponentType.YourType];
@@ -53,7 +62,13 @@ All services auto-register via `ServiceCollectionExtensions.AddComponentDetectio
5362
}
5463
```
5564

56-
3. **Register Components**:
65+
3. **Register Detector in DI**:
66+
Add to `ServiceCollectionExtensions.AddComponentDetection()` in Orchestrator:
67+
```csharp
68+
services.AddSingleton<IComponentDetector, YourDetector>();
69+
```
70+
71+
4. **Register Components in Code**:
5772
```csharp
5873
var component = new DetectedComponent(new YourComponent("name", "1.0.0"));
5974
recorder.RegisterUsage(

docs/creating-a-new-detector.md

Lines changed: 12 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -67,7 +67,7 @@ Go inside the project MS.VS.Services.Governance.ComponentDetection.Detectors, an
6767

6868
![ruby-component-detector.png](./images/creating-a-new-detector/ruby-component-detector.png)
6969

70-
- **Export**: All detectors are loaded during runtime, so this attribute helps with the discoverability.
70+
- **Constructor Injection**: Detectors use standard .NET dependency injection. Inject required services like `IComponentStreamEnumerableFactory`, `IObservableDirectoryWalkerFactory`, and `ILogger<T>` through the constructor.
7171
- **FileComponentDetector**: This is base class of all file based detectors
7272
- **IDefaultOffComponentDetector**: All new detectors should also implement this interface (not shown in above screenshot) so new detectors are not going to run as part of the default set of detectors. They are only run when a user manually enables the detector via [argument](./enable-default-off.md).
7373
- **Id**: Detector's identifier
@@ -81,6 +81,17 @@ Go inside the project MS.VS.Services.Governance.ComponentDetection.Detectors, an
8181
### Advanced detection
8282
The above example is a basic introduction to creating your own detector and should be sufficient for most new detectors. Sometimes you need more granularity when processing files, as such we have 2 additional detection [lifecycle methods](#-Detector-File-Processing-Lifecycle).
8383

84+
## Register the detector in dependency injection
85+
86+
After creating your detector class, you must register it in the dependency injection container. Add your detector to `src/Microsoft.ComponentDetection.Orchestrator/Extensions/ServiceCollectionExtensions.cs` in the `AddComponentDetection` method:
87+
88+
```csharp
89+
// YourEcosystem
90+
services.AddSingleton<IComponentDetector, YourDetector>();
91+
```
92+
93+
This registration allows the orchestrator to discover and instantiate your detector at runtime.
94+
8495
## Registering Components
8596

8697
Each instance of a detector has a `ComponentRecorder`. A `ComponentRecorder` contains a set of `SingleFileComponentRecorder`s. A `SingleFileComponentRecorder` is an immutable graph store for components associated to a particular file. The purpose of any detector is to populate a given `SingleFileComponentRecorder` with a graph representation of all of the components found in a given file.

docs/creating-a-new-service.md

Lines changed: 55 additions & 41 deletions
Original file line numberDiff line numberDiff line change
@@ -1,73 +1,87 @@
11
# Creating a new service
22

3-
We will be using [this PR](https://github.com/microsoft/component-detection/pull/12) following `EnvironmentVariableService` as a model for adding a new service.
4-
The following steps are distilled and organized from that PR.
3+
Component Detection uses standard .NET dependency injection for service registration. This guide shows how to add a new service to the system.
54

6-
1. Create your new service interface in `src/Microsoft.ComponentDetection.Contracts/IMyNewService.cs`
7-
2. Create your new service implementation in `src/Microsoft.ComponentDetection.Common/MyNewService.cs` implementing and exporting `IMyNewService`.
5+
## Steps to create a new service
86

9-
```c#
10-
using System;
11-
using System.Composition;
12-
using Microsoft.ComponentDetection.Contracts;
7+
1. **Create your service interface** in `src/Microsoft.ComponentDetection.Contracts/IMyNewService.cs`
138

14-
namespace Microsoft.ComponentDetection.Common
9+
```c#
10+
namespace Microsoft.ComponentDetection.Contracts
1511
{
16-
[Export(typeof(IMyNewService))]
17-
public class MyNewService : IMyNewService
12+
public interface IMyNewService
1813
{
19-
...
14+
// Define your service methods
15+
string DoSomething();
2016
}
2117
}
2218
```
2319

24-
3. Add your new service to `src/Microsoft.ComponentDetection.Contracts/IDetectorDependencies.cs`
20+
2. **Create your service implementation** in `src/Microsoft.ComponentDetection.Common/MyNewService.cs`
2521

2622
```c#
27-
namespace Microsoft.ComponentDetection.Contracts
23+
using Microsoft.ComponentDetection.Contracts;
24+
25+
namespace Microsoft.ComponentDetection.Common
2826
{
29-
public interface IDetectorDependencies
27+
public class MyNewService : IMyNewService
3028
{
31-
...
32-
IMyNewService MyNewService { get; set; }
29+
// Inject any dependencies your service needs
30+
public MyNewService(ILogger<MyNewService> logger)
31+
{
32+
// Constructor injection
33+
}
34+
35+
public string DoSomething()
36+
{
37+
// Implementation
38+
}
3339
}
3440
}
3541
```
3642

37-
4. Add your new service to `src/Microsoft.ComponentDetection.Common/DetectorDependencies.cs`
43+
3. **Register your service** in `src/Microsoft.ComponentDetection.Orchestrator/Extensions/ServiceCollectionExtensions.cs`
44+
45+
Add your service registration to the `AddComponentDetection` method:
3846

3947
```c#
40-
namespace Microsoft.ComponentDetection.Common
48+
public static IServiceCollection AddComponentDetection(this IServiceCollection services)
4149
{
42-
[Export(typeof(IDetectorDependencies))]
43-
public class DetectorDependencies : IDetectorDependencies
44-
{
45-
...
46-
[Import]
47-
public IMyNewService MyNewService { get; set; }
48-
}
50+
// ... existing registrations ...
51+
52+
// Your new service
53+
services.AddSingleton<IMyNewService, MyNewService>();
54+
55+
// ... more registrations ...
56+
return services;
4957
}
5058
```
5159

52-
5. Add your new service to `src/Microsoft.ComponentDetection.Contracts/Internal/InjectionParameters.cs`
60+
4. **Use your service** in detectors or other services via constructor injection:
5361

5462
```c#
55-
namespace Microsoft.ComponentDetection.Contracts.Internal
63+
public class MyDetector : FileComponentDetector
5664
{
57-
internal class InjectionParameters
65+
private readonly IMyNewService myNewService;
66+
67+
public MyDetector(
68+
IComponentStreamEnumerableFactory componentStreamEnumerableFactory,
69+
IObservableDirectoryWalkerFactory walkerFactory,
70+
ILogger<MyDetector> logger,
71+
IMyNewService myNewService) // Inject your service
5872
{
59-
internal InjectionParameters(IDetectorDependencies detectorDependencies)
60-
{
61-
...
62-
myNewServiceStatic = detectorDependencies.MyNewService;
63-
}
73+
this.ComponentStreamEnumerableFactory = componentStreamEnumerableFactory;
74+
this.Scanner = walkerFactory;
75+
this.Logger = logger;
76+
this.myNewService = myNewService;
6477
}
65-
66-
...
67-
private static IMyNewService myNewServiceStatic;
68-
69-
...
70-
[Export(typeof(IMyNewService))]
71-
public IMyNewService MyNewService => myNewServiceStatic;
7278
}
7379
```
80+
81+
## Service Lifetimes
82+
83+
- Use `AddSingleton` for stateless services or services that should be reused across the application lifetime
84+
- Use `AddScoped` for services that should be created once per scan operation (rare in this codebase)
85+
- Use `AddTransient` for lightweight, stateless services that should be created each time they're requested
86+
87+
Most services in Component Detection are registered as singletons.

0 commit comments

Comments
 (0)