|
1 | 1 | # Dependency injection for standalone Screenplay |
2 | 2 |
|
3 | | -If you are [using Screenplay standalone] then the [`Screenplay.ExecuteAsPerformanceAsync`] permits resolution of dependencies via its parameter. |
4 | | -That parameter is a `Func<IServiceProvider,CancellationToken,Task<bool?>>`. |
5 | | -The service provider may be used to resolve dependency services for the performance's logic. |
6 | | - |
7 | | -Developers are urged to consider encapsulating their performance logic in implementations of [`IHostsPerformance`]. |
8 | | -Through an overload (extension method) named [`ExecuteAsPerformanceAsync<T>`], developers may specify the concrete implementation of that interface. |
9 | | -This extension method will resolve that implementation type along with any of its constructor-injected dependencies. |
10 | | -This avoids the service locator anti-pattern and provides a convenient pattern by which to write performance logic. |
11 | | - |
12 | | -Use services resolved from the service provider, or injected into your [`IHostsPerformance`] implementation, to get access to [commonly-used Screenplay services] and anything else required at the root level of your performance logic. |
| 3 | +If you are [using Screenplay standalone] then you are likely using the method [`Screenplay.ExecuteAsPerformanceAsync`] or one of its overloads. |
13 | 4 |
|
14 | 5 | [using Screenplay standalone]: ../gettingStarted/nonTesting/index.md |
15 | 6 | [`Screenplay.ExecuteAsPerformanceAsync`]: xref:CSF.Screenplay.Screenplay.ExecuteAsPerformanceAsync(System.Func{System.IServiceProvider,System.Threading.CancellationToken,System.Threading.Tasks.Task{System.Nullable{System.Boolean}}},System.Collections.Generic.IList{CSF.Screenplay.Performances.IdentifierAndName},System.Threading.CancellationToken) |
| 7 | + |
| 8 | +## Recommended: Use `IHostsPerformance` |
| 9 | + |
| 10 | +Developers are urged to consider encapsulating their performance logic in a class which derives from [`IHostsPerformance`]. |
| 11 | +Through an overload (extension method) named [`ExecuteAsPerformanceAsync<T>`], developers may specify the concrete implementation type of that class as a generic type parameter. |
| 12 | +This overload of `ExecuteAsPerformanceAsync` will resolve your class which derives from `IHostsPerformance` from dependency injection (_remember to add it to the container!_). |
| 13 | +This resolution will include all the class' dependencies which are constructor-injected and leads to very clean code. |
| 14 | +The service provider is never exposed, thus removing the temptation to use the service locator anti-pattern. |
| 15 | + |
16 | 16 | [`IHostsPerformance`]: xref:CSF.Screenplay.IHostsPerformance |
17 | 17 | [`ExecuteAsPerformanceAsync<T>`]: xref:CSF.Screenplay.ScreenplayExtensions.ExecuteAsPerformanceAsync``1(CSF.Screenplay.Screenplay,System.Collections.Generic.IList{CSF.Screenplay.Performances.IdentifierAndName},System.Threading.CancellationToken) |
| 18 | + |
| 19 | +### Example of the performance host technique |
| 20 | + |
| 21 | +This example is functionally identical to the example below. |
| 22 | + |
| 23 | +```csharp |
| 24 | +public class MyPerformance(ICast cast) : IHostsPerformance |
| 25 | +{ |
| 26 | + public Task<bool?> ExecutePerformanceAsync(CancellationToken cancellationToken) |
| 27 | + { |
| 28 | + var aaron = cast.GetActor<Aaron>(); |
| 29 | + // Further performance logic ... |
| 30 | + } |
| 31 | +} |
| 32 | + |
| 33 | +// To consume the above: |
| 34 | +await screenplay.ExecuteAsPerformanceAsync<MyPerformance>(); |
| 35 | +``` |
| 36 | + |
| 37 | +## Alternative: Use a function |
| 38 | + |
| 39 | +The original [`Screenplay.ExecuteAsPerformanceAsync`] overload accepts up to three parameters, the first of which is a function. |
| 40 | +That function should contain the logic which makes up the performance. |
| 41 | +The function (which drives the performance logic) provides two parameters itself: |
| 42 | + |
| 43 | +* An [`IServiceProvider`](xref:System.IServiceProvider) |
| 44 | +* A [`CancellationToken`](xref:System.Threading.CancellationToken) |
| 45 | + |
| 46 | +The serivce provider may be used to resolve services which may be used by the performance logic. |
| 47 | + |
| 48 | +### Example of the function-based technique |
| 49 | + |
| 50 | +This example is functionally identical to the example above. |
| 51 | + |
| 52 | +```csharp |
| 53 | +await screenplay.ExecuteAsPerformanceAsync((services, cancellationToken) => { |
| 54 | + var cast = services.GetRequiredService<ICast>(); |
| 55 | + var aaron = cast.GetActor<Aaron>(); |
| 56 | + // Further performance logic ... |
| 57 | +}); |
| 58 | + |
| 59 | +``` |
0 commit comments