diff --git a/F4SDM42WebApi/F4SD - M42WebApi.csproj b/F4SDM42WebApi/F4SD - M42WebApi.csproj
index d37bdb6..340913d 100644
--- a/F4SDM42WebApi/F4SD - M42WebApi.csproj
+++ b/F4SDM42WebApi/F4SD - M42WebApi.csproj
@@ -13,7 +13,7 @@
false
6673a25d-33d6-4072-91d9-abed4be1a966
C4ITF4SD*.*
- 1.4.0.26
+ 1.4.0.27
true
diff --git a/F4SDM42WebApi/F4SDHelperService.cs b/F4SDM42WebApi/F4SDHelperService.cs
index a37e549..f6f2040 100644
--- a/F4SDM42WebApi/F4SDHelperService.cs
+++ b/F4SDM42WebApi/F4SDHelperService.cs
@@ -1448,7 +1448,7 @@ namespace C4IT.F4SD
private static IReadOnlyList LoadJournalEntries(Guid activityEOID)
{
- var journalService = F4SDM42WebApiController.defaultInstance.GetJournalService();
+ var journalService = F4SDM42WebApiController.defaultInstance.GetJournalServiceInstance();
var serviceType = journalService.GetType();
var objectLinkTemplate = "{2}";
var methods = serviceType
diff --git a/F4SDM42WebApi/F4SDM42WebApiController.cs b/F4SDM42WebApi/F4SDM42WebApiController.cs
index f78f88b..9440a6f 100644
--- a/F4SDM42WebApi/F4SDM42WebApiController.cs
+++ b/F4SDM42WebApi/F4SDM42WebApiController.cs
@@ -96,6 +96,103 @@ namespace C4IT.F4SD
return GetRequiredService();
}
+ internal object GetJournalServiceInstance()
+ {
+ try
+ {
+ return GetRequiredService();
+ }
+ catch (Exception ex)
+ {
+ LogEntry($"IJournalService could not be resolved by the Matrix42 container. Falling back to direct JournalService construction. {ex.GetType().FullName}: {ex.Message}", LogLevels.Warning);
+ return CreateJournalServiceInstance();
+ }
+ }
+
+ private object CreateJournalServiceInstance()
+ {
+ var journalServiceType = FindLoadedType("Matrix42.ServiceManager.BizLogic.Services.JournalService")
+ ?? Type.GetType("Matrix42.ServiceManager.BizLogic.Services.JournalService, Matrix42.ServiceManager.BizLogic", true);
+ var constructor = journalServiceType
+ .GetConstructors()
+ .OrderByDescending(item => item.GetParameters().Length)
+ .FirstOrDefault();
+
+ if (constructor == null)
+ throw new InvalidOperationException($"No public constructor was found for {journalServiceType.FullName}.");
+
+ var parameters = constructor.GetParameters();
+ var arguments = new object[parameters.Length];
+ for (int i = 0; i < parameters.Length; i++)
+ arguments[i] = ResolveJournalServiceConstructorParameter(parameters[i]);
+
+ return constructor.Invoke(arguments);
+ }
+
+ private object ResolveJournalServiceConstructorParameter(System.Reflection.ParameterInfo parameter)
+ {
+ if (parameter.ParameterType == typeof(IDependencyResolver))
+ return _resolver;
+
+ if (parameter.ParameterType.FullName == "Matrix42.Contracts.Platform.MsTeams.ITeamsNotificationService")
+ return CreateNoOpInterfaceProxy(parameter.ParameterType);
+
+ var service = _resolver.TryGet(parameter.ParameterType);
+ if (service != null)
+ return service;
+
+ throw new InvalidOperationException($"Required JournalService constructor dependency is not registered: {parameter.ParameterType.FullName} ({parameter.Name}).");
+ }
+
+ private static Type FindLoadedType(string fullName)
+ {
+ return AppDomain.CurrentDomain
+ .GetAssemblies()
+ .Select(assembly => assembly.GetType(fullName, false))
+ .FirstOrDefault(type => type != null);
+ }
+
+ private static object CreateNoOpInterfaceProxy(Type interfaceType)
+ {
+ var createMethod = typeof(DispatchProxy)
+ .GetMethods(BindingFlags.Public | BindingFlags.Static)
+ .Single(method => method.Name == nameof(DispatchProxy.Create) && method.IsGenericMethodDefinition);
+
+ return createMethod
+ .MakeGenericMethod(interfaceType, typeof(NoOpInterfaceProxy))
+ .Invoke(null, null);
+ }
+
+ private sealed class NoOpInterfaceProxy : DispatchProxy
+ {
+ protected override object Invoke(MethodInfo targetMethod, object[] args)
+ {
+ return GetDefaultValue(targetMethod?.ReturnType);
+ }
+ }
+
+ private static object GetDefaultValue(Type returnType)
+ {
+ if (returnType == null || returnType == typeof(void))
+ return null;
+
+ if (returnType == typeof(Task))
+ return Task.CompletedTask;
+
+ if (returnType.IsGenericType && returnType.GetGenericTypeDefinition() == typeof(Task<>))
+ {
+ var resultType = returnType.GetGenericArguments()[0];
+ var result = resultType.IsValueType ? Activator.CreateInstance(resultType) : null;
+ return typeof(Task)
+ .GetMethods(BindingFlags.Public | BindingFlags.Static)
+ .Single(method => method.Name == nameof(Task.FromResult) && method.IsGenericMethodDefinition)
+ .MakeGenericMethod(resultType)
+ .Invoke(null, new[] { result });
+ }
+
+ return returnType.IsValueType ? Activator.CreateInstance(returnType) : null;
+ }
+
[Route("getDirectLinkCreateTicket"), HttpGet]
public async Task getDirectLinkCreateTicket(string sid = "", string assetname = "")
{