implement ClickOnce installation method and use registry to autostart

pull/9/head
sleevezipper 4 years ago
parent 2590bd50b0
commit a3125734ec

@ -0,0 +1,7 @@
{
"ExpandedNodes": [
""
],
"SelectedNode": "\\hass-workstation-service.sln",
"PreviewInSolutionExplorer": false
}

Binary file not shown.

@ -2,7 +2,6 @@ using System;
using System.Collections.Generic;
using System.IO;
using System.IO.IsolatedStorage;
using System.Reflection;
using System.Text.Json;
using hass_workstation_service.Communication;
using hass_workstation_service.Domain.Sensors;
@ -30,10 +29,7 @@ namespace hass_workstation_service.Data
public async void ReadSettings()
{
IsolatedStorageFileStream stream = this._fileStorage.OpenFile("configured-sensors.json", FileMode.OpenOrCreate);
String filePath = stream.GetType().GetField("m_FullPath",
BindingFlags.Instance | BindingFlags.NonPublic).GetValue(stream).ToString();
Console.WriteLine(filePath);
Log.Logger.Information($"reading configured sensors from: {filePath}");
Log.Logger.Information($"reading configured sensors from: {stream.Name}");
List<ConfiguredSensor> sensors = new List<ConfiguredSensor>();
if (stream.Length > 0)
{
@ -43,7 +39,7 @@ namespace hass_workstation_service.Data
foreach (ConfiguredSensor configuredSensor in sensors)
{
AbstractSensor sensor;
#pragma warning disable IDE0066
#pragma warning disable IDE0066
switch (configuredSensor.Type)
{
case "UserNotificationStateSensor":
@ -68,7 +64,7 @@ namespace hass_workstation_service.Data
foreach (AbstractSensor sensor in this.ConfiguredSensors)
{
configuredSensorsToSave.Add(new ConfiguredSensor() { Id = sensor.Id, Name = sensor.Name, Type = sensor.GetType().Name });
configuredSensorsToSave.Add(new ConfiguredSensor(){Id = sensor.Id, Name = sensor.Name, Type = sensor.GetType().Name});
}
await JsonSerializer.SerializeAsync(stream, configuredSensorsToSave);

@ -10,12 +10,12 @@ using hass_workstation_service.Data;
using System.Linq;
using System.Diagnostics;
using System.Threading.Tasks;
using hass_workstation_service.ServiceHost;
using Serilog;
using Serilog.Formatting.Compact;
using System.IO.IsolatedStorage;
using System.Reflection;
using System.IO;
using Microsoft.Win32;
namespace hass_workstation_service
{
@ -28,20 +28,34 @@ namespace hass_workstation_service
.WriteTo.Console()
.WriteTo.File(new RenderedCompactJsonFormatter(), "logs/log.ndjson")
.CreateLogger();
try
{
if (RuntimeInformation.IsOSPlatform(OSPlatform.Windows))
{
var isService = !(Debugger.IsAttached || args.Contains("--console"));
if (isService)
if (args.Contains("--autostart=true"))
{
await CreateHostBuilder(args).RunAsServiceAsync();
Log.Logger.Information("configuring autostart");
// The path to the key where Windows looks for startup applications
RegistryKey rkApp = Registry.CurrentUser.OpenSubKey(@"SOFTWARE\Microsoft\Windows\CurrentVersion\Run", true);
//Path to launch shortcut
string startPath = Environment.GetFolderPath(Environment.SpecialFolder.Programs) + @"\hass-workstation-service\hass-workstation-service.appref-ms";
rkApp.SetValue("hass-workstation-service", startPath);
rkApp.Close();
}
else
else if (args.Contains("--autostart=false"))
{
await CreateHostBuilder(args).RunConsoleAsync();
Log.Logger.Information("removing autostart");
RegistryKey rkApp = Registry.CurrentUser.OpenSubKey(@"SOFTWARE\Microsoft\Windows\CurrentVersion\Run", true);
rkApp.DeleteSubKey("hass-workstation-service");
rkApp.Close();
}
await CreateHostBuilder(args).RunConsoleAsync();
}
else
{
@ -82,7 +96,7 @@ namespace hass_workstation_service
Identifiers = "hass-workstation-service",
Manufacturer = Environment.UserName,
Model = Environment.OSVersion.ToString(),
Sw_version = "0.0.5"
Sw_version = Assembly.GetExecutingAssembly().GetName().Version.ToString()
};
services.AddSingleton(configuration);
services.AddSingleton(deviceConfig);

@ -0,0 +1,36 @@
<?xml version="1.0" encoding="utf-8"?>
<!--
https://go.microsoft.com/fwlink/?LinkID=208121.
-->
<Project ToolsVersion="4.0" xmlns="http://schemas.microsoft.com/developer/msbuild/2003">
<PropertyGroup>
<ApplicationRevision>4</ApplicationRevision>
<ApplicationVersion>1.0.0.*</ApplicationVersion>
<BootstrapperEnabled>True</BootstrapperEnabled>
<Configuration>Release</Configuration>
<CreateDesktopShortcut>True</CreateDesktopShortcut>
<GenerateManifests>True</GenerateManifests>
<Install>true</Install>
<InstallFrom>Disk</InstallFrom>
<IsRevisionIncremented>True</IsRevisionIncremented>
<IsWebBootstrapper>False</IsWebBootstrapper>
<ManifestCertificateThumbprint>820B7EDF3E26E24BB4C25B177A05B3D0C77BF73A</ManifestCertificateThumbprint>
<ManifestKeyFile>hass-workstation-service_TemporaryKey.pfx</ManifestKeyFile>
<MapFileExtensions>true</MapFileExtensions>
<OpenBrowserOnPublish>false</OpenBrowserOnPublish>
<Platform>Any CPU</Platform>
<PublishDir>bin\publish\</PublishDir>
<PublishUrl>bin\publish\</PublishUrl>
<PublishProtocol>ClickOnce</PublishProtocol>
<PublishReadyToRun>False</PublishReadyToRun>
<PublishSingleFile>False</PublishSingleFile>
<RuntimeIdentifier>win-x64</RuntimeIdentifier>
<SelfContained>False</SelfContained>
<SignatureAlgorithm>sha256RSA</SignatureAlgorithm>
<SignManifests>True</SignManifests>
<TargetFramework>netcoreapp3.1</TargetFramework>
<TrustUrlParameters>False</TrustUrlParameters>
<UpdateEnabled>False</UpdateEnabled>
<UpdateMode>Foreground</UpdateMode>
</PropertyGroup>
</Project>

@ -0,0 +1,6 @@
<?xml version="1.0" encoding="utf-8"?>
<!--
https://go.microsoft.com/fwlink/?LinkID=208121.
-->
<Project ToolsVersion="4.0" xmlns="http://schemas.microsoft.com/developer/msbuild/2003">
</Project>

@ -1,64 +0,0 @@
using Microsoft.Extensions.Hosting;
using System;
using System.ServiceProcess;
using System.Threading;
using System.Threading.Tasks;
namespace hass_workstation_service.ServiceHost
{
public class ServiceBaseLifetime : ServiceBase, IHostLifetime
{
private IHostApplicationLifetime ApplicationLifetime { get; }
private readonly TaskCompletionSource<object> _delayStart = new TaskCompletionSource<object>();
public ServiceBaseLifetime(IHostApplicationLifetime applicationLifetime)
{
ApplicationLifetime = applicationLifetime ?? throw new ArgumentNullException(nameof(applicationLifetime));
}
public Task WaitForStartAsync(CancellationToken cancellationToken)
{
cancellationToken.Register(() => _delayStart.TrySetCanceled());
ApplicationLifetime.ApplicationStopping.Register(Stop);
new Thread(Run).Start(); // Otherwise this would block and prevent IHost.StartAsync from finishing.
return _delayStart.Task;
}
private void Run()
{
try
{
Run(this); // This blocks until the service is stopped.
_delayStart.TrySetException(new InvalidOperationException("Stopped without starting"));
}
catch (Exception ex)
{
_delayStart.TrySetException(ex);
}
}
public Task StopAsync(CancellationToken cancellationToken)
{
Stop();
return Task.CompletedTask;
}
// Called by base.Run when the service is ready to start.
protected override void OnStart(string[] args)
{
_delayStart.TrySetResult(null);
base.OnStart(args);
}
// Called by base.Stop. This may be called multiple times by service Stop, ApplicationStopping, and StopAsync.
// That's OK because StopApplication uses a CancellationTokenSource and prevents any recursion.
protected override void OnStop()
{
ApplicationLifetime.StopApplication();
base.OnStop();
}
}
}

@ -1,21 +0,0 @@
using System.Threading;
using System.Threading.Tasks;
using Microsoft.Extensions.DependencyInjection;
using Microsoft.Extensions.Hosting;
namespace hass_workstation_service.ServiceHost
{
public static class ServiceBaseLifetimeHostExtensions
{
public static IHostBuilder UseServiceBaseLifetime(this IHostBuilder hostBuilder)
{
return hostBuilder.ConfigureServices((hostContext, services) => services.AddSingleton<IHostLifetime, ServiceBaseLifetime>());
}
public static Task RunAsServiceAsync(this IHostBuilder hostBuilder, CancellationToken cancellationToken = default)
{
return hostBuilder.UseServiceBaseLifetime().Build().RunAsync(cancellationToken);
}
}
}

@ -8,8 +8,8 @@
<ItemGroup>
<PackageReference Include="Microsoft.Extensions.Hosting" Version="3.1.10" />
<PackageReference Include="Microsoft.Win32.Registry" Version="5.0.0" />
<PackageReference Include="MQTTnet" Version="3.0.13" />
<PackageReference Include="Serilog.AspNetCore" Version="3.4.0" />
<PackageReference Include="System.ServiceProcess.ServiceController" Version="5.0.0" />
</ItemGroup>
</Project>

@ -0,0 +1,6 @@
<?xml version="1.0" encoding="utf-8"?>
<Project ToolsVersion="Current" xmlns="http://schemas.microsoft.com/developer/msbuild/2003">
<PropertyGroup>
<_LastSelectedProfileId>C:\Users\Maurits\Documents\Repo\hass-desktop-service\Properties\PublishProfiles\ClickOnceProfile.pubxml</_LastSelectedProfileId>
</PropertyGroup>
</Project>

@ -0,0 +1,31 @@

Microsoft Visual Studio Solution File, Format Version 12.00
# Visual Studio Version 16
VisualStudioVersion = 16.0.30804.86
MinimumVisualStudioVersion = 10.0.40219.1
Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "hass-workstation-service", "hass-workstation-service.csproj", "{78EC7ACA-8826-4A0A-AA8E-664D03ACBE88}"
EndProject
Global
GlobalSection(SolutionConfigurationPlatforms) = preSolution
Debug|Any CPU = Debug|Any CPU
Debug|x86 = Debug|x86
Release|Any CPU = Release|Any CPU
Release|x86 = Release|x86
EndGlobalSection
GlobalSection(ProjectConfigurationPlatforms) = postSolution
{78EC7ACA-8826-4A0A-AA8E-664D03ACBE88}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
{78EC7ACA-8826-4A0A-AA8E-664D03ACBE88}.Debug|Any CPU.Build.0 = Debug|Any CPU
{78EC7ACA-8826-4A0A-AA8E-664D03ACBE88}.Debug|x86.ActiveCfg = Debug|Any CPU
{78EC7ACA-8826-4A0A-AA8E-664D03ACBE88}.Debug|x86.Build.0 = Debug|Any CPU
{78EC7ACA-8826-4A0A-AA8E-664D03ACBE88}.Release|Any CPU.ActiveCfg = Release|Any CPU
{78EC7ACA-8826-4A0A-AA8E-664D03ACBE88}.Release|Any CPU.Build.0 = Release|Any CPU
{78EC7ACA-8826-4A0A-AA8E-664D03ACBE88}.Release|x86.ActiveCfg = Release|Any CPU
{78EC7ACA-8826-4A0A-AA8E-664D03ACBE88}.Release|x86.Build.0 = Release|Any CPU
EndGlobalSection
GlobalSection(SolutionProperties) = preSolution
HideSolutionNode = FALSE
EndGlobalSection
GlobalSection(ExtensibilityGlobals) = postSolution
SolutionGuid = {1F972DB9-1E76-4295-B272-511FF17F749D}
EndGlobalSection
EndGlobal
Loading…
Cancel
Save