diff --git a/F4SDM42WebApi/C4ITF4SDM42WebApi.dll.host.config b/F4SDM42WebApi/C4ITF4SDM42WebApi.dll.host.config index cfb7d8c..01bb731 100644 --- a/F4SDM42WebApi/C4ITF4SDM42WebApi.dll.host.config +++ b/F4SDM42WebApi/C4ITF4SDM42WebApi.dll.host.config @@ -9,6 +9,7 @@ + diff --git a/F4SDM42WebApi/F4SD - M42WebApi.csproj b/F4SDM42WebApi/F4SD - M42WebApi.csproj index e836f90..88aaaa6 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.31 + 1.4.0.32 true @@ -34,10 +34,6 @@ M42Libraries\26.1\Matrix42.Contracts.ServiceManagement.dll false - - M42Libraries\26.1\Matrix42.BizLogic.Journal.dll - false - M42Libraries\26.1\Matrix42.Hosting.Contracts.dll false diff --git a/F4SDM42WebApi/F4SDHelperService.cs b/F4SDM42WebApi/F4SDHelperService.cs index 1c84ee2..617dbee 100644 --- a/F4SDM42WebApi/F4SDHelperService.cs +++ b/F4SDM42WebApi/F4SDHelperService.cs @@ -1,7 +1,6 @@ using C4IT.F4SDM; using C4IT.FASD.Base; using C4IT.Logging; -using Matrix42.BizLogic.Common.Journal; using Matrix42.Common; using Newtonsoft.Json; using System; @@ -1455,7 +1454,7 @@ namespace C4IT.F4SD private static IReadOnlyList LoadJournalEntries(Guid activityEOID) { - var journalService = F4SDM42WebApiController.defaultInstance.GetJournalServiceInstance(); + var journalService = F4SDM42WebApiController.defaultInstance.GetJournalService(); var serviceType = journalService.GetType(); var objectLinkTemplate = "{2}"; var methods = serviceType @@ -1482,12 +1481,6 @@ namespace C4IT.F4SD } catch (TargetInvocationException ex) when (ex.InnerException != null) { - if (IsStorageWebApiExplorerResolutionFailure(ex.InnerException)) - { - LogEntry("JournalService.GetJournalList requires IStorageService in this Matrix42 build. Falling back to JournalManager.GetObjectEntries for sandbox compatibility.", LogLevels.Warning); - return LoadJournalEntriesFromJournalManager(activityEOID, objectLinkTemplate); - } - throw ex.InnerException; } } @@ -1495,38 +1488,6 @@ namespace C4IT.F4SD throw new MissingMethodException($"No compatible IJournalService.GetJournalList overload was found on '{serviceType.FullName}'. Available overloads: {string.Join("; ", methods.Select(FormatMethodSignature))}"); } - private static IReadOnlyList LoadJournalEntriesFromJournalManager(Guid activityEOID, string objectLinkTemplate) - { - var entries = JournalManager.GetObjectEntries( - activityEOID, - false, - null, - 0, - 50, - false, - objectLinkTemplate, - 120); - - return entries - .Select(item => new Matrix42.Contracts.Platform.Data.JournalEntryInfo - { - Id = item.Id, - Creator = item.CreatorName, - CreatedDate = item.CreatedDate, - Header = item.Header, - Text = item.Body ?? string.Empty, - VisibleInPortal = item.VisibleInPortal - }) - .ToList(); - } - - private static bool IsStorageWebApiExplorerResolutionFailure(Exception exception) - { - var details = exception.ToString(); - return details.Contains("Matrix42.StorageService.Contracts.IStorageService") - && details.Contains("System.Web.Http.Description.IApiExplorer"); - } - private static bool IsJournalReaderMethod(MethodInfo method) { var methodName = method.Name; diff --git a/F4SDM42WebApi/F4SDM42WebApiController.cs b/F4SDM42WebApi/F4SDM42WebApiController.cs index b48d35d..f78f88b 100644 --- a/F4SDM42WebApi/F4SDM42WebApiController.cs +++ b/F4SDM42WebApi/F4SDM42WebApiController.cs @@ -43,12 +43,6 @@ namespace C4IT.F4SD private readonly F4SDHelperService _f4stHelperService; - private const string TeamsNotificationServiceTypeName = "Matrix42.Contracts.Platform.MsTeams.ITeamsNotificationService"; - private const string StorageServiceTypeName = "Matrix42.StorageService.Contracts.IStorageService"; - private const int JournalStart = 0; - private const int JournalCount = 50; - private const int JournalTimeOffset = 120; - private const string JournalObjectLinkTemplate = "{2}"; public string BaseUrl => Request?.RequestUri == null ? string.Empty : $"{Request.RequestUri.Scheme}://{Request.RequestUri.Host}"; public string EndpointBaseUrl => $"{BaseUrl}/m42Services/api/c4itf4sdwebapi"; @@ -102,165 +96,6 @@ 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 CreateJournalDependencyResolver(_resolver); - - if (parameter.ParameterType.FullName == TeamsNotificationServiceTypeName || parameter.ParameterType.FullName == StorageServiceTypeName) - 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 IDependencyResolver CreateJournalDependencyResolver(IDependencyResolver resolver) - { - var proxy = DispatchProxy.Create(); - ((JournalDependencyResolverProxy)(object)proxy).Inner = resolver; - return proxy; - } - - 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); - } - - public class JournalDependencyResolverProxy : DispatchProxy - { - public IDependencyResolver Inner { get; set; } - - protected override object Invoke(MethodInfo targetMethod, object[] args) - { - var requestedType = GetRequestedServiceType(targetMethod, args); - if (requestedType?.FullName == StorageServiceTypeName) - return CreateResolverResultForStorageService(targetMethod, requestedType); - - try - { - return targetMethod.Invoke(Inner, args); - } - catch (TargetInvocationException ex) when (ex.InnerException != null) - { - throw ex.InnerException; - } - } - } - - private static Type GetRequestedServiceType(MethodInfo targetMethod, object[] args) - { - if (targetMethod.IsGenericMethod && targetMethod.GetGenericArguments().Length > 0) - return targetMethod.GetGenericArguments()[0]; - - if (args?.Length > 0 && args[0] is Type type) - return type; - - return null; - } - - private static object CreateResolverResultForStorageService(MethodInfo targetMethod, Type requestedType) - { - if (targetMethod.Name.StartsWith("IsRegistered", StringComparison.Ordinal)) - return true; - - if (targetMethod.Name.Contains("All")) - return CreateEmptyEnumerable(targetMethod.ReturnType, requestedType); - - return CreateNoOpInterfaceProxy(requestedType); - } - - private static object CreateEmptyEnumerable(Type returnType, Type itemType) - { - if (returnType.IsGenericType) - return Array.CreateInstance(returnType.GetGenericArguments()[0], 0); - - return Array.CreateInstance(itemType ?? typeof(object), 0); - } - - public class NoOpInterfaceProxy : DispatchProxy - { - public NoOpInterfaceProxy() - { - } - - 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 = "") { @@ -308,13 +143,6 @@ namespace C4IT.F4SD { try { - var journalPortalEntries = await TryGetJournalPortalEntries(objectId); - if (journalPortalEntries != null) - { - LogEntry($"{journalPortalEntries.Count} Journal entries loaded from Matrix42 JournalPortalController for ObjectID={objectId}", LogLevels.Debug); - return F4SDHelperService.CreateTicketJournalItems(objectId, journalPortalEntries); - } - return await _f4stHelperService.GetJournalEntries(objectId); } catch (MissingMethodException ex) @@ -323,90 +151,6 @@ namespace C4IT.F4SD } } - private async Task> TryGetJournalPortalEntries(Guid objectId) - { - if (Request?.RequestUri == null) - return null; - - foreach (var requestUri in BuildJournalPortalUris(objectId)) - { - try - { - using (var handler = new HttpClientHandler { UseDefaultCredentials = true, AutomaticDecompression = DecompressionMethods.All }) - using (var client = new HttpClient(handler)) - using (var request = new HttpRequestMessage(HttpMethod.Get, requestUri)) - { - client.Timeout = TimeSpan.FromSeconds(15); - CopyIncomingHeaders(request); - using (var response = await client.SendAsync(request)) - { - var responseText = await response.Content.ReadAsStringAsync(); - if (!response.IsSuccessStatusCode) - { - LogEntry($"Matrix42 JournalPortalController returned {(int)response.StatusCode} {response.ReasonPhrase} for {requestUri}. {responseText}", LogLevels.Warning); - continue; - } - - var entries = DeserializeJournalPortalEntries(responseText); - if (entries != null) - return entries; - - LogEntry($"Matrix42 JournalPortalController response could not be deserialized for {requestUri}. {responseText}", LogLevels.Warning); - } - } - } - catch (Exception ex) - { - LogEntry($"Matrix42 JournalPortalController request failed for {requestUri}. {ex.GetType().FullName}: {ex.Message}", LogLevels.Warning); - } - } - - return null; - } - - private IEnumerable BuildJournalPortalUris(Guid objectId) - { - var query = $"objectId={Uri.EscapeDataString(objectId.ToString())}&start={JournalStart}&count={JournalCount}&objectLinkTemplate={Uri.EscapeDataString(JournalObjectLinkTemplate)}&timeOffset={JournalTimeOffset}"; - yield return new Uri($"{BaseUrl}/m42Services/api/journalPortal?{query}"); - yield return new Uri($"{BaseUrl}/api/journalPortal?{query}"); - } - - private void CopyIncomingHeaders(HttpRequestMessage request) - { - foreach (var header in Request.Headers) - { - if (string.Equals(header.Key, "Host", StringComparison.OrdinalIgnoreCase) - || string.Equals(header.Key, "Connection", StringComparison.OrdinalIgnoreCase) - || string.Equals(header.Key, "Accept-Encoding", StringComparison.OrdinalIgnoreCase)) - continue; - - request.Headers.TryAddWithoutValidation(header.Key, header.Value); - } - } - - private static Matrix42.Contracts.Platform.Data.JournalEntryInfo[] DeserializeJournalPortalEntries(string responseText) - { - try - { - return Newtonsoft.Json.JsonConvert.DeserializeObject(responseText); - } - catch - { - var token = Newtonsoft.Json.Linq.JToken.Parse(responseText); - if (token.Type == Newtonsoft.Json.Linq.JTokenType.Array) - return token.ToObject(); - - foreach (var propertyName in new[] { "result", "Result", "value", "Value" }) - { - var resultToken = token[propertyName]; - if (resultToken != null && resultToken.Type != Newtonsoft.Json.Linq.JTokenType.Null) - return resultToken.ToObject(); - } - - return null; - } - } - internal static List CreateMissingMethodDiagnostics(string stage, Guid objectId, MissingMethodException ex) { var details = BuildMissingMethodDiagnostic(stage, objectId, ex);