From 3f4ea2e61ed0838c3324b9845f6b90b5cfc27211 Mon Sep 17 00:00:00 2001
From: Lilla Orban <36889371+lilla28@users.noreply.github.com>
Date: Tue, 27 Jan 2026 16:24:54 +0100
Subject: [PATCH] feat(fdc3)- Add functionality for channel selector; Refactor
channel management by replacing ChannelFactory and related interfaces with
the new ChannelHandler abstraction across .NET and TypeScript codebases
(Renamed internal classes of channel management). All async calls now use
.ConfigureAwait(false). Update DesktopAgent, IntentsClient, and related
classes to use ChannelHandler, and improve logging, error handling, and
resource management. Update tests and public API surface to reflect new
abstractions. Add documentation and README updates for channel selector
integration.
---
.../Infrastructure/DesktopAgentClient.cs | 120 ++++++++----------
...{IChannelFactory.cs => IChannelHandler.cs} | 11 +-
.../{ChannelFactory.cs => ChannelHandler.cs} | 83 ++++++++++--
.../Infrastructure/Internal/IntentsClient.cs | 16 +--
.../Internal/Protocol/Channel.cs | 4 +-
.../Internal/Protocol/IntentResolution.cs | 8 +-
.../Internal/Protocol/PrivateChannel.cs | 33 +++--
.../test/IntegrationTests/EndToEndTests.cs | 12 +-
.../DesktopAgentClient.Tests.cs | 8 +-
...ctory.Tests.cs => ChannelHandler.Tests.cs} | 64 ++++++----
.../Internal/IntentsClient.Tests.cs | 7 +-
.../Internal/OpenClient.Tests.cs | 2 +-
.../Protocol/IntentResolution.Tests.cs | 6 +-
.../Contracts/JoinUserChannelRequest.cs | 2 +-
.../Contracts/JoinUserChannelResponse.cs | 2 +-
.../Exceptions/ThrowHelper.cs | 5 +-
.../Fdc3StartupProperties.cs | 7 +-
.../Fdc3Topic.cs | 20 +++
.../IModuleChannelSelector.cs | 39 ++++++
.../ServiceCollectionExtensions.cs | 2 +
.../Fdc3DesktopAgentService.cs | 112 ++++++++--------
.../Fdc3StartupAction.cs | 4 +-
.../IChannelSelector.cs | 28 ++++
.../IResolverUICommunicator.cs | 4 +-
.../Fdc3DesktopAgentMessagingService.cs | 50 ++++----
.../Infrastructure/Internal/IntentResolver.cs | 8 +-
.../Internal/ResolverUICommunicator.cs | 15 ++-
.../Internal/UserChannelSetReader.cs | 10 +-
.../ModuleChannelSelector.cs | 84 ++++++++++++
.../README.md | 63 +++++++++
.../Fdc3DesktopAgentServiceTestsBase.cs | 2 +
.../Fdc3DesktopAgentMessagingServiceTests.cs | 8 +-
.../Internal/ResolverUICommunicatorTests.cs | 4 +-
.../ModuleChannelSelectorTests.cs | 92 ++++++++++++++
.../RaiseIntentForContextTests.cs | 16 +--
.../RaiseIntentTests.cs | 2 +-
.../src/ComposeUIDesktopAgent.spec.ts | 9 +-
.../src/ComposeUIDesktopAgent.ts | 92 +++++++-------
... ComposeUIMessagingChannelHandler.spec.ts} | 20 +--
src/fdc3/js/composeui-fdc3/src/index.ts | 31 +++++
.../{ChannelFactory.ts => ChannelHandler.ts} | 39 +++++-
.../src/infrastructure/ChannelItem.ts | 3 +
.../src/infrastructure/ComposeUIChannel.ts | 2 +-
.../ComposeUIContextListener.ts | 9 +-
.../ComposeUIIntentResolution.ts | 10 +-
.../infrastructure/ComposeUIPrivateChannel.ts | 2 +-
.../src/infrastructure/ComposeUITopic.ts | 8 ++
...lFactory.ts => MessagingChannelHandler.ts} | 93 +++++++++++---
.../infrastructure/MessagingIntentsClient.ts | 14 +-
.../src/Client/Client/MessageRouterClient.cs | 3 +-
.../Fdc3/ResolverUI/ResolverUIService.cs | 6 +-
src/shell/dotnet/src/Shell/Shell.csproj | 6 +-
52 files changed, 942 insertions(+), 358 deletions(-)
rename src/fdc3/dotnet/DesktopAgent.Client/src/MorganStanley.ComposeUI.Fdc3.DesktopAgent.Client/Infrastructure/{IChannelFactory.cs => IChannelHandler.cs} (90%)
rename src/fdc3/dotnet/DesktopAgent.Client/src/MorganStanley.ComposeUI.Fdc3.DesktopAgent.Client/Infrastructure/Internal/{ChannelFactory.cs => ChannelHandler.cs} (79%)
rename src/fdc3/dotnet/DesktopAgent.Client/test/MorganStanley.ComposeUI.Fdc3.DesktopAgent.Client.Tests/Infrastructure/Internal/{ChannelFactory.Tests.cs => ChannelHandler.Tests.cs} (82%)
create mode 100644 src/fdc3/dotnet/DesktopAgent.Shared/src/MorganStanley.ComposeUI.Fdc3.DesktopAgent.Shared/IModuleChannelSelector.cs
create mode 100644 src/fdc3/dotnet/DesktopAgent/src/MorganStanley.ComposeUI.Fdc3.DesktopAgent/IChannelSelector.cs
create mode 100644 src/fdc3/dotnet/DesktopAgent/src/MorganStanley.ComposeUI.Fdc3.DesktopAgent/ModuleChannelSelector.cs
create mode 100644 src/fdc3/dotnet/DesktopAgent/test/MorganStanley.ComposeUI.Fdc3.DesktopAgent.Tests/ModuleChannelSelectorTests.cs
rename src/fdc3/js/composeui-fdc3/src/{ComposeUIMessagingChannelFactory.spec.ts => ComposeUIMessagingChannelHandler.spec.ts} (87%)
rename src/fdc3/js/composeui-fdc3/src/infrastructure/{ChannelFactory.ts => ChannelHandler.ts} (53%)
rename src/fdc3/js/composeui-fdc3/src/infrastructure/{MessagingChannelFactory.ts => MessagingChannelHandler.ts} (68%)
diff --git a/src/fdc3/dotnet/DesktopAgent.Client/src/MorganStanley.ComposeUI.Fdc3.DesktopAgent.Client/Infrastructure/DesktopAgentClient.cs b/src/fdc3/dotnet/DesktopAgent.Client/src/MorganStanley.ComposeUI.Fdc3.DesktopAgent.Client/Infrastructure/DesktopAgentClient.cs
index 2f4f09f98..50cbcf772 100644
--- a/src/fdc3/dotnet/DesktopAgent.Client/src/MorganStanley.ComposeUI.Fdc3.DesktopAgent.Client/Infrastructure/DesktopAgentClient.cs
+++ b/src/fdc3/dotnet/DesktopAgent.Client/src/MorganStanley.ComposeUI.Fdc3.DesktopAgent.Client/Infrastructure/DesktopAgentClient.cs
@@ -25,16 +25,16 @@
namespace MorganStanley.ComposeUI.Fdc3.DesktopAgent.Client.Infrastructure;
///
-/// Desktop Agent client implementation.
+/// Desktop Agent client implementation for native apps.
///
-public class DesktopAgentClient : IDesktopAgent
+public class DesktopAgentClient : IDesktopAgent, IAsyncDisposable
{
private readonly IMessaging _messaging;
private readonly ILoggerFactory _loggerFactory;
private readonly ILogger _logger;
private readonly string _appId;
private readonly string _instanceId;
- private IChannelFactory _channelFactory;
+ private IChannelHandler _channelHandler;
private IMetadataClient _metadataClient;
private IIntentsClient _intentsClient;
private IOpenClient _openClient;
@@ -48,12 +48,7 @@ public class DesktopAgentClient : IDesktopAgent
private readonly SemaphoreSlim _currentChannelLock = new(1, 1);
- private readonly ConcurrentDictionary _userChannels = new();
- private readonly ConcurrentDictionary _appChannels = new();
- private readonly SemaphoreSlim _appChannelsLock = new(1, 1);
-
private readonly TaskCompletionSource _initializationTaskCompletionSource = new(TaskCreationOptions.RunContinuationsAsynchronously);
- private string? _openedAppContextId;
public DesktopAgentClient(
IMessaging messaging,
@@ -74,7 +69,7 @@ public DesktopAgentClient(
_metadataClient = new MetadataClient(_appId, _instanceId, _messaging, _loggerFactory.CreateLogger());
_openClient = new OpenClient(_instanceId, _messaging, this, _loggerFactory.CreateLogger());
- _ = Task.Run(() => InitializeAsync());
+ _ = Task.Run(() => InitializeAsync().ConfigureAwait(false));
}
///
@@ -105,12 +100,13 @@ private async Task InitializeAsync()
if (!string.IsNullOrEmpty(openedAppContextId))
{
- _openedAppContextId = openedAppContextId;
await GetOpenedAppContextAsync(openedAppContextId!).ConfigureAwait(false);
}
- _channelFactory = new ChannelFactory(_messaging, _instanceId, _openedAppContext, _loggerFactory);
- _intentsClient = new IntentsClient(_messaging, _channelFactory, _instanceId, _loggerFactory);
+ _channelHandler = new ChannelHandler(_messaging, _instanceId, this, _openedAppContext, _loggerFactory);
+ _intentsClient = new IntentsClient(_messaging, _channelHandler, _instanceId, _loggerFactory);
+
+ await _channelHandler.ConfigureChannelSelectorAsync(CancellationToken.None).ConfigureAwait(false);
_initializationTaskCompletionSource.SetResult(_instanceId);
}
@@ -142,21 +138,21 @@ public async Task AddContextListener(string? contextType, ContextH
"Checking if the app was opened via fdc3.open. OpenedAppContext exists: {IsNotNull}, current context listener's context type: {ContextType}, received app context's type via open call: {OpenedAppContextType}.", _openedAppContext != null, contextType, _openedAppContext?.Type);
}
- listener = await _channelFactory.CreateContextListenerAsync(handler, _currentChannel, contextType);
+ listener = await _channelHandler.CreateContextListenerAsync(handler, _currentChannel, contextType).ConfigureAwait(false);
_contextListeners.Add(
listener,
async (channelId, channelType, cancellationToken) =>
{
- await listener.SubscribeAsync(channelId, channelType, cancellationToken);
- await HandleLastContextAsync(listener);
+ await listener.SubscribeAsync(channelId, channelType, cancellationToken).ConfigureAwait(false);
+ await HandleLastContextAsync(listener).ConfigureAwait(false);
});
return listener;
}
finally
{
- await HandleLastContextAsync(listener);
+ await HandleLastContextAsync(listener).ConfigureAwait(false);
_currentChannelLock.Release();
}
@@ -178,7 +174,7 @@ public async Task AddIntentListener(string intent, IntentHandler(intent, handler);
+ var listener = await _intentsClient.AddIntentListenerAsync(intent, handler).ConfigureAwait(false);
if (!_intentListeners.TryAdd(intent, listener))
{
@@ -209,7 +205,7 @@ public async Task Broadcast(IContext context)
throw ThrowHelper.ClientNotConnectedToUserChannel();
}
- await _currentChannel.Broadcast(context);
+ await _currentChannel.Broadcast(context).ConfigureAwait(false);
}
finally
{
@@ -224,7 +220,7 @@ public async Task Broadcast(IContext context)
public async Task CreatePrivateChannel()
{
await _initializationTaskCompletionSource.Task.ConfigureAwait(false);
- var privateChannel = await _channelFactory.CreatePrivateChannelAsync();
+ var privateChannel = await _channelHandler.CreatePrivateChannelAsync().ConfigureAwait(false);
return privateChannel;
}
@@ -238,7 +234,7 @@ public async Task> FindInstances(IAppIdentifier app)
{
await _initializationTaskCompletionSource.Task.ConfigureAwait(false);
- var instances = await _metadataClient.FindInstancesAsync(app);
+ var instances = await _metadataClient.FindInstancesAsync(app).ConfigureAwait(false);
return instances;
}
@@ -253,7 +249,7 @@ public async Task FindIntent(string intent, IContext? context = null
{
await _initializationTaskCompletionSource.Task.ConfigureAwait(false);
- var result = await _intentsClient.FindIntentAsync(intent, context, resultType);
+ var result = await _intentsClient.FindIntentAsync(intent, context, resultType).ConfigureAwait(false);
return result;
}
@@ -267,7 +263,7 @@ public async Task> FindIntentsByContext(IContext context
{
await _initializationTaskCompletionSource.Task.ConfigureAwait(false);
- var appIntents = await _intentsClient.FindIntentsByContextAsync(context, resultType);
+ var appIntents = await _intentsClient.FindIntentsByContextAsync(context, resultType).ConfigureAwait(false);
return appIntents;
}
@@ -280,7 +276,7 @@ public async Task GetAppMetadata(IAppIdentifier app)
{
await _initializationTaskCompletionSource.Task.ConfigureAwait(false);
- var appMetadata = await _metadataClient.GetAppMetadataAsync(app);
+ var appMetadata = await _metadataClient.GetAppMetadataAsync(app).ConfigureAwait(false);
return appMetadata;
}
@@ -303,7 +299,7 @@ public async Task GetInfo()
{
await _initializationTaskCompletionSource.Task.ConfigureAwait(false);
- var implementationMetadata = await _metadataClient.GetInfoAsync();
+ var implementationMetadata = await _metadataClient.GetInfoAsync().ConfigureAwait(false);
return implementationMetadata;
}
@@ -314,32 +310,9 @@ public async Task GetInfo()
///
public async Task GetOrCreateChannel(string channelId)
{
- try
- {
- await _initializationTaskCompletionSource.Task.ConfigureAwait(false);
- await _appChannelsLock.WaitAsync().ConfigureAwait(false);
-
- if (_appChannels.TryGetValue(channelId, out var existingChannel))
- {
- return existingChannel;
- }
-
- var channel = await _channelFactory.CreateAppChannelAsync(channelId);
-
- if (!_appChannels.TryAdd(channelId, channel))
- {
- if (_logger.IsEnabled(LogLevel.Warning))
- {
- _logger.LogWarning("Failed to add app channel to the internal collection: {ChannelId}.", channelId);
- }
- }
-
- return channel;
- }
- finally
- {
- _appChannelsLock.Release();
- }
+ await _initializationTaskCompletionSource.Task.ConfigureAwait(false);
+ var channel = await _channelHandler.CreateAppChannelAsync(channelId).ConfigureAwait(false);
+ return channel;
}
///
@@ -349,8 +322,7 @@ public async Task GetOrCreateChannel(string channelId)
public async Task> GetUserChannels()
{
await _initializationTaskCompletionSource.Task.ConfigureAwait(false);
-
- var channels = await _channelFactory.GetUserChannelsAsync();
+ var channels = await _channelHandler.GetUserChannelsAsync().ConfigureAwait(false);
return channels;
}
@@ -373,12 +345,7 @@ public async Task JoinUserChannel(string channelId)
await LeaveCurrentChannel().ConfigureAwait(false);
}
- if (!_userChannels.TryGetValue(channelId, out var channel))
- {
- channel = await _channelFactory.JoinUserChannelAsync(channelId).ConfigureAwait(false);
- _userChannels[channelId] = channel;
- }
-
+ var channel = await _channelHandler.JoinUserChannelAsync(channelId).ConfigureAwait(false);
_currentChannel = channel;
}
finally
@@ -422,7 +389,10 @@ public async Task LeaveCurrentChannel()
contextListener.Key.Unsubscribe();
}
- _currentChannel = null;
+ if (_currentChannel != null)
+ {
+ _currentChannel = null;
+ }
}
finally
{
@@ -440,7 +410,7 @@ public async Task Open(IAppIdentifier app, IContext? context = n
{
await _initializationTaskCompletionSource.Task.ConfigureAwait(false);
- var appIdentifier = await _openClient.OpenAsync(app, context);
+ var appIdentifier = await _openClient.OpenAsync(app, context).ConfigureAwait(false);
return appIdentifier;
}
@@ -455,7 +425,7 @@ public async Task RaiseIntent(string intent, IContext context
{
await _initializationTaskCompletionSource.Task.ConfigureAwait(false);
- var intentResolution = await _intentsClient.RaiseIntentAsync(intent, context, app);
+ var intentResolution = await _intentsClient.RaiseIntentAsync(intent, context, app).ConfigureAwait(false);
return intentResolution;
}
@@ -469,7 +439,7 @@ public async Task RaiseIntentForContext(IContext context, IAp
{
await _initializationTaskCompletionSource.Task.ConfigureAwait(false);
- var intentResolution = await _intentsClient.RaiseIntentForContextAsync(context, app);
+ var intentResolution = await _intentsClient.RaiseIntentForContextAsync(context, app).ConfigureAwait(false);
return intentResolution;
}
@@ -482,7 +452,7 @@ internal async ValueTask GetOpenedAppContextAsync(string openedAppContextId)
{
try
{
- _openedAppContext = await _openClient.GetOpenAppContextAsync(openedAppContextId);
+ _openedAppContext = await _openClient.GetOpenAppContextAsync(openedAppContextId).ConfigureAwait(false);
}
catch (Fdc3DesktopAgentException exception)
{
@@ -513,7 +483,7 @@ private async Task HandleLastContextAsync(
return;
}
- var lastContext = await _currentChannel.GetCurrentContext(listener.ContextType);
+ var lastContext = await _currentChannel.GetCurrentContext(listener.ContextType).ConfigureAwait(false);
if (lastContext == null)
{
@@ -526,6 +496,26 @@ private async Task HandleLastContextAsync(
_logger.LogDebug("Invoking context handler for the last context of type: {ContextType}.", listener.ContextType ?? "null");
}
- await listener.HandleContextAsync(lastContext);
+ await listener.HandleContextAsync(lastContext).ConfigureAwait(false);
+ }
+
+ public ValueTask DisposeAsync()
+ {
+ if (_channelHandler != null)
+ {
+ return _channelHandler.DisposeAsync();
+ }
+
+ foreach (var intentListener in _intentListeners.Values)
+ {
+ intentListener.Unsubscribe();
+ }
+
+ foreach (var contextListener in _contextListeners.Keys)
+ {
+ contextListener.Unsubscribe();
+ }
+
+ return new ValueTask();
}
}
\ No newline at end of file
diff --git a/src/fdc3/dotnet/DesktopAgent.Client/src/MorganStanley.ComposeUI.Fdc3.DesktopAgent.Client/Infrastructure/IChannelFactory.cs b/src/fdc3/dotnet/DesktopAgent.Client/src/MorganStanley.ComposeUI.Fdc3.DesktopAgent.Client/Infrastructure/IChannelHandler.cs
similarity index 90%
rename from src/fdc3/dotnet/DesktopAgent.Client/src/MorganStanley.ComposeUI.Fdc3.DesktopAgent.Client/Infrastructure/IChannelFactory.cs
rename to src/fdc3/dotnet/DesktopAgent.Client/src/MorganStanley.ComposeUI.Fdc3.DesktopAgent.Client/Infrastructure/IChannelHandler.cs
index eab12afd2..3862ce12d 100644
--- a/src/fdc3/dotnet/DesktopAgent.Client/src/MorganStanley.ComposeUI.Fdc3.DesktopAgent.Client/Infrastructure/IChannelFactory.cs
+++ b/src/fdc3/dotnet/DesktopAgent.Client/src/MorganStanley.ComposeUI.Fdc3.DesktopAgent.Client/Infrastructure/IChannelHandler.cs
@@ -21,7 +21,7 @@ namespace MorganStanley.ComposeUI.Fdc3.DesktopAgent.Client.Infrastructure;
///
/// Provides methods for creating context listeners and joining channels and doing other channel operations.
///
-internal interface IChannelFactory
+internal interface IChannelHandler : IAsyncDisposable
{
///
/// Creates a context listener for the specified context type.
@@ -70,4 +70,11 @@ public ValueTask> CreateContextListenerAsync(
///
///
public ValueTask CreatePrivateChannelAsync();
-}
+
+ ///
+ /// Sets the handler when the user choose a user channel to join to from the UI.
+ ///
+ ///
+ ///
+ public ValueTask ConfigureChannelSelectorAsync(CancellationToken cancellationToken = default);
+}
\ No newline at end of file
diff --git a/src/fdc3/dotnet/DesktopAgent.Client/src/MorganStanley.ComposeUI.Fdc3.DesktopAgent.Client/Infrastructure/Internal/ChannelFactory.cs b/src/fdc3/dotnet/DesktopAgent.Client/src/MorganStanley.ComposeUI.Fdc3.DesktopAgent.Client/Infrastructure/Internal/ChannelHandler.cs
similarity index 79%
rename from src/fdc3/dotnet/DesktopAgent.Client/src/MorganStanley.ComposeUI.Fdc3.DesktopAgent.Client/Infrastructure/Internal/ChannelFactory.cs
rename to src/fdc3/dotnet/DesktopAgent.Client/src/MorganStanley.ComposeUI.Fdc3.DesktopAgent.Client/Infrastructure/Internal/ChannelHandler.cs
index a60eafb3b..32a57e729 100644
--- a/src/fdc3/dotnet/DesktopAgent.Client/src/MorganStanley.ComposeUI.Fdc3.DesktopAgent.Client/Infrastructure/Internal/ChannelFactory.cs
+++ b/src/fdc3/dotnet/DesktopAgent.Client/src/MorganStanley.ComposeUI.Fdc3.DesktopAgent.Client/Infrastructure/Internal/ChannelHandler.cs
@@ -23,31 +23,35 @@
using MorganStanley.ComposeUI.Fdc3.DesktopAgent.Shared.Contracts;
using MorganStanley.ComposeUI.Fdc3.DesktopAgent.Shared.Exceptions;
using MorganStanley.ComposeUI.Messaging.Abstractions;
+using MorganStanley.ComposeUI.Messaging.Abstractions.Exceptions;
namespace MorganStanley.ComposeUI.Fdc3.DesktopAgent.Client.Infrastructure.Internal;
-//TODO: Rename this class and its interface to better reflect their responsibilities
-internal class ChannelFactory : IChannelFactory
+internal class ChannelHandler : IChannelHandler
{
private readonly IMessaging _messaging;
private readonly string _instanceId;
+ private readonly IDesktopAgent _desktopAgent;
private readonly IContext? _openedAppContext;
private readonly ILoggerFactory _loggerFactory;
- private readonly ILogger _logger;
+ private readonly ILogger _logger;
private readonly JsonSerializerOptions _jsonSerializerOptions = SerializerOptionsHelper.JsonSerializerOptionsWithContextSerialization;
private readonly ConcurrentDictionary _privateChannels = new();
+ private IAsyncDisposable _channelSelector;
- public ChannelFactory(
+ public ChannelHandler(
IMessaging messaging,
string fdc3InstanceId,
+ IDesktopAgent desktopAgent,
IContext? openedAppContext = null,
ILoggerFactory? loggerFactory = null)
{
_messaging = messaging;
_instanceId = fdc3InstanceId;
+ _desktopAgent = desktopAgent;
_openedAppContext = openedAppContext;
_loggerFactory = loggerFactory ?? NullLoggerFactory.Instance;
- _logger = _loggerFactory.CreateLogger();
+ _logger = _loggerFactory.CreateLogger();
}
public async ValueTask> CreateContextListenerAsync(
@@ -67,7 +71,7 @@ public async ValueTask> CreateContextListenerAsync(
logger: _loggerFactory.CreateLogger>());
}
- if (await currentChannel.AddContextListener(contextType, contextHandler) is ContextListener contextListener)
+ if (await currentChannel.AddContextListener(contextType, contextHandler).ConfigureAwait(false) is ContextListener contextListener)
{
_logger.LogDebug("Added context listener to channel {CurrentChannelId} for context type {ContextType}.)", currentChannel.Id, contextType ?? "null");
@@ -90,7 +94,7 @@ public async ValueTask CreateAppChannelAsync(string channelId)
var response = await _messaging.InvokeJsonServiceAsync(
Fdc3Topic.CreateAppChannel,
request,
- _jsonSerializerOptions);
+ _jsonSerializerOptions).ConfigureAwait(false);
if (response == null)
{
@@ -126,7 +130,7 @@ public async ValueTask> GetUserChannelsAsync()
var response = await _messaging.InvokeJsonServiceAsync(
Fdc3Topic.GetUserChannels,
request,
- _jsonSerializerOptions);
+ _jsonSerializerOptions).ConfigureAwait(false);
if (response == null)
{
@@ -183,7 +187,7 @@ public async ValueTask JoinUserChannelAsync(string channelId)
var response = await _messaging.InvokeJsonServiceAsync(
serviceName: Fdc3Topic.JoinUserChannel,
request,
- _jsonSerializerOptions);
+ _jsonSerializerOptions).ConfigureAwait(false);
if (response == null)
{
@@ -209,6 +213,17 @@ public async ValueTask JoinUserChannelAsync(string channelId)
displayMetadata: response.DisplayMetadata,
loggerFactory: _loggerFactory);
+ try
+ {
+ var result = await _messaging.InvokeServiceAsync(Fdc3Topic.ChannelSelectorFromAPI(_instanceId), channelId).ConfigureAwait(false);
+
+ _logger.LogDebug("Triggered channel selector from API for module: {InstanceId}, with {ChannelId}, and backend returned result: {Result}", _instanceId, channel.Id, result);
+ }
+ catch (Exception exception)
+ {
+ _logger.LogWarning(exception, "Failed to trigger channel selector from API for module: {InstanceId}, with {ChannelId}.", channelId, _instanceId);
+ }
+
return channel;
}
@@ -223,7 +238,7 @@ public async ValueTask FindChannelAsync(string channelId, ChannelType
var response = await _messaging.InvokeJsonServiceAsync(
Fdc3Topic.FindChannel,
request,
- _jsonSerializerOptions);
+ _jsonSerializerOptions).ConfigureAwait(false);
if (response == null)
{
@@ -242,7 +257,7 @@ public async ValueTask FindChannelAsync(string channelId, ChannelType
if (channelType == ChannelType.Private)
{
- return await JoinPrivateChannelAsync(channelId);
+ return await JoinPrivateChannelAsync(channelId).ConfigureAwait(false);
}
//This is only called when raising an intent, the RaiseIntent logic.
@@ -265,7 +280,7 @@ public async ValueTask CreatePrivateChannelAsync()
var response = await _messaging.InvokeJsonServiceAsync(
Fdc3Topic.CreatePrivateChannel,
request,
- _jsonSerializerOptions);
+ _jsonSerializerOptions).ConfigureAwait(false);
if (response == null)
{
@@ -291,6 +306,35 @@ public async ValueTask CreatePrivateChannelAsync()
return channel;
}
+ public async ValueTask ConfigureChannelSelectorAsync(CancellationToken cancellationToken = default)
+ {
+ _channelSelector = await _messaging.RegisterServiceAsync(
+ Fdc3Topic.ChannelSelectorFromUI(_instanceId),
+ ChannelSelectorFromUI,
+ cancellationToken).ConfigureAwait(false);
+ }
+
+ private async ValueTask ChannelSelectorFromUI(string? request)
+ {
+ if (string.IsNullOrEmpty(request))
+ {
+ return null;
+ }
+
+ var joinUserChannelRequest = JsonSerializer.Deserialize(request, _jsonSerializerOptions);
+
+ if (joinUserChannelRequest == null || string.IsNullOrEmpty(joinUserChannelRequest.ChannelId))
+ {
+ _logger.LogDebug("Channel selector from UI received invalid request: {Request}", request);
+
+ return null;
+ }
+
+ await _desktopAgent.JoinUserChannel(joinUserChannelRequest.ChannelId).ConfigureAwait(false);
+
+ return joinUserChannelRequest.ChannelId;
+ }
+
private async ValueTask JoinPrivateChannelAsync(string channelId)
{
var request = new JoinPrivateChannelRequest
@@ -302,7 +346,7 @@ private async ValueTask JoinPrivateChannelAsync(string channelI
var response = await _messaging.InvokeJsonServiceAsync(
Fdc3Topic.JoinPrivateChannel,
request,
- _jsonSerializerOptions);
+ _jsonSerializerOptions).ConfigureAwait(false);
if (response == null)
{
@@ -337,4 +381,17 @@ private async ValueTask JoinPrivateChannelAsync(string channelI
return channel;
}
+
+ public async ValueTask DisposeAsync()
+ {
+ if (_channelSelector != null)
+ {
+ await _channelSelector.DisposeAsync();
+ }
+
+ foreach (var privateChannel in _privateChannels.Values)
+ {
+ privateChannel.Disconnect();
+ }
+ }
}
diff --git a/src/fdc3/dotnet/DesktopAgent.Client/src/MorganStanley.ComposeUI.Fdc3.DesktopAgent.Client/Infrastructure/Internal/IntentsClient.cs b/src/fdc3/dotnet/DesktopAgent.Client/src/MorganStanley.ComposeUI.Fdc3.DesktopAgent.Client/Infrastructure/Internal/IntentsClient.cs
index a5c9a2f46..1b7e494b3 100644
--- a/src/fdc3/dotnet/DesktopAgent.Client/src/MorganStanley.ComposeUI.Fdc3.DesktopAgent.Client/Infrastructure/Internal/IntentsClient.cs
+++ b/src/fdc3/dotnet/DesktopAgent.Client/src/MorganStanley.ComposeUI.Fdc3.DesktopAgent.Client/Infrastructure/Internal/IntentsClient.cs
@@ -31,7 +31,7 @@ internal class IntentsClient : IIntentsClient
private static int _messageIdCounter = 0;
private readonly IMessaging _messaging;
- private readonly IChannelFactory _channelFactory;
+ private readonly IChannelHandler _channelFactory;
private readonly string _instanceId;
private readonly ILoggerFactory _loggerFactory;
private readonly ILogger _logger;
@@ -39,7 +39,7 @@ internal class IntentsClient : IIntentsClient
public IntentsClient(
IMessaging messaging,
- IChannelFactory channelFactory,
+ IChannelHandler channelFactory,
string instanceId,
ILoggerFactory? loggerFactory = null)
{
@@ -59,7 +59,7 @@ public async ValueTask AddIntentListenerAsync(string intent, Inten
handler,
_loggerFactory.CreateLogger>());
- await listener.RegisterIntentHandlerAsync();
+ await listener.RegisterIntentHandlerAsync().ConfigureAwait(false);
var request = new IntentListenerRequest
{
@@ -71,7 +71,7 @@ public async ValueTask AddIntentListenerAsync(string intent, Inten
var response = await _messaging.InvokeJsonServiceAsync(
Fdc3Topic.AddIntentListener,
request,
- _jsonSerializerOptions);
+ _jsonSerializerOptions).ConfigureAwait(false);
if (response == null)
{
@@ -114,7 +114,7 @@ public async ValueTask FindIntentAsync(string intent, IContext? cont
var response = await _messaging.InvokeJsonServiceAsync(
Fdc3Topic.FindIntent,
request,
- _jsonSerializerOptions);
+ _jsonSerializerOptions).ConfigureAwait(false);
if (response == null)
{
@@ -151,7 +151,7 @@ public async ValueTask> FindIntentsByContextAsync(IConte
var response = await _messaging.InvokeJsonServiceAsync(
Fdc3Topic.FindIntentsByContext,
request,
- _jsonSerializerOptions);
+ _jsonSerializerOptions).ConfigureAwait(false);
if (response == null)
{
@@ -200,7 +200,7 @@ public async ValueTask RaiseIntentAsync(string intent, IConte
var response = await _messaging.InvokeJsonServiceAsync(
Fdc3Topic.RaiseIntent,
request,
- _jsonSerializerOptions);
+ _jsonSerializerOptions).ConfigureAwait(false);
if (response == null)
{
@@ -258,7 +258,7 @@ public async ValueTask RaiseIntentForContextAsync(IContext co
var response = await _messaging.InvokeJsonServiceAsync(
Fdc3Topic.RaiseIntentForContext,
request,
- _jsonSerializerOptions);
+ _jsonSerializerOptions).ConfigureAwait(false);
if (response == null)
{
diff --git a/src/fdc3/dotnet/DesktopAgent.Client/src/MorganStanley.ComposeUI.Fdc3.DesktopAgent.Client/Infrastructure/Internal/Protocol/Channel.cs b/src/fdc3/dotnet/DesktopAgent.Client/src/MorganStanley.ComposeUI.Fdc3.DesktopAgent.Client/Infrastructure/Internal/Protocol/Channel.cs
index 867bd6366..36ce83d39 100644
--- a/src/fdc3/dotnet/DesktopAgent.Client/src/MorganStanley.ComposeUI.Fdc3.DesktopAgent.Client/Infrastructure/Internal/Protocol/Channel.cs
+++ b/src/fdc3/dotnet/DesktopAgent.Client/src/MorganStanley.ComposeUI.Fdc3.DesktopAgent.Client/Infrastructure/Internal/Protocol/Channel.cs
@@ -80,7 +80,7 @@ public virtual async Task AddContextListener(string? contextType,
openedAppContext: _openedAppContext,
logger: _loggerFactory.CreateLogger>());
- await listener.SubscribeAsync(_channelId, _channelType);
+ await listener.SubscribeAsync(_channelId, _channelType).ConfigureAwait(false);
return listener;
}
@@ -100,7 +100,7 @@ public virtual async Task Broadcast(IContext context)
await _messaging.PublishJsonAsync(
new ChannelTopics(_channelId, _channelType).Broadcast,
context,
- _jsonSerializerOptions);
+ _jsonSerializerOptions).ConfigureAwait(false);
}
finally
{
diff --git a/src/fdc3/dotnet/DesktopAgent.Client/src/MorganStanley.ComposeUI.Fdc3.DesktopAgent.Client/Infrastructure/Internal/Protocol/IntentResolution.cs b/src/fdc3/dotnet/DesktopAgent.Client/src/MorganStanley.ComposeUI.Fdc3.DesktopAgent.Client/Infrastructure/Internal/Protocol/IntentResolution.cs
index a90951d74..bf207572a 100644
--- a/src/fdc3/dotnet/DesktopAgent.Client/src/MorganStanley.ComposeUI.Fdc3.DesktopAgent.Client/Infrastructure/Internal/Protocol/IntentResolution.cs
+++ b/src/fdc3/dotnet/DesktopAgent.Client/src/MorganStanley.ComposeUI.Fdc3.DesktopAgent.Client/Infrastructure/Internal/Protocol/IntentResolution.cs
@@ -29,13 +29,13 @@ internal class IntentResolution : IIntentResolution
{
private readonly string _messageId;
private readonly IMessaging _messaging;
- private readonly IChannelFactory _channelFactory;
+ private readonly IChannelHandler _channelFactory;
private readonly JsonSerializerOptions _jsonSerializerOptions = SerializerOptionsHelper.JsonSerializerOptionsWithContextSerialization;
public IntentResolution(
string messageId,
IMessaging messaging,
- IChannelFactory channelFactory,
+ IChannelHandler channelFactory,
string intent,
IAppIdentifier source,
ILogger? logger = null)
@@ -73,7 +73,7 @@ public IntentResolution(
var response = await _messaging.InvokeJsonServiceAsync(
Fdc3Topic.GetIntentResult,
request,
- _jsonSerializerOptions);
+ _jsonSerializerOptions).ConfigureAwait(false);
if (response == null)
{
@@ -88,7 +88,7 @@ public IntentResolution(
if (!string.IsNullOrEmpty(response.ChannelId)
&& response.ChannelType != null)
{
- var channel = await _channelFactory.FindChannelAsync(response.ChannelId!, response.ChannelType.Value);
+ var channel = await _channelFactory.FindChannelAsync(response.ChannelId!, response.ChannelType.Value).ConfigureAwait(false);
return channel;
}
else if (!string.IsNullOrEmpty(response.Context))
diff --git a/src/fdc3/dotnet/DesktopAgent.Client/src/MorganStanley.ComposeUI.Fdc3.DesktopAgent.Client/Infrastructure/Internal/Protocol/PrivateChannel.cs b/src/fdc3/dotnet/DesktopAgent.Client/src/MorganStanley.ComposeUI.Fdc3.DesktopAgent.Client/Infrastructure/Internal/Protocol/PrivateChannel.cs
index a8fca2423..ab31a43b1 100644
--- a/src/fdc3/dotnet/DesktopAgent.Client/src/MorganStanley.ComposeUI.Fdc3.DesktopAgent.Client/Infrastructure/Internal/Protocol/PrivateChannel.cs
+++ b/src/fdc3/dotnet/DesktopAgent.Client/src/MorganStanley.ComposeUI.Fdc3.DesktopAgent.Client/Infrastructure/Internal/Protocol/PrivateChannel.cs
@@ -75,7 +75,7 @@ private async ValueTask InitializeAsync()
_logger.LogDebug("Subscribing to private channel internal events for channel {ChannelId}, instance {InstanceId}, topic: {Topic}.", Id, InstanceId, _internalEventsTopic);
}
- _subscription = await Messaging.SubscribeAsync(_internalEventsTopic, HandleInternalEvent);
+ _subscription = await Messaging.SubscribeAsync(_internalEventsTopic, HandleInternalEvent).ConfigureAwait(false);
var topic = _privateChannelTopics.GetContextHandlers(_isOriginalCreator);
@@ -84,7 +84,7 @@ private async ValueTask InitializeAsync()
_logger.LogDebug("Registering remote private channel context handlers service for channel {ChannelId}, instance {InstanceId}, service: {Service}.", Id, InstanceId, topic);
}
- _serviceRegistration = await Messaging.RegisterServiceAsync(topic, HandleRemoteContextListener);
+ _serviceRegistration = await Messaging.RegisterServiceAsync(topic, HandleRemoteContextListener).ConfigureAwait(false);
_initializationTaskCompletionSource.SetResult(Id);
}
@@ -128,7 +128,7 @@ public override async Task AddContextListener(string? contextType,
throw ThrowHelper.PrivateChannelDisconnected(Id, InstanceId);
}
- var listener = await base.AddContextListener(contextType, handler) as ContextListener;
+ var listener = await base.AddContextListener(contextType, handler).ConfigureAwait(false) as ContextListener;
if (listener != null)
{
@@ -146,7 +146,7 @@ public override async Task AddContextListener(string? contextType,
return listener;
}
- throw ThrowHelper.PrivatChannelSubscribeFailure(contextType, Id, InstanceId);
+ throw ThrowHelper.PrivateChannelSubscribeFailure(contextType, Id, InstanceId);
}
finally
{
@@ -204,19 +204,26 @@ public async void Disconnect()
foreach (var listener in _contextHandlers)
{
- //Fire and forget
- listener.Unsubscribe();
+ try
+ {
+ //Fire and forget
+ listener.Unsubscribe();
- if (_logger.IsEnabled(LogLevel.Trace))
+ if (_logger.IsEnabled(LogLevel.Trace))
+ {
+ _logger.LogTrace("Unsubscribed context listener on private channel {ChannelId}.", Id);
+ }
+ }
+ catch (Exception exception)
{
- _logger.LogTrace("Unsubscribed context listener on private channel {ChannelId}.", Id);
+ _logger.LogWarning(exception, "Error unsubscribing context listener on private channel {ChannelId}.", Id);
}
}
var request = PrivateChannelInternalEvents.Disconnected(InstanceId);
var serializedRequest = JsonSerializer.Serialize(request, _jsonSerializerOptions);
- await Messaging.PublishAsync(_internalEventsTopic, serializedRequest);
+ await Messaging.PublishAsync(_internalEventsTopic, serializedRequest).ConfigureAwait(false);
if (_logger.IsEnabled(LogLevel.Debug))
{
@@ -225,6 +232,10 @@ public async void Disconnect()
_onDisconnect();
}
+ catch (Exception exception)
+ {
+ _logger.LogError(exception, "Error during disconnecting private channel {ChannelId}, instance {InstanceId}.", Id, InstanceId);
+ }
finally
{
_lock.Release();
@@ -415,7 +426,7 @@ private async ValueTask FireContextHandlerAdded(string? contextType)
var serializedRequest = JsonSerializer.Serialize(request, _jsonSerializerOptions);
- await Messaging.PublishAsync(_internalEventsTopic, serializedRequest);
+ await Messaging.PublishAsync(_internalEventsTopic, serializedRequest).ConfigureAwait(false);
if (_logger.IsEnabled(LogLevel.Debug))
{
@@ -458,7 +469,7 @@ private async ValueTask FireUnsubscribed(string? contextType)
var serializedRequest = JsonSerializer.Serialize(request, _jsonSerializerOptions);
- await Messaging.PublishAsync(_internalEventsTopic, serializedRequest);
+ await Messaging.PublishAsync(_internalEventsTopic, serializedRequest).ConfigureAwait(false);
if (_logger.IsEnabled(LogLevel.Debug))
{
diff --git a/src/fdc3/dotnet/DesktopAgent.Client/test/IntegrationTests/EndToEndTests.cs b/src/fdc3/dotnet/DesktopAgent.Client/test/IntegrationTests/EndToEndTests.cs
index 7bda5af23..3a02be51a 100644
--- a/src/fdc3/dotnet/DesktopAgent.Client/test/IntegrationTests/EndToEndTests.cs
+++ b/src/fdc3/dotnet/DesktopAgent.Client/test/IntegrationTests/EndToEndTests.cs
@@ -11,6 +11,7 @@
using DisplayMetadata = MorganStanley.ComposeUI.Fdc3.DesktopAgent.Shared.Protocol.DisplayMetadata;
using AppIdentifier = MorganStanley.ComposeUI.Fdc3.DesktopAgent.Shared.Protocol.AppIdentifier;
using MorganStanley.ComposeUI.Fdc3.DesktopAgent.Client.IntegrationTests.Helpers;
+using MorganStanley.ComposeUI.Fdc3.DesktopAgent.Shared;
namespace MorganStanley.ComposeUI.Fdc3.DesktopAgent.Client.IntegrationTests;
@@ -26,6 +27,7 @@ public class EndToEndTests : IAsyncLifetime
private readonly List _runningApps = [];
private IDisposable _runningAppsObserver;
private IDesktopAgent _desktopAgent;
+
public EndToEndTests()
{
var repoRoot = RootPathResolver.GetRepositoryRoot();
@@ -199,7 +201,9 @@ public async Task JoinUserChannel_joins_to_a_user_channel_and_registers_already_
{
var resultContexts = new List();
- var module = await _moduleLoader.StartModule(new StartRequest("appId1-native", new Dictionary() { { "Fdc3InstanceId", Guid.NewGuid().ToString() } })); // This will ensure that the DesktopAgent backend knows its an FDC3 enabled module. The app broadcasts an instrument context after it joined to the fdc3.channel.1.
+ var instanceId = Guid.NewGuid().ToString();
+
+ var module = await _moduleLoader.StartModule(new StartRequest("appId1-native", new Dictionary() { { "Fdc3InstanceId", instanceId } })); // This will ensure that the DesktopAgent backend knows its an FDC3 enabled module. The app broadcasts an instrument context after it joined to the fdc3.channel.1.
//We need to wait somehow for the module to finish up the broadcast
await Task.Delay(2000);
@@ -320,7 +324,9 @@ public async Task GetOrCreateChannel_creates_channel_and_client_able_to_broadcas
resultContexts.Add(context);
});
- var module = await _moduleLoader.StartModule(new StartRequest("appId1-native", new Dictionary() { { "Fdc3InstanceId", Guid.NewGuid().ToString() } })); // This will ensure that the DesktopAgent backend knows its an FDC3 enabled module. For test only
+ var instanceId = Guid.NewGuid().ToString();
+
+ var module = await _moduleLoader.StartModule(new StartRequest("appId1-native", new Dictionary() { { "Fdc3InstanceId", instanceId } })); // This will ensure that the DesktopAgent backend knows its an FDC3 enabled module. For test only
//We need to wait somehow for the module to finish up the broadcast
await Task.Delay(2000);
@@ -331,6 +337,8 @@ public async Task GetOrCreateChannel_creates_channel_and_client_able_to_broadcas
resultContexts.Should().BeEquivalentTo(new List() { new Instrument(new InstrumentID { Ticker = $"test-instrument-2" }, "test-name2") });
}
+ private void ChannelSelectorBehavior(string? obj) { }
+
[Fact]
public async Task FindIntent_returns_AppIntent()
{
diff --git a/src/fdc3/dotnet/DesktopAgent.Client/test/MorganStanley.ComposeUI.Fdc3.DesktopAgent.Client.Tests/Infrastructure/DesktopAgentClient.Tests.cs b/src/fdc3/dotnet/DesktopAgent.Client/test/MorganStanley.ComposeUI.Fdc3.DesktopAgent.Client.Tests/Infrastructure/DesktopAgentClient.Tests.cs
index c32da578d..f4dd10b7a 100644
--- a/src/fdc3/dotnet/DesktopAgent.Client/test/MorganStanley.ComposeUI.Fdc3.DesktopAgent.Client.Tests/Infrastructure/DesktopAgentClient.Tests.cs
+++ b/src/fdc3/dotnet/DesktopAgent.Client/test/MorganStanley.ComposeUI.Fdc3.DesktopAgent.Client.Tests/Infrastructure/DesktopAgentClient.Tests.cs
@@ -231,6 +231,7 @@ public async Task JoinUserChannel_handles_last_context_for_all_the_registered_to
It.IsAny(),
It.IsAny()))
.Returns(new ValueTask(JsonSerializer.Serialize(new JoinUserChannelResponse { Success = true, DisplayMetadata = new DisplayMetadata() { Name = "test-channelId" } }, _jsonSerializerOptions)))
+ .Returns(new ValueTask("test-channelId"))
.Returns(new ValueTask(JsonSerializer.Serialize(new AddContextListenerResponse { Success = true, Id = Guid.NewGuid().ToString() }, _jsonSerializerOptions)))
.Returns(new ValueTask(JsonSerializer.Serialize(new Instrument(new InstrumentID { Ticker = "test-instrument" }, "test-name"), _jsonSerializerOptions))) //GetCurrentContext response after joining to the channels when iterating through the context listeners
.Returns(new ValueTask(JsonSerializer.Serialize(new AddContextListenerResponse { Success = true, Id = Guid.NewGuid().ToString() }, _jsonSerializerOptions)))
@@ -311,6 +312,7 @@ public async Task AddContextListener_handles_last_context_on_the_channel()
var subscriptionMock = new Mock();
var messagingMock = new Mock();
+
messagingMock.Setup(
_ => _.SubscribeAsync(
It.IsAny(),
@@ -324,6 +326,7 @@ public async Task AddContextListener_handles_last_context_on_the_channel()
It.IsAny(),
It.IsAny()))
.Returns(new ValueTask(JsonSerializer.Serialize(new JoinUserChannelResponse { Success = true, DisplayMetadata = new DisplayMetadata() { Name = "test-channelId" } }, _jsonSerializerOptions)))
+ .Returns(new ValueTask("test-channelId"))
.Returns(new ValueTask(JsonSerializer.Serialize(new AddContextListenerResponse { Success = true, Id = Guid.NewGuid().ToString() }, _jsonSerializerOptions)))
.Returns(new ValueTask(JsonSerializer.Serialize(new Instrument(new InstrumentID { Ticker = "test-instrument" }, "test-name"), _jsonSerializerOptions)))
.Returns(new ValueTask(JsonSerializer.Serialize(new AddContextListenerResponse { Success = true, Id = Guid.NewGuid().ToString() }, _jsonSerializerOptions)))
@@ -363,6 +366,7 @@ public async Task AddContextListener_receives_messages()
It.IsAny(),
It.IsAny()))
.Returns(new ValueTask(JsonSerializer.Serialize(new JoinUserChannelResponse { Success = true, DisplayMetadata = new DisplayMetadata() { Name = "test-channelId" } }, _jsonSerializerOptions)))
+ .Returns(new ValueTask("test-channelId"))
.Returns(new ValueTask(JsonSerializer.Serialize(new AddContextListenerResponse { Success = true, Id = Guid.NewGuid().ToString() }, _jsonSerializerOptions)))
.Returns(new ValueTask(JsonSerializer.Serialize(new Instrument(new InstrumentID { Ticker = "test-instrument" }, "test-name"), _jsonSerializerOptions)))
.Returns(new ValueTask(JsonSerializer.Serialize(new AddContextListenerResponse { Success = true, Id = Guid.NewGuid().ToString() }, _jsonSerializerOptions)))
@@ -904,7 +908,7 @@ public async Task RaiseIntentForContext_returns_channel_as_IntentResolution()
MessageId = Guid.NewGuid().ToString()
};
- var channelFactoryMock = new Mock();
+ var channelFactoryMock = new Mock();
channelFactoryMock
.Setup(_ => _.FindChannelAsync(It.IsAny(), It.IsAny()))
.ReturnsAsync(new Channel("test-channel-id", ChannelType.User, messagingMock.Object, It.IsAny(), null, It.IsAny(), It.IsAny()));
@@ -1017,7 +1021,7 @@ public async Task RaiseIntentForContext_returns_channel_if_everything_is_defined
MessageId = Guid.NewGuid().ToString()
};
- var channelFactoryMock = new Mock();
+ var channelFactoryMock = new Mock();
channelFactoryMock
.Setup(_ => _.FindChannelAsync(It.IsAny(), It.IsAny()))
.ReturnsAsync(new Channel("test-channel-id", ChannelType.App, messagingMock.Object, It.IsAny(), null, It.IsAny(), It.IsAny()));
diff --git a/src/fdc3/dotnet/DesktopAgent.Client/test/MorganStanley.ComposeUI.Fdc3.DesktopAgent.Client.Tests/Infrastructure/Internal/ChannelFactory.Tests.cs b/src/fdc3/dotnet/DesktopAgent.Client/test/MorganStanley.ComposeUI.Fdc3.DesktopAgent.Client.Tests/Infrastructure/Internal/ChannelHandler.Tests.cs
similarity index 82%
rename from src/fdc3/dotnet/DesktopAgent.Client/test/MorganStanley.ComposeUI.Fdc3.DesktopAgent.Client.Tests/Infrastructure/Internal/ChannelFactory.Tests.cs
rename to src/fdc3/dotnet/DesktopAgent.Client/test/MorganStanley.ComposeUI.Fdc3.DesktopAgent.Client.Tests/Infrastructure/Internal/ChannelHandler.Tests.cs
index 42975bad2..e7ba9ae4f 100644
--- a/src/fdc3/dotnet/DesktopAgent.Client/test/MorganStanley.ComposeUI.Fdc3.DesktopAgent.Client.Tests/Infrastructure/Internal/ChannelFactory.Tests.cs
+++ b/src/fdc3/dotnet/DesktopAgent.Client/test/MorganStanley.ComposeUI.Fdc3.DesktopAgent.Client.Tests/Infrastructure/Internal/ChannelHandler.Tests.cs
@@ -25,7 +25,7 @@
namespace MorganStanley.ComposeUI.Fdc3.DesktopAgent.Client.Tests.Infrastructure.Internal;
-public class ChannelFactoryTests
+public class ChannelHandlerTests
{
private readonly JsonSerializerOptions _jsonSerializerOptions = SerializerOptionsHelper.JsonSerializerOptionsWithContextSerialization;
@@ -37,11 +37,13 @@ public async Task CreateContextListenerAsync_returns_listener_from_channel_when_
var handler = new ContextHandler((ctx, _)=> { });
var expectedListener = new ContextListener("instanceId", handler, messagingMock.Object, "fdc3.instrument");
+ var desktopAgentClientMock = new Mock();
+
channelMock
.Setup(c => c.AddContextListener("fdc3.instrument", handler))
.ReturnsAsync(expectedListener);
- var factory = new ChannelFactory(messagingMock.Object, "instanceId");
+ var factory = new ChannelHandler(messagingMock.Object, "instanceId", desktopAgentClientMock.Object);
var result = await factory.CreateContextListenerAsync(handler, channelMock.Object, "fdc3.instrument");
@@ -53,7 +55,8 @@ public async Task CreateContextListenerAsync_creates_new_listener_when_currentCh
{
var messagingMock = new Mock();
var handler = new ContextHandler((ctx, _) => { });
- var factory = new ChannelFactory(messagingMock.Object, "instanceId");
+ var desktopAgentClientMock = new Mock();
+ var factory = new ChannelHandler(messagingMock.Object, "instanceId", desktopAgentClientMock.Object);
var result = await factory.CreateContextListenerAsync(handler, null, "fdc3.instrument");
@@ -78,7 +81,8 @@ public async Task JoinUserChannelAsync_returns_channel_when_successful()
It.IsAny()))
.Returns(new ValueTask(JsonSerializer.Serialize(response, _jsonSerializerOptions)));
- var factory = new ChannelFactory(messagingMock.Object, "instanceId");
+ var desktopAgentClientMock = new Mock();
+ var factory = new ChannelHandler(messagingMock.Object, "instanceId", desktopAgentClientMock.Object);
var result = await factory.JoinUserChannelAsync("channelId");
@@ -97,7 +101,8 @@ public async Task JoinUserChannelAsync_returns_error_when_response_is_null()
It.IsAny()))
.Returns(new ValueTask((string?) null));
- var factory = new ChannelFactory(messagingMock.Object, "instanceId");
+ var desktopAgentClientMock = new Mock();
+ var factory = new ChannelHandler(messagingMock.Object, "instanceId", desktopAgentClientMock.Object);
var act = async () => await factory.JoinUserChannelAsync("channelId");
@@ -122,7 +127,8 @@ public async Task JoinUserChannelAsync_returns_error_when_response_has_error()
It.IsAny()))
.Returns(new ValueTask(JsonSerializer.Serialize(response, _jsonSerializerOptions)));
- var factory = new ChannelFactory(messagingMock.Object, "instanceId");
+ var desktopAgentClientMock = new Mock();
+ var factory = new ChannelHandler(messagingMock.Object, "instanceId", desktopAgentClientMock.Object);
var act = async () => await factory.JoinUserChannelAsync("channelId");
@@ -147,7 +153,8 @@ public async Task JoinUserChannelAsync_returns_error_when_response_is_unsuccessf
It.IsAny()))
.Returns(new ValueTask(JsonSerializer.Serialize(response, _jsonSerializerOptions)));
- var factory = new ChannelFactory(messagingMock.Object, "instanceId");
+ var desktopAgentClientMock = new Mock();
+ var factory = new ChannelHandler(messagingMock.Object, "instanceId", desktopAgentClientMock.Object);
var act = async() => await factory.JoinUserChannelAsync("channelId");
@@ -167,7 +174,8 @@ public async Task JoinUserChannelAsync_returns_error_when_messaging_throws()
It.IsAny()))
.ThrowsAsync(new InvalidOperationException("Messaging error"));
- var factory = new ChannelFactory(messagingMock.Object, "instanceId");
+ var desktopAgentClientMock = new Mock();
+ var factory = new ChannelHandler(messagingMock.Object, "instanceId", desktopAgentClientMock.Object);
var act = async () => await factory.JoinUserChannelAsync("channelId");
@@ -192,7 +200,8 @@ public async Task CreateAppChannelAsync_returns_channel_when_successful()
It.IsAny()))
.Returns(new ValueTask(JsonSerializer.Serialize(response, _jsonSerializerOptions)));
- var factory = new ChannelFactory(messagingMock.Object, "instanceId");
+ var desktopAgentClientMock = new Mock();
+ var factory = new ChannelHandler(messagingMock.Object, "instanceId", desktopAgentClientMock.Object);
var result = await factory.CreateAppChannelAsync("channelId");
@@ -210,7 +219,8 @@ public async Task CreateAppChannelAsync_returns_error_when_response_is_null()
It.IsAny()))
.Returns(new ValueTask((string?) null));
- var factory = new ChannelFactory(messagingMock.Object, "instanceId");
+ var desktopAgentClientMock = new Mock();
+ var factory = new ChannelHandler(messagingMock.Object, "instanceId", desktopAgentClientMock.Object);
var act = async () => await factory.CreateAppChannelAsync("channelId");
@@ -235,7 +245,8 @@ public async Task CreateAppChannelAsync_returns_error_when_response_has_error()
It.IsAny()))
.Returns(new ValueTask(JsonSerializer.Serialize(response, _jsonSerializerOptions)));
- var factory = new ChannelFactory(messagingMock.Object, "instanceId");
+ var desktopAgentClientMock = new Mock();
+ var factory = new ChannelHandler(messagingMock.Object, "instanceId", desktopAgentClientMock.Object);
var act = async () => await factory.CreateAppChannelAsync("channelId");
@@ -260,7 +271,8 @@ public async Task CreateAppChannelAsync_returns_error_when_response_is_unsuccess
It.IsAny()))
.Returns(new ValueTask(JsonSerializer.Serialize(response, _jsonSerializerOptions)));
- var factory = new ChannelFactory(messagingMock.Object, "instanceId");
+ var desktopAgentClientMock = new Mock();
+ var factory = new ChannelHandler(messagingMock.Object, "instanceId", desktopAgentClientMock.Object);
var act = async () => await factory.CreateAppChannelAsync("channelId");
@@ -280,7 +292,8 @@ public async Task CreateAppChannelAsync_returns_error_when_messaging_throws()
It.IsAny()))
.ThrowsAsync(new InvalidOperationException("Messaging error"));
- var factory = new ChannelFactory(messagingMock.Object, "instanceId");
+ var desktopAgentClientMock = new Mock();
+ var factory = new ChannelHandler(messagingMock.Object, "instanceId", desktopAgentClientMock.Object);
var act = async () => await factory.CreateAppChannelAsync("channelId");
@@ -307,7 +320,8 @@ public async Task FindChannelAsync_returns_Channel_when_found()
It.IsAny()))
.ReturnsAsync(responseJson);
- var factory = new ChannelFactory(messagingMock.Object, "instanceId");
+ var desktopAgentClientMock = new Mock();
+ var factory = new ChannelHandler(messagingMock.Object, "instanceId", desktopAgentClientMock.Object);
var result = await factory.FindChannelAsync("myChannel", ChannelType.User);
result.Id.Should().Be("myChannel");
@@ -325,7 +339,8 @@ public async Task FindChannelAsync_throws_when_response_is_null()
It.IsAny()))
.ReturnsAsync((string?) null);
- var factory = new ChannelFactory(messagingMock.Object, "instanceId");
+ var desktopAgentClientMock = new Mock();
+ var factory = new ChannelHandler(messagingMock.Object, "instanceId", desktopAgentClientMock.Object);
var act = async () => await factory.FindChannelAsync("myChannel", ChannelType.User);
await act.Should().ThrowAsync()
@@ -350,7 +365,8 @@ public async Task FindChannelAsync_throws_when_response_has_error()
It.IsAny()))
.ReturnsAsync(responseJson);
- var factory = new ChannelFactory(messagingMock.Object, "instanceId");
+ var desktopAgentClientMock = new Mock();
+ var factory = new ChannelHandler(messagingMock.Object, "instanceId", desktopAgentClientMock.Object);
var act = async () => await factory.FindChannelAsync("myChannel", ChannelType.User);
await act.Should().ThrowAsync()
@@ -375,7 +391,8 @@ public async Task FindChannelAsync_throws_when_channel_not_found()
It.IsAny()))
.ReturnsAsync(responseJson);
- var factory = new ChannelFactory(messagingMock.Object, "instanceId");
+ var desktopAgentClientMock = new Mock();
+ var factory = new ChannelHandler(messagingMock.Object, "instanceId", desktopAgentClientMock.Object);
var act = async () => await factory.FindChannelAsync("myChannel", ChannelType.User);
await act.Should().ThrowAsync()
@@ -386,7 +403,6 @@ await act.Should().ThrowAsync()
public async Task FindChannelAsync_joins_private_channel()
{
var messagingMock = new Mock();
- var instanceId = "test-instance";
var channelId = "private-channel";
var findChannelResponse = new FindChannelResponse { Found = true };
@@ -400,7 +416,8 @@ public async Task FindChannelAsync_joins_private_channel()
.ReturnsAsync(JsonSerializer.Serialize(findChannelResponse, _jsonSerializerOptions))
.ReturnsAsync(JsonSerializer.Serialize(joinPrivateChannelResponse, _jsonSerializerOptions));
- var factory = new ChannelFactory(messagingMock.Object, instanceId);
+ var desktopAgentClientMock = new Mock();
+ var factory = new ChannelHandler(messagingMock.Object, "instanceId", desktopAgentClientMock.Object);
var result = await factory.FindChannelAsync(channelId, ChannelType.Private);
@@ -425,7 +442,8 @@ public async Task FindChannelAsync_try_to_join_private_channel_but_throws_when_m
.ReturnsAsync(JsonSerializer.Serialize(findChannelResponse, _jsonSerializerOptions))
.ReturnsAsync(JsonSerializer.Serialize((string?)null));
- var factory = new ChannelFactory(messagingMock.Object, instanceId);
+ var desktopAgentClientMock = new Mock();
+ var factory = new ChannelHandler(messagingMock.Object, "instanceId", desktopAgentClientMock.Object);
var act = async() => await factory.FindChannelAsync(channelId, ChannelType.Private);
@@ -451,7 +469,8 @@ public async Task FindChannelAsync_try_to_join_private_channel_but_throws_when_e
.ReturnsAsync(JsonSerializer.Serialize(findChannelResponse, _jsonSerializerOptions))
.ReturnsAsync(JsonSerializer.Serialize(joinPrivateChannelResponse, _jsonSerializerOptions));
- var factory = new ChannelFactory(messagingMock.Object, instanceId);
+ var desktopAgentClientMock = new Mock();
+ var factory = new ChannelHandler(messagingMock.Object, "instanceId", desktopAgentClientMock.Object);
var act = async () => await factory.FindChannelAsync(channelId, ChannelType.Private);
@@ -477,7 +496,8 @@ public async Task FindChannelAsync_try_to_join_private_channel_but_throws_when_n
.ReturnsAsync(JsonSerializer.Serialize(findChannelResponse, _jsonSerializerOptions))
.ReturnsAsync(JsonSerializer.Serialize(joinPrivateChannelResponse, _jsonSerializerOptions));
- var factory = new ChannelFactory(messagingMock.Object, instanceId);
+ var desktopAgentClientMock = new Mock();
+ var factory = new ChannelHandler(messagingMock.Object, "instanceId", desktopAgentClientMock.Object);
var act = async () => await factory.FindChannelAsync(channelId, ChannelType.Private);
diff --git a/src/fdc3/dotnet/DesktopAgent.Client/test/MorganStanley.ComposeUI.Fdc3.DesktopAgent.Client.Tests/Infrastructure/Internal/IntentsClient.Tests.cs b/src/fdc3/dotnet/DesktopAgent.Client/test/MorganStanley.ComposeUI.Fdc3.DesktopAgent.Client.Tests/Infrastructure/Internal/IntentsClient.Tests.cs
index 703638048..5ba362b7c 100644
--- a/src/fdc3/dotnet/DesktopAgent.Client/test/MorganStanley.ComposeUI.Fdc3.DesktopAgent.Client.Tests/Infrastructure/Internal/IntentsClient.Tests.cs
+++ b/src/fdc3/dotnet/DesktopAgent.Client/test/MorganStanley.ComposeUI.Fdc3.DesktopAgent.Client.Tests/Infrastructure/Internal/IntentsClient.Tests.cs
@@ -25,10 +25,7 @@
using AppMetadata = MorganStanley.ComposeUI.Fdc3.DesktopAgent.Shared.Protocol.AppMetadata;
using AppIntent = MorganStanley.ComposeUI.Fdc3.DesktopAgent.Shared.Protocol.AppIntent;
using MorganStanley.ComposeUI.Fdc3.DesktopAgent.Client.Infrastructure;
-using MorganStanley.ComposeUI.Fdc3.DesktopAgent.Shared.Protocol;
-using MorganStanley.ComposeUI.Fdc3.DesktopAgent.Client.Infrastructure.Internal.Protocol;
using Finos.Fdc3;
-using IntentResolution = MorganStanley.ComposeUI.Fdc3.DesktopAgent.Client.Infrastructure.Internal.Protocol.IntentResolution;
using AppIdentifier = MorganStanley.ComposeUI.Fdc3.DesktopAgent.Shared.Protocol.AppIdentifier;
namespace MorganStanley.ComposeUI.Fdc3.DesktopAgent.Client.Tests.Infrastructure.Internal;
@@ -37,12 +34,12 @@ public class IntentsClientTests
{
private readonly JsonSerializerOptions _jsonSerializerOptions = SerializerOptionsHelper.JsonSerializerOptionsWithContextSerialization;
private readonly Mock _messagingMock = new();
- private readonly Mock _channelFactoryMock = new();
+ private readonly Mock _channelHandlerMock = new();
private readonly IntentsClient _client;
public IntentsClientTests()
{
- _client = new IntentsClient(_messagingMock.Object, _channelFactoryMock.Object, "testInstance");
+ _client = new IntentsClient(_messagingMock.Object, _channelHandlerMock.Object, "testInstance");
}
[Fact]
diff --git a/src/fdc3/dotnet/DesktopAgent.Client/test/MorganStanley.ComposeUI.Fdc3.DesktopAgent.Client.Tests/Infrastructure/Internal/OpenClient.Tests.cs b/src/fdc3/dotnet/DesktopAgent.Client/test/MorganStanley.ComposeUI.Fdc3.DesktopAgent.Client.Tests/Infrastructure/Internal/OpenClient.Tests.cs
index 79ad3dbf3..5f94913e3 100644
--- a/src/fdc3/dotnet/DesktopAgent.Client/test/MorganStanley.ComposeUI.Fdc3.DesktopAgent.Client.Tests/Infrastructure/Internal/OpenClient.Tests.cs
+++ b/src/fdc3/dotnet/DesktopAgent.Client/test/MorganStanley.ComposeUI.Fdc3.DesktopAgent.Client.Tests/Infrastructure/Internal/OpenClient.Tests.cs
@@ -32,7 +32,7 @@ namespace MorganStanley.ComposeUI.Fdc3.DesktopAgent.Client.Tests.Infrastructure.
public class OpenClientTests
{
private readonly Mock _messagingMock = new();
- private readonly Mock _channelFactoryMock = new();
+ private readonly Mock _channelHandlerMock = new();
private readonly Mock _listenerMock = new();
private readonly Mock _desktopAgentMock = new();
private readonly JsonSerializerOptions _jsonSerializerOptions = SerializerOptionsHelper.JsonSerializerOptionsWithContextSerialization;
diff --git a/src/fdc3/dotnet/DesktopAgent.Client/test/MorganStanley.ComposeUI.Fdc3.DesktopAgent.Client.Tests/Infrastructure/Internal/Protocol/IntentResolution.Tests.cs b/src/fdc3/dotnet/DesktopAgent.Client/test/MorganStanley.ComposeUI.Fdc3.DesktopAgent.Client.Tests/Infrastructure/Internal/Protocol/IntentResolution.Tests.cs
index 3e2ff1665..9222c696e 100644
--- a/src/fdc3/dotnet/DesktopAgent.Client/test/MorganStanley.ComposeUI.Fdc3.DesktopAgent.Client.Tests/Infrastructure/Internal/Protocol/IntentResolution.Tests.cs
+++ b/src/fdc3/dotnet/DesktopAgent.Client/test/MorganStanley.ComposeUI.Fdc3.DesktopAgent.Client.Tests/Infrastructure/Internal/Protocol/IntentResolution.Tests.cs
@@ -31,7 +31,7 @@ namespace MorganStanley.ComposeUI.Fdc3.DesktopAgent.Client.Tests.Infrastructure.
public class IntentResolutionTests
{
private readonly Mock _messagingMock = new();
- private readonly Mock _channelFactoryMock = new();
+ private readonly Mock _channelHandleryMock = new();
private readonly Mock> _loggerMock = new();
private readonly string _messageId = "msg-1";
private readonly string _intent = "ViewChart";
@@ -43,7 +43,7 @@ private IntentResolution CreateIntentResolution()
return new IntentResolution(
_messageId,
_messagingMock.Object,
- _channelFactoryMock.Object,
+ _channelHandleryMock.Object,
_intent,
_source,
_loggerMock.Object);
@@ -67,7 +67,7 @@ public async Task GetResult_returns_channel_when_channelId_and_type_are_present(
It.IsAny()))
.ReturnsAsync(JsonSerializer.Serialize(response, _jsonOptions));
- _channelFactoryMock
+ _channelHandleryMock
.Setup(f => f.FindChannelAsync("ch1", ChannelType.User))
.ReturnsAsync(channelMock.Object);
diff --git a/src/fdc3/dotnet/DesktopAgent.Shared/src/MorganStanley.ComposeUI.Fdc3.DesktopAgent.Shared/Contracts/JoinUserChannelRequest.cs b/src/fdc3/dotnet/DesktopAgent.Shared/src/MorganStanley.ComposeUI.Fdc3.DesktopAgent.Shared/Contracts/JoinUserChannelRequest.cs
index 47467d245..b92c2cfbb 100644
--- a/src/fdc3/dotnet/DesktopAgent.Shared/src/MorganStanley.ComposeUI.Fdc3.DesktopAgent.Shared/Contracts/JoinUserChannelRequest.cs
+++ b/src/fdc3/dotnet/DesktopAgent.Shared/src/MorganStanley.ComposeUI.Fdc3.DesktopAgent.Shared/Contracts/JoinUserChannelRequest.cs
@@ -14,7 +14,7 @@
namespace MorganStanley.ComposeUI.Fdc3.DesktopAgent.Shared.Contracts;
-internal sealed class JoinUserChannelRequest
+public sealed class JoinUserChannelRequest
{
///
/// Uniques identifier of the channel.
diff --git a/src/fdc3/dotnet/DesktopAgent.Shared/src/MorganStanley.ComposeUI.Fdc3.DesktopAgent.Shared/Contracts/JoinUserChannelResponse.cs b/src/fdc3/dotnet/DesktopAgent.Shared/src/MorganStanley.ComposeUI.Fdc3.DesktopAgent.Shared/Contracts/JoinUserChannelResponse.cs
index bdf987a8e..f70ef5731 100644
--- a/src/fdc3/dotnet/DesktopAgent.Shared/src/MorganStanley.ComposeUI.Fdc3.DesktopAgent.Shared/Contracts/JoinUserChannelResponse.cs
+++ b/src/fdc3/dotnet/DesktopAgent.Shared/src/MorganStanley.ComposeUI.Fdc3.DesktopAgent.Shared/Contracts/JoinUserChannelResponse.cs
@@ -16,7 +16,7 @@
namespace MorganStanley.ComposeUI.Fdc3.DesktopAgent.Shared.Contracts;
-internal sealed class JoinUserChannelResponse
+public sealed class JoinUserChannelResponse
{
///
/// Error while executing the JoinUserChannel call.
diff --git a/src/fdc3/dotnet/DesktopAgent.Shared/src/MorganStanley.ComposeUI.Fdc3.DesktopAgent.Shared/Exceptions/ThrowHelper.cs b/src/fdc3/dotnet/DesktopAgent.Shared/src/MorganStanley.ComposeUI.Fdc3.DesktopAgent.Shared/Exceptions/ThrowHelper.cs
index d952f9908..1b94dbe2b 100644
--- a/src/fdc3/dotnet/DesktopAgent.Shared/src/MorganStanley.ComposeUI.Fdc3.DesktopAgent.Shared/Exceptions/ThrowHelper.cs
+++ b/src/fdc3/dotnet/DesktopAgent.Shared/src/MorganStanley.ComposeUI.Fdc3.DesktopAgent.Shared/Exceptions/ThrowHelper.cs
@@ -122,9 +122,12 @@ internal static Fdc3DesktopAgentException PrivateChannelCreationFailed() =>
internal static Fdc3DesktopAgentException PrivateChannelDisconnected(string channelId, string instanceId) =>
new($"Private channel is disconnected. ChannelId: {channelId}; instance id: {instanceId}.");
- internal static Fdc3DesktopAgentException PrivatChannelSubscribeFailure(string? contextType, string channelId, string instanceId) =>
+ internal static Fdc3DesktopAgentException PrivateChannelSubscribeFailure(string? contextType, string channelId, string instanceId) =>
new($"Private channel was not able to add context listener. ChannelId: {channelId}; instance id: {instanceId}; context type: {contextType}.");
internal static Fdc3DesktopAgentException PrivateChannelJoiningFailed(string channelId) =>
new($"Client was not able to join to private channel. ChannelId: {channelId}.");
+
+ internal static Fdc3DesktopAgentException MissingInstanceId(string methodName) =>
+ new($"Fdc3InstanceId was missing before executing: {methodName}.");
}
\ No newline at end of file
diff --git a/src/fdc3/dotnet/DesktopAgent.Shared/src/MorganStanley.ComposeUI.Fdc3.DesktopAgent.Shared/Fdc3StartupProperties.cs b/src/fdc3/dotnet/DesktopAgent.Shared/src/MorganStanley.ComposeUI.Fdc3.DesktopAgent.Shared/Fdc3StartupProperties.cs
index 78dedc8e6..c9f8040a2 100644
--- a/src/fdc3/dotnet/DesktopAgent.Shared/src/MorganStanley.ComposeUI.Fdc3.DesktopAgent.Shared/Fdc3StartupProperties.cs
+++ b/src/fdc3/dotnet/DesktopAgent.Shared/src/MorganStanley.ComposeUI.Fdc3.DesktopAgent.Shared/Fdc3StartupProperties.cs
@@ -14,7 +14,10 @@
namespace MorganStanley.ComposeUI.Fdc3.DesktopAgent.Shared;
-internal class Fdc3StartupProperties
+///
+/// FDC3 specific startup properties for the application/module.
+///
+public class Fdc3StartupProperties
{
///
/// Fdc3 DesktopAgent's specific identifier for the created application instance.
@@ -27,7 +30,7 @@ internal class Fdc3StartupProperties
public string? ChannelId { get; init; }
///
- /// This implies that the opened app was started via using the fdc3.open() call. Thi id ensures that if the app opens and it's available on the object then the opened app can request the context and handle it when its context listener is being registered for the right context type.
+ /// This implies that the opened app was started via using the fdc3.open() call. This id ensures that if the app opens and it's available on the object then the opened app can request the context and handle it when its context listener is being registered for the right context type.
///
public string? OpenedAppContextId { get; set; }
}
diff --git a/src/fdc3/dotnet/DesktopAgent.Shared/src/MorganStanley.ComposeUI.Fdc3.DesktopAgent.Shared/Fdc3Topic.cs b/src/fdc3/dotnet/DesktopAgent.Shared/src/MorganStanley.ComposeUI.Fdc3.DesktopAgent.Shared/Fdc3Topic.cs
index 1ccdbe6d5..7d664e5c1 100644
--- a/src/fdc3/dotnet/DesktopAgent.Shared/src/MorganStanley.ComposeUI.Fdc3.DesktopAgent.Shared/Fdc3Topic.cs
+++ b/src/fdc3/dotnet/DesktopAgent.Shared/src/MorganStanley.ComposeUI.Fdc3.DesktopAgent.Shared/Fdc3Topic.cs
@@ -53,6 +53,26 @@ public static class Fdc3Topic
///
public static string ResolverUIIntent => TopicRoot + "resolverUIIntent";
+ ///
+ /// Topic for handling join user channel request from the UI (per container)
+ ///
+ ///
+ ///
+ public static string ChannelSelectorFromUI(string fdc3InstanceId)
+ {
+ return $"{TopicRoot}channelSelector/UI/{fdc3InstanceId}";
+ }
+
+ ///
+ /// Topic for handling join user channel request from the API (per container)
+ ///
+ ///
+ ///
+ public static string ChannelSelectorFromAPI(string fdc3InstanceId)
+ {
+ return $"{TopicRoot}channelSelector/API/{fdc3InstanceId}";
+ }
+
//IntentListeners will be listening at this endpoint
internal static string RaiseIntentResolution(string intent, string instanceId)
{
diff --git a/src/fdc3/dotnet/DesktopAgent.Shared/src/MorganStanley.ComposeUI.Fdc3.DesktopAgent.Shared/IModuleChannelSelector.cs b/src/fdc3/dotnet/DesktopAgent.Shared/src/MorganStanley.ComposeUI.Fdc3.DesktopAgent.Shared/IModuleChannelSelector.cs
new file mode 100644
index 000000000..7b49b5aa0
--- /dev/null
+++ b/src/fdc3/dotnet/DesktopAgent.Shared/src/MorganStanley.ComposeUI.Fdc3.DesktopAgent.Shared/IModuleChannelSelector.cs
@@ -0,0 +1,39 @@
+/*
+ * Morgan Stanley makes this available to you under the Apache License,
+ * Version 2.0 (the "License"). You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0.
+ *
+ * See the NOTICE file distributed with this work for additional information
+ * regarding copyright ownership. Unless required by applicable law or agreed
+ * to in writing, software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express
+ * or implied. See the License for the specific language governing permissions
+ * and limitations under the License.
+ */
+
+namespace MorganStanley.ComposeUI.Fdc3.DesktopAgent.Shared;
+
+///
+/// Responsible for registering endpoint to handle channel selection requests from the API.
+///
+public interface IModuleChannelSelector : IAsyncDisposable
+{
+ ///
+ /// Registers a handler to process channel selection requests initiated from desktop agent clients. If the client send a leaveCurrentChannel request then the onChannelJoined callback will be invoked with null or empty string.
+ ///
+ ///
+ ///
+ ///
+ ///
+ public ValueTask RegisterChannelSelectorHandlerInitiatedFromClientsAsync(string fdc3InstanceId, Action onChannelJoined, CancellationToken cancellationToken = default);
+
+ ///
+ /// Invokes the client library to handle the channel join request initiated from the UI.
+ ///
+ ///
+ ///
+ ///
+ ///
+ public ValueTask InvokeJoinUserChannelFromUIAsync(string fdc3InstanceId, string channelId, CancellationToken cancellationToken = default);
+}
\ No newline at end of file
diff --git a/src/fdc3/dotnet/DesktopAgent/src/MorganStanley.ComposeUI.Fdc3.DesktopAgent/DependencyInjection/ServiceCollectionExtensions.cs b/src/fdc3/dotnet/DesktopAgent/src/MorganStanley.ComposeUI.Fdc3.DesktopAgent/DependencyInjection/ServiceCollectionExtensions.cs
index f33de3603..5ca765461 100644
--- a/src/fdc3/dotnet/DesktopAgent/src/MorganStanley.ComposeUI.Fdc3.DesktopAgent/DependencyInjection/ServiceCollectionExtensions.cs
+++ b/src/fdc3/dotnet/DesktopAgent/src/MorganStanley.ComposeUI.Fdc3.DesktopAgent/DependencyInjection/ServiceCollectionExtensions.cs
@@ -14,6 +14,7 @@
using MorganStanley.ComposeUI.Fdc3.DesktopAgent;
using MorganStanley.ComposeUI.Fdc3.DesktopAgent.Infrastructure.Internal;
+using MorganStanley.ComposeUI.Fdc3.DesktopAgent.Shared;
using MorganStanley.ComposeUI.ModuleLoader;
// ReSharper disable once CheckNamespace
@@ -49,6 +50,7 @@ public static IServiceCollection AddFdc3DesktopAgent(
serviceCollection.AddSingleton();
serviceCollection.AddTransient();
serviceCollection.AddTransient();
+ serviceCollection.AddTransient();
return serviceCollection;
}
diff --git a/src/fdc3/dotnet/DesktopAgent/src/MorganStanley.ComposeUI.Fdc3.DesktopAgent/Fdc3DesktopAgentService.cs b/src/fdc3/dotnet/DesktopAgent/src/MorganStanley.ComposeUI.Fdc3.DesktopAgent/Fdc3DesktopAgentService.cs
index d47c0cc69..ffbacbdb2 100644
--- a/src/fdc3/dotnet/DesktopAgent/src/MorganStanley.ComposeUI.Fdc3.DesktopAgent/Fdc3DesktopAgentService.cs
+++ b/src/fdc3/dotnet/DesktopAgent/src/MorganStanley.ComposeUI.Fdc3.DesktopAgent/Fdc3DesktopAgentService.cs
@@ -25,6 +25,7 @@
using MorganStanley.ComposeUI.Fdc3.DesktopAgent.Shared;
using MorganStanley.ComposeUI.Fdc3.DesktopAgent.Shared.Contracts;
using MorganStanley.ComposeUI.Fdc3.DesktopAgent.Shared.Exceptions;
+using MorganStanley.ComposeUI.Fdc3.DesktopAgent.Shared.Protocol;
using MorganStanley.ComposeUI.Messaging.Abstractions.Exceptions;
using MorganStanley.ComposeUI.ModuleLoader;
using AppChannel = MorganStanley.ComposeUI.Fdc3.DesktopAgent.Channels.AppChannel;
@@ -70,6 +71,7 @@ public Fdc3DesktopAgentService(
IOptions options,
IResolverUICommunicator resolverUI,
IUserChannelSetReader userChannelSetReader,
+ IChannelSelector? channelSelector = null,
ILoggerFactory? loggerFactory = null)
{
_appDirectory = appDirectory;
@@ -91,7 +93,7 @@ public Fdc3DesktopAgentService(
return null;
}
- var userChannelSet = await _userChannelSetReader.GetUserChannelSet();
+ var userChannelSet = await _userChannelSetReader.GetUserChannelSet().ConfigureAwait(false);
if (!userChannelSet.TryGetValue(channelId, out var channelItem) || channelItem == null)
{
@@ -108,7 +110,7 @@ public Fdc3DesktopAgentService(
try
{
- await userChannel!.Connect();
+ await userChannel!.Connect().ConfigureAwait(false);
return userChannel;
}
catch (DuplicateServiceNameException exception)
@@ -147,7 +149,7 @@ public async ValueTask CreateOrJoinPrivateChannel(Func a
SafeAddToPrivateChannelsDictionary(instanceId, privateChannel);
- await privateChannel!.Connect();
+ await privateChannel!.Connect().ConfigureAwait(false);
}
catch (DuplicateServiceNameException exception)
{
@@ -232,7 +234,7 @@ public async ValueTask AddAppChannel(Func x.Value.DisposeAsync()).ToArray();
var appChannelDisposeTasks = _appChannels.Select(x => x.Value.DisposeAsync()).ToArray();
- await SafeWaitAsync(privateChannelDisposeTasks);
- await SafeWaitAsync(userChannelDisposeTasks);
- await SafeWaitAsync(appChannelDisposeTasks);
+ await SafeWaitAsync(privateChannelDisposeTasks).ConfigureAwait(false);
+ await SafeWaitAsync(userChannelDisposeTasks).ConfigureAwait(false);
+ await SafeWaitAsync(appChannelDisposeTasks).ConfigureAwait(false);
_startedLifetimeEventSubscription?.Dispose();
_stoppedLifetimeEventSubscription?.Dispose();
@@ -291,7 +293,7 @@ public async Task StopAsync(CancellationToken cancellationToken)
_pendingStartRequests.Clear();
_userChannels.Clear();
_privateChannels.Clear();
- _privateChannelsByInstanceId.Clear();
+ _privateChannelsByInstanceId?.Clear();
_appChannels.Clear();
lock (_contextListenerLock)
@@ -321,7 +323,7 @@ public async ValueTask FindIntent(FindIntentRequest? request
return FindIntentResponse.Failure(ResolveError.IntentDeliveryFailed);
}
- var result = await GetAppIntentsByRequest(request.Intent, contextType, request.ResultType, null);
+ var result = await GetAppIntentsByRequestAsync(request.Intent, contextType, request.ResultType, null).ConfigureAwait(false);
return result.AppIntents.TryGetValue(request.Intent, out var appIntent)
? FindIntentResponse.Success(appIntent)
@@ -335,7 +337,7 @@ public async ValueTask FindIntentsByContext(FindIn
return FindIntentsByContextResponse.Failure(ResolveError.IntentDeliveryFailed);
}
- var result = await GetAppIntentsByRequest(contextType: contextType, resultType: request.ResultType);
+ var result = await GetAppIntentsByRequestAsync(contextType: contextType, resultType: request.ResultType).ConfigureAwait(false);
return !result.AppIntents.Any()
? FindIntentsByContextResponse.Failure(ResolveError.NoAppsFound)
@@ -357,9 +359,9 @@ public async ValueTask GetIntentResult(GetIntentResultR
try
{
var intentResolutionTask = GetIntentResolutionResult(request);
- if (await Task.WhenAny(intentResolutionTask, Task.Delay(_options.IntentResultTimeout)) == intentResolutionTask)
+ if (await Task.WhenAny(intentResolutionTask, Task.Delay(_options.IntentResultTimeout)).ConfigureAwait(false) == intentResolutionTask)
{
- var intentResolution = await intentResolutionTask; // Completed in time
+ var intentResolution = await intentResolutionTask.ConfigureAwait(false); // Completed in time
// Use intentResolution as needed
if (intentResolution == null)
@@ -485,7 +487,7 @@ public async ValueTask GetUserChannels(GetUserChannelsR
return GetUserChannelsResponse.Failure(ChannelError.AccessDenied);
}
- var result = (await _userChannelSetReader.GetUserChannelSet()).Values;
+ var result = (await _userChannelSetReader.GetUserChannelSet().ConfigureAwait(false)).Values;
if (result == null)
{
return GetUserChannelsResponse.Failure(Fdc3DesktopAgentErrors.NoUserChannelSetFound);
@@ -501,7 +503,7 @@ public async ValueTask GetUserChannels(GetUserChannelsR
return JoinUserChannelResponse.Failed(Fdc3DesktopAgentErrors.MissingId);
}
- var userChannelSet = await _userChannelSetReader.GetUserChannelSet();
+ var userChannelSet = await _userChannelSetReader.GetUserChannelSet().ConfigureAwait(false);
if (!userChannelSet.TryGetValue(request.ChannelId, out var channelItem))
{
return JoinUserChannelResponse.Failed(ChannelError.NoChannelFound);
@@ -509,7 +511,7 @@ public async ValueTask GetUserChannels(GetUserChannelsR
try
{
- await AddUserChannel(addUserChannelFactory, request.ChannelId);
+ await AddUserChannel(addUserChannelFactory, request.ChannelId).ConfigureAwait(false);
}
catch (Exception exception)
{
@@ -537,7 +539,7 @@ public async ValueTask GetInfo(GetInfoRequest? request)
return GetInfoResponse.Failure(Fdc3DesktopAgentErrors.MissingId);
}
- var result = await GetAppInfo(request.AppIdentifier);
+ var result = await GetAppInfo(request.AppIdentifier).ConfigureAwait(false);
return result;
}
@@ -556,7 +558,7 @@ public async ValueTask FindInstances(FindInstancesRequest
try
{
- await _appDirectory.GetApp(request.AppIdentifier.AppId!);
+ await _appDirectory.GetApp(request.AppIdentifier.AppId!).ConfigureAwait(false);
}
catch (AppNotFoundException)
{
@@ -607,7 +609,7 @@ public async ValueTask GetAppMetadata(GetAppMetadataRequ
try
{
- var app = await _appDirectory.GetApp(request.AppIdentifier.AppId);
+ var app = await _appDirectory.GetApp(request.AppIdentifier.AppId).ConfigureAwait(false);
var appMetadata = app.ToAppMetadata();
return GetAppMetadataResponse.Success(appMetadata);
}
@@ -707,7 +709,7 @@ public async ValueTask GetAppMetadata(GetAppMetadataRequ
try
{
- var fdc3App = await _appDirectory.GetApp(request.AppIdentifier!.AppId);
+ var fdc3App = await _appDirectory.GetApp(request.AppIdentifier!.AppId).ConfigureAwait(false);
var appMetadata = fdc3App.ToAppMetadata();
var parameters = new Dictionary();
@@ -722,7 +724,7 @@ public async ValueTask GetAppMetadata(GetAppMetadataRequ
parameters.Add(Fdc3StartupParameters.Fdc3ChannelId, request.ChannelId);
}
- var target = await StartModule(appMetadata, parameters);
+ var target = await StartModuleAsync(appMetadata, parameters).ConfigureAwait(false);
if (!Guid.TryParse(target.InstanceId, out var targetInstanceId))
{
@@ -736,11 +738,11 @@ public async ValueTask GetAppMetadata(GetAppMetadataRequ
}
var cancellationToken = new CancellationToken();
- var contextListenerTask = GetContextListener(targetInstanceId, contextType!, cancellationToken);
- if (await Task.WhenAny(contextListenerTask, Task.Delay(_options.ListenerRegistrationTimeout, cancellationToken)) == contextListenerTask)
+ var contextListenerTask = GetContextListenerAsync(targetInstanceId, contextType!, cancellationToken);
+ if (await Task.WhenAny(contextListenerTask, Task.Delay(_options.ListenerRegistrationTimeout, cancellationToken)).ConfigureAwait(false) == contextListenerTask)
{
// Task completed within timeout
- _ = await contextListenerTask;
+ _ = await contextListenerTask.ConfigureAwait(false);
}
else
{
@@ -807,7 +809,7 @@ public async ValueTask> RaiseIntentForCon
_logger.LogWarning("Source app did not register its raiseable intent(s) for context: {ContextType} in the `raises` section of AppDirectory.", contextType);
}
- var filteredAppIntents = await GetAppIntentsByRequest(contextType: contextType, targetAppIdentifier: request.TargetAppIdentifier);
+ var filteredAppIntents = await GetAppIntentsByRequestAsync(contextType: contextType, targetAppIdentifier: request.TargetAppIdentifier).ConfigureAwait(false);
if (filteredAppIntents.AppIntents == null || !filteredAppIntents.AppIntents.Any())
{
@@ -821,7 +823,7 @@ public async ValueTask> RaiseIntentForCon
if (filteredAppIntents.AppIntents.Count > 1)
{
using var resolverUIIntentCancellationSource = new CancellationTokenSource(TimeSpan.FromMinutes(2));
- var resolverUIIntentResponse = await _resolverUI.SendResolverUIIntentRequest(filteredAppIntents.AppIntents.Select(x => x.Value.Intent.Name), resolverUIIntentCancellationSource.Token);
+ var resolverUIIntentResponse = await _resolverUI.SendResolverUIIntentRequestAsync(filteredAppIntents.AppIntents.Select(x => x.Value.Intent.Name), resolverUIIntentCancellationSource.Token).ConfigureAwait(false);
if (resolverUIIntentResponse == null)
{
@@ -885,16 +887,16 @@ public async ValueTask> RaiseIntentForCon
if (appIntent.Apps.Count() == 1)
{
raiseIntentSpecification.TargetAppMetadata = appIntent.Apps.ElementAt(0);
- return await RaiseIntentToApplication(raiseIntentSpecification);
+ return await RaiseIntentToApplicationAsync(raiseIntentSpecification).ConfigureAwait(false);
}
using var resolverUICancellationTokenSource = new CancellationTokenSource(TimeSpan.FromMinutes(2));
- var resolverUIResult = await _resolverUI.SendResolverUIRequest(appIntent.Apps, resolverUICancellationTokenSource.Token);
+ var resolverUIResult = await _resolverUI.SendResolverUIRequestAsync(appIntent.Apps, resolverUICancellationTokenSource.Token).ConfigureAwait(false);
if (resolverUIResult != null && resolverUIResult.Error == null)
{
raiseIntentSpecification.TargetAppMetadata = (AppMetadata) resolverUIResult.AppMetadata!;
- return await RaiseIntentToApplication(raiseIntentSpecification);
+ return await RaiseIntentToApplicationAsync(raiseIntentSpecification).ConfigureAwait(false);
}
if (resolverUIResult?.Error != null)
@@ -939,7 +941,7 @@ public async ValueTask> RaiseIntent(Raise
_logger.LogWarning("Source app did not register its raiseable intent(s) for context: {ContextType} in the `raises` section of AppDirectory.", contextType);
}
- var intentQueryResult = await GetAppIntentsByRequest(request.Intent, contextType, targetAppIdentifier: request.TargetAppIdentifier);
+ var intentQueryResult = await GetAppIntentsByRequestAsync(request.Intent, contextType, targetAppIdentifier: request.TargetAppIdentifier).ConfigureAwait(false);
if (intentQueryResult.Error != null)
{
@@ -970,17 +972,17 @@ public async ValueTask> RaiseIntent(Raise
{
raiseIntentSpecification.TargetAppMetadata = appIntent.Apps.ElementAt(0);
- return await RaiseIntentToApplication(raiseIntentSpecification);
+ return await RaiseIntentToApplicationAsync(raiseIntentSpecification).ConfigureAwait(false);
}
var cancellationTokenSource = new CancellationTokenSource(TimeSpan.FromMinutes(2));
//Resolve to one app via ResolverUI.
- var result = await _resolverUI.SendResolverUIRequest(appIntent.Apps, cancellationTokenSource.Token);
+ var result = await _resolverUI.SendResolverUIRequestAsync(appIntent.Apps, cancellationTokenSource.Token).ConfigureAwait(false);
if (result != null && result.Error == null)
{
raiseIntentSpecification.TargetAppMetadata = (AppMetadata) result.AppMetadata!;
- return await RaiseIntentToApplication(raiseIntentSpecification);
+ return await RaiseIntentToApplicationAsync(raiseIntentSpecification).ConfigureAwait(false);
}
if (result?.Error != null)
@@ -1037,9 +1039,9 @@ private static IEnumerable FilterAppIntentsByAppId(IEnumerable> RaiseIntentToApplication(RaiseIntentSpecification raiseIntentSpecification)
+ private async ValueTask> RaiseIntentToApplicationAsync(RaiseIntentSpecification raiseIntentSpecification)
{
- async Task?> GetRaiseIntentResponse(RaiseIntentSpecification raiseIntentSpecification, string messageId)
+ async Task?> GetRaiseIntentResponseAsync(RaiseIntentSpecification raiseIntentSpecification, string messageId)
{
RaiseIntentResult? response = null;
@@ -1048,11 +1050,11 @@ private async ValueTask> RaiseIntentToApp
if (!_raisedIntentResolutions.TryGetValue(new(raiseIntentSpecification.TargetAppMetadata.InstanceId!), out var registeredFdc3App)
|| !registeredFdc3App.IsIntentListenerRegistered(raiseIntentSpecification.Intent))
{
- await Task.Delay(1);
+ await Task.Delay(1).ConfigureAwait(false);
continue;
}
- var resolution = await GetRaiseIntentResolutionMessage(messageId, raiseIntentSpecification);
+ var resolution = await GetRaiseIntentResolutionMessageAsync(messageId, raiseIntentSpecification).ConfigureAwait(false);
response = new()
{
Response = RaiseIntentResponse.Success(messageId, raiseIntentSpecification.Intent, raiseIntentSpecification.TargetAppMetadata),
@@ -1071,11 +1073,11 @@ private async ValueTask> RaiseIntentToApp
{
var raisedIntentMessageId = StoreRaisedIntentForTarget(raiseIntentSpecification);
- var responseTask = GetRaiseIntentResponse(raiseIntentSpecification, raisedIntentMessageId);
- var completedTask = await Task.WhenAny(responseTask, Task.Delay(_options.ListenerRegistrationTimeout));
+ var responseTask = GetRaiseIntentResponseAsync(raiseIntentSpecification, raisedIntentMessageId);
+ var completedTask = await Task.WhenAny(responseTask, Task.Delay(_options.ListenerRegistrationTimeout)).ConfigureAwait(false);
if (completedTask == responseTask)
{
- var response = await responseTask;
+ var response = await responseTask.ConfigureAwait(false);
if (response != null)
{
return response;
@@ -1090,7 +1092,7 @@ private async ValueTask> RaiseIntentToApp
try
{
- var module = await StartModule(raiseIntentSpecification.TargetAppMetadata);
+ var module = await StartModuleAsync(raiseIntentSpecification.TargetAppMetadata).ConfigureAwait(false);
raiseIntentSpecification.TargetAppMetadata = module;
@@ -1104,11 +1106,11 @@ private async ValueTask> RaiseIntentToApp
};
}
- var responseTask = GetRaiseIntentResponse(raiseIntentSpecification, raisedIntentMessageId);
- var completedTask = await Task.WhenAny(responseTask, Task.Delay(_options.ListenerRegistrationTimeout));
+ var responseTask = GetRaiseIntentResponseAsync(raiseIntentSpecification, raisedIntentMessageId);
+ var completedTask = await Task.WhenAny(responseTask, Task.Delay(_options.ListenerRegistrationTimeout)).ConfigureAwait(false);
if (completedTask == responseTask)
{
- var response = await responseTask;
+ var response = await responseTask.ConfigureAwait(false);
if (response != null)
{
@@ -1140,7 +1142,7 @@ private async ValueTask> RaiseIntentToApp
}
}
- private async ValueTask StartModule(AppMetadata targetAppMetadata, IEnumerable>? additionalStartupParameters = null)
+ private async ValueTask StartModuleAsync(AppMetadata targetAppMetadata, IEnumerable>? additionalStartupParameters = null)
{
var startupParameters = additionalStartupParameters?.ToDictionary(x => x.Key, y => y.Value) ?? [];
@@ -1170,7 +1172,7 @@ private async ValueTask StartModule(AppMetadata targetAppMetadata,
};
}
- var moduleInstance = await _moduleLoader.StartModule(startRequest);
+ var moduleInstance = await _moduleLoader.StartModule(startRequest).ConfigureAwait(false);
if (moduleInstance == null)
{
@@ -1184,7 +1186,7 @@ private async ValueTask StartModule(AppMetadata targetAppMetadata,
taskCompletionSource.TrySetException(exception);
}
- await taskCompletionSource.Task;
+ await taskCompletionSource.Task.ConfigureAwait(false);
return new AppMetadata
{
@@ -1212,7 +1214,7 @@ private async ValueTask StartModule(AppMetadata targetAppMetadata,
&& resolution.ResultContext == null
&& resolution.ResultVoid == null))
{
- await Task.Delay(100);
+ await Task.Delay(100).ConfigureAwait(false);
}
return resolution;
@@ -1241,7 +1243,7 @@ private string StoreRaisedIntentForTarget(RaiseIntentSpecification raiseIntentSp
}
//Publishing intent resolution request to the fdc3 clients, they will receive the message and start their IntentHandler appropriately, and send a store request back to the backend.
- private Task GetRaiseIntentResolutionMessage(
+ private Task GetRaiseIntentResolutionMessageAsync(
string raisedIntentMessageId,
RaiseIntentSpecification raiseIntentSpecification)
{
@@ -1273,7 +1275,7 @@ private string StoreRaisedIntentForTarget(RaiseIntentSpecification raiseIntentSp
});
}
- private async Task GetAppIntentsByRequest(
+ private async Task GetAppIntentsByRequestAsync(
string? intent = null,
string? contextType = null,
string? resultType = null,
@@ -1286,7 +1288,7 @@ private async Task GetAppIntentsByRequest(
{
try
{
- var filteredApps = await _intentResolver.GetMatchingAppsFromAppDirectory(intent, contextType, resultType, targetAppIdentifier?.AppId);
+ var filteredApps = await _intentResolver.GetMatchingAppsFromAppDirectoryAsync(intent, contextType, resultType, targetAppIdentifier?.AppId).ConfigureAwait(false);
var appIntents = GetAppIntentsFromIntentMetadataCollection(filteredApps);
result.AppIntents = appIntents;
@@ -1305,7 +1307,7 @@ private async Task GetAppIntentsByRequest(
try
{
- var filteredInstances = await _intentResolver.GetMatchingAppInstances(intent, contextType, resultType, targetAppIdentifier?.AppId, targetAppIdentifier?.InstanceId == null ? null : instanceId);
+ var filteredInstances = await _intentResolver.GetMatchingAppInstancesAsync(intent, contextType, resultType, targetAppIdentifier?.AppId, targetAppIdentifier?.InstanceId == null ? null : instanceId).ConfigureAwait(false);
var appIntents = GetAppIntentsFromIntentMetadataCollection(filteredInstances);
foreach (var app in appIntents)
{
@@ -1394,7 +1396,7 @@ private ValueTask