3

I have a UWP app that hosts an AppService in it's same process (in-process AppService).

When consuming that AppService from a Console app running in the same PC the UWP host app is running (and while it is running), I have noted that the AppServiceConnection lasts between 25-30 seconds. After that time no further communication can be performed to the UWP host unless AppServiceConnection.OpenAsync() is executed again.

Aversely, the following question suggests that there is no time limit to an AppService connection.

Could someone clarify what the expected behavior should be or point out what I might be missing in order to have a "unlimited time" AppService connection?

code snippets

UWP host - app.xaml.cs

...

private AppServiceConnection AppServiceConnection;
private BackgroundTaskDeferral AppServiceDeferral;

protected override void OnBackgroundActivated(BackgroundActivatedEventArgs args)
{
    base.OnBackgroundActivated(args);

    IBackgroundTaskInstance taskInstance = args.TaskInstance;
    AppServiceTriggerDetails appService = taskInstance.TriggerDetails as AppServiceTriggerDetails;
    AppServiceDeferral = taskInstance.GetDeferral();
    taskInstance.Canceled += OnAppServicesCanceled;
    AppServiceConnection = appService.AppServiceConnection;
    AppServiceConnection.RequestReceived += OnAppServiceRequestReceived;
    AppServiceConnection.ServiceClosed += AppServiceConnection_ServiceClosed;
}
private async void OnAppServiceRequestReceived(AppServiceConnection sender, AppServiceRequestReceivedEventArgs args)
{
    AppServiceDeferral messageDeferral = args.GetDeferral();
    ValueSet response = (await IPC.Controller.ProcessIncomeRequests(args.Request.Message.ToDictionary())).ToValueSet();
    await args.Request.SendResponseAsync(response);
    messageDeferral.Complete();
}

private void OnAppServicesCanceled(IBackgroundTaskInstance sender, BackgroundTaskCancellationReason reason)
{
    AppServiceDeferral.Complete();
}
private void AppServiceConnection_ServiceClosed(AppServiceConnection sender, AppServiceClosedEventArgs args)
{
    AppServiceDeferral.Complete();
}

...

Console client app

public static AppServiceConnection AppServiceConnection;
public static async Task<bool> ConnectToUWPApp()
{
    if(AppServiceConnection != null)
        AppServiceConnection.Dispose();

    AppServiceConnection = new AppServiceConnection() 
    {
        AppServiceName = "<AppServiceName>",
        PackageFamilyName = "<PackageFamilyName>"
    };
    var connStatus = await AppServiceConnection.OpenAsync(); // Opens AppService Connection to the installed UWP App
    return connStatus == AppServiceConnectionStatus.Success;
}

static async Task Main(string[] args)
{
    Console.WriteLine("Testing background communication time");
    Console.WriteLine("Press ENTER key to start the test");
    while (Console.ReadKey(true).Key != ConsoleKey.Enter) ;

    Stopwatch stopwatch = new Stopwatch();
    List<double> connectionsDuration = new List<double>();
    while (true)
    {
        Console.Write("\n\nConnecting... ");
        bool isIPCConnected = await ConnectToUWPApp();

        stopwatch.Restart();

        if (isIPCConnected)
        {
            Console.WriteLine("Succeeded");
            Console.Write("Exchanging IPC messages ");
            while ((await SendIPCMessage(new ValueSet() { }, false))?.StatusCode != null) 
            { 
                await Task.Delay(100);
                Console.Write(".");
            }
            stopwatch.Stop();
            connectionsDuration.Add(stopwatch.Elapsed.TotalSeconds);
            Console.WriteLine($"\nIPC connection lost after {stopwatch.Elapsed.TotalSeconds} seconds");
            Console.WriteLine($"Total connections duration average: {connectionsDuration.Average()} seconds");
        }
        else
        {
            Console.WriteLine("IPC Connection could not be established. Please make sure there's a running instance of the UWP App.");
            Console.WriteLine("Retrying in 30 seconds...");
            await Task.Delay(TimeSpan.FromSeconds(30));
        }
    }

}

screenshots

enter image description here

Miguel
  • 143
  • 1
  • 7
  • I did some tests, and there is no time limit for services between UWP and UWP and WPF apps. How do you connect to the UWP service in the console? – Junjie Zhu - MSFT Jul 13 '23 at 08:16
  • I have edited the question and added the code for the method `ConnectToUWPApp()`. Please make sure not to be debugging the UWP app. While debugging I think connections do not get closed. – Miguel Jul 13 '23 at 12:24
  • @JunjieZhu-MSFT I have also observed that the AppService connection between UWP (host) and WPF (client) is always lost after 25 seconds. Could you share how you tested it? – emoacht Jul 16 '23 at 02:05
  • @Miguel, This is my test picture https://i.stack.imgur.com/jqywm.gif , I used your code and only changed `SendIPCMessage`. – Junjie Zhu - MSFT Jul 17 '23 at 10:10
  • @emoacht, For AppService connection between UWP (host) and WPF (client), you can refer to Stefan Wick's blog, open your browser and search `UWP with Desktop Extension – Part 3`. – Junjie Zhu - MSFT Jul 17 '23 at 10:11
  • @JunjieZhu-MSFT it's strange... Why would it last only 25s to emoacht and to me? Also, I cannot appreciate from the attached picture: are you debugging as well the UWP app? – Miguel Jul 17 '23 at 12:29
  • @Miguel I only built and deployed my UWP project, I didn't debug it. If I run the console from the exe, it keeps connecting with the Appservice. It is recommended that you refer to the [official documentation in-process App Services](https://learn.microsoft.com/en-us/windows/uwp/launch-resume/convert-app-service-in-process) to simplify your code in order to confirm whether it is a problem in `SendIPCMessage`. – Junjie Zhu - MSFT Jul 18 '23 at 02:31
  • When you say built and deployed the UWP project, that means as well that is not running while performing the connection from the console? – Miguel Jul 21 '23 at 12:28
  • Yes, I didn't run the UWP project, only run the console. The console app wakes up the appservice. – Junjie Zhu - MSFT Jul 24 '23 at 09:05
  • My question is specific for the UWP project running at the same time. Anyway, I have tested as well with the UWP project not running, and the output I am getting doesn't change: connection is lost after ~25s. `SendIPCMessage` sends the input `ValueSet` message and checks that the `AppServiceResponse.Status == AppServiceResponseStatus.Success`. Is your implementation on the UWP side any different from the one I've shown? – Miguel Jul 27 '23 at 15:33
  • @Miguel, I discussed your question with the team today, I re-wrote the code and was able to reproduce your behavior. I misplaced the trigger in my code, which resulted in wrong behavior, sorry for misleading you. – Junjie Zhu - MSFT Jul 28 '23 at 08:54
  • @JunjieZhu-MSFT no worries. Out of curiosity, where did you place the trigger? Is there a way of placing it somewhere in order to have an indefinite connection? – Miguel Jul 28 '23 at 12:31
  • My mistake was not a solution, I mistakenly put `SendMessageAsync` outside of the `while`. :) As I explained in my answer, In-process AppService is started via `OnBackgroundActivated`, background tasks are limited to 30 seconds of wall-clock usage. So, the current approach is to reconnect AppService within this 25s. By the way, what is your scenario? Maybe we can solve the problem from another way. – Junjie Zhu - MSFT Jul 31 '23 at 06:37
  • Understood. I am using AppServices to expose an interface to control my UWP app through 3rd party software. Through this interface the 3rd party software can retrieve live measurements the UWP app is acquiring from some propietary sensors, and also send some commands to these sensors. For this particular scenario I don't think it is so bad to request the "client" software to refresh the connection every 25s. Of course it would be nice to avoid it, though. The only thing I still don't understand is why in the SO question I've linked they state they establish an indefinite connection – Miguel Jul 31 '23 at 13:35

1 Answers1

0

Since In-process AppService is started via OnBackgroundActivated, according to the Background task resource constraints, background tasks are limited to 30 seconds of wall-clock usage.

Junjie Zhu - MSFT
  • 2,086
  • 1
  • 2
  • 6