Skip to content

Instantly share code, notes, and snippets.

@xt0rted
Created August 30, 2018 07:58
Show Gist options
  • Save xt0rted/d820b4fc43fec9b7e4ca71239c612391 to your computer and use it in GitHub Desktop.
Save xt0rted/d820b4fc43fec9b7e4ca71239c612391 to your computer and use it in GitHub Desktop.
ASP.NET Core tag helper for Sentry
namespace Website.TagHelpers
{
using System.Security.Claims;
using System.Text;
using System.Text.Encodings.Web;
using Microsoft.AspNetCore.Mvc.Rendering;
using Microsoft.AspNetCore.Mvc.ViewFeatures;
using Microsoft.AspNetCore.Razor.TagHelpers;
using Microsoft.Extensions.Options;
using Sentry;
using Sentry.AspNetCore;
[HtmlTargetElement("head")]
public class SentryTagHelper : TagHelper
{
// ToDo: try to get this added to SentryAspNetCoreOptions so it can be easily injected
private const string SentryVersion = "3.26.4";
private readonly IHtmlHelper _htmlHelper;
private readonly IHub _sentry;
private readonly JavaScriptEncoder _encoder;
private readonly SentryAspNetCoreOptions _settings;
public SentryTagHelper(
IHtmlHelper htmlHelper,
IHub sentry,
JavaScriptEncoder encoder,
IOptions<SentryAspNetCoreOptions> settings)
{
_htmlHelper = htmlHelper ?? throw new ArgumentNullException(nameof(htmlHelper));
_sentry = sentry ?? throw new ArgumentNullException(nameof(sentry));
_encoder = encoder ?? throw new ArgumentNullException(nameof(encoder));
_settings = settings?.Value ?? throw new ArgumentNullException(nameof(settings));
}
public override int Order => 1;
[ViewContext]
public ViewContext ViewContext { get; set; }
public override void Process(TagHelperContext context, TagHelperOutput output)
{
if (!_sentry.IsEnabled)
{
return;
}
((IViewContextAware) _htmlHelper).Contextualize(ViewContext);
var js = new StringBuilder();
js.AppendLine("window.SENTRY_SDK = {");
js.AppendFormat(" url: 'https://cdn.ravenjs.com/{0}/raven.min.js',", _encoder.Encode(SentryVersion)).AppendLine();
js.AppendFormat(" dsn: '{0}',", _encoder.Encode(_settings.Dsn)).AppendLine();
js.AppendLine(" options: {");
js.AppendFormat(" environment: '{0}',", _encoder.Encode(_settings.Environment ?? string.Empty)).AppendLine();
js.AppendFormat(" release: '{0}'", _encoder.Encode(_settings.Release ?? string.Empty)).AppendLine();
js.AppendLine(" }");
if (ViewContext.HttpContext?.User?.Identity is ClaimsIdentity identity && identity.IsAuthenticated)
{
var email = identity.FindFirst(ClaimTypes.Email)?.Value;
var firstName = identity.FindFirst(ClaimTypes.GivenName)?.Value;
var lastName = identity.FindFirst(ClaimTypes.Surname)?.Value;
js.AppendLine(" , setup: function() {");
js.AppendLine(" Raven.setUserContext({");
js.AppendFormat(" id: '{0}',", _encoder.Encode(identity.Name));
js.AppendFormat(" username: '{0}',", _encoder.Encode($"{firstName} {lastName}"));
js.AppendFormat(" email: '{0}'", _encoder.Encode(email));
js.Append(" });");
js.Append(" }");
}
js.AppendLine("};");
// This MUST be added immediately after the .install() call: 'undefined'!=typeof k.setup&&k.setup();
js.AppendLine("(function(a,b,g,e,h){var k=a.SENTRY_SDK,f=function(a){f.data.push(a)};f.data=[];var l=a[e];a[e]=function(c,b,e,d,h){f({e:[].slice.call(arguments)});l&&l.apply(a,arguments)};var m=a[h];a[h]=function(c){f({p:c.reason});m&&m.apply(a,arguments)};var n=b.getElementsByTagName(g)[0];b=b.createElement(g);b.src=k.url;b.crossorigin=\"anonymous\";b.addEventListener(\"load\",function(){try{a[e]=l;a[h]=m;var c=f.data,b=a.Raven;b.config(k.dsn,k.options).install();'undefined'!=typeof k.setup&&k.setup();var g=a[e];if(c.length)for(var d=0;d<c.length;d++)c[d].e?g.apply(b.TraceKit,c[d].e):c[d].p&&b.captureException(c[d].p)}catch(p){console.log(p)}});n.parentNode.insertBefore(b,n)})(window,document,\"script\",\"onerror\",\"onunhandledrejection\");");
var tag = new TagBuilder("script");
tag.InnerHtml.AppendHtml(js.ToString());
output.PostContent.AppendHtml(tag);
}
}
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment