Skip to content

Commit

Permalink
Added exception handling
Browse files Browse the repository at this point in the history
  • Loading branch information
whyvra committed Dec 26, 2020
1 parent 9e876b4 commit d831df1
Show file tree
Hide file tree
Showing 27 changed files with 376 additions and 71 deletions.
5 changes: 4 additions & 1 deletion .gitignore
Original file line number Diff line number Diff line change
Expand Up @@ -236,4 +236,7 @@ _Pvt_Extensions
.fake/

# SQLite database
*.sqlite3
*.sqlite3

# .NET Core logging
logs/
21 changes: 17 additions & 4 deletions Whyvra.Tunnel.Api/Filters/HttpExceptionFilter.cs
Original file line number Diff line number Diff line change
@@ -1,6 +1,7 @@
using System;
using Microsoft.AspNetCore.Mvc;
using Microsoft.AspNetCore.Mvc.Filters;
using Whyvra.Tunnel.Common.Models;

namespace Whyvra.Tunnel.Api.Filters
{
Expand All @@ -10,21 +11,33 @@ public void OnException(ExceptionContext context)
{
if (context.Exception.GetType() == typeof(NullReferenceException))
{
var error = new {message = context.Exception.Message, status = "Not Found", statusCode = 404};
var error = new ApiMessage {Message = context.Exception.Message, Status = "Not Found", StatusCode = 404};
context.Result = new JsonResult(error)
{
StatusCode = 404
};
}

if (context.Exception.GetType() == typeof(ArgumentException))
else if (context.Exception.GetType() == typeof(ArgumentException))
{
var error = new {message = context.Exception.Message, status = "Bad Request", statusCode = 400};
var error = new ApiMessage {Message = context.Exception.Message, Status = "Bad Request", StatusCode = 400};
context.Result = new JsonResult(error)
{
StatusCode = 400
};
}
else
{
var error = new ApiMessage {Message = context.Exception.Message, Status = "Inner Server Error", StatusCode = 500};
if (context.Exception.InnerException != null)
{
error.InnerException = context.Exception.InnerException.Message;
}

context.Result = new JsonResult(error)
{
StatusCode = 500
};
}
}
}
}
11 changes: 10 additions & 1 deletion Whyvra.Tunnel.Api/Program.cs
Original file line number Diff line number Diff line change
@@ -1,5 +1,7 @@
using System;
using Microsoft.AspNetCore.Hosting;
using Microsoft.Extensions.Hosting;
using Serilog;

namespace Whyvra.Tunnel.Api
{
Expand All @@ -12,6 +14,13 @@ public static void Main(string[] args)

public static IHostBuilder CreateHostBuilder(string[] args) =>
Host.CreateDefaultBuilder(args)
.ConfigureWebHostDefaults(webBuilder => webBuilder.UseStartup<Startup>());
.ConfigureWebHostDefaults(webBuilder => webBuilder
.UseSerilog((context, loggerConfiguration) =>
loggerConfiguration
.ReadFrom.Configuration(context.Configuration)
.Enrich.WithProperty("MachineName", Environment.MachineName)
)
.UseStartup<Startup>()
);
}
}
1 change: 1 addition & 0 deletions Whyvra.Tunnel.Api/Whyvra.Tunnel.Api.csproj
Original file line number Diff line number Diff line change
Expand Up @@ -13,6 +13,7 @@
<ItemGroup>
<PackageReference Include="FluentValidation.AspNetCore" Version="9.2.0" />
<PackageReference Include="Microsoft.AspNetCore.Authentication.JwtBearer" Version="3.1.9" />
<PackageReference Include="Serilog.AspNetCore" Version="3.4.0" />
<PackageReference Include="Swashbuckle.AspNetCore" Version="5.6.3" />
</ItemGroup>

Expand Down
29 changes: 25 additions & 4 deletions Whyvra.Tunnel.Api/appsettings.json
Original file line number Diff line number Diff line change
@@ -1,9 +1,30 @@
{
"Logging": {
"LogLevel": {
"Serilog": {
"Using": [ "Serilog.Sinks.Console", "Serilog.Sinks.File" ],
"MinimumLevel": {
"Default": "Information",
"Microsoft": "Warning",
"Microsoft.Hosting.Lifetime": "Information"
"Override": {
"Microsoft": "Warning",
"Microsoft.EntityFrameworkCore.Database.Command": "Warning",
"Microsoft.Hosting.Lifetime": "Information",
"System": "Warning"
}
},
"WriteTo": [
{ "Name": "Console" },
{
"Name": "File",
"Args": {
"formatter": "Serilog.Formatting.Compact.RenderedCompactJsonFormatter, Serilog.Formatting.Compact",
"path": "logs/api_log_.json",
"retainedFileCountLimit": 7,
"rollingInterval": "Day"
}
}
],
"Enrich": [ "FromLogContext" ],
"Properties": {
"Application": "Tunnel API"
}
},
"AllowedHosts": "*",
Expand Down
13 changes: 13 additions & 0 deletions Whyvra.Tunnel.Common/Models/ApiMessage.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,13 @@
namespace Whyvra.Tunnel.Common.Models
{
public class ApiMessage
{
public string InnerException { get; set; }

public string Message { get; set; }

public string Status { get; set; }

public int StatusCode { get; set; }
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -36,7 +36,7 @@ public async Task<int> Handle(CreateClientCommand command, CancellationToken can

var addresses = await _context.Clients
.AsNoTracking()
.Where(x => x.ServerId == command.ServerId && !x.IsRevoked)
.Where(x => x.ServerId == command.ServerId)
.Select(x => x.AssignedIp.addr)
.ToListAsync();

Expand Down
2 changes: 1 addition & 1 deletion Whyvra.Tunnel.Presentation/Components/Notification.razor
Original file line number Diff line number Diff line change
Expand Up @@ -8,7 +8,7 @@
</span>
</div>
<div class="level-item">
@NotificationDto.Message
@((MarkupString) NotificationDto.Message)
</div>
</div>
</div>
Expand Down
2 changes: 2 additions & 0 deletions Whyvra.Tunnel.Presentation/Components/NotificationDto.cs
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,8 @@ public class NotificationDto

public string IconCss { get; set; }

public bool IsVisible { get; set; }

public string Message { get; set; }

public string Severity { get; set; }
Expand Down
32 changes: 32 additions & 0 deletions Whyvra.Tunnel.Presentation/Configuration/TunnelException.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,32 @@
using System;
using Whyvra.Tunnel.Common.Models;

namespace Whyvra.Tunnel.Presentation.Configuration
{
public class TunnelException : Exception
{
private readonly string _formattedMessage;

public TunnelException() : base()
{
}

public TunnelException(string message) : base(message)
{
}

public TunnelException(string message, string formattedMessage, ApiMessage apiMessage) : base(message)
{
ApiMessage = apiMessage;
_formattedMessage = formattedMessage;
}

public TunnelException(string message, Exception innerException) : base(message, innerException)
{
}

public ApiMessage ApiMessage { get; }

public string FormattedMessage => _formattedMessage ?? Message;
}
}
14 changes: 14 additions & 0 deletions Whyvra.Tunnel.Presentation/Logging/ExceptionHandler.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,14 @@
using System;

namespace Whyvra.Tunnel.Presentation.Logging
{
public class ExceptionHandler : IExceptionHandler
{
public event EventHandler<Exception> OnUnhandledException;

public void Handle(Exception e)
{
OnUnhandledException?.Invoke(this, e);
}
}
}
38 changes: 38 additions & 0 deletions Whyvra.Tunnel.Presentation/Logging/ExceptionLogger.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,38 @@
using System;
using Microsoft.Extensions.Logging;

namespace Whyvra.Tunnel.Presentation.Logging
{
public class ExceptionLogger : ILogger
{
private readonly IExceptionHandler _handler;

public ExceptionLogger(IExceptionHandler handler)
{
_handler = handler;
}

public IDisposable BeginScope<TState>(TState state)
{
return new NoopDisposable();
}

public bool IsEnabled(LogLevel logLevel)
{
return true;
}

public void Log<TState>(LogLevel logLevel, EventId eventId, TState state, Exception exception, Func<TState, Exception, string> formatter)
{
if (exception == null) return;
_handler.Handle(exception);
}

private class NoopDisposable : IDisposable
{
public void Dispose()
{
}
}
}
}
23 changes: 23 additions & 0 deletions Whyvra.Tunnel.Presentation/Logging/ExceptionLoggerProvider.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,23 @@
using Microsoft.Extensions.Logging;

namespace Whyvra.Tunnel.Presentation.Logging
{
public class ExceptionLoggerProvider : ILoggerProvider
{
private readonly IExceptionHandler _handler;

public ExceptionLoggerProvider(IExceptionHandler handler)
{
_handler = handler;
}

public ILogger CreateLogger(string categoryName)
{
return new ExceptionLogger(_handler);
}

public void Dispose()
{
}
}
}
11 changes: 11 additions & 0 deletions Whyvra.Tunnel.Presentation/Logging/IExceptionHandler.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,11 @@
using System;

namespace Whyvra.Tunnel.Presentation.Logging
{
public interface IExceptionHandler
{
event EventHandler<Exception> OnUnhandledException;

void Handle(Exception e);
}
}
30 changes: 24 additions & 6 deletions Whyvra.Tunnel.Presentation/Pages/Server.razor
Original file line number Diff line number Diff line change
Expand Up @@ -107,9 +107,9 @@
{
<Modal Icon="server" IconCss="has-text-info" Title="Server configuration" OnClose="@(() => _showServerConfig = false)">
<ChildContent>
@if (_isNotificationVisible)
@if (_notification.IsVisible)
{
<Notification NotificationDto="@_notification" OnClose="@(() => _isNotificationVisible = false)"></Notification>
<Notification NotificationDto="@_notification" OnClose="@(() => _notification.IsVisible = false)"></Notification>
}
<pre class="codeblock">
<code class="language-ini">@_serverConfig</code>
Expand All @@ -132,14 +132,25 @@
</Modal>
}
}
else if (_notFound)
{
<div class="subtitle has-text-centered">
<div>
<span class="icon is-large">
<i class="fas fa-times-circle fa-3x"></i>
</span>
</div>
Looks like there is nothing here.
</div>
}

@code
{
private int? _clientId = null;
private bool _isLoading;
private bool _isNotificationVisible;
private bool _isRevokedShowing;
private NotificationDto _notification;
private bool _notFound;
private NotificationDto _notification = new NotificationDto();
private string _serverConfig;
private bool _showPopup;
private bool _showServerConfig;
Expand All @@ -151,7 +162,14 @@

protected override async Task OnInitializedAsync()
{
_server = await ServerService.Get(ServerId);
try {
_server = await ServerService.Get(ServerId);
}
catch (TunnelException e)
{
if (e.ApiMessage.StatusCode == 404) _notFound = true;
else throw e;
}
}

protected override async Task OnAfterRenderAsync(bool firstRender)
Expand Down Expand Up @@ -185,7 +203,7 @@
Message = "Copied to clipboard! Don't forget to swap the server's private key.",
Severity = "info"
};
_isNotificationVisible = true;
_notification.IsVisible = true;
}

private async Task GetRevoked()
Expand Down
Loading

0 comments on commit d831df1

Please sign in to comment.