Skip to content

Commit

Permalink
Merge pull request #5 from NotCoffee418/dev
Browse files Browse the repository at this point in the history
Remove Autofac dependency
  • Loading branch information
NotCoffee418 authored Mar 23, 2024
2 parents d223a5d + a246fee commit 082bce4
Show file tree
Hide file tree
Showing 8 changed files with 102 additions and 96 deletions.
4 changes: 2 additions & 2 deletions CSharpScriptOperations.sln
Original file line number Diff line number Diff line change
@@ -1,11 +1,11 @@


Microsoft Visual Studio Solution File, Format Version 12.00
# Visual Studio Version 17
VisualStudioVersion = 17.0.31912.275
MinimumVisualStudioVersion = 10.0.40219.1
Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "CSharpScriptOperations", "CSharpScriptOperations\CSharpScriptOperations.csproj", "{8D54816D-2826-4287-AFF8-7722775207AC}"
EndProject
Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "DemoApp", "DemoApp\DemoApp.csproj", "{EF66B8B7-4344-458D-AECE-5537AD1D197F}"
Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "DemoApp", "DemoApp\DemoApp.csproj", "{EF66B8B7-4344-458D-AECE-5537AD1D197F}"
EndProject
Global
GlobalSection(SolutionConfigurationPlatforms) = preSolution
Expand Down
50 changes: 0 additions & 50 deletions CSharpScriptOperations/Application.cs

This file was deleted.

7 changes: 3 additions & 4 deletions CSharpScriptOperations/CSharpScriptOperations.csproj
Original file line number Diff line number Diff line change
Expand Up @@ -26,10 +26,9 @@
</None>
</ItemGroup>

<ItemGroup>
<PackageReference Include="Autofac" Version="[7,]" /> <!-- Autofac version "[8,]" -->
<PackageReference Include="Autofac.Extensions.DependencyInjection" Version="[8,]" /> <!-- Autofac version "[8,]" -->
<PackageReference Include="CoffeeToolkit.Linq" Version="2022.12.26.241" />
<ItemGroup> <!-- Autofac version "[8,]" --> <!-- Autofac version "[8,]" -->
<PackageReference Include="Microsoft.Extensions.DependencyInjection" Version="8.0.0" />
<PackageReference Include="Microsoft.Extensions.DependencyInjection.Abstractions" Version="8.0.1" />
</ItemGroup>

</Project>
81 changes: 57 additions & 24 deletions CSharpScriptOperations/OperationManager.cs
Original file line number Diff line number Diff line change
Expand Up @@ -16,12 +16,10 @@ private static Dictionary<int, Type> _registeredOperations
/// <summary>
/// Use to register additional dependencies
/// </summary>
public static ContainerBuilder ContainerBuilder = new ContainerBuilder();
public static IServiceCollection Services = new ServiceCollection();

internal static IServiceProvider EffectiveServiceProvider = null;

/// <summary>
/// Built container for internal access
/// </summary>
internal static Autofac.IContainer Container = null;

/// <summary>
/// Read-only access to RegisteredOperations.
Expand Down Expand Up @@ -52,7 +50,7 @@ public static void RegisterOperation(Type operation, int overrideIndex = 0)
_registeredOperations.Add(newIndex, operation);

// Register as dependency
ContainerBuilder.RegisterType(operation);
Services.AddTransient(operation);
}

/// <summary>
Expand All @@ -70,7 +68,8 @@ public static void AutoRegisterOperations()
// Get all applicable types
List<Type> operationTypes = AppDomain.CurrentDomain.GetAssemblies()
.SelectMany(x => x.GetTypes())
.UniqueBy( x => x.FullName)
.GroupBy(x => x.FullName)
.Select(g => g.First())
.Where(t => !t.IsInterface && !t.IsAbstract && t.GetInterfaces().Any(t => t.FullName == typeof(IOperation).FullName))
// Don't include any internal operations
.Where(a => !a.FullName.StartsWith(nameof(CSharpScriptOperations)))
Expand All @@ -81,26 +80,61 @@ public static void AutoRegisterOperations()

/// <summary>
/// Starts the listener loop which displays the registered operations,
/// requests user input and runs the requested operation.
/// requests user input, and runs the requested operation.
/// This will keep looping until the Exit Application operation is called.
///
/// Register any dependencies before calling this function.
/// </summary>
/// <returns></returns>
public static async Task StartListeningAsync()
/// <param name="serviceProvider">The IServiceProvider to use for resolving dependencies.</param>
/// <returns>A Task representing the asynchronous operation.</returns>
public static async Task StartListeningAsync(IServiceProvider serviceProvider = null)
{
// Register application dependencies
ContainerBuilder.RegisterType<Application>();
// Use the provided serviceProvider, or fallback to the Services property.
EffectiveServiceProvider = serviceProvider
?? Services.BuildServiceProvider();

// List all operations
Console.Write(GetOperationsDisplay());

// Request user
while (true) // Breakout is calling Exit operation
{
Console.WriteLine(); // empty
Console.WriteLine("Select an operation ('help' for list of operations)");
string userInput = Console.ReadLine();

// Handle "help"
if (userInput.ToLower() == "help")
{
Console.Write(GetOperationsDisplay());
continue;
}

// Prevents IServiceProvider related issues
// See: https://stackoverflow.com/questions/61779868/injecting-iserviceprovider-into-factory-class-with-autofac
ContainerBuilder.Populate(Enumerable.Empty<ServiceDescriptor>());
// Parse input, report and repeat on invalid
int reqOperationId = -1;
if (!int.TryParse(userInput, out reqOperationId))
{
Console.WriteLine("Input must be the numeric identifier of a registered operation. Try again.");
continue;
}

// Create container with all dependencies
Container = ContainerBuilder.Build();
// Handle invalid operation id
if (!OperationIdExists(reqOperationId))
{
Console.WriteLine("Invalid operation number. Try again.");
continue;
}

// Start listening in container
await Container.Resolve<Application>().RunAsync();
// Create instance
Type operationType = GetOperationTypeById(reqOperationId);
IOperation operationInstance = (IOperation)EffectiveServiceProvider.GetService(operationType);

// Valid registered operation, report and run it run it.
Console.WriteLine();
Console.WriteLine($"Running operation {reqOperationId}...");
await operationInstance.RunAsync();
Console.WriteLine();
}
}

/// <summary>
Expand All @@ -110,20 +144,18 @@ public static async Task StartListeningAsync()
public static string GetOperationsDisplay()
{
// Handle incorrect usage
if (Container is null)
if (EffectiveServiceProvider is null)
return "Cannot call GetOperationsDisplay() manually before calling StartListeningAsync(), which will print it automatically.";

/// Display operations
string result = "Available Operations: " + Environment.NewLine;
foreach (var opKvp in _registeredOperations)
{


/// Find the description
// Default
string description = "Add an [OperationDescription(\"goes here\")] attribute to the operation class.";
// Try via description attribute
OperationDescriptionAttribute? descAttr = opKvp.Value.GetCustomAttributes(typeof(OperationDescriptionAttribute), false)
OperationDescriptionAttribute descAttr = opKvp.Value.GetCustomAttributes(typeof(OperationDescriptionAttribute), false)
.FirstOrDefault() as OperationDescriptionAttribute;
if (descAttr is not null) // via attribute
description = descAttr.Description;
Expand All @@ -134,7 +166,7 @@ public static string GetOperationsDisplay()
IOperation operationInstance = null;
try
{
operationInstance = (IOperation)Container.Resolve(opKvp.Value);
operationInstance = (IOperation)EffectiveServiceProvider.GetService(opKvp.Value);
description = opKvp.Value.GetProperty("Description").GetValue(operationInstance) as string;
}
catch {/* Use default description */}
Expand Down Expand Up @@ -162,4 +194,5 @@ public static Type GetOperationTypeById(int operationId)
=> OperationIdExists(operationId) ?
_registeredOperations[operationId] :
throw new ArgumentException("GetOperationTypeById failed because the input id has no registered operation");

}
5 changes: 1 addition & 4 deletions CSharpScriptOperations/Usings.cs
Original file line number Diff line number Diff line change
Expand Up @@ -4,9 +4,6 @@
global using System.Reflection;
global using System.Linq;
global using System.Threading.Tasks;
global using Autofac;
global using Autofac.Extensions.DependencyInjection;
global using CSharpScriptOperations.InteralOperations;
global using System.Collections.ObjectModel;
global using Microsoft.Extensions.DependencyInjection;
global using CoffeeToolkit.Linq;
global using Microsoft.Extensions.DependencyInjection;
10 changes: 4 additions & 6 deletions DemoApp/DemoApp.csproj
Original file line number Diff line number Diff line change
@@ -1,18 +1,16 @@
<Project Sdk="Microsoft.NET.Sdk">

<PropertyGroup>
<OutputType>Exe</OutputType>
<TargetFramework>net6.0</TargetFramework>
<TargetFramework>net8.0</TargetFramework>
<ImplicitUsings>enable</ImplicitUsings>
<Nullable>enable</Nullable>
</PropertyGroup>

<ItemGroup>
<PackageReference Include="Autofac" Version="8.0.0" />
<PackageReference Include="Autofac.Extensions.DependencyInjection" Version="9.0.0" />
<PackageReference Include="Newtonsoft.Json" Version="13.0.3" />
</ItemGroup>

<ItemGroup>
<ProjectReference Include="..\CSharpScriptOperations\CSharpScriptOperations.csproj" />
</ItemGroup>

</Project>
</Project>
23 changes: 21 additions & 2 deletions DemoApp/Program.cs
Original file line number Diff line number Diff line change
@@ -1,9 +1,11 @@
using Autofac; // Import Autofac if you want DI
using Autofac.Extensions.DependencyInjection;
using CSharpScriptOperations;
using DemoApp.Logic;
using DemoApp.Operations;


/* --- REGISTER OPERATIONS --- */
// You can automatically register all operations
OperationManager.AutoRegisterOperations();

Expand All @@ -22,14 +24,31 @@
// }
//);


/* --- OPTIONAL: REGISTER DEPENDENCIES --- */
// Optionally register any custom dependencies through "OperationManager.ContainerBuilder" if needed
OperationManager.ContainerBuilder
// This example uses Autofac to register our operations. You need the following nuget dependencies:
// - Autofac
// - Autofac.Extensions.DependencyInjection
ContainerBuilder AutofacContainerBuilder = new ContainerBuilder();

// Include application dependencies
AutofacContainerBuilder
.RegisterType<ExampleDependency>()
.As<IExampleDependency>();

// Include the services registered by the OperationManager
AutofacContainerBuilder.Populate(OperationManager.Services);

// Build the container
var serviceProvider = new AutofacServiceProvider(AutofacContainerBuilder.Build());



/* --- START LISTENING --- */
// Start the listener loop
// This will display our options and interpret user input to run the approperiate operation
await OperationManager.StartListeningAsync();
await OperationManager.StartListeningAsync(serviceProvider); // optional service provider

// Alternatively, you can implement your own approach
// using the OperationManager.RegisteredOperations object
18 changes: 14 additions & 4 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -92,22 +92,32 @@ OperationManager.RegisterOperation(typeof(HelloWorld));
```

### 4. Register dependencies (optional)
If you'd like to use dependency injection with autofac, make sure to install the [autofac nuget package](https://www.nuget.org/packages/Autofac) and add the using statement.
You can optionally use dependency injection with Autofac or Microsoft Dependency Injection.


```csharp
using Autofac;
```
Register any dependencies to `OperationManager.ContainerBuilder` before starting the listener.
```csharp
ContainerBuilder AutofacContainerBuilder = new ContainerBuilder();

// Include application dependencies
OperationManager.ContainerBuilder
.RegisterType<ExampleDependency>()
.As<IExampleDependency>();

// Include the services registered by the OperationManager
AutofacContainerBuilder.Populate(OperationManager.Services);

// Build the container
var serviceProvider = new AutofacServiceProvider(AutofacContainerBuilder.Build());
```

### 5. Start the listener
This will display our options and interpret user input to run the approperiate operation.
```csharp
await OperationManager.StartListeningAsync();

// or if you use dependency injection
await OperationManager.StartListeningAsync(serviceProvider);
```
Alternatively you can implement your own version of `StartListening()`.
You can access the registered operations and it's classes through the
Expand Down

0 comments on commit 082bce4

Please sign in to comment.