Compare commits

..

5 Commits

Author SHA1 Message Date
Florian Rappl
456135a562 Merge pull request #1015 from hillin/main
Update Migration Guide
2026-01-21 12:18:25 +01:00
lucas
300f52510c Update Migration Guide with details on electron-builder.json location and launch settings 2026-01-21 15:30:44 +08:00
Florian Rappl
7e6760a428 Merge pull request #998 from ElectronNET/develop
Release 0.4.0
2025-12-19 00:09:34 +01:00
Florian Rappl
cb20fbad25 Merge pull request #991 from ElectronNET/develop
Release 0.3.1
2025-12-16 19:00:07 +01:00
Florian Rappl
bdfbcd5b77 Merge pull request #986 from ElectronNET/develop
Release 0.3.0
2025-12-14 22:13:10 +01:00
22 changed files with 42 additions and 289 deletions

View File

@@ -1,10 +1,3 @@
# 0.4.1
## ElectronNET.Core
- Fixed handling of `Center` property for windows (#1001)
- Added missing methods on `Cookies` (#1000)
# 0.4.0
## ElectronNET.Core

View File

@@ -8,9 +8,7 @@ When you build an Electron.NET project, the following validation checks are perf
| Code | Check | Description |
|------|-------|-------------|
| [ELECTRON001](#1-packagejson-rules) | package.json location rules | Ensures `package.json`/`package-lock.json` arent present in unsupported locations (root `package.json` handled separately) |
| [ELECTRON008](#1-packagejson-rules) | root package.json contains electron | Warns when root `package.json` contains the word `electron` (case-insensitive) |
| [ELECTRON009](#1-packagejson-rules) | root package.json copied to output | Warns when root `package.json` is configured to be copied to output/publish |
| [ELECTRON001](#1-packagejson-not-allowed) | package.json not allowed | Ensures no package.json exists outside ElectronHostHook |
| [ELECTRON002](#2-electron-manifestjson-not-allowed) | electron-manifest.json not allowed | Detects deprecated manifest files |
| [ELECTRON003](#3-electron-builderjson-location) | electron-builder.json location | Verifies electron-builder.json exists in Properties folder |
| [ELECTRON004](#3-electron-builderjson-location) | electron-builder.json wrong location | Warns if electron-builder.json is found in incorrect locations |
@@ -20,38 +18,24 @@ When you build an Electron.NET project, the following validation checks are perf
---
## 1. package.json rules
## 1. package.json not allowed
**Warning Codes:** `ELECTRON001`, `ELECTRON008`, `ELECTRON009`
**Warning Code:** `ELECTRON001`
### What is checked
The build system scans for `package.json` and `package-lock.json` files in your project directory.
Rules:
- **ELECTRON001**: `package.json` / `package-lock.json` must not exist in the project directory or subdirectories
- Exception: `ElectronHostHook` folder is allowed
- Note: a **root** `package.json` is **excluded** from `ELECTRON001` and validated by `ELECTRON008` / `ELECTRON009`
- **ELECTRON008**: If a root `package.json` exists, it must **not** contain electron-related dependencies or configuration.
- **ELECTRON009**: If a root `package.json` exists, it must **not** be configured to be copied to output/publish (for example via `CopyToOutputDirectory` / `CopyToPublishDirectory` metadata)
The build system scans for `package.json` and `package-lock.json` files in your project directory. These files should not exist in the project root or subdirectories (with one exception).
### Why this matters
Electron.NET generates its Electron-related `package.json` during publishing based on MSBuild properties. A user-maintained Electron-related `package.json` can conflict with that process.
Also, ensuring the root `package.json` is not copied prevents accidentally shipping it with the published app.
In previous versions of Electron.NET, a `package.json` file was required in the project. The new version generates this file automatically from MSBuild properties defined in your `.csproj` file.
### Exception
A `package.json` / `package-lock.json` file **is allowed** in the `ElectronHostHook` folder if you're using custom host hooks.
A `package.json` file **is allowed** in the `ElectronHostHook` folder if you're using custom host hooks. This is the only valid location for a manually maintained package.json.
### How to fix
If you have an Electron-related `package.json` from older Electron.NET versions:
1. **Open your project's `.csproj` file**
2. **Add the required properties** to a PropertyGroup with the label `ElectronNetCommon`:
@@ -67,12 +51,7 @@ If you have an Electron-related `package.json` from older Electron.NET versions:
</PropertyGroup>
```
3. **Delete** Electron-related `package.json` / `package-lock.json` files (except those under `ElectronHostHook` if applicable)
If you keep a root `package.json` for non-Electron reasons:
- Ensure it does **not** contain electron dependencies or configuration (fixes `ELECTRON008`)
- Ensure it is **not** copied to output/publish (fixes `ELECTRON009`)
3. **Delete the old `package.json`** file from your project root
> **See also:** [Migration Guide](Migration-Guide.md) for complete migration instructions.

View File

@@ -31,7 +31,7 @@ dotnet add package ElectronNET.Core.AspNet # For ASP.NET projects
### Step 2: Configure Project Settings
**Auto-generated Configuration:**
ElectronNET.Core automatically creates `electron-builder.json` during the first build or NuGet restore. No manual configuration is needed for basic setups.
ElectronNET.Core automatically creates `electron-builder.json` in the `Properties` folder of your project during the first build or NuGet restore. No manual configuration is needed for basic setups.
**Migrate Existing Configuration:**
If you have an existing `electron.manifest.json` file:
@@ -63,6 +63,9 @@ You can also manually edit `electron-builder.json`:
}
```
**Modify Launch Settings:**
ElectronNET.Core no longer needs a separate CLI tool (electronize.exe) for launching. You should update your launch settings to use either the ASP.NET-first or Electron-first approach. See [Debugging](../Using/Debugging.md) for details.
## 🎯 Testing Migration
After completing the migration steps:

View File

@@ -54,7 +54,7 @@ Add the Electron.NET configuration to your `.csproj` file:
</PropertyGroup>
<ItemGroup>
<PackageReference Include="ElectronNET.Core" Version="0.4.1" />
<PackageReference Include="ElectronNET.Core" Version="0.4.0" />
</ItemGroup>
```

View File

@@ -314,9 +314,7 @@ namespace ElectronNET.API
{
if (this.tcs != null)
{
var ex = new TimeoutException(
$"No response after {(long)timeout.TotalMilliseconds}ms trying to retrieve value {apiBase.objectName}.{callerName}()"
);
var ex = new TimeoutException($"No response after {timeout:D}ms trying to retrieve value {apiBase.objectName}.{callerName}()");
this.tcs.TrySetException(ex);
this.tcs = null;
}

View File

@@ -186,19 +186,6 @@ public class BrowserWindow : ApiBase
remove => RemoveEvent(value, Id);
}
/// <summary>
/// Emitted when the window is moved or resized.
/// </summary>
/// <remarks>
/// While not being an original Electron event, this one includes the bounds values,
/// saving the additional roundtrip for calling <see cref="GetBoundsAsync"/>.
/// </remarks>
public event Action<Rectangle> OnBoundsChanged
{
add => AddEvent(value, Id);
remove => RemoveEvent(value, Id);
}
/// <summary>
/// macOS: Emitted once when the window is moved to a new position.
/// </summary>

View File

@@ -2,7 +2,6 @@ using ElectronNET.API.Entities;
using ElectronNET.API.Serialization;
using System;
using System.Text.Json;
using System.Threading.Tasks;
namespace ElectronNET.API
{
@@ -55,79 +54,10 @@ namespace ElectronNET.API
_changed -= value;
if (_changed == null)
{
BridgeConnector.Socket.Off("webContents-session-cookies-changed" + Id);
}
}
}
private event Action<Cookie, CookieChangedCause, bool> _changed;
/// <summary>
/// Sends a request to get all cookies matching filter, and resolves a callack with the response.
/// </summary>
/// <param name="filter">
/// </param>
/// <returns>A task which resolves an array of cookie objects.</returns>
public Task<Cookie[]> GetAsync(CookieFilter filter)
{
var tcs = new TaskCompletionSource<Cookie[]>();
var guid = Guid.NewGuid().ToString();
BridgeConnector.Socket.Once<Cookie[]>("webContents-session-cookies-get-completed" + guid, tcs.SetResult);
BridgeConnector.Socket.Emit("webContents-session-cookies-get", Id, filter, guid);
return tcs.Task;
}
/// <summary>
///
/// </summary>
/// <param name="details"></param>
/// <returns></returns>
public Task SetAsync(CookieDetails details)
{
var tcs = new TaskCompletionSource<object>();
var guid = Guid.NewGuid().ToString();
BridgeConnector.Socket.Once<object>("webContents-session-cookies-set-completed" + guid, tcs.SetResult);
BridgeConnector.Socket.Emit("webContents-session-cookies-set", Id, details, guid);
return tcs.Task;
}
/// <summary>
/// Removes the cookies matching url and name
/// </summary>
/// <param name="url">The URL associated with the cookie.</param>
/// <param name="name">The name of cookie to remove.</param>
/// <returns>A task which resolves when the cookie has been removed</returns>
public Task RemoveAsync(string url, string name)
{
var tcs = new TaskCompletionSource<object>();
var guid = Guid.NewGuid().ToString();
BridgeConnector.Socket.Once<object>("webContents-session-cookies-remove-completed" + guid, tcs.SetResult);
BridgeConnector.Socket.Emit("webContents-session-cookies-remove", Id, url, name, guid);
return tcs.Task;
}
/// <summary>
/// Writes any unwritten cookies data to disk.
/// </summary>
/// <returns>A task which resolves when the cookie store has been flushed</returns>
public Task FlushStoreAsync()
{
var tcs = new TaskCompletionSource<object>();
var guid = Guid.NewGuid().ToString();
BridgeConnector.Socket.Once<object>("webContents-session-cookies-flushStore-completed" + guid, tcs.SetResult);
BridgeConnector.Socket.Emit("webContents-session-cookies-flushStore", Id, guid);
return tcs.Task;
}
}
}

View File

@@ -24,13 +24,13 @@ namespace ElectronNET.API.Entities
/// ( if y is used) Window's left offset from screen. Default is to center the
/// window.
/// </summary>
public int? X { get; set; }
public int X { get; set; } = -1;
/// <summary>
/// ( if x is used) Window's top offset from screen. Default is to center the
/// window.
/// </summary>
public int? Y { get; set; }
public int Y { get; set; } = -1;
/// <summary>
/// The width and height would be used as web page's size, which means the actual

View File

@@ -24,7 +24,7 @@
/// <summary>
/// Gets or sets a value indicating whether the cookie is a host-only cookie; this will only be true if no domain was passed.
/// </summary>
public bool? HostOnly { get; set; }
public bool HostOnly { get; set; }
/// <summary>
/// Gets or sets the path of the cookie.
@@ -34,22 +34,22 @@
/// <summary>
/// Gets or sets a value indicating whether the cookie is marked as secure.
/// </summary>
public bool? Secure { get; set; }
public bool Secure { get; set; }
/// <summary>
/// Gets or sets a value indicating whether the cookie is marked as HTTP only.
/// </summary>
public bool? HttpOnly { get; set; }
public bool HttpOnly { get; set; }
/// <summary>
/// Gets or sets a value indicating whether the cookie is a session cookie or a persistent cookie with an expiration date.
/// </summary>
public bool? Session { get; set; }
public bool Session { get; set; }
/// <summary>
/// Gets or sets the expiration date of the cookie as the number of seconds since the UNIX epoch. Not provided for session cookies.
/// </summary>
public double? ExpirationDate { get; set; }
public double ExpirationDate { get; set; }
/// <summary>
/// Gets or sets the SameSite policy applied to this cookie. Can be "unspecified", "no_restriction", "lax" or "strict".

View File

@@ -29,16 +29,16 @@
/// <summary>
/// (optional) - Filters cookies by their Secure property.
/// </summary>
public bool? Secure { get; set; }
public bool Secure { get; set; }
/// <summary>
/// (optional) - Filters out session or persistent cookies.
/// </summary>
public bool? Session { get; set; }
public bool Session { get; set; }
/// <summary>
/// (optional) - Filters cookies by httpOnly.
/// </summary>
public bool? HttpOnly { get; set; }
public bool HttpOnly { get; set; }
}
}

View File

@@ -130,8 +130,11 @@ namespace ElectronNET.API
options.Height += 7;
}
if (!options.X.HasValue && !options.Y.HasValue)
if (options.X == -1 && options.Y == -1)
{
options.X = 0;
options.Y = 0;
await BridgeConnector.Socket.Emit("createBrowserWindow", options, loadUrl).ConfigureAwait(false);
}
else

View File

@@ -70,7 +70,7 @@
<ProjectReference Include="..\ElectronNET.API\ElectronNET.API.csproj" Condition="$(ElectronNetDevMode)" />
</ItemGroup>
<ItemGroup>
<PackageReference Include="ElectronNET.Core" Version="0.4.1" Condition="'$(ElectronNetDevMode)' != 'true'" />
<PackageReference Include="ElectronNET.Core" Version="0.4.0" Condition="'$(ElectronNetDevMode)' != 'true'" />
</ItemGroup>
<Import Project="..\ElectronNET\build\ElectronNET.Core.targets" Condition="$(ElectronNetDevMode)" />

View File

@@ -1,4 +1,4 @@
<Project Sdk="Microsoft.VisualStudio.JavaScript.Sdk/1.0.3864779">
<Project Sdk="Microsoft.VisualStudio.JavaScript.Sdk/1.0.4110890">
<ItemGroup>
<None Include=".vscode\tasks.json" />
</ItemGroup>

View File

@@ -112,12 +112,6 @@ module.exports = (socket, app) => {
electronSocket.emit("browserWindow-move" + id);
});
});
socket.on("register-browserWindow-bounds-changed", (id) => {
const window = getWindowById(id);
const cb = () => electronSocket.emit("browserWindow-bounds-changed" + id, window.getBounds());
window.on("resize", cb);
window.on("move", cb);
});
socket.on("register-browserWindow-moved", (id) => {
getWindowById(id).on("moved", () => {
electronSocket.emit("browserWindow-moved" + id);

File diff suppressed because one or more lines are too long

View File

@@ -139,13 +139,6 @@ export = (socket: Socket, app: Electron.App) => {
});
});
socket.on("register-browserWindow-bounds-changed", (id) => {
const window = getWindowById(id);
const cb = () => electronSocket.emit("browserWindow-bounds-changed" + id, window.getBounds());
window.on("resize", cb);
window.on("move", cb);
});
socket.on("register-browserWindow-moved", (id) => {
getWindowById(id).on("moved", () => {
electronSocket.emit("browserWindow-moved" + id);

View File

@@ -257,57 +257,5 @@ namespace ElectronNET.IntegrationTests.Tests
win.SetDocumentEdited(false);
}
[IntegrationFact]
public async Task BoundsChanged_event_fires_with_updated_bounds()
{
BrowserWindow window = null;
try
{
window = await Electron.WindowManager.CreateWindowAsync(
new BrowserWindowOptions { Show = false, Width = 300, Height = 200 },
"about:blank");
var tcs = new TaskCompletionSource<Rectangle>(TaskCreationOptions.RunContinuationsAsynchronously);
window.OnBoundsChanged += bounds => tcs.TrySetResult(bounds);
await Task.Delay(500.ms());
var target = new Rectangle { X = 25, Y = 35, Width = 420, Height = 310 };
window.SetBounds(target);
var completed = await Task.WhenAny(tcs.Task, Task.Delay(3.seconds()));
completed.Should().Be(tcs.Task);
var observed = await tcs.Task;
observed.Width.Should().Be(target.Width);
observed.Height.Should().Be(target.Height);
}
finally
{
window?.Destroy();
}
}
[IntegrationFact]
public async Task BoundsChanged_event_can_fire_on_resize_of_existing_window()
{
var win = this.MainWindow;
var tcs = new TaskCompletionSource<Rectangle>(TaskCreationOptions.RunContinuationsAsynchronously);
win.OnBoundsChanged += bounds => tcs.TrySetResult(bounds);
await Task.Delay(500.ms());
win.SetBounds(new Rectangle { X = 10, Y = 10, Width = 560, Height = 440 });
var completed = await Task.WhenAny(tcs.Task, Task.Delay(3.seconds()));
completed.Should().Be(tcs.Task);
var boundsObserved = await tcs.Task;
boundsObserved.Width.Should().Be(560);
boundsObserved.Height.Should().Be(440);
}
}
}

View File

@@ -27,8 +27,8 @@
</ItemGroup>
<ItemGroup>
<PackageReference Include="ElectronNET.Core" Version="0.4.1" Condition="'$(ElectronNetDevMode)' != 'true'" />
<PackageReference Include="ElectronNET.Core.AspNet" Version="0.4.1" Condition="'$(ElectronNetDevMode)' != 'true'" />
<PackageReference Include="ElectronNET.Core" Version="0.2.0" Condition="'$(ElectronNetDevMode)' != 'true'" />
<PackageReference Include="ElectronNET.Core.AspNet" Version="0.2.0" Condition="'$(ElectronNetDevMode)' != 'true'" />
<PackageReference Include="Microsoft.TypeScript.MSBuild" Version="5.9.3" />
</ItemGroup>

View File

@@ -76,8 +76,8 @@
<ProjectReference Include="..\ElectronNET.AspNet\ElectronNET.AspNet.csproj" Condition="$(ElectronNetDevMode)" />
</ItemGroup>
<ItemGroup>
<PackageReference Include="ElectronNET.Core" Version="0.4.1" Condition="'$(ElectronNetDevMode)' != 'true'" />
<PackageReference Include="ElectronNET.Core.AspNet" Version="0.4.1" Condition="'$(ElectronNetDevMode)' != 'true'" />
<PackageReference Include="ElectronNET.Core" Version="0.4.0" Condition="'$(ElectronNetDevMode)' != 'true'" />
<PackageReference Include="ElectronNET.Core.AspNet" Version="0.4.0" Condition="'$(ElectronNetDevMode)' != 'true'" />
<PackageReference Include="Microsoft.TypeScript.MSBuild" Version="5.9.3" />
</ItemGroup>

View File

@@ -522,7 +522,7 @@ For more information, see: https://github.com/ElectronNET/Electron.NET/wiki/Migr
<_NpxCmd Condition="'$(IsLinuxWsl)' == 'true'">wsl bash -ic '$(_NpxCmd)'</_NpxCmd>
</PropertyGroup>
<Exec Command="$(_NpxCmd)" WorkingDirectory="$(ElectronPublishDirFullPath)" Timeout="1800000" StandardOutputImportance="High" StandardErrorImportance="High" ContinueOnError="false" Condition="@(CopiedFiles->Count()) > 0">
<Exec Command="$(_NpxCmd)" WorkingDirectory="$(ElectronPublishDirFullPath)" Timeout="900000" StandardOutputImportance="High" StandardErrorImportance="High" ContinueOnError="false" Condition="@(CopiedFiles->Count()) > 0">
<Output TaskParameter="ExitCode" PropertyName="ExecExitCode"/>
</Exec>

View File

@@ -4,8 +4,6 @@
<PropertyGroup>
<ElectronMigrationChecksDependsOn>
ElectronCheckNoPackageJson;
ElectronCheckRootPackageJsonNoElectron;
ElectronCheckRootPackageJsonNotCopied;
ElectronCheckNoManifestJson;
ElectronCheckElectronBuilderJson;
ElectronCheckNoParentPaths;
@@ -21,17 +19,14 @@
</Target>
<!--
Check 1: No package.json/package-lock.json must be present in the project (except ElectronHostHook folder)
NOTE: Root package.json is excluded from ELECTRON001 and checked by separate targets.
Check 1: No package.json must be present in the project (except ElectronHostHook folder)
-->
<Target Name="ElectronCheckNoPackageJson">
<!-- Find all package.json files, excluding ElectronHostHook folder, root, and output directories -->
<!-- Find all package.json files, excluding ElectronHostHook folder and output directories -->
<ItemGroup>
<_InvalidPackageJson Include="$(MSBuildProjectDirectory)\**\package.json"
Exclude="$(MSBuildProjectDirectory)\package.json;
$(MSBuildProjectDirectory)\ElectronHostHook\**\package.json;
Exclude="$(MSBuildProjectDirectory)\ElectronHostHook\**\package.json;
$(MSBuildProjectDirectory)\bin\**\package.json;
$(MSBuildProjectDirectory)\obj\**\package.json;
$(MSBuildProjectDirectory)\publish\**\package.json;
@@ -51,87 +46,17 @@
<Warning Condition="'$(_HasInvalidPackageJson)' == 'true'"
Code="ELECTRON001"
Text="Found package.json or package-lock.json file(s) in unsupported location(s). These files are no longer supported in this location.
Text="Found package.json or package-lock.json file(s) in the project root or subdirectories. These files are no longer supported in this location.
Files found:
@(_InvalidPackageJson, '%0A')@(_InvalidPackageLockJson, '%0A')
MIGRATION REQUIRED:
All Electron.NET-related properties from an existing package.json must now be specified as MSBuild properties in the project file.
All properties from an existing package.json file must now be specified as MSBuild properties in the project file.
For more information, see: https://github.com/ElectronNET/Electron.NET/wiki/Migration-Checks#1-packagejson-not-allowed
EXCEPTION:
- package.json and package-lock.json files ARE allowed in the 'ElectronHostHook' folder for custom host hook implementations.
- A package.json in the project root is handled by separate migration checks." />
</Target>
<!--
Check 1b: Root package.json must not contain Electron-related configuration
-->
<Target Name="ElectronCheckRootPackageJsonNoElectron"
Condition="Exists('$(MSBuildProjectDirectory)\package.json')">
<ItemGroup>
<_RootPackageJsonLines Include="$([System.IO.File]::ReadAllLines('$(MSBuildProjectDirectory)\package.json'))" />
</ItemGroup>
<PropertyGroup>
<_RootPackageJsonContent>@(_RootPackageJsonLines, ' ')</_RootPackageJsonContent>
<_RootPackageJsonHasElectron>false</_RootPackageJsonHasElectron>
<_RootPackageJsonHasElectron Condition="$([System.Text.RegularExpressions.Regex]::IsMatch('$(_RootPackageJsonContent)', 'electron', System.Text.RegularExpressions.RegexOptions.IgnoreCase))">true</_RootPackageJsonHasElectron>
</PropertyGroup>
<Warning
Condition="'$(_RootPackageJsonHasElectron)' == 'true'"
Code="ELECTRON008"
Text="The project contains a root package.json that references 'electron' (case-insensitive).
File:
$(MSBuildProjectDirectory)\package.json
MIGRATION REQUIRED:
Electron.NET configuration must be defined via MSBuild properties and electron-builder.json (not via a user-provided package.json).
HOW TO FIX:
- Remove Electron-related entries from the root package.json, or delete the file if it's only used for Electron configuration.
For more information, see: https://github.com/ElectronNET/Electron.NET/wiki/Migration-Checks#1-packagejson-not-allowed" />
</Target>
<!--
Check 1c: Root package.json must not be copied to output/publish
-->
<Target Name="ElectronCheckRootPackageJsonNotCopied"
Condition="Exists('$(MSBuildProjectDirectory)\package.json')">
<ItemGroup>
<_RootPackageJsonFile Include="@(Content);@(None)"
Condition="'%(Identity)' == 'package.json' OR '%(Identity)' == '$(MSBuildProjectDirectory)\package.json'" />
</ItemGroup>
<PropertyGroup>
<_RootPackageJsonIsCopied>false</_RootPackageJsonIsCopied>
<_RootPackageJsonIsCopied Condition="'@(_RootPackageJsonFile)' != '' AND ( '%(_RootPackageJsonFile.CopyToOutputDirectory)' != '' OR '%(_RootPackageJsonFile.CopyToPublishDirectory)' != '' )">true</_RootPackageJsonIsCopied>
</PropertyGroup>
<Warning
Condition="'$(_RootPackageJsonIsCopied)' == 'true'"
Code="ELECTRON009"
Text="The project contains a root package.json that is configured to be copied to the output/publish directory.
File:
$(MSBuildProjectDirectory)\package.json
MIGRATION REQUIRED:
Root package.json must not be copied during build/publish.
HOW TO FIX:
- Remove CopyToOutputDirectory / CopyToPublishDirectory metadata for package.json in your project file.
For more information, see: https://github.com/ElectronNET/Electron.NET/wiki/Migration-Checks#1-packagejson-not-allowed" />
EXCEPTION: package.json and package-lock.json files ARE allowed in the 'ElectronHostHook' folder for custom host hook implementations." />
</Target>

View File

@@ -1,6 +1,6 @@
<Project>
<PropertyGroup>
<Version>0.4.1</Version>
<Version>0.4.0</Version>
<PackageNamePrefix>ElectronNET.Core</PackageNamePrefix>
<Authors>Gregor Biswanger, Florian Rappl, softworkz</Authors>
<Product>Electron.NET</Product>