Merge pull request #139 from spaceisfun/dontdisposenull
Fixes Bug 32803715: [Watson Failure] caused by CLR_EXCEPTION_System.NullReferenceException_80004003_Microsoft.FactoryOrchestrator.Service.dll!Microsoft.FactoryOrchestrator.Service.FOService.Dispose Fixes backwards check for DisableContainerSupport Fixes #113 - ResetService is buggy Fixes #135 - Support /etc/FactoryOrchestrator/appsettings.json Fixes #111 - WDP doesn't work on Desktop Related to #140 - Implements the workaround, but will keep the issue open until an official .NET fix is made
This commit is contained in:
Коммит
6db51c26e2
|
@ -8,7 +8,7 @@
|
|||
description="Factory Orchestrator Service"
|
||||
displayName="Factory Orchestrator Service"
|
||||
errorControl="normal"
|
||||
imagePath="%systemroot%\system32\manufacturing\FactoryOrchestrator\Microsoft.FactoryOrchestrator.Service.exe action:run"
|
||||
imagePath="%systemroot%\system32\manufacturing\FactoryOrchestrator\Microsoft.FactoryOrchestrator.Service.exe -IsService"
|
||||
name="Microsoft.FactoryOrchestrator.Service"
|
||||
objectName="LocalSystem"
|
||||
start="auto"
|
||||
|
|
|
@ -0,0 +1,10 @@
|
|||
#### [Microsoft.FactoryOrchestrator.Client](./Microsoft-FactoryOrchestrator-Client.md 'Microsoft.FactoryOrchestrator.Client')
|
||||
### [Microsoft.FactoryOrchestrator.Client](./Microsoft-FactoryOrchestrator-Client.md 'Microsoft.FactoryOrchestrator.Client').[FactoryOrchestratorClient](./Microsoft-FactoryOrchestrator-Client-FactoryOrchestratorClient.md 'Microsoft.FactoryOrchestrator.Client.FactoryOrchestratorClient')
|
||||
## FactoryOrchestratorClient.GetWdpHttpPort() Method
|
||||
Asynchronously Gets the Windows Device Portal HTTP port. Does not ensure WDP is running or supports HTTP.
|
||||
```csharp
|
||||
public System.Threading.Tasks.Task<int> GetWdpHttpPort();
|
||||
```
|
||||
#### Returns
|
||||
[System.Threading.Tasks.Task<](https://docs.microsoft.com/en-us/dotnet/api/System.Threading.Tasks.Task-1 'System.Threading.Tasks.Task')[System.Int32](https://docs.microsoft.com/en-us/dotnet/api/System.Int32 'System.Int32')[>](https://docs.microsoft.com/en-us/dotnet/api/System.Threading.Tasks.Task-1 'System.Threading.Tasks.Task')
|
||||
The HTTP port.
|
|
@ -12,7 +12,7 @@ If true, are logs not deleted.
|
|||
|
||||
<a name='Microsoft-FactoryOrchestrator-Client-FactoryOrchestratorClient-ResetService(bool_bool)-factoryReset'></a>
|
||||
`factoryReset` [System.Boolean](https://docs.microsoft.com/en-us/dotnet/api/System.Boolean 'System.Boolean')
|
||||
If true, the service is restarted as if it is first boot.
|
||||
If true, the service is restarted as if it is first boot. NOTE: Network communication is not disabled, connected clients may encounter issues and the 'EnableNetworkAccess' setting will be ignored!
|
||||
|
||||
#### Returns
|
||||
[System.Threading.Tasks.Task](https://docs.microsoft.com/en-us/dotnet/api/System.Threading.Tasks.Task 'System.Threading.Tasks.Task')
|
||||
|
|
|
@ -62,6 +62,7 @@ Inheritance [System.Object](https://docs.microsoft.com/en-us/dotnet/api/System.O
|
|||
- [GetServiceVersionString()](./Microsoft-FactoryOrchestrator-Client-FactoryOrchestratorClient-GetServiceVersionString().md 'Microsoft.FactoryOrchestrator.Client.FactoryOrchestratorClient.GetServiceVersionString()')
|
||||
- [GetTaskListGuids()](./Microsoft-FactoryOrchestrator-Client-FactoryOrchestratorClient-GetTaskListGuids().md 'Microsoft.FactoryOrchestrator.Client.FactoryOrchestratorClient.GetTaskListGuids()')
|
||||
- [GetTaskListSummaries()](./Microsoft-FactoryOrchestrator-Client-FactoryOrchestratorClient-GetTaskListSummaries().md 'Microsoft.FactoryOrchestrator.Client.FactoryOrchestratorClient.GetTaskListSummaries()')
|
||||
- [GetWdpHttpPort()](./Microsoft-FactoryOrchestrator-Client-FactoryOrchestratorClient-GetWdpHttpPort().md 'Microsoft.FactoryOrchestrator.Client.FactoryOrchestratorClient.GetWdpHttpPort()')
|
||||
- [InstallApp(string, System.Collections.Generic.List<string>, string)](./Microsoft-FactoryOrchestrator-Client-FactoryOrchestratorClient-InstallApp(string_System-Collections-Generic-List-string-_string).md 'Microsoft.FactoryOrchestrator.Client.FactoryOrchestratorClient.InstallApp(string, System.Collections.Generic.List<string>, string)')
|
||||
- [IsContainerRunning()](./Microsoft-FactoryOrchestrator-Client-FactoryOrchestratorClient-IsContainerRunning().md 'Microsoft.FactoryOrchestrator.Client.FactoryOrchestratorClient.IsContainerRunning()')
|
||||
- [IsExecutingBootTasks()](./Microsoft-FactoryOrchestrator-Client-FactoryOrchestratorClient-IsExecutingBootTasks().md 'Microsoft.FactoryOrchestrator.Client.FactoryOrchestratorClient.IsExecutingBootTasks()')
|
||||
|
|
|
@ -0,0 +1,10 @@
|
|||
#### [Microsoft.FactoryOrchestrator.Core](./Microsoft-FactoryOrchestrator-Core.md 'Microsoft.FactoryOrchestrator.Core')
|
||||
### [Microsoft.FactoryOrchestrator.Core](./Microsoft-FactoryOrchestrator-Core.md 'Microsoft.FactoryOrchestrator.Core').[IFactoryOrchestratorService](./Microsoft-FactoryOrchestrator-Core-IFactoryOrchestratorService.md 'Microsoft.FactoryOrchestrator.Core.IFactoryOrchestratorService')
|
||||
## IFactoryOrchestratorService.GetWdpHttpPort() Method
|
||||
Gets the Windows Device Portal HTTP port. Does not ensure WDP is running or supports HTTP.
|
||||
```csharp
|
||||
int GetWdpHttpPort();
|
||||
```
|
||||
#### Returns
|
||||
[System.Int32](https://docs.microsoft.com/en-us/dotnet/api/System.Int32 'System.Int32')
|
||||
The HTTP port.
|
|
@ -12,5 +12,5 @@ If true, are logs not deleted.
|
|||
|
||||
<a name='Microsoft-FactoryOrchestrator-Core-IFactoryOrchestratorService-ResetService(bool_bool)-factoryReset'></a>
|
||||
`factoryReset` [System.Boolean](https://docs.microsoft.com/en-us/dotnet/api/System.Boolean 'System.Boolean')
|
||||
If true, the service is restarted as if it is first boot.
|
||||
If true, the service is restarted as if it is first boot. NOTE: Network communication is not disabled, connected clients may encounter issues and the 'EnableNetworkAccess' setting will be ignored!
|
||||
|
||||
|
|
|
@ -35,6 +35,7 @@ public interface IFactoryOrchestratorService
|
|||
- [GetServiceVersionString()](./Microsoft-FactoryOrchestrator-Core-IFactoryOrchestratorService-GetServiceVersionString().md 'Microsoft.FactoryOrchestrator.Core.IFactoryOrchestratorService.GetServiceVersionString()')
|
||||
- [GetTaskListGuids()](./Microsoft-FactoryOrchestrator-Core-IFactoryOrchestratorService-GetTaskListGuids().md 'Microsoft.FactoryOrchestrator.Core.IFactoryOrchestratorService.GetTaskListGuids()')
|
||||
- [GetTaskListSummaries()](./Microsoft-FactoryOrchestrator-Core-IFactoryOrchestratorService-GetTaskListSummaries().md 'Microsoft.FactoryOrchestrator.Core.IFactoryOrchestratorService.GetTaskListSummaries()')
|
||||
- [GetWdpHttpPort()](./Microsoft-FactoryOrchestrator-Core-IFactoryOrchestratorService-GetWdpHttpPort().md 'Microsoft.FactoryOrchestrator.Core.IFactoryOrchestratorService.GetWdpHttpPort()')
|
||||
- [InstallApp(string, System.Collections.Generic.List<string>, string)](./Microsoft-FactoryOrchestrator-Core-IFactoryOrchestratorService-InstallApp(string_System-Collections-Generic-List-string-_string).md 'Microsoft.FactoryOrchestrator.Core.IFactoryOrchestratorService.InstallApp(string, System.Collections.Generic.List<string>, string)')
|
||||
- [IsContainerRunning()](./Microsoft-FactoryOrchestrator-Core-IFactoryOrchestratorService-IsContainerRunning().md 'Microsoft.FactoryOrchestrator.Core.IFactoryOrchestratorService.IsContainerRunning()')
|
||||
- [IsExecutingBootTasks()](./Microsoft-FactoryOrchestrator-Core-IFactoryOrchestratorService-IsExecutingBootTasks().md 'Microsoft.FactoryOrchestrator.Core.IFactoryOrchestratorService.IsExecutingBootTasks()')
|
||||
|
|
|
@ -1,10 +1,11 @@
|
|||
# Factory Orchestrator service configuration using appsettings.json
|
||||
The Factory Orchestrator service has many configurable settings that impact its startup behavior, enabled features, and more. This configuration is easily modified using an [appsettings.json file](https://docs.microsoft.com/en-us/dotnet/core/extensions/configuration-providers#json-configuration-provider).
|
||||
|
||||
The appsettings.json file is checked for in two locations:
|
||||
The appsettings.json file is checked for in the following locations:
|
||||
|
||||
- The directory where the service executable (Microsoft.FactoryOrchestrator.Service) is located
|
||||
- The [service log file directory](#factory-orchestrator-service-log-file) (`%ProgramData%\FactoryOrchestrator\` or `/var/log/FactoryOrchestrator/`)
|
||||
- The [service log file directory](#factory-orchestrator-service-log-file): `%ProgramData%\FactoryOrchestrator\` (Windows) or `/var/log/FactoryOrchestrator/`(Linux)
|
||||
- (Linux only) The `/etc/FactoryOrchestrator/` directory
|
||||
|
||||
The following table describes each setting and its usage:
|
||||
|
||||
|
|
|
@ -56,7 +56,7 @@ else
|
|||
}
|
||||
else
|
||||
{
|
||||
$null = New-Service -Name "Microsoft.FactoryOrchestrator" -BinaryPathName "$installdir\Microsoft.FactoryOrchestrator.Service.exe" -Description "Factory Orchestrator service version $Version$" -StartupType Manual
|
||||
$null = New-Service -Name "Microsoft.FactoryOrchestrator" -BinaryPathName "$installdir\Microsoft.FactoryOrchestrator.Service.exe -IsService" -Description "Factory Orchestrator service version $Version$" -StartupType Manual
|
||||
}
|
||||
|
||||
Write-Host "Factory Orchestrator service version $Version$ is installed to `"$installdir`" and configured as a Windows service!`n"
|
||||
|
|
|
@ -173,7 +173,7 @@
|
|||
<value>Could not connect to {0}.
|
||||
|
||||
Check that the IP address, Server Name and Certificate Hash is correct and that the Factory Orchestrator Service is running on the target IP.</value>
|
||||
<comment>Message displayed to the user if connection to the target machine cannot be established.</comment>
|
||||
<comment>Message displayed to the user if connection to the target machine cannot be established.</comment>
|
||||
</data>
|
||||
<data name="BadIpTitle" xml:space="preserve">
|
||||
<value>Unable to connect to target IP</value>
|
||||
|
@ -283,7 +283,7 @@ Check that the IP address, Server Name and Certificate Hash is correct and that
|
|||
|
||||
Manually exported FactoryOrchestratorXML files will not be deleted, but will need to be manually imported via "Load FactoryOrchestratorXML file".
|
||||
|
||||
If "Factory Reset" is chosen, the service is restarted as if it is first boot. First boot and every boot tasks will re-run. Initial TaskLists will be loaded. "Factory Reset" will temporarily interrupt communication with clients, including this app.</value>
|
||||
If "Factory Reset" is chosen, the service is restarted as if it is first boot. First boot and every boot tasks will re-run. Initial TaskLists will be loaded. NOTE: Network communication is not disabled, connected clients may encounter issues and the 'EnableNetworkAccess' setting will be ignored!</value>
|
||||
</data>
|
||||
<data name="DeleteButton.[using:Windows.UI.Xaml.Automation]AutomationProperties.Name" xml:space="preserve">
|
||||
<value>Delete</value>
|
||||
|
@ -720,7 +720,7 @@ On retry</value>
|
|||
<value>Launch Windows Device Portal</value>
|
||||
</data>
|
||||
<data name="WDPFailedContent" xml:space="preserve">
|
||||
<value>Make sure Windows Device Portal is running and try again.</value>
|
||||
<value>Make sure Windows Device Portal is running and supports HTTP with no authentication, then try again.</value>
|
||||
</data>
|
||||
<data name="WDPFailedTitle" xml:space="preserve">
|
||||
<value>Failed to launch Windows Device Portal</value>
|
||||
|
@ -770,10 +770,10 @@ On retry</value>
|
|||
</data>
|
||||
<data name="CertHash.Text" xml:space="preserve">
|
||||
<value>Certificate Hash:</value>
|
||||
<comment>Hash value of the Certificate of the target machine.</comment>
|
||||
<comment>Hash value of the Certificate of the target machine.</comment>
|
||||
</data>
|
||||
<data name="ServerName.Text" xml:space="preserve">
|
||||
<value>Server Identity:</value>
|
||||
<comment>Distinguished Name of the target machine.</comment>
|
||||
<comment>Distinguished Name of the target machine.</comment>
|
||||
</data>
|
||||
</root>
|
|
@ -49,7 +49,7 @@ namespace Microsoft.FactoryOrchestrator.UWP
|
|||
if (await IsWindowsDevicePortalRunning())
|
||||
{
|
||||
string ipAddress = Client.IsLocalHost ? "localhost" : $"{Client.IpAddress.ToString()}";
|
||||
string url = "http://" + ipAddress + ":80";
|
||||
string url = "http://" + ipAddress + ":" + await Client.GetWdpHttpPort();
|
||||
Uri myUri = new Uri(url);
|
||||
wdp.Navigate(myUri);
|
||||
}
|
||||
|
|
|
@ -157,7 +157,7 @@ namespace Microsoft.FactoryOrchestrator.Client
|
|||
|
||||
try
|
||||
{
|
||||
await WDPHelpers.InstallAppWithWDP(appFilename, dependentPackages, certificateFile, IpAddress.ToString());
|
||||
await WDPHelpers.InstallAppWithWDP(appFilename, dependentPackages, certificateFile, IpAddress.ToString(), await GetWdpHttpPort());
|
||||
}
|
||||
catch (Exception ex)
|
||||
{
|
||||
|
|
|
@ -6,8 +6,8 @@ using System;
|
|||
using System.Collections;
|
||||
using System.Collections.Generic;
|
||||
using System.Net;
|
||||
using System.Runtime.InteropServices;
|
||||
|
||||
using System.Runtime.InteropServices;
|
||||
|
||||
namespace Microsoft.FactoryOrchestrator.Core
|
||||
{
|
||||
/// <summary>
|
||||
|
@ -193,7 +193,7 @@ namespace Microsoft.FactoryOrchestrator.Core
|
|||
/// Stops all running Tasks and deletes all TaskLists.
|
||||
/// </summary>
|
||||
/// <param name="preserveLogs">If true, are logs not deleted.</param>
|
||||
/// <param name="factoryReset">If true, the service is restarted as if it is first boot.</param>
|
||||
/// <param name="factoryReset">If true, the service is restarted as if it is first boot. NOTE: Network communication is not disabled, connected clients may encounter issues and the 'EnableNetworkAccess' setting will be ignored! </param>
|
||||
void ResetService(bool preserveLogs = false, bool factoryReset = false);
|
||||
/// <summary>
|
||||
/// Gets all Service events.
|
||||
|
@ -287,6 +287,11 @@ namespace Microsoft.FactoryOrchestrator.Core
|
|||
/// </summary>
|
||||
/// <returns><c>true</c> if the service allows connections over the local network.</returns>
|
||||
bool IsNetworkAccessEnabled();
|
||||
/// <summary>
|
||||
/// Gets the Windows Device Portal HTTP port. Does not ensure WDP is running or supports HTTP.
|
||||
/// </summary>
|
||||
/// <returns>The HTTP port.</returns>
|
||||
int GetWdpHttpPort();
|
||||
|
||||
// TaskList APIs
|
||||
/// <summary>
|
||||
|
@ -371,14 +376,14 @@ namespace Microsoft.FactoryOrchestrator.Core
|
|||
/// </summary>
|
||||
/// <param name="guid">The Task GUID.</param>
|
||||
/// <returns></returns>
|
||||
TaskBase QueryTask(Guid guid);
|
||||
|
||||
TaskBase QueryTask(Guid guid);
|
||||
|
||||
/// <summary>
|
||||
/// Gets the AUMIDs of all installed apps on the OS. Requires Windows Device Portal.
|
||||
/// </summary>
|
||||
/// <returns>The list of app AUMIDs.</returns>
|
||||
List<string> GetInstalledApps();
|
||||
|
||||
List<string> GetInstalledApps();
|
||||
|
||||
/// <summary>
|
||||
/// Gets all installed apps on the OS. Requires Windows Device Portal.
|
||||
/// </summary>
|
||||
|
|
|
@ -26,6 +26,7 @@
|
|||
<EmbeddedResource Include="FactoryOrchestratorXML.xsd">
|
||||
<SubType>Designer</SubType>
|
||||
</EmbeddedResource>
|
||||
<PackageReference Include="Microsoft.Win32.Registry" Version="5.0.0" />
|
||||
<PackageReference Include="Newtonsoft.Json" Version="12.0.3" />
|
||||
<PackageReference Include="System.Net.Http" Version="4.3.4" />
|
||||
<PackageReference Include="System.Private.Uri" Version="4.3.2" />
|
||||
|
@ -63,7 +64,7 @@
|
|||
</Target>
|
||||
<Target Name="FixAndCopyMd" AfterTargets="Build">
|
||||
<ItemGroup>
|
||||
<FilesToMove Include="$(DefaultDocumentationFolder)/*.md"/>
|
||||
<FilesToMove Include="$(DefaultDocumentationFolder)/*.md" />
|
||||
</ItemGroup>
|
||||
<Exec Command="$(PowerShellExeName) $(ProjectDir)../../build/FixupAPIMarkdown.ps1 -DefaultDocumentationFolder $(DefaultDocumentationFolder)" />
|
||||
<Move SourceFiles="@(FilesToMove)" DestinationFolder="../../docs/docs/CoreLibrary" />
|
||||
|
|
|
@ -358,7 +358,7 @@
|
|||
<value>Error: Failed to launch AUMID: {0}</value>
|
||||
</data>
|
||||
<data name="WDPAppLaunchFailed2" xml:space="preserve">
|
||||
<value>Error: Device Portal is required for app launch and may not be running on the system.</value>
|
||||
<value>Error: Device Portal is required for app launch and may not be running on the system or may not support HTTP with no authentication.</value>
|
||||
</data>
|
||||
<data name="WDPAppLaunchFailed3" xml:space="preserve">
|
||||
<value>Error: If it is running, the AUMID may be incorrect.</value>
|
||||
|
@ -373,7 +373,7 @@
|
|||
<value>Windows Device Portal failed with HTTP error</value>
|
||||
</data>
|
||||
<data name="WDPNotRunningError" xml:space="preserve">
|
||||
<value>Windows Device Portal must be running to call GetInstalledApps!</value>
|
||||
<value>Windows Device Portal may not be running or may not support HTTP with no authentication!</value>
|
||||
</data>
|
||||
<data name="WindowsOnlyError" xml:space="preserve">
|
||||
<value>{0} is only supported on Windows!</value>
|
||||
|
|
|
@ -11,6 +11,7 @@ using System.Runtime.Serialization;
|
|||
using System.Runtime.Serialization.Json;
|
||||
using System.Text;
|
||||
using System.Threading.Tasks;
|
||||
using Microsoft.Win32;
|
||||
|
||||
namespace Microsoft.FactoryOrchestrator.Core
|
||||
{
|
||||
|
@ -79,6 +80,38 @@ namespace Microsoft.FactoryOrchestrator.Core
|
|||
/// </summary>
|
||||
public static readonly HttpClient WdpHttpClient = new HttpClient();
|
||||
|
||||
/// <summary>
|
||||
/// Gets the Windows Device Portal HTTP port.
|
||||
/// </summary>
|
||||
public static int GetWdpHttpPort()
|
||||
{
|
||||
using (var osdata = Registry.LocalMachine.OpenSubKey(@"OSDATA\SOFTWARE\Microsoft\Windows\CurrentVersion\WebManagement\Service", false))
|
||||
{
|
||||
if (osdata != null)
|
||||
{
|
||||
var osdataPort = osdata.GetValue("HttpPort");
|
||||
if (osdataPort != null)
|
||||
{
|
||||
return (int)osdataPort;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
using (var sft = Registry.LocalMachine.OpenSubKey(@"SOFTWARE\Microsoft\Windows\CurrentVersion\WebManagement\Service", false))
|
||||
{
|
||||
if (sft != null)
|
||||
{
|
||||
var port = sft.GetValue("HttpPort");
|
||||
if (port != null)
|
||||
{
|
||||
return (int)port;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return 80;
|
||||
}
|
||||
|
||||
private static HttpMultipartFileContent CreateAppInstallContent(string appFilePath, List<string> dependentAppsFilePaths, string certFilePath)
|
||||
{
|
||||
var content = new HttpMultipartFileContent();
|
||||
|
@ -101,17 +134,19 @@ namespace Microsoft.FactoryOrchestrator.Core
|
|||
/// Builds the application installation Uri and generates a unique boundary string for the multipart form data.
|
||||
/// </summary>
|
||||
/// <param name="packageName">The name of the application package.</param>
|
||||
/// <param name="ipAddress">The ip address of the device to install the app on</param>
|
||||
/// <param name="ipAddress">The ip address of the device to install the app on</param>
|
||||
/// <param name="port">The port for WDP on the target device.</param>
|
||||
/// <param name="uri">The endpoint for the install request.</param>
|
||||
/// <param name="boundaryString">Unique string used to separate the parts of the multipart form data.</param>
|
||||
private static void CreateAppInstallEndpointAndBoundaryString(
|
||||
string packageName,
|
||||
string ipAddress,
|
||||
int port,
|
||||
out Uri uri,
|
||||
out string boundaryString)
|
||||
{
|
||||
uri = BuildEndpoint(
|
||||
new Uri($"http://{ipAddress}"),
|
||||
new Uri($"http://{ipAddress}:{port}"),
|
||||
"api/app/packagemanager/package",
|
||||
$"package={packageName}");
|
||||
|
||||
|
@ -135,12 +170,12 @@ namespace Microsoft.FactoryOrchestrator.Core
|
|||
return new Uri(baseUri, relativePart);
|
||||
}
|
||||
|
||||
private static async Task<ApplicationInstallStatus> GetInstallStatusAsync(string ipAddress = "localhost")
|
||||
private static async Task<ApplicationInstallStatus> GetInstallStatusAsync(string ipAddress = "localhost", int port = 80)
|
||||
{
|
||||
ApplicationInstallStatus status = ApplicationInstallStatus.None;
|
||||
|
||||
Uri uri = BuildEndpoint(
|
||||
new Uri($"http://{ipAddress}"),
|
||||
new Uri($"http://{ipAddress}:{port}"),
|
||||
"api/app/packagemanager/state");
|
||||
|
||||
using (HttpResponseMessage response = await WdpHttpClient.GetAsync(uri).ConfigureAwait(false))
|
||||
|
@ -213,10 +248,11 @@ namespace Microsoft.FactoryOrchestrator.Core
|
|||
/// <param name="appFilePath">The app package file path.</param>
|
||||
/// <param name="dependentAppsFilePaths">The dependent app packages file paths.</param>
|
||||
/// <param name="certFilePath">The certificate file path.</param>
|
||||
/// <param name="ipAddress">The ip address of the device to install the app on.</param>
|
||||
/// <param name="ipAddress">The ip address of the device to install the app on.</param>
|
||||
/// <param name="port">The port for WDP on the target device.</param>
|
||||
/// <exception cref="FileNotFoundException">
|
||||
/// </exception>
|
||||
public static async Task InstallAppWithWDP(string appFilePath, List<string> dependentAppsFilePaths, string certFilePath, string ipAddress = "localhost")
|
||||
public static async Task InstallAppWithWDP(string appFilePath, List<string> dependentAppsFilePaths, string certFilePath, string ipAddress = "localhost", int port = 80)
|
||||
{
|
||||
ApplicationInstallStatus status = ApplicationInstallStatus.InProgress;
|
||||
|
||||
|
@ -244,7 +280,7 @@ namespace Microsoft.FactoryOrchestrator.Core
|
|||
}
|
||||
}
|
||||
|
||||
CreateAppInstallEndpointAndBoundaryString(Path.GetFileName(appFilePath), ipAddress, out var uri, out _);
|
||||
CreateAppInstallEndpointAndBoundaryString(Path.GetFileName(appFilePath), ipAddress, port, out var uri, out _);
|
||||
using (var content = CreateAppInstallContent(appFilePath, dependentAppsFilePaths, certFilePath))
|
||||
{
|
||||
await WdpHttpClient.PostAsync(uri, content);
|
||||
|
@ -253,7 +289,7 @@ namespace Microsoft.FactoryOrchestrator.Core
|
|||
while (status == ApplicationInstallStatus.InProgress)
|
||||
{
|
||||
await Task.Delay(500);
|
||||
status = await GetInstallStatusAsync(ipAddress);
|
||||
status = await GetInstallStatusAsync(ipAddress, port);
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -262,17 +298,18 @@ namespace Microsoft.FactoryOrchestrator.Core
|
|||
/// Closes a running app package application with Windows Device Portal.
|
||||
/// </summary>
|
||||
/// <param name="app">The app package to exit .</param>
|
||||
/// <param name="ipAddress">The ip address of the device to exit the app on.</param>
|
||||
/// <param name="ipAddress">The ip address of the device to exit the app on.</param>
|
||||
/// <param name="port">The port for WDP on the target device.</param>
|
||||
/// <exception cref="ArgumentException">
|
||||
/// </exception>
|
||||
public static async Task CloseAppWithWDP(string app, string ipAddress = "localhost")
|
||||
public static async Task CloseAppWithWDP(string app, string ipAddress = "localhost", int port = 80)
|
||||
{
|
||||
if (string.IsNullOrWhiteSpace(app))
|
||||
{
|
||||
throw new ArgumentException(Resources.WDPError, nameof(app));
|
||||
}
|
||||
|
||||
var uri = BuildEndpoint(new Uri($"http://{ipAddress}"),
|
||||
var uri = BuildEndpoint(new Uri($"http://{ipAddress}:{port}"),
|
||||
"api/taskmanager/app",
|
||||
$"package={Convert.ToBase64String(System.Text.Encoding.UTF8.GetBytes(app))}");
|
||||
|
||||
|
@ -283,11 +320,12 @@ namespace Microsoft.FactoryOrchestrator.Core
|
|||
/// Gets the collection of applications installed on the device.
|
||||
/// </summary>
|
||||
/// <param name="ipAddress">The ip address of the device to query.</param>
|
||||
/// <param name="port">The port for WDP on the target device.</param>
|
||||
/// <returns>AppPackages object containing the list of installed application packages.</returns>
|
||||
public static async Task<AppPackages> GetInstalledAppPackagesAsync(string ipAddress = "localhost")
|
||||
public static async Task<AppPackages> GetInstalledAppPackagesAsync(string ipAddress = "localhost", int port = 80)
|
||||
{
|
||||
Uri uri = BuildEndpoint(
|
||||
new Uri($"http://{ipAddress}"),
|
||||
new Uri($"http://{ipAddress}:{port}"),
|
||||
"api/app/packagemanager/packages");
|
||||
|
||||
var resp = await WdpHttpClient.GetAsync(uri).ConfigureAwait(false);
|
||||
|
|
|
@ -11,7 +11,7 @@
|
|||
<OutputPath>$(OutputRootPath)$(Configuration)/$(Platform)/$(TargetName)</OutputPath>
|
||||
</PropertyGroup>
|
||||
<ItemGroup>
|
||||
<PackageReference Include="System.Security.Principal.Windows" Version="4.7.0" />
|
||||
<PackageReference Include="System.Security.Principal.Windows" Version="5.0.0" />
|
||||
</ItemGroup>
|
||||
<ItemGroup>
|
||||
<ProjectReference Include="../CoreLibrary/Microsoft.FactoryOrchestrator.Core.csproj" />
|
||||
|
|
|
@ -414,8 +414,8 @@ namespace Microsoft.FactoryOrchestrator.Service
|
|||
|
||||
if (factoryReset)
|
||||
{
|
||||
// Pause a bit to allow the IPC call to return before we kill it off
|
||||
Task.Run(() => { System.Threading.Thread.Sleep(500); FOService.Instance.Stop(); FOService.Instance.Start(true, new CancellationToken()); });
|
||||
FOService.Instance.Stop(true);
|
||||
FOService.Instance.Start(true, new CancellationToken());
|
||||
}
|
||||
}
|
||||
catch (Exception e)
|
||||
|
@ -802,12 +802,12 @@ namespace Microsoft.FactoryOrchestrator.Service
|
|||
throw new FactoryOrchestratorException(string.Format(CultureInfo.CurrentCulture, Resources.WindowsOnlyError, "TerminateApp"));
|
||||
}
|
||||
|
||||
var apps = WDPHelpers.GetInstalledAppPackagesAsync().Result;
|
||||
var apps = WDPHelpers.GetInstalledAppPackagesAsync("localhost", WDPHelpers.GetWdpHttpPort()).Result;
|
||||
var app = apps.Packages.Where(x => x.AppId.Equals(aumid, StringComparison.OrdinalIgnoreCase)).DefaultIfEmpty(null).FirstOrDefault();
|
||||
|
||||
if (app != null)
|
||||
{
|
||||
WDPHelpers.CloseAppWithWDP(app.FullName).Wait();
|
||||
WDPHelpers.CloseAppWithWDP(app.FullName, "localhost", WDPHelpers.GetWdpHttpPort()).Wait();
|
||||
}
|
||||
|
||||
FOService.Instance.ServiceLogger.LogDebug($"{Resources.Finish}: TerminateApp {aumid}");
|
||||
|
@ -1014,7 +1014,7 @@ namespace Microsoft.FactoryOrchestrator.Service
|
|||
}
|
||||
}
|
||||
|
||||
WDPHelpers.InstallAppWithWDP(appPackagePath, dependentPackages, certificateFile).Wait();
|
||||
WDPHelpers.InstallAppWithWDP(appPackagePath, dependentPackages, certificateFile, "localhost", WDPHelpers.GetWdpHttpPort()).Wait();
|
||||
|
||||
FOService.Instance.ServiceLogger.LogDebug($"{Resources.Finish}: InstallApp {appPackagePath}");
|
||||
}
|
||||
|
@ -1037,7 +1037,7 @@ namespace Microsoft.FactoryOrchestrator.Service
|
|||
}
|
||||
|
||||
// Get installed packages on the system
|
||||
var apps = WDPHelpers.GetInstalledAppPackagesAsync().Result;
|
||||
var apps = WDPHelpers.GetInstalledAppPackagesAsync("localhost", WDPHelpers.GetWdpHttpPort()).Result;
|
||||
|
||||
List<string> aumids = apps.Packages.Select(x => x.AppId).ToList();
|
||||
|
||||
|
@ -1063,7 +1063,7 @@ namespace Microsoft.FactoryOrchestrator.Service
|
|||
}
|
||||
|
||||
// Get installed packages on the system
|
||||
var apps = WDPHelpers.GetInstalledAppPackagesAsync().Result;
|
||||
var apps = WDPHelpers.GetInstalledAppPackagesAsync("localhost", WDPHelpers.GetWdpHttpPort()).Result;
|
||||
|
||||
FOService.Instance.ServiceLogger.LogDebug($"{Resources.Finish}: GetInstalledAppsDetailed");
|
||||
return apps.Packages;
|
||||
|
@ -1238,5 +1238,21 @@ namespace Microsoft.FactoryOrchestrator.Service
|
|||
throw;
|
||||
}
|
||||
}
|
||||
|
||||
public int GetWdpHttpPort()
|
||||
{
|
||||
try
|
||||
{
|
||||
FOService.Instance.ServiceLogger.LogDebug($"{Resources.Start}: GetWdpHttpPort");
|
||||
int ret = WDPHelpers.GetWdpHttpPort();
|
||||
FOService.Instance.ServiceLogger.LogDebug($"{Resources.Finish}: GetWdpHttpPort");
|
||||
return ret;
|
||||
}
|
||||
catch (Exception e)
|
||||
{
|
||||
FOService.Instance.LogServiceEvent(new ServiceEvent(ServiceEventType.ServiceError, null, e.AllExceptionsToString()));
|
||||
throw;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -2,7 +2,7 @@
|
|||
// Licensed under the MIT license.
|
||||
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Collections.Generic;
|
||||
using System.Globalization;
|
||||
using System.IO;
|
||||
using System.Linq;
|
||||
|
@ -16,7 +16,9 @@ using JKang.IpcServiceFramework.Hosting;
|
|||
using Microsoft.Extensions.Configuration;
|
||||
using Microsoft.Extensions.DependencyInjection;
|
||||
using Microsoft.Extensions.Hosting;
|
||||
using Microsoft.Extensions.Hosting.WindowsServices;
|
||||
using Microsoft.Extensions.Logging;
|
||||
using Microsoft.Extensions.Logging.EventLog;
|
||||
using Microsoft.FactoryOrchestrator.Client;
|
||||
using Microsoft.FactoryOrchestrator.Core;
|
||||
using Microsoft.FactoryOrchestrator.Server;
|
||||
|
@ -106,19 +108,43 @@ namespace Microsoft.FactoryOrchestrator.Service
|
|||
}).Build();
|
||||
|
||||
public static void Main(string[] args)
|
||||
{
|
||||
Host.CreateDefaultBuilder(null).UseSystemd().UseWindowsService().ConfigureServices((hostContext, services) =>
|
||||
{
|
||||
services.AddHostedService<Worker>();
|
||||
}).ConfigureLogging(builder =>
|
||||
{
|
||||
{
|
||||
#if DEBUG
|
||||
var _logLevel = LogLevel.Debug;
|
||||
var _logLevel = LogLevel.Debug;
|
||||
#else
|
||||
var _logLevel = LogLevel.Information;
|
||||
var _logLevel = LogLevel.Information;
|
||||
#endif
|
||||
builder.SetMinimumLevel(_logLevel).AddConsole().AddProvider(new LogFileProvider());
|
||||
}).Build().Run();
|
||||
var hostBuilder = Host.CreateDefaultBuilder(null).UseSystemd().ConfigureServices((hostContext, services) =>
|
||||
{
|
||||
services.AddHostedService<Worker>();
|
||||
}).ConfigureLogging(builder =>
|
||||
{
|
||||
builder.SetMinimumLevel(_logLevel).AddConsole().AddProvider(new LogFileProvider());
|
||||
});
|
||||
|
||||
bool isService = ((args != null) && (args.Length > 0));
|
||||
if (RuntimeInformation.IsOSPlatform(OSPlatform.Windows) && isService)
|
||||
{
|
||||
hostBuilder.UseContentRoot(AppContext.BaseDirectory);
|
||||
hostBuilder.ConfigureLogging((hostingContext, logging) =>
|
||||
{
|
||||
logging.AddEventLog();
|
||||
logging.SetMinimumLevel(_logLevel);
|
||||
})
|
||||
.ConfigureServices((hostContext, services) =>
|
||||
{
|
||||
services.AddSingleton<IHostLifetime, WindowsServiceLifetime>();
|
||||
services.Configure<EventLogSettings>(settings =>
|
||||
{
|
||||
if (string.IsNullOrEmpty(settings.SourceName))
|
||||
{
|
||||
settings.SourceName = hostContext.HostingEnvironment.ApplicationName;
|
||||
}
|
||||
});
|
||||
});
|
||||
}
|
||||
|
||||
hostBuilder.Build().Run();
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -447,10 +473,13 @@ namespace Microsoft.FactoryOrchestrator.Service
|
|||
return;
|
||||
}
|
||||
|
||||
// Start IPC server on desired port. Only start after all boot tasks are complete.
|
||||
_ipcHost = FOServiceExe.CreateIpcHost(IsNetworkAccessEnabled, NetworkPort, SSLCertificate);
|
||||
_ipcCancellationToken = new System.Threading.CancellationTokenSource();
|
||||
_ipcHost.RunAsync(_ipcCancellationToken.Token);
|
||||
// Start IPC server on desired port. Only start if not a reset operation.
|
||||
if (_ipcHost == null)
|
||||
{
|
||||
_ipcHost = FOServiceExe.CreateIpcHost(IsNetworkAccessEnabled, NetworkPort, SSLCertificate);
|
||||
_ipcCancellationToken = new System.Threading.CancellationTokenSource();
|
||||
_ipcHost.RunAsync(_ipcCancellationToken.Token);
|
||||
}
|
||||
|
||||
if (IsNetworkAccessEnabled)
|
||||
{
|
||||
|
@ -531,10 +560,14 @@ namespace Microsoft.FactoryOrchestrator.Service
|
|||
/// <summary>
|
||||
/// Service stop.
|
||||
/// </summary>
|
||||
public void Stop()
|
||||
{
|
||||
// Disable inter process communication interfaces
|
||||
_ipcCancellationToken?.Cancel();
|
||||
public void Stop(bool isFactoryReset = false)
|
||||
{
|
||||
if (!isFactoryReset)
|
||||
{
|
||||
// Disable inter process communication interfaces if not a reset operation
|
||||
_ipcCancellationToken?.Cancel();
|
||||
}
|
||||
|
||||
_containerHeartbeatToken?.Cancel();
|
||||
_containerClient = null;
|
||||
ContainerGuid = Guid.Empty;
|
||||
|
@ -719,13 +752,13 @@ namespace Microsoft.FactoryOrchestrator.Service
|
|||
{
|
||||
// Exit URDC if we launched it.
|
||||
// There may be a preview app & official app installed, close them all
|
||||
var rdApps = (await WDPHelpers.GetInstalledAppPackagesAsync()).Packages.Where(x => (x.FullName.StartsWith("Microsoft", StringComparison.OrdinalIgnoreCase)) && (x.FullName.Contains("RemoteDesktop", StringComparison.OrdinalIgnoreCase)));
|
||||
var rdApps = (await WDPHelpers.GetInstalledAppPackagesAsync("localhost", WDPHelpers.GetWdpHttpPort())).Packages.Where(x => (x.FullName.StartsWith("Microsoft", StringComparison.OrdinalIgnoreCase)) && (x.FullName.Contains("RemoteDesktop", StringComparison.OrdinalIgnoreCase)));
|
||||
|
||||
foreach (var app in rdApps)
|
||||
{
|
||||
try
|
||||
{
|
||||
await WDPHelpers.CloseAppWithWDP(app.FullName);
|
||||
await WDPHelpers.CloseAppWithWDP(app.FullName, "localhost", WDPHelpers.GetWdpHttpPort());
|
||||
}
|
||||
catch (Exception)
|
||||
{
|
||||
|
@ -1192,6 +1225,8 @@ namespace Microsoft.FactoryOrchestrator.Service
|
|||
/// <returns></returns>
|
||||
public void ExecuteServerBootTasks(CancellationToken cancellationToken)
|
||||
{
|
||||
IsExecutingBootTasks = true;
|
||||
|
||||
if (_isWindows)
|
||||
{
|
||||
// Open Registry Keys
|
||||
|
@ -1266,7 +1301,6 @@ namespace Microsoft.FactoryOrchestrator.Service
|
|||
LastEventIndex = 0;
|
||||
LastEventTime = DateTime.MinValue;
|
||||
LocalLoopbackApps = new List<string>();
|
||||
IsExecutingBootTasks = true;
|
||||
_openedFiles = new Dictionary<string, (Stream stream, System.Threading.Timer timer)>();
|
||||
|
||||
ContainerGuid = Guid.Empty;
|
||||
|
@ -1686,6 +1720,12 @@ namespace Microsoft.FactoryOrchestrator.Service
|
|||
.SetBasePath(AppContext.BaseDirectory)
|
||||
.AddJsonFile(Path.Combine(FOServiceExe.ServiceExeLogFolder, "appsettings.json"), optional: true)
|
||||
.AddJsonFile("appsettings.json", optional: true);
|
||||
|
||||
if (!_isWindows)
|
||||
{
|
||||
builder.AddJsonFile("/etc/FactoryOrchestrator/appsettings.json", optional:true);
|
||||
}
|
||||
|
||||
Appsettings = builder.Build();
|
||||
|
||||
// Look for each setting in the registry (Windows only, OEM Customizations) or in the IConfiguration
|
||||
|
@ -1804,7 +1844,7 @@ namespace Microsoft.FactoryOrchestrator.Service
|
|||
{
|
||||
try
|
||||
{
|
||||
IsContainerSupportEnabled = Convert.ToBoolean(GetAppSetting(_disableContainerValue) ?? new ArgumentNullException(), CultureInfo.InvariantCulture);
|
||||
IsContainerSupportEnabled = !Convert.ToBoolean(GetAppSetting(_disableContainerValue) ?? new ArgumentNullException(), CultureInfo.InvariantCulture);
|
||||
}
|
||||
catch (Exception)
|
||||
{
|
||||
|
@ -1941,7 +1981,7 @@ namespace Microsoft.FactoryOrchestrator.Service
|
|||
{
|
||||
if (disposing)
|
||||
{
|
||||
_ipcHost.Dispose();
|
||||
_ipcHost?.Dispose();
|
||||
_ipcCancellationToken?.Dispose();
|
||||
_containerHeartbeatToken?.Dispose();
|
||||
_mutableKey?.Dispose();
|
||||
|
|
|
@ -3,7 +3,7 @@
|
|||
|
||||
<!-- Assembly, App, Package version for all non-OSS files. Uses SemVer. -->
|
||||
<PropertyGroup Label="Version">
|
||||
<VersionPrefix>10.0.0</VersionPrefix>
|
||||
<VersionPrefix>10.1.0</VersionPrefix>
|
||||
</PropertyGroup>
|
||||
|
||||
<!-- Common packaging properties -->
|
||||
|
|
Загрузка…
Ссылка в новой задаче