3 Commits

25 changed files with 369 additions and 80 deletions

28
.github/workflows/dotnet.yml vendored Normal file
View File

@@ -0,0 +1,28 @@
# This workflow will build a .NET project
# For more information see: https://docs.github.com/en/actions/automating-builds-and-tests/building-and-testing-net
name: .NET
on:
push:
branches: [ "preview" ]
pull_request:
branches: [ "preview" ]
jobs:
build:
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v4
- name: Setup .NET
uses: actions/setup-dotnet@v4
with:
dotnet-version: 8.0.x
- name: Restore dependencies
run: dotnet restore
- name: Build
run: dotnet build --no-restore
- name: Test
run: dotnet test --no-build --verbosity normal

1
.gitignore vendored
View File

@@ -460,3 +460,4 @@ $RECYCLE.BIN/
/WebUI/bin
/WebUI_Old/bin
Data/
/WebUI/Libraries

View File

@@ -12,7 +12,7 @@
</ItemGroup>
<ItemGroup>
<PackageReference Include="Newtonsoft.Json" Version="13.0.3" />
<PackageReference Include="Newtonsoft.Json" Version="13.0.4" />
</ItemGroup>
</Project>

View File

@@ -8,7 +8,7 @@
</PropertyGroup>
<ItemGroup>
<PackageReference Include="Microsoft.Data.Sqlite.Core" Version="9.0.3" />
<PackageReference Include="Microsoft.Data.Sqlite.Core" Version="9.0.9" />
</ItemGroup>
</Project>

View File

@@ -24,6 +24,13 @@ public sealed class Logger : ILogger
LogMessages = new List<ILogMessage>();
}
public void Log(string message) => Log(new LogMessage(message, string.Empty, LogType.Info));
public void Log(string message, LogType logType) => Log(new LogMessage(message, logType));
public void Log(string message, object sender) => Log(new LogMessage(message, sender));
public void Log(string message, object sender, LogType type) => Log(new LogMessage(message, sender, type));
public void LogException(Exception exception, object sender, bool logFullStack = false) => Log(LogMessage.CreateFromException(exception, sender, logFullStack));
private string GenerateLogMessage(ILogMessage message)
{
string messageAsString = new string(_LogMessageFormat);
@@ -54,9 +61,4 @@ public sealed class Logger : ILogger
await LogToFile(messageAsString);
}
public void Log(string message) => Log(new LogMessage(message, string.Empty, LogType.Info));
public void Log(string message, LogType logType) => Log(new LogMessage(message, logType));
public void Log(string message, object sender) => Log(new LogMessage(message, sender));
public void Log(string message, object sender, LogType type) => Log(new LogMessage(message, sender, type));
public void LogException(Exception exception, object sender, bool logFullStack = false) => Log(LogMessage.CreateFromException(exception, sender, logFullStack));
}

View File

@@ -8,7 +8,7 @@
</PropertyGroup>
<ItemGroup>
<PackageReference Include="Discord.Net" Version="3.17.2" />
<PackageReference Include="Discord.Net" Version="3.18.0" />
</ItemGroup>
<ItemGroup>

View File

@@ -6,8 +6,8 @@
<Platforms>AnyCPU;x64;ARM64</Platforms>
</PropertyGroup>
<ItemGroup>
<PackageReference Include="Discord.Net" Version="3.17.2" />
<PackageReference Include="Microsoft.Data.Sqlite" Version="9.0.3" />
<PackageReference Include="Discord.Net" Version="3.18.0" />
<PackageReference Include="Microsoft.Data.Sqlite" Version="9.0.9" />
</ItemGroup>
<ItemGroup>
<ProjectReference Include="..\DiscordBotCore.Configuration\DiscordBotCore.Configuration.csproj" />

View File

@@ -4,12 +4,6 @@ namespace CppCompatibilityModule.Extern;
public static class Delegates
{
[UnmanagedFunctionPointer(CallingConvention.Cdecl)]
public delegate void ProcessObject(ref object obj);
[UnmanagedFunctionPointer(CallingConvention.Cdecl)]
public delegate void ExecuteDelegateFunction();
[UnmanagedFunctionPointer(CallingConvention.Cdecl)]
public delegate void SetExternFunctionPointerDelegate(IntPtr funcPtr);

View File

@@ -117,22 +117,5 @@ namespace CppCompatibilityModule.Extern
return result;
}
public void CallFunction(string methodName, ref object parameter)
{
var functionDelegate = GetDelegateForFunctionPointer<Delegates.ProcessObject>(methodName);
functionDelegate(ref parameter);
_Logger.Log($"Function {methodName} called successfully with parameter");
}
public void CallFunction(string methodName)
{
var functionDelegate = GetDelegateForFunctionPointer<Delegates.ExecuteDelegateFunction>(methodName);
functionDelegate();
_Logger.Log($"Function {methodName} called successfully");
}
}
}

View File

@@ -17,24 +17,14 @@ public class ExternalApplication
this._Logger = logger;
}
internal void CallFunction(string methodName, ref object parameter)
{
_ExternLibrary.CallFunction(methodName, ref parameter);
}
internal void CallFunction(string methodName)
{
_ExternLibrary.CallFunction(methodName);
}
internal T GetDelegateForFunctionPointer<T>(string methodName) where T : Delegate
{
return _ExternLibrary.GetDelegateForFunctionPointer<T>(methodName);
}
internal void SetExternFunctionToPointToFunction(string externalFunctionName, Delegates.CsharpFunctionDelegate localFunction)
internal object? SetExternFunctionToPointToFunction<TLocalFunctionDelegate>(string externalFunctionName, TLocalFunctionDelegate localFunction) where TLocalFunctionDelegate : Delegate
{
_ExternLibrary.SetExternFunctionSetterPointerToCustomDelegate<Delegates.SetExternFunctionPointerDelegate, Delegates.CsharpFunctionDelegate>(externalFunctionName, localFunction);
return _ExternLibrary.SetExternFunctionSetterPointerToCustomDelegate<Delegates.SetExternFunctionPointerDelegate, TLocalFunctionDelegate>(externalFunctionName, localFunction);
}
internal void FreeLibrary()

View File

@@ -43,25 +43,26 @@ public class ExternalApplicationHandler
_ExternalApplicationManager.FreeApplication(applicationId);
}
public void CallFunctionWithParameter(Guid appId, string functionName, ref object parameter)
public T GetFunctionDelegate<T>(Guid applicationId, string functionName) where T : Delegate
{
if (_ExternalApplicationManager is null)
{
_Logger.Log("Failed to call function because the manager is not initialized. This should have never happened in the first place!!!", this, LogType.Critical);
return;
_Logger.Log("Failed to get function delegate because the manager is not initialized. This should have never happened in the first place!!!", this, LogType.Critical);
return default!;
}
_ExternalApplicationManager.ExecuteApplicationFunctionWithParameter(appId, functionName, ref parameter);
return _ExternalApplicationManager.GetFunctionDelegate<T>(applicationId, functionName);
}
public void CallFunctionWithoutParameter(Guid appId, string functionName)
public object? SetExternFunctionToPointToFunction<TLocalFunctionDelegate>(Guid applicationId, string functionName,
TLocalFunctionDelegate localFunction) where TLocalFunctionDelegate : Delegate
{
if(_ExternalApplicationManager is null)
{
_Logger.Log("Failed to call function because the manager is not initialized. This should have never happened in the first place!!!", this, LogType.Critical);
return;
_Logger.Log("Failed to set external function pointer because the manager is not initialized. This should have never happened in the first place!!!", this, LogType.Critical);
return null;
}
_ExternalApplicationManager.ExecuteApplicationFunctionWithoutParameter(appId, functionName);
return _ExternalApplicationManager.SetExternFunctionToPointToFunction(applicationId, functionName, localFunction);
}
}

View File

@@ -46,30 +46,28 @@ internal class ExternalApplicationManager
_Logger.Log($"Application with id {applicationId} freed successfully");
}
public void ExecuteApplicationFunctionWithParameter(Guid appId, string functionName, ref object parameter)
public T GetFunctionDelegate<T>(Guid applicationId, string functionName) where T : Delegate
{
var application = _ExternalApplications.FirstOrDefault(app => app.ApplicationId == appId);
var application = _ExternalApplications.FirstOrDefault(app => app.ApplicationId == applicationId, null);
if(application is null)
{
_Logger.Log($"Couldn't find application with id {appId}");
return;
_Logger.Log($"Couldn't find application with id {applicationId}");
return default!;
}
application.CallFunction(functionName, ref parameter);
return application.GetDelegateForFunctionPointer<T>(functionName);
}
public void ExecuteApplicationFunctionWithoutParameter(Guid appId, string functionName)
public object? SetExternFunctionToPointToFunction<TLocalFunctionDelegate>(Guid applicationId, string externalFunctionName, TLocalFunctionDelegate localFunction) where TLocalFunctionDelegate : Delegate
{
var application = _ExternalApplications.FirstOrDefault(app => app.ApplicationId == appId);
var application = _ExternalApplications.FirstOrDefault(app => app.ApplicationId == applicationId, null);
if(application is null)
{
_Logger.Log($"Couldn't find application with id {appId}");
return;
_Logger.Log($"Couldn't find application with id {applicationId}");
return null;
}
application.CallFunction(functionName);
return application.SetExternFunctionToPointToFunction<TLocalFunctionDelegate>(externalFunctionName, localFunction);
}
}

View File

@@ -0,0 +1,14 @@
<Project Sdk="Microsoft.NET.Sdk">
<PropertyGroup>
<TargetFramework>net8.0</TargetFramework>
<ImplicitUsings>enable</ImplicitUsings>
<Nullable>enable</Nullable>
</PropertyGroup>
<ItemGroup>
<ProjectReference Include="..\..\DiscordBotCore.PluginCore\DiscordBotCore.PluginCore.csproj" />
<ProjectReference Include="..\..\Modules\CppCompatibilityModule\CppCompatibilityModule.csproj" />
</ItemGroup>
</Project>

View File

@@ -0,0 +1,9 @@
using System.Runtime.InteropServices;
namespace CppModuleDemo;
public static class Delegates
{
[UnmanagedFunctionPointer(CallingConvention.Cdecl)]
public delegate void ModifyComplexObject(ref ExampleComplexObject obj);
}

View File

@@ -0,0 +1,19 @@
using System.Runtime.InteropServices;
namespace CppModuleDemo;
[StructLayout(LayoutKind.Sequential, CharSet = CharSet.Ansi)]
public struct ExampleComplexObject
{
public int IntegerValue;
public double DoubleValue;
[MarshalAs(UnmanagedType.ByValTStr, SizeConst = 256)]
public string StringValue;
public ExampleComplexObject(int integerValue, double doubleValue, string stringValue)
{
IntegerValue = integerValue;
DoubleValue = doubleValue;
StringValue = stringValue;
}
}

View File

@@ -0,0 +1,10 @@
using CppCompatibilityModule;
using CppCompatibilityModule.Extern;
namespace CppModuleDemo;
internal static class InternalSettings
{
internal static ExternalApplicationHandler? ExternalApplicationHandler { get; set; } = null;
internal static Guid DemoModuleInternalId { get; set; } = Guid.Empty;
}

View File

@@ -0,0 +1,78 @@
using Discord;
using Discord.WebSocket;
using DiscordBotCore.Logging;
using DiscordBotCore.PluginCore.Interfaces;
namespace CppModuleDemo;
public class ModuleSlashCommand : IDbSlashCommand
{
public string Name => "cpp-module-demo";
public string Description => "A demo command to showcase the C++ module integration with Discord Bot Core.";
public bool CanUseDm => false;
public bool HasInteraction => false;
public List<SlashCommandOptionBuilder> Options => new List<SlashCommandOptionBuilder>()
{
new SlashCommandOptionBuilder()
{
Name = "example-integer-value", Description = "An example integer value",
Type = ApplicationCommandOptionType.Integer, IsRequired = true
},
new SlashCommandOptionBuilder()
{
Name = "example-number-value", Description = "An example number value",
Type = ApplicationCommandOptionType.Number, IsRequired = true
},
new SlashCommandOptionBuilder()
{
Name = "example-string-value", Description = "An example boolean value",
Type = ApplicationCommandOptionType.String, IsRequired = true
}
};
public async void ExecuteServer(ILogger logger, SocketSlashCommand context)
{
long integerValue = (long)context.Data.Options.First(option => option.Name == "example-integer-value").Value;
double numberValue = (double)context.Data.Options.First(option => option.Name == "example-number-value").Value;
string stringValue = (string)context.Data.Options.First(option => option.Name == "example-string-value").Value;
if(integerValue > int.MaxValue || integerValue < int.MinValue)
{
await context.Channel.SendMessageAsync("The provided integer value is out of range. Please provide a valid integer.");
return;
}
await context.RespondAsync("Processing your request...", ephemeral: true);
await context.Channel.SendMessageAsync("CppModuleDemo invoked with: \n" +
$"Integer Value: {integerValue}\n" +
$"Number Value: {numberValue}\n" +
$"String Value: {stringValue}");
ExampleComplexObject complexObject = new ExampleComplexObject
{
IntegerValue = (int)integerValue,
DoubleValue = numberValue,
StringValue = stringValue
};
Delegates.ModifyComplexObject? modifyComplexObject =
InternalSettings.ExternalApplicationHandler?.GetFunctionDelegate<Delegates.ModifyComplexObject>(
InternalSettings.DemoModuleInternalId, "modifyComplexObject");
if (modifyComplexObject is null)
{
await context.Channel.SendMessageAsync("Failed to retrieve the C++ function delegate. Please check the C++ module integration.");
return;
}
modifyComplexObject(ref complexObject);
await context.Channel.SendMessageAsync("CppModuleDemo command executed successfully! New values are:\n" +
$"Integer Value: {((ExampleComplexObject)complexObject).IntegerValue}\n" +
$"Number Value: {((ExampleComplexObject)complexObject).DoubleValue}\n" +
$"String Value: {((ExampleComplexObject)complexObject).StringValue}");
}
}

View File

@@ -0,0 +1,31 @@
using CppCompatibilityModule;
using CppCompatibilityModule.Extern;
using DiscordBotCore.PluginCore.Helpers.Execution.DbEvent;
using DiscordBotCore.PluginCore.Interfaces;
namespace CppModuleDemo;
public class StartupEvent : IDbEvent
{
public string Name => "CppModuleDemoStartupEvent";
public string Description => "A demo event to showcase the C++ module integration with Discord Bot Core on startup.";
private static string _DllModule = "libCppModuleDemo.dylib";
public void Start(IDbEventExecutingArgument args)
{
args.PluginBaseDirectory.Create();
InternalSettings.ExternalApplicationHandler = new ExternalApplicationHandler(args.Logger);
string fullPath = Path.Combine(args.PluginBaseDirectory.FullName, _DllModule);
Guid id = InternalSettings.ExternalApplicationHandler.CreateApplication(fullPath);
if (id == Guid.Empty)
{
args.Logger.Log("Failed to create the C++ module application. Please check the DLL path and ensure it is correct.", this);
return;
}
args.Logger.Log($"CppModuleDemo started successfully with application ID: {id}", this);
InternalSettings.DemoModuleInternalId = id;
}
}

View File

@@ -0,0 +1,37 @@
using Discord;
using Discord.WebSocket;
using DiscordBotCore.Logging;
using DiscordBotCore.PluginCore.Interfaces;
namespace CppModuleDemo;
public class StopSlashCommand : IDbSlashCommand
{
public string Name => "stop-cpp-module-demo";
public string Description => "Stops the C++ module demo and cleans up resources.";
public bool CanUseDm => false;
public bool HasInteraction => false;
public List<SlashCommandOptionBuilder> Options => [];
public async void ExecuteServer(ILogger logger, SocketSlashCommand context)
{
if (InternalSettings.ExternalApplicationHandler == null)
{
logger.Log("No C++ module is currently running.", this);
return;
}
Guid id = InternalSettings.DemoModuleInternalId;
if (id == Guid.Empty)
{
logger.Log("No valid C++ module ID found. Cannot stop the module.", this);
return;
}
InternalSettings.ExternalApplicationHandler.StopApplication(id);
InternalSettings.DemoModuleInternalId = Guid.Empty;
logger.Log("CppModuleDemo stopped successfully.", this);
await context.Channel.SendMessageAsync("CppModuleDemo has been stopped and resources cleaned up.");
}
}

View File

@@ -5,9 +5,6 @@ MinimumVisualStudioVersion = 10.0.40219.1
Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "DiscordBotCore", "DiscordBotCore\DiscordBotCore.csproj", "{5A99BFC3-EB39-4AEF-8D61-3CE22D013B02}"
EndProject
Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "Plugins", "Plugins", "{5CF9AD7B-6BF0-4035-835F-722F989C01E1}"
ProjectSection(SolutionItems) = preProject
Plugins\README.md = Plugins\README.md
EndProjectSection
EndProject
Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "Modules", "Modules", "{EA4FA308-7B2C-458E-8485-8747D745DD59}"
EndProject
@@ -41,6 +38,8 @@ Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "Tests.DiscordBotCore.Loggin
EndProject
Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "Tests.DiscordBotCore.Configuration", "Tests\Tests.DiscordBotCore.Configuration\Tests.DiscordBotCore.Configuration.csproj", "{52C59C73-C23C-4608-8827-383577DEB8D8}"
EndProject
Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "CppModuleDemo", "Plugins\CppModuleDemo\CppModuleDemo.csproj", "{55425935-456E-4ED4-9283-2CB6A6C7AC7D}"
EndProject
Global
GlobalSection(SolutionConfigurationPlatforms) = preSolution
Debug|Any CPU = Debug|Any CPU
@@ -231,6 +230,18 @@ Global
{52C59C73-C23C-4608-8827-383577DEB8D8}.Release|ARM64.Build.0 = Release|Any CPU
{52C59C73-C23C-4608-8827-383577DEB8D8}.Release|x64.ActiveCfg = Release|Any CPU
{52C59C73-C23C-4608-8827-383577DEB8D8}.Release|x64.Build.0 = Release|Any CPU
{55425935-456E-4ED4-9283-2CB6A6C7AC7D}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
{55425935-456E-4ED4-9283-2CB6A6C7AC7D}.Debug|Any CPU.Build.0 = Debug|Any CPU
{55425935-456E-4ED4-9283-2CB6A6C7AC7D}.Debug|ARM64.ActiveCfg = Debug|Any CPU
{55425935-456E-4ED4-9283-2CB6A6C7AC7D}.Debug|ARM64.Build.0 = Debug|Any CPU
{55425935-456E-4ED4-9283-2CB6A6C7AC7D}.Debug|x64.ActiveCfg = Debug|Any CPU
{55425935-456E-4ED4-9283-2CB6A6C7AC7D}.Debug|x64.Build.0 = Debug|Any CPU
{55425935-456E-4ED4-9283-2CB6A6C7AC7D}.Release|Any CPU.ActiveCfg = Release|Any CPU
{55425935-456E-4ED4-9283-2CB6A6C7AC7D}.Release|Any CPU.Build.0 = Release|Any CPU
{55425935-456E-4ED4-9283-2CB6A6C7AC7D}.Release|ARM64.ActiveCfg = Release|Any CPU
{55425935-456E-4ED4-9283-2CB6A6C7AC7D}.Release|ARM64.Build.0 = Release|Any CPU
{55425935-456E-4ED4-9283-2CB6A6C7AC7D}.Release|x64.ActiveCfg = Release|Any CPU
{55425935-456E-4ED4-9283-2CB6A6C7AC7D}.Release|x64.Build.0 = Release|Any CPU
EndGlobalSection
GlobalSection(SolutionProperties) = preSolution
HideSolutionNode = FALSE
@@ -241,6 +252,7 @@ Global
{9A4B98C1-00AC-481C-BE55-A70C0B9D3BE7} = {5CF9AD7B-6BF0-4035-835F-722F989C01E1}
{94238D37-60C6-4E40-80EC-4B4D242F5914} = {8F27B3EA-F292-40DF-B9B3-4B0E6BEA4E70}
{52C59C73-C23C-4608-8827-383577DEB8D8} = {8F27B3EA-F292-40DF-B9B3-4B0E6BEA4E70}
{55425935-456E-4ED4-9283-2CB6A6C7AC7D} = {5CF9AD7B-6BF0-4035-835F-722F989C01E1}
EndGlobalSection
GlobalSection(ExtensibilityGlobals) = postSolution
SolutionGuid = {3FB3C5DE-ED21-4D2E-ABDD-3A00EE4A2FFF}

View File

@@ -10,11 +10,17 @@
</PropertyGroup>
<ItemGroup>
<PackageReference Include="coverlet.collector" Version="6.0.0"/>
<PackageReference Include="Microsoft.NET.Test.Sdk" Version="17.8.0"/>
<PackageReference Include="coverlet.collector" Version="6.0.4">
<PrivateAssets>all</PrivateAssets>
<IncludeAssets>runtime; build; native; contentfiles; analyzers; buildtransitive</IncludeAssets>
</PackageReference>
<PackageReference Include="Microsoft.NET.Test.Sdk" Version="18.0.0" />
<PackageReference Include="Moq" Version="4.20.72" />
<PackageReference Include="xunit" Version="2.5.3"/>
<PackageReference Include="xunit.runner.visualstudio" Version="2.5.3"/>
<PackageReference Include="xunit" Version="2.9.3" />
<PackageReference Include="xunit.runner.visualstudio" Version="3.1.5">
<PrivateAssets>all</PrivateAssets>
<IncludeAssets>runtime; build; native; contentfiles; analyzers; buildtransitive</IncludeAssets>
</PackageReference>
</ItemGroup>
<ItemGroup>

View File

@@ -11,10 +11,17 @@
</PropertyGroup>
<ItemGroup>
<PackageReference Include="coverlet.collector" Version="6.0.0"/>
<PackageReference Include="Microsoft.NET.Test.Sdk" Version="17.8.0"/>
<PackageReference Include="xunit" Version="2.5.3"/>
<PackageReference Include="xunit.runner.visualstudio" Version="2.5.3"/>
<PackageReference Include="coverlet.collector" Version="6.0.4">
<PrivateAssets>all</PrivateAssets>
<IncludeAssets>runtime; build; native; contentfiles; analyzers; buildtransitive</IncludeAssets>
</PackageReference>
<PackageReference Include="Microsoft.NET.Test.Sdk" Version="18.0.0" />
<PackageReference Include="Newtonsoft.Json" Version="13.0.4" />
<PackageReference Include="xunit" Version="2.9.3" />
<PackageReference Include="xunit.runner.visualstudio" Version="3.1.5">
<PrivateAssets>all</PrivateAssets>
<IncludeAssets>runtime; build; native; contentfiles; analyzers; buildtransitive</IncludeAssets>
</PackageReference>
</ItemGroup>
<ItemGroup>

View File

@@ -65,6 +65,7 @@
var buffer = new byte[file.Size];
await file.OpenReadStream().ReadAsync(buffer);
_message = $"Uploaded file: {file.Name} ({file.Size} bytes)";
selectedFile = file;
}
private async Task HandleValidSubmit()

View File

@@ -1,7 +1,68 @@
using System.Reflection;
using WebUI;
using WebUI.Services;
using WebUI.Components;
#region Load External (Unmanaged) Assemblies
// This code is used to load external (unmanaged) assemblies from the same folder as the executing assembly.
// It handles the AssemblyResolve event to search for the requested assembly in a specific folder structure.
// The folder structure is expected to be: <ExecutingAssemblyDirectory>/Libraries/<RequestingAssemblyName>/<AssemblyName>.<Extension>
// The extensions to search for are specified in the 'extensions' parameter.
var currentDomain = AppDomain.CurrentDomain;
currentDomain.AssemblyResolve += (sender, args) => LoadFromSameFolder(sender,args, [".dll", ".so", ".dylib"]);
static Assembly? LoadFromSameFolder(object? sender, ResolveEventArgs args, string[] extensions)
{
string? requestingAssemblyName = args.RequestingAssembly?.GetName().Name;
string executingAssemblyLocation = Assembly.GetExecutingAssembly().Location;
string? executingAssemblyDirectory = Path.GetDirectoryName(executingAssemblyLocation);
if (string.IsNullOrEmpty(executingAssemblyDirectory))
{
Console.WriteLine($"Error: Could not determine the directory of the executing assembly.");
return null;
}
string librariesFolder = Path.Combine(executingAssemblyDirectory, "Libraries", requestingAssemblyName ?? "");
string requestedAssemblyNameWithoutExtension = new AssemblyName(args.Name).Name;
Console.WriteLine($"Requesting Assembly: {requestingAssemblyName}");
Console.WriteLine($"Requested Assembly Name (without extension): {requestedAssemblyNameWithoutExtension}");
Console.WriteLine($"Searching in folder: {librariesFolder}");
Console.WriteLine($"Searching for extensions: {string.Join(", ", extensions)}");
foreach (string extension in extensions)
{
string assemblyFileName = requestedAssemblyNameWithoutExtension + extension;
string assemblyPath = Path.Combine(librariesFolder, assemblyFileName);
Console.WriteLine($"Attempting to load from: {assemblyPath}");
if (!File.Exists(assemblyPath))
{
Console.WriteLine($"File not found: {assemblyPath}");
continue;
}
try
{
Assembly assembly = Assembly.LoadFrom(assemblyPath);
return assembly;
}
catch (Exception ex)
{
Console.WriteLine($"Failed to load assembly: {assemblyPath}. Error message: {ex.Message}");
}
}
Console.WriteLine($"Failed to load assembly '{args.Name}' from the specified locations.");
return null;
}
#endregion
var builder = WebApplication.CreateBuilder(args);
// Add services to the container.

7
global.json Normal file
View File

@@ -0,0 +1,7 @@
{
"sdk": {
"version": "8.0.0",
"rollForward": "latestMajor",
"allowPrerelease": false
}
}