diff --git a/NetworkResurrector.Abstractions/INotifier.cs b/NetworkResurrector.Abstractions/INotifier.cs
new file mode 100644
index 0000000..04d1f9e
--- /dev/null
+++ b/NetworkResurrector.Abstractions/INotifier.cs
@@ -0,0 +1,8 @@
+namespace NetworkResurrector.Abstractions
+{
+ public interface INotifier
+ {
+ void NotifyMessage(string message);
+ void NotifyError(string message);
+ }
+}
diff --git a/NetworkResurrector.Abstractions/IWakeOnLanService.cs b/NetworkResurrector.Abstractions/IWakeOnLanService.cs
new file mode 100644
index 0000000..3901008
--- /dev/null
+++ b/NetworkResurrector.Abstractions/IWakeOnLanService.cs
@@ -0,0 +1,9 @@
+using System.Threading.Tasks;
+
+namespace NetworkResurrector.Abstractions
+{
+ public interface IWakeOnLanService
+ {
+ Task<(bool success, string message)> Wake(string macAddress);
+ }
+}
diff --git a/NetworkResurrector.Abstractions/NetworkResurrector.Abstractions.csproj b/NetworkResurrector.Abstractions/NetworkResurrector.Abstractions.csproj
new file mode 100644
index 0000000..9f5c4f4
--- /dev/null
+++ b/NetworkResurrector.Abstractions/NetworkResurrector.Abstractions.csproj
@@ -0,0 +1,7 @@
+
+
+
+ netstandard2.0
+
+
+
diff --git a/NetworkResurrector.Api/Controllers/ResurrectorController.cs b/NetworkResurrector.Api/Controllers/ResurrectorController.cs
index 6bcc75b..e9160e0 100644
--- a/NetworkResurrector.Api/Controllers/ResurrectorController.cs
+++ b/NetworkResurrector.Api/Controllers/ResurrectorController.cs
@@ -1,6 +1,7 @@
using MediatR;
using Microsoft.AspNetCore.Authorization;
using Microsoft.AspNetCore.Mvc;
+using NetworkResurrector.Application.Commands;
using NetworkResurrector.Application.Queries;
using System.Threading.Tasks;
@@ -31,5 +32,12 @@ namespace NetworkResurrector.Api.Controllers
{
return Ok("Valid");
}
+
+ [HttpPost("wake")]
+ public async Task WakeMachine([FromBody] WakeMachine wakeMachine)
+ {
+ var result = await _mediator.Send(wakeMachine);
+ return Ok(result);
+ }
}
}
diff --git a/NetworkResurrector.Api/Extensions/WakeOnLanExtensions.cs b/NetworkResurrector.Api/Extensions/WakeOnLanExtensions.cs
new file mode 100644
index 0000000..ce7a454
--- /dev/null
+++ b/NetworkResurrector.Api/Extensions/WakeOnLanExtensions.cs
@@ -0,0 +1,14 @@
+using Microsoft.Extensions.Configuration;
+using Microsoft.Extensions.DependencyInjection;
+using NetworkResurrector.WakeOnLan;
+
+namespace NetworkResurrector.Api.Extensions
+{
+ public static class WakeOnLanExtensions
+ {
+ public static void AddWakeOnLan(this IServiceCollection services, IConfiguration configuration)
+ {
+ services.AddWakeOnLanService();
+ }
+ }
+}
diff --git a/NetworkResurrector.Api/NetworkResurrector.Api.csproj b/NetworkResurrector.Api/NetworkResurrector.Api.csproj
index 6f5a4b1..8105434 100644
--- a/NetworkResurrector.Api/NetworkResurrector.Api.csproj
+++ b/NetworkResurrector.Api/NetworkResurrector.Api.csproj
@@ -23,6 +23,7 @@
+
diff --git a/NetworkResurrector.Api/Startup.cs b/NetworkResurrector.Api/Startup.cs
index 81e9148..61bc16b 100644
--- a/NetworkResurrector.Api/Startup.cs
+++ b/NetworkResurrector.Api/Startup.cs
@@ -8,6 +8,7 @@ using Microsoft.Extensions.Configuration;
using Microsoft.Extensions.DependencyInjection;
using Microsoft.Extensions.Hosting;
using NetworkResurrector.Api.Authentication;
+using NetworkResurrector.Api.Extensions;
using NetworkResurrector.Api.Swagger;
using NetworkResurrector.Application;
using Newtonsoft.Json;
@@ -17,13 +18,13 @@ namespace NetworkResurrector.Api
{
public class Startup
{
+ private readonly IConfiguration _configuration;
+
public Startup(IConfiguration configuration)
{
- Configuration = configuration;
+ _configuration = configuration;
}
- public IConfiguration Configuration { get; }
-
// This method gets called by the runtime. Use this method to add services to the container.
public void ConfigureServices(IServiceCollection services)
{
@@ -48,6 +49,9 @@ namespace NetworkResurrector.Api
// Application
services.AddApplicationServices();
+
+ // WakeOnLan
+ services.AddWakeOnLan(_configuration);
}
// This method gets called by the runtime. Use this method to configure the HTTP request pipeline.
diff --git a/NetworkResurrector.Application/CommandHandlers/WakeMachineHandler.cs b/NetworkResurrector.Application/CommandHandlers/WakeMachineHandler.cs
new file mode 100644
index 0000000..397e26b
--- /dev/null
+++ b/NetworkResurrector.Application/CommandHandlers/WakeMachineHandler.cs
@@ -0,0 +1,38 @@
+using MediatR;
+using Microsoft.Extensions.Logging;
+using NetworkResurrector.Abstractions;
+using NetworkResurrector.Application.Commands;
+using NetworkResurrector.Application.Events;
+using System;
+using System.Threading;
+using System.Threading.Tasks;
+
+namespace NetworkResurrector.Application.CommandHandlers
+{
+ public class WakeMachineHandler : IRequestHandler
+ {
+ private readonly ILogger _logger;
+ private readonly IWakeOnLanService _wakeOnLanService;
+
+ public WakeMachineHandler(ILogger logger, IWakeOnLanService wakeOnLanService)
+ {
+ _logger = logger;
+ _wakeOnLanService = wakeOnLanService;
+ }
+
+ public async Task Handle(WakeMachine command, CancellationToken cancellationToken)
+ {
+ try
+ {
+ var (success, status) = await _wakeOnLanService.Wake(command.MacAddress);
+ return new MachineWaked(success, status);
+ }
+ catch (Exception ex)
+ {
+ var correlationIdMsg = $"CorrelationId: {command.Metadata.CorrelationId}";
+ _logger.LogError(ex, $"An unexpected error has occurred. {correlationIdMsg}");
+ return new MachineWaked(false, $"{ex.Message} {correlationIdMsg}");
+ }
+ }
+ }
+}
diff --git a/NetworkResurrector.Application/Commands/WakeMachine.cs b/NetworkResurrector.Application/Commands/WakeMachine.cs
new file mode 100644
index 0000000..2ace6a3
--- /dev/null
+++ b/NetworkResurrector.Application/Commands/WakeMachine.cs
@@ -0,0 +1,15 @@
+using NetworkResurrector.Application.Events;
+using System;
+
+namespace NetworkResurrector.Application.Commands
+{
+ public class WakeMachine : Command
+ {
+ public string MacAddress { get; set; }
+
+ public WakeMachine(string macAddress) : base(new Metadata() { CorrelationId = Guid.NewGuid() })
+ {
+ MacAddress = macAddress;
+ }
+ }
+}
\ No newline at end of file
diff --git a/NetworkResurrector.Application/Events/MachineWaked.cs b/NetworkResurrector.Application/Events/MachineWaked.cs
new file mode 100644
index 0000000..f249f9d
--- /dev/null
+++ b/NetworkResurrector.Application/Events/MachineWaked.cs
@@ -0,0 +1,14 @@
+namespace NetworkResurrector.Application.Events
+{
+ public class MachineWaked
+ {
+ public bool Success { get; }
+ public string Status { get; }
+
+ public MachineWaked(bool success, string status)
+ {
+ Success = success;
+ Status = status;
+ }
+ }
+}
diff --git a/NetworkResurrector.Application/NetworkResurrector.Application.csproj b/NetworkResurrector.Application/NetworkResurrector.Application.csproj
index dd8ca69..78e26c2 100644
--- a/NetworkResurrector.Application/NetworkResurrector.Application.csproj
+++ b/NetworkResurrector.Application/NetworkResurrector.Application.csproj
@@ -14,6 +14,7 @@
+
diff --git a/NetworkResurrector.WakeOnLan/DependencyInjectionExtensions.cs b/NetworkResurrector.WakeOnLan/DependencyInjectionExtensions.cs
new file mode 100644
index 0000000..87ea4fa
--- /dev/null
+++ b/NetworkResurrector.WakeOnLan/DependencyInjectionExtensions.cs
@@ -0,0 +1,14 @@
+using Microsoft.Extensions.DependencyInjection;
+using NetworkResurrector.Abstractions;
+
+namespace NetworkResurrector.WakeOnLan
+{
+ public static class DependencyInjectionExtensions
+ {
+ public static void AddWakeOnLanService(this IServiceCollection services)
+ {
+ services.AddScoped();
+ services.AddScoped();
+ }
+ }
+}
diff --git a/NetworkResurrector.WakeOnLan/NetworkResurrector.WakeOnLan.csproj b/NetworkResurrector.WakeOnLan/NetworkResurrector.WakeOnLan.csproj
new file mode 100644
index 0000000..a0dc859
--- /dev/null
+++ b/NetworkResurrector.WakeOnLan/NetworkResurrector.WakeOnLan.csproj
@@ -0,0 +1,16 @@
+
+
+
+ netstandard2.0
+
+
+
+
+
+
+
+
+
+
+
+
diff --git a/NetworkResurrector.WakeOnLan/WolClient.cs b/NetworkResurrector.WakeOnLan/WolClient.cs
new file mode 100644
index 0000000..b6c34f1
--- /dev/null
+++ b/NetworkResurrector.WakeOnLan/WolClient.cs
@@ -0,0 +1,45 @@
+using Microsoft.Extensions.Logging;
+using System;
+using System.Net.Sockets;
+
+namespace NetworkResurrector.WakeOnLan
+{
+ internal class WolClient : UdpClient
+ {
+ private readonly ILogger _logger;
+
+ ///
+ /// Initializes a new instance of .
+ ///
+ public WolClient(ILogger logger) : base()
+ {
+ _logger = logger;
+ }
+
+ ///
+ /// Sets up the UDP client to broadcast packets.
+ ///
+ /// if the UDP client is set in
+ /// broadcast mode.
+ public bool SetClientInBrodcastMode()
+ {
+ bool broadcast = false;
+ if (this.Active)
+ {
+ try
+ {
+ this.Client.SetSocketOption(SocketOptionLevel.Socket, SocketOptionName.Broadcast, 0);
+ _logger.LogInformation("WolClient => SetClientInBrodcastMode succedded.");
+ broadcast = true;
+ }
+ catch(Exception ex)
+ {
+ broadcast = false;
+ _logger.LogError("WolClient => SetClientInBrodcastMode failed.", ex);
+ }
+ }
+
+ return broadcast;
+ }
+ }
+}
diff --git a/NetworkResurrector.WakeOnLan/WolDriver.cs b/NetworkResurrector.WakeOnLan/WolDriver.cs
new file mode 100644
index 0000000..019bf63
--- /dev/null
+++ b/NetworkResurrector.WakeOnLan/WolDriver.cs
@@ -0,0 +1,92 @@
+using NetworkResurrector.Abstractions;
+using System.Globalization;
+using System.Net;
+using System.Text.RegularExpressions;
+using System.Threading.Tasks;
+
+namespace NetworkResurrector.WakeOnLan
+{
+ internal class WolDriver : IWakeOnLanService
+ {
+ private readonly WolClient _client;
+
+ public WolDriver(WolClient client)
+ {
+ _client = client;
+ }
+
+ public async Task<(bool success, string message)> Wake(string macAddress)
+ {
+ //remove all non 0-9, A-F, a-f characters
+ macAddress = Regex.Replace(macAddress, @"[^0-9A-Fa-f]", "");
+
+ //check if mac adress length is valid
+ if (macAddress.Length != 12)
+ return (false, "Invalid MAC address.");
+ else
+ return await Wakeup(macAddress);
+ }
+
+ #region Wakeup
+ ///
+ /// Wakes up the machine with the given .
+ ///
+ ///
+ ///
+ ///
+ ///
+ /// - The motherboard must support Wake On LAN.
+ /// - The NIC must support Wake On LAN.
+ /// - There must be a wire connecting the motherboard's WOL port to
+ /// the NIC's WOL port. Usually there always is a connection on most of
+ /// the PCs.
+ /// - The Wake On LAN feature must be enabled in the motherboard's
+ /// BIOS. Usually this is also enabled by default, but you might like to
+ /// check again.
+ /// - The "Good Connection" light on the back of the NIC must be lit
+ /// when the machine is off. (By default always good if you are not
+ /// facing any network issues)
+ /// - Port 12287 (0x2FFF) must be open. (By default it should be
+ /// open unless some antivirus or any other such program has changed
+ /// settings.)
+ /// - Packets cannot be broadcast across the Internet. That's why
+ /// it's called Wake On Lan, not Wake On Internet.
+ /// - To find your MAC address, run the MSINFO32.EXE tool that is a
+ /// part of Windows and navigate to Components > Network > Adapter
+ /// or simply type nbtstat -a <your hostname < at command prompt.
+ /// e.g. nbtstat -a mymachinename or nbtstat -A 10.2.100.213.
+ /// The MAC address of the host which has to be
+ /// woken up.
+ ///
+ private async Task<(bool success, string message)> Wakeup(string macAddress)
+ {
+ _client.Connect(new IPAddress(0xffffffff) /*255.255.255.255 i.e broadcast*/, 0x2fff /*port = 12287*/);
+
+ if (!_client.SetClientInBrodcastMode())
+ return (false, "Remote client could not be set in broadcast mode!");
+
+ int byteCount = 0;
+ byte[] bytes = new byte[102];
+
+ for (int trailer = 0; trailer < 6; trailer++)
+ {
+ bytes[byteCount++] = 0xFF;
+ }
+
+ for (int macPackets = 0; macPackets < 16; macPackets++)
+ {
+ int i = 0;
+ for (int macBytes = 0; macBytes < 6; macBytes++)
+ {
+ bytes[byteCount++] = byte.Parse(macAddress.Substring(i, 2), NumberStyles.HexNumber);
+ i += 2;
+ }
+ }
+
+ int returnValue = await _client.SendAsync(bytes, byteCount);
+
+ return (true, $"{returnValue} bytes sent to {macAddress}");
+ }
+ #endregion
+ }
+}
diff --git a/NetworkResurrector.sln b/NetworkResurrector.sln
index 3a84ceb..c47a381 100644
--- a/NetworkResurrector.sln
+++ b/NetworkResurrector.sln
@@ -13,9 +13,13 @@ Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "Solution Items", "Solution
Directory.Build.props = Directory.Build.props
EndProjectSection
EndProject
-Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "NetworkResurrector.Application", "NetworkResurrector.Application\NetworkResurrector.Application.csproj", "{15D65D65-CC96-45DE-8590-AF9132889D98}"
+Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "NetworkResurrector.Application", "NetworkResurrector.Application\NetworkResurrector.Application.csproj", "{15D65D65-CC96-45DE-8590-AF9132889D98}"
EndProject
-Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "NetworkResurrector.Domain", "NetworkResurrector.Domain\NetworkResurrector.Domain.csproj", "{EC78E88E-22DC-4FFD-881E-DEECF0D2494E}"
+Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "NetworkResurrector.Domain", "NetworkResurrector.Domain\NetworkResurrector.Domain.csproj", "{EC78E88E-22DC-4FFD-881E-DEECF0D2494E}"
+EndProject
+Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "NetworkResurrector.WakeOnLan", "NetworkResurrector.WakeOnLan\NetworkResurrector.WakeOnLan.csproj", "{A7B3FCE1-70F5-4EAE-A8FB-EF938AE1D105}"
+EndProject
+Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "NetworkResurrector.Abstractions", "NetworkResurrector.Abstractions\NetworkResurrector.Abstractions.csproj", "{B7408385-ED73-4ED3-9654-9AFF8CDFDA8D}"
EndProject
Global
GlobalSection(SolutionConfigurationPlatforms) = preSolution
@@ -35,6 +39,14 @@ Global
{EC78E88E-22DC-4FFD-881E-DEECF0D2494E}.Debug|Any CPU.Build.0 = Debug|Any CPU
{EC78E88E-22DC-4FFD-881E-DEECF0D2494E}.Release|Any CPU.ActiveCfg = Release|Any CPU
{EC78E88E-22DC-4FFD-881E-DEECF0D2494E}.Release|Any CPU.Build.0 = Release|Any CPU
+ {A7B3FCE1-70F5-4EAE-A8FB-EF938AE1D105}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
+ {A7B3FCE1-70F5-4EAE-A8FB-EF938AE1D105}.Debug|Any CPU.Build.0 = Debug|Any CPU
+ {A7B3FCE1-70F5-4EAE-A8FB-EF938AE1D105}.Release|Any CPU.ActiveCfg = Release|Any CPU
+ {A7B3FCE1-70F5-4EAE-A8FB-EF938AE1D105}.Release|Any CPU.Build.0 = Release|Any CPU
+ {B7408385-ED73-4ED3-9654-9AFF8CDFDA8D}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
+ {B7408385-ED73-4ED3-9654-9AFF8CDFDA8D}.Debug|Any CPU.Build.0 = Debug|Any CPU
+ {B7408385-ED73-4ED3-9654-9AFF8CDFDA8D}.Release|Any CPU.ActiveCfg = Release|Any CPU
+ {B7408385-ED73-4ED3-9654-9AFF8CDFDA8D}.Release|Any CPU.Build.0 = Release|Any CPU
EndGlobalSection
GlobalSection(SolutionProperties) = preSolution
HideSolutionNode = FALSE
diff --git a/dependencies.props b/dependencies.props
index 0bd60d6..40ace42 100644
--- a/dependencies.props
+++ b/dependencies.props
@@ -9,7 +9,5 @@
7.0.0
6.0.0
5.3.1
- 3.1.3
- 3.1.3
\ No newline at end of file