Skip to content

Commit 265dc0e

Browse files
committed
include stack traces when not in production
1 parent 035aede commit 265dc0e

File tree

7 files changed

+83
-49
lines changed

7 files changed

+83
-49
lines changed

src/JsonApiDotNetCore/Configuration/JsonApiOptions.cs

Lines changed: 10 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -10,6 +10,16 @@ namespace JsonApiDotNetCore.Configuration
1010
{
1111
public class JsonApiOptions
1212
{
13+
/// <summary>
14+
/// Whether or not stack traces should be serialized in Error objects
15+
/// </summary>
16+
public static bool DisableErrorStackTraces { get; set; }
17+
18+
/// <summary>
19+
/// Whether or not source URLs should be serialized in Error objects
20+
/// </summary>
21+
public static bool DisableErrorSource { get; set; }
22+
1323
public string Namespace { get; set; }
1424
public int DefaultPageSize { get; set; }
1525
public bool IncludeTotalRecordCount { get; set; }

src/JsonApiDotNetCore/Extensions/IApplicationBuilderExtensions.cs

Lines changed: 10 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,7 @@
1+
using JsonApiDotNetCore.Configuration;
12
using JsonApiDotNetCore.Middleware;
23
using Microsoft.AspNetCore.Builder;
4+
using Microsoft.AspNetCore.Hosting;
35

46
namespace JsonApiDotNetCore.Extensions
57
{
@@ -8,6 +10,14 @@ public static class IApplicationBuilderExtensions
810
{
911
public static IApplicationBuilder UseJsonApi(this IApplicationBuilder app, bool useMvc = true)
1012
{
13+
var environment = (IHostingEnvironment)app.ApplicationServices.GetService(typeof(IHostingEnvironment));
14+
15+
if(environment.IsProduction())
16+
{
17+
JsonApiOptions.DisableErrorStackTraces = true;
18+
JsonApiOptions.DisableErrorSource = true;
19+
}
20+
1121
app.UseMiddleware<RequestMiddleware>();
1222

1323
if (useMvc)

src/JsonApiDotNetCore/Formatters/JsonApiWriter.cs

Lines changed: 7 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -26,8 +26,6 @@ public async Task WriteAsync(OutputFormatterWriteContext context)
2626
if (context == null)
2727
throw new ArgumentNullException(nameof(context));
2828

29-
_logger?.LogInformation("Formatting response as JSONAPI");
30-
3129
var response = context.HttpContext.Response;
3230
using (var writer = context.WriterFactory(response.Body, Encoding.UTF8))
3331
{
@@ -40,9 +38,7 @@ public async Task WriteAsync(OutputFormatterWriteContext context)
4038
catch (Exception e)
4139
{
4240
_logger?.LogError(new EventId(), e, "An error ocurred while formatting the response");
43-
var errors = new ErrorCollection();
44-
errors.Add(new Error("400", e.Message));
45-
responseContent = errors.GetJson();
41+
responseContent = GetErrorResponse(e);
4642
response.StatusCode = 400;
4743
}
4844

@@ -51,9 +47,12 @@ public async Task WriteAsync(OutputFormatterWriteContext context)
5147
}
5248
}
5349

54-
private string GetResponseBody(object responseObject)
50+
private string GetResponseBody(object responseObject) => _serializer.Serialize(responseObject);
51+
private string GetErrorResponse(Exception e)
5552
{
56-
return _serializer.Serialize(responseObject);
57-
}
53+
var errors = new ErrorCollection();
54+
errors.Add(new Error(400, e.Message, ErrorMeta.FromException(e)));
55+
return errors.GetJson();
56+
}
5857
}
5958
}

src/JsonApiDotNetCore/Internal/Error.cs

Lines changed: 36 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,6 @@
11
using System;
2+
using System.Diagnostics;
3+
using JsonApiDotNetCore.Configuration;
24
using Newtonsoft.Json;
35

46
namespace JsonApiDotNetCore.Internal
@@ -8,30 +10,40 @@ public class Error
810
public Error()
911
{ }
1012

11-
public Error(string status, string title)
13+
[Obsolete("Use Error constructors with int typed status")]
14+
public Error(string status, string title, ErrorMeta meta = null, string source = null)
1215
{
1316
Status = status;
1417
Title = title;
18+
Meta = meta;
19+
Source = source;
1520
}
1621

17-
public Error(int status, string title)
22+
public Error(int status, string title, ErrorMeta meta = null, string source = null)
1823
{
1924
Status = status.ToString();
2025
Title = title;
26+
Meta = meta;
27+
Source = source;
2128
}
2229

23-
public Error(string status, string title, string detail)
30+
[Obsolete("Use Error constructors with int typed status")]
31+
public Error(string status, string title, string detail, ErrorMeta meta = null, string source = null)
2432
{
2533
Status = status;
2634
Title = title;
2735
Detail = detail;
36+
Meta = meta;
37+
Source = source;
2838
}
2939

30-
public Error(int status, string title, string detail)
40+
public Error(int status, string title, string detail, ErrorMeta meta = null, string source = null)
3141
{
3242
Status = status.ToString();
3343
Title = title;
3444
Detail = detail;
45+
Meta = meta;
46+
Source = source;
3547
}
3648

3749
[JsonProperty("title")]
@@ -45,5 +57,25 @@ public Error(int status, string title, string detail)
4557

4658
[JsonIgnore]
4759
public int StatusCode => int.Parse(Status);
60+
61+
[JsonProperty("source")]
62+
public string Source { get; set; }
63+
64+
[JsonProperty("meta")]
65+
public ErrorMeta Meta { get; set; }
66+
67+
public bool ShouldSerializeMeta() => (JsonApiOptions.DisableErrorStackTraces == false);
68+
public bool ShouldSerializeSource() => (JsonApiOptions.DisableErrorSource == false);
69+
}
70+
71+
public class ErrorMeta
72+
{
73+
[JsonProperty("stackTrace")]
74+
public string[] StackTrace { get; set; }
75+
76+
public static ErrorMeta FromException(Exception e)
77+
=> new ErrorMeta {
78+
StackTrace = e.Demystify().ToString().Split(new[] { "\n"}, int.MaxValue, StringSplitOptions.RemoveEmptyEntries)
79+
};
4880
}
4981
}

src/JsonApiDotNetCore/Internal/JsonApiException.cs

Lines changed: 13 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -13,30 +13,29 @@ public JsonApiException(ErrorCollection errorCollection)
1313
}
1414

1515
public JsonApiException(Error error)
16-
: base(error.Title)
17-
=> _errors.Add(error);
16+
: base(error.Title) => _errors.Add(error);
1817

1918
[Obsolete("Use int statusCode overload instead")]
20-
public JsonApiException(string statusCode, string message)
19+
public JsonApiException(string statusCode, string message, string source = null)
2120
: base(message)
22-
=> _errors.Add(new Error(statusCode, message, null));
21+
=> _errors.Add(new Error(statusCode, message, null, GetMeta(), source));
2322

2423
[Obsolete("Use int statusCode overload instead")]
25-
public JsonApiException(string statusCode, string message, string detail)
24+
public JsonApiException(string statusCode, string message, string detail, string source = null)
2625
: base(message)
27-
=> _errors.Add(new Error(statusCode, message, detail));
26+
=> _errors.Add(new Error(statusCode, message, detail, GetMeta(), source));
2827

29-
public JsonApiException(int statusCode, string message)
28+
public JsonApiException(int statusCode, string message, string source = null)
3029
: base(message)
31-
=> _errors.Add(new Error(statusCode, message, null));
30+
=> _errors.Add(new Error(statusCode, message, null, GetMeta(), source));
3231

33-
public JsonApiException(int statusCode, string message, string detail)
32+
public JsonApiException(int statusCode, string message, string detail, string source = null)
3433
: base(message)
35-
=> _errors.Add(new Error(statusCode, message, detail));
34+
=> _errors.Add(new Error(statusCode, message, detail, GetMeta(), source));
3635

3736
public JsonApiException(int statusCode, string message, Exception innerException)
3837
: base(message, innerException)
39-
=> _errors.Add(new Error(statusCode, message, innerException.Message));
38+
=> _errors.Add(new Error(statusCode, message, innerException.Message, GetMeta(innerException)));
4039

4140
public ErrorCollection GetError() => _errors;
4241

@@ -53,5 +52,8 @@ public int GetStatusCode()
5352

5453
return 500;
5554
}
55+
56+
private ErrorMeta GetMeta() => ErrorMeta.FromException(this);
57+
private ErrorMeta GetMeta(Exception e) => ErrorMeta.FromException(e);
5658
}
5759
}
Lines changed: 5 additions & 24 deletions
Original file line numberDiff line numberDiff line change
@@ -1,36 +1,17 @@
11
using System;
2-
using System.Linq;
32

43
namespace JsonApiDotNetCore.Internal
54
{
65
public static class JsonApiExceptionFactory
76
{
8-
private const string JsonApiException = nameof(JsonApiException);
9-
private const string InvalidCastException = nameof(InvalidCastException);
10-
117
public static JsonApiException GetException(Exception exception)
128
{
13-
var exceptionType = exception.GetType().ToString().Split('.').Last();
14-
switch(exceptionType)
15-
{
16-
case JsonApiException:
17-
return (JsonApiException)exception;
18-
case InvalidCastException:
19-
return new JsonApiException(409, exception.Message);
20-
default:
21-
return new JsonApiException(500, exception.Message, GetExceptionDetail(exception.InnerException));
22-
}
23-
}
9+
var exceptionType = exception.GetType();
2410

25-
private static string GetExceptionDetail(Exception exception)
26-
{
27-
string detail = null;
28-
while(exception != null)
29-
{
30-
detail = $"{detail}{exception.Message}; ";
31-
exception = exception.InnerException;
32-
}
33-
return detail;
11+
if(exceptionType == typeof(JsonApiException))
12+
return (JsonApiException)exception;
13+
14+
return new JsonApiException(500, exceptionType.Name, exception);
3415
}
3516
}
3617
}

src/JsonApiDotNetCore/JsonApiDotNetCore.csproj

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -15,11 +15,11 @@
1515
<RepositoryUrl>https://github.com/json-api-dotnet/JsonApiDotNetCore</RepositoryUrl>
1616
</PropertyGroup>
1717
<ItemGroup>
18+
<PackageReference Include="Ben.Demystifier" Version="0.1.0" />
1819
<PackageReference Include="Microsoft.AspNetCore.Routing" Version="$(AspNetCoreVersion)" />
1920
<PackageReference Include="Microsoft.AspNetCore.Mvc" Version="$(AspNetCoreVersion)" />
2021
<PackageReference Include="Microsoft.EntityFrameworkCore" Version="$(EFCoreVersion)" />
2122
<PackageReference Include="Microsoft.Extensions.Logging" Version="$(MicrosoftLoggingVersion)" />
2223
<PackageReference Include="System.ValueTuple" Version="$(TuplesVersion)" />
2324
</ItemGroup>
24-
25-
</Project>
25+
</Project>

0 commit comments

Comments
 (0)