Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Fix dependency-injection problems #30

Merged
merged 16 commits into from
Feb 25, 2018
27 changes: 17 additions & 10 deletions src/Pidget.AspNet/SentryMiddleware.cs
Original file line number Diff line number Diff line change
Expand Up @@ -7,29 +7,36 @@
using System.Threading.Tasks;
using Pidget.Client.DataModels;

using static System.DateTimeOffset;

namespace Pidget.AspNet
{
public class SentryMiddleware
{
public SentryOptions Options { get; }

private readonly RateLimit _rateLimit;

private readonly RequestDelegate _next;

private readonly SentryClient _sentryClient;

private readonly RateLimit _rateLimit;

public SentryMiddleware(RequestDelegate next,
IOptions<SentryOptions> optionsAccessor,
IConfigureOptions<SentryOptions> optionSetup,
SentryClient sentryClient,
RateLimit rateLimit)
{
_next = next;
_sentryClient = sentryClient;
_rateLimit = rateLimit;
Options = optionsAccessor.Value;
Options = GetOptions(optionSetup);
}

private SentryOptions GetOptions(IConfigureOptions<SentryOptions> optionSetup)
{
var options = new SentryOptions();

optionSetup.Configure(options);

return options;
}

public async Task Invoke(HttpContext http)
Expand All @@ -42,7 +49,7 @@ public async Task Invoke(HttpContext http)
{
await CaptureAsync(ex, http);

SilentlyRethrow(ex);
ForwardException(ex);
}
}

Expand All @@ -62,7 +69,7 @@ private async Task CaptureAsync(Exception ex, HttpContext http)

private async Task<SentryResponse> SendEventAsync(SentryEventData eventData)
{
if (_rateLimit.IsHit(UtcNow))
if (_rateLimit.IsHit(DateTimeOffset.UtcNow))
{
return null;
}
Expand All @@ -89,7 +96,7 @@ private SentryEventBuilder BuildEventData(Exception ex, HttpContext http)
.SetRequestData(GetRequestData(http.Request));

private UserData GetUserData(HttpContext http)
=> UserDataProvider.Default.GetUserData(http);
=> UserDataProvider.GetUserData(http);

private RequestData GetRequestData(HttpRequest req)
{
Expand All @@ -103,7 +110,7 @@ private RequestData GetRequestData(HttpRequest req)
/// Re-throws the provided exception without adding to the stack trace.
/// </summary>
/// <param name="ex">The exception to re-throw.</param>
private static void SilentlyRethrow(Exception ex)
private static void ForwardException(Exception ex)
=> ExceptionDispatchInfo.Capture(ex).Throw();
}
}
16 changes: 13 additions & 3 deletions src/Pidget.AspNet/Setup/ClientFactory.cs
Original file line number Diff line number Diff line change
Expand Up @@ -9,10 +9,20 @@ public static class ClientFactory
{
public static SentryClient CreateClient(IServiceProvider serviceProvider)
{
var optionsAccessor = serviceProvider
.GetRequiredService<IOptions<SentryOptions>>();
var options = GetOptions(serviceProvider);

return Sentry.CreateClient(GetDsn(optionsAccessor.Value));
return Sentry.CreateClient(GetDsn(options));
}

private static SentryOptions GetOptions(IServiceProvider provider)
{
var options = new SentryOptions();
var setup = provider
.GetRequiredService<IConfigureOptions<SentryOptions>>();

setup.Configure(options);

return options;
}

private static Dsn GetDsn(SentryOptions options)
Expand Down
14 changes: 10 additions & 4 deletions src/Pidget.AspNet/Setup/SetupExtensions.cs
Original file line number Diff line number Diff line change
Expand Up @@ -11,10 +11,16 @@ public static class SetupExtensions
public static IServiceCollection AddPidgetMiddleware(
this IServiceCollection services,
IConfiguration configuration,
Action<CallbackSetup> setupCallbacks = null)
=> AddPidgetMiddleware(services, configuration.Bind)
.Configure<SentryOptions>(opts
=> setupCallbacks(new CallbackSetup(opts)));
Action<CallbackSetup> callbackSetup = null)
=> AddPidgetMiddleware(services, opts =>
{
configuration.Bind(opts);

if (callbackSetup != null)
{
callbackSetup(new CallbackSetup(opts));
}
});

public static IServiceCollection AddPidgetMiddleware(
this IServiceCollection services,
Expand Down
43 changes: 12 additions & 31 deletions src/Pidget.AspNet/UserDataProvider.cs
Original file line number Diff line number Diff line change
@@ -1,56 +1,37 @@
using Microsoft.AspNetCore.Http;
using Pidget.Client.DataModels;
using System;
using System.Security.Claims;

namespace Pidget.AspNet
{
public class UserDataProvider
public static class UserDataProvider
{
public static UserDataProvider Default { get; }
= new UserDataProvider();

public UserData GetUserData(HttpContext http)
{
AssertContextNotNull(http);

var user = http.User == null
? new UserData()
: new UserData
public static UserData GetUserData(HttpContext http)
=> http.User != null
? new UserData
{
Id = GetId(http.User),
UserName = GetUserName(http.User),
Email = GetEmail(http.User),
};

user.IpAddress = GetIpAddress(http);

return user;
}

private void AssertContextNotNull(HttpContext context)
{
if (context == null)
{
throw new ArgumentNullException(nameof(context));
}
}
IpAddress = GetIpAddress(http)
}
: null;

public string GetUserName(ClaimsPrincipal user)
public static string GetUserName(ClaimsPrincipal user)
=> user.Identity?.Name
?? user.FindFirst(ClaimTypes.Name)?.Value;

public string GetEmail(ClaimsPrincipal user)
public static string GetEmail(ClaimsPrincipal user)
=> user.FindFirst(ClaimTypes.Email)?.Value;

public string GetId(ClaimsPrincipal user)
public static string GetId(ClaimsPrincipal user)
=> user.FindFirst(ClaimTypes.NameIdentifier)?.Value;

public string GetIpAddress(HttpContext http)
public static string GetIpAddress(HttpContext http)
=> GetXForwardedFor(http.Request)
?? http.Connection?.RemoteIpAddress?.ToString();

private string GetXForwardedFor(HttpRequest req)
private static string GetXForwardedFor(HttpRequest req)
{
req.Headers?.TryGetValue("X-Forwarded-For",
out var forwardedFor);
Expand Down
11 changes: 6 additions & 5 deletions src/Pidget.Client/Http/SentryHttpClient.cs
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,7 @@
using System.IO;
using System.Net.Http;
using System.Threading.Tasks;
using System.Collections.Generic;

using static System.Threading.CancellationToken;

Expand Down Expand Up @@ -86,17 +87,17 @@ private HttpRequestMessage ComposeMessage(Stream stream)
var message = new HttpRequestMessage(HttpMethod.Post,
Dsn.GetCaptureUrl());

AddSentryAuthHeader(message);
message.Headers.Add(SentryAuthHeader.Name,
GetSentryAuthHeader());

message.Content = GetContent(stream);

return message;
}

private void AddSentryAuthHeader(HttpRequestMessage message)
=> message.Headers.Add(SentryAuthHeader.Name,
SentryAuthHeader.GetValues(
SentryAuth.Issue(this, DateTimeOffset.Now)));
private IEnumerable<string> GetSentryAuthHeader()
=> SentryAuthHeader.GetValues(
SentryAuth.Issue(this, DateTimeOffset.Now));

private static StreamContent GetContent(Stream stream)
{
Expand Down
3 changes: 2 additions & 1 deletion src/Pidget.Client/SentryClient.cs
Original file line number Diff line number Diff line change
Expand Up @@ -8,7 +8,8 @@ public abstract class SentryClient
{
public const string Name = "pidget";

public static string Version => VersionNumber.Get();
public static string Version { get; }
= VersionNumber.Get();

public Dsn Dsn { get; }

Expand Down
2 changes: 1 addition & 1 deletion src/Pidget.Client/Serialization/JsonStreamSerializer.cs
Original file line number Diff line number Diff line change
Expand Up @@ -22,7 +22,7 @@ public JsonStreamSerializer(Encoding encoding,

public Stream Serialize(object item)
{
var stream = new MemoryStream(256);
var stream = new MemoryStream(BufferSize);

using (var writer = CreateWriter(stream))
{
Expand Down
5 changes: 0 additions & 5 deletions src/Pidget.Client/VersionNumber.cs
Original file line number Diff line number Diff line change
Expand Up @@ -5,12 +5,7 @@ namespace Pidget.Client
{
internal static class VersionNumber
{
private static string _versionNumber;

public static string Get()
=> (_versionNumber ?? (_versionNumber = GetProductVersion()));

private static string GetProductVersion()
=> FileVersionInfo.GetVersionInfo(
Assembly.GetExecutingAssembly().Location).ProductVersion;
}
Expand Down
1 change: 1 addition & 0 deletions test/Pidget.AspNet.Test/Pidget.AspNet.Test.csproj
Original file line number Diff line number Diff line change
Expand Up @@ -10,6 +10,7 @@
<PackageReference Include="Moq" Version="4.7.142" />
<PackageReference Include="xunit" Version="2.2.0" />
<PackageReference Include="xunit.runner.visualstudio" Version="2.2.0" />
<PackageReference Include="Microsoft.Extensions.DependencyInjection" Version="2.0.0" />
</ItemGroup>

<ItemGroup>
Expand Down
17 changes: 10 additions & 7 deletions test/Pidget.AspNet.Test/SentryMiddlewareTests.cs
Original file line number Diff line number Diff line change
Expand Up @@ -21,7 +21,7 @@ public class SentryMiddlewareTests

public RequestDelegate Next_Noop = _ => Task.CompletedTask;

public SentryOptions ExceptionReportingOptions
public SentryOptions SentryOptions
= new SentryOptions
{
Dsn = "https://PUBLIC:SECRET@sentry.io/PROJECT_ID"
Expand All @@ -31,7 +31,7 @@ public SentryOptions ExceptionReportingOptions
public async Task SuccessfulInvoke_DoesNotSend()
{
var clientMock = new Mock<SentryClient>(
Dsn.Create(ExceptionReportingOptions.Dsn));
Dsn.Create(SentryOptions.Dsn));

var middleware = CreateMiddleware(Next_Noop, clientMock.Object);

Expand All @@ -54,7 +54,7 @@ public async Task CapturesExceptionOnInvokation(string eventId)
.Returns(reqMock.Object);

var clientMock = new Mock<SentryClient>(
Dsn.Create(ExceptionReportingOptions.Dsn));
Dsn.Create(SentryOptions.Dsn));

clientMock.Setup(c => c.SendEventAsync(It.IsAny<SentryEventData>()))
.ReturnsAsync(new SentryResponse { EventId = eventId })
Expand Down Expand Up @@ -96,7 +96,7 @@ public async Task CapturesRequestData(string eventId,
.Returns(reqMock.Object);

var clientMock = new Mock<SentryClient>(
Dsn.Create(ExceptionReportingOptions.Dsn));
Dsn.Create(SentryOptions.Dsn));

clientMock.Setup(c => c.SendEventAsync(It.Is<SentryEventData>(r
=> r.Request.Url == url.Split('?', StringSplitOptions.None)[0]
Expand Down Expand Up @@ -153,7 +153,7 @@ public async Task CapturesUserData(string eventId,
.Returns(reqMock.Object);

var clientMock = new Mock<SentryClient>(
Dsn.Create(ExceptionReportingOptions.Dsn));
Dsn.Create(SentryOptions.Dsn));

clientMock.Setup(c => c.SendEventAsync(It.Is<SentryEventData>(r
=> r.User.Id == userId
Expand Down Expand Up @@ -185,7 +185,7 @@ public async Task Honors429RetryAfter()
.Returns(reqMock.Object);

var clientMock = new Mock<SentryClient>(
Dsn.Create(ExceptionReportingOptions.Dsn));
Dsn.Create(SentryOptions.Dsn));

const int retryAfterMs = 500;

Expand Down Expand Up @@ -234,7 +234,10 @@ await Assert.ThrowsAsync<InvalidOperationException>(
public SentryMiddleware CreateMiddleware(RequestDelegate next,
SentryClient client)
=> new SentryMiddleware(next,
Options.Create(ExceptionReportingOptions),
new ConfigureOptions<SentryOptions>(opts =>
{
opts.Dsn = SentryOptions.Dsn;
}),
client,
new RateLimit());
}
Expand Down
Loading