Skip to content
This repository has been archived by the owner on Aug 30, 2023. It is now read-only.

Commit

Permalink
Merge pull request #69 from BeeWarloc/http-context-fix
Browse files Browse the repository at this point in the history
Hopefully fixed static HttpContext threading problems.
  • Loading branch information
asbjornu committed Mar 24, 2015
2 parents b61b042 + 2263e6d commit 5331264
Show file tree
Hide file tree
Showing 5 changed files with 220 additions and 77 deletions.
165 changes: 165 additions & 0 deletions src/SharpRaven.sln.DotSettings
Original file line number Diff line number Diff line change
Expand Up @@ -10,6 +10,8 @@
<s:Boolean x:Key="/Default/CodeStyle/CodeCleanup/Profiles/=OKB/@EntryIndexRemoved">True</s:Boolean>
<s:String x:Key="/Default/CodeStyle/CodeCleanup/RecentlyUsedProfile/@EntryValue">Custom</s:String>
<s:String x:Key="/Default/CodeStyle/CodeCleanup/SilentCleanupProfile/@EntryValue">Custom</s:String>
<s:String x:Key="/Default/CodeStyle/CodeFormatting/CSharpCodeStyle/ThisQualifier/INSTANCE_MEMBERS_QUALIFY_DECLARED_IN/@EntryValue">ThisClass</s:String>
<s:String x:Key="/Default/CodeStyle/CodeFormatting/CSharpCodeStyle/ThisQualifier/INSTANCE_MEMBERS_QUALIFY_MEMBERS/@EntryValue">Field</s:String>
<s:Boolean x:Key="/Default/CodeStyle/CodeFormatting/CSharpFormat/ALIGN_FIRST_ARG_BY_PAREN/@EntryValue">False</s:Boolean>
<s:Boolean x:Key="/Default/CodeStyle/CodeFormatting/CSharpFormat/ALIGN_MULTILINE_ARGUMENT/@EntryValue">True</s:Boolean>
<s:Boolean x:Key="/Default/CodeStyle/CodeFormatting/CSharpFormat/ALIGN_MULTILINE_CALLS_CHAIN/@EntryValue">True</s:Boolean>
Expand Down Expand Up @@ -41,6 +43,167 @@
<s:String x:Key="/Default/CodeStyle/CodeFormatting/XmlFormatter/ProcessingInstructionAttributesFormat/@EntryValue">OnSingleLine</s:String>
<s:String x:Key="/Default/CodeStyle/CodeFormatting/XmlFormatter/TagAttributeIndenting/@EntryValue">ByFirstAttr</s:String>
<s:String x:Key="/Default/CodeStyle/CodeFormatting/XmlFormatter/TagAttributesFormat/@EntryValue">OnSingleLine</s:String>
<s:String x:Key="/Default/CodeStyle/CSharpFileLayoutPatterns/Pattern/@EntryValue">&lt;Patterns xmlns="urn:schemas-jetbrains-com:member-reordering-patterns"&gt;&#xD;
&lt;TypePattern DisplayName="COM interfaces or structs"&gt;&#xD;
&lt;TypePattern.Match&gt;&#xD;
&lt;Or&gt;&#xD;
&lt;And&gt;&#xD;
&lt;Kind Is="Interface" /&gt;&#xD;
&lt;Or&gt;&#xD;
&lt;HasAttribute Name="System.Runtime.InteropServices.InterfaceTypeAttribute" /&gt;&#xD;
&lt;HasAttribute Name="System.Runtime.InteropServices.ComImport" /&gt;&#xD;
&lt;/Or&gt;&#xD;
&lt;/And&gt;&#xD;
&lt;HasAttribute Name="System.Runtime.InteropServices.StructLayoutAttribute" /&gt;&#xD;
&lt;/Or&gt;&#xD;
&lt;/TypePattern.Match&gt;&#xD;
&lt;/TypePattern&gt;&#xD;
&#xD;
&lt;TypePattern DisplayName="NUnit Test Fixtures" RemoveRegions="All"&gt;&#xD;
&lt;TypePattern.Match&gt;&#xD;
&lt;And&gt;&#xD;
&lt;Kind Is="Class" /&gt;&#xD;
&lt;HasAttribute Name="NUnit.Framework.TestFixtureAttribute" Inherited="true" /&gt;&#xD;
&lt;HasAttribute Name="NUnit.Framework.TestCaseFixtureAttribute" Inherited="true" /&gt;&#xD;
&lt;/And&gt;&#xD;
&lt;/TypePattern.Match&gt;&#xD;
&#xD;
&lt;Entry DisplayName="Setup/Teardown Methods"&gt;&#xD;
&lt;Entry.Match&gt;&#xD;
&lt;And&gt;&#xD;
&lt;Kind Is="Method" /&gt;&#xD;
&lt;Or&gt;&#xD;
&lt;HasAttribute Name="NUnit.Framework.SetUpAttribute" Inherited="true" /&gt;&#xD;
&lt;HasAttribute Name="NUnit.Framework.TearDownAttribute" Inherited="true" /&gt;&#xD;
&lt;HasAttribute Name="NUnit.Framework.FixtureSetUpAttribute" Inherited="true" /&gt;&#xD;
&lt;HasAttribute Name="NUnit.Framework.FixtureTearDownAttribute" Inherited="true" /&gt;&#xD;
&lt;/Or&gt;&#xD;
&lt;/And&gt;&#xD;
&lt;/Entry.Match&gt;&#xD;
&lt;/Entry&gt;&#xD;
&#xD;
&lt;Entry DisplayName="All other members" /&gt;&#xD;
&#xD;
&lt;Entry DisplayName="Test Methods" Priority="100"&gt;&#xD;
&lt;Entry.Match&gt;&#xD;
&lt;And&gt;&#xD;
&lt;Kind Is="Method" /&gt;&#xD;
&lt;HasAttribute Name="NUnit.Framework.TestAttribute" Inherited="false" /&gt;&#xD;
&lt;/And&gt;&#xD;
&lt;/Entry.Match&gt;&#xD;
&#xD;
&lt;Entry.SortBy&gt;&#xD;
&lt;Name /&gt;&#xD;
&lt;/Entry.SortBy&gt;&#xD;
&lt;/Entry&gt;&#xD;
&lt;/TypePattern&gt;&#xD;
&#xD;
&lt;TypePattern DisplayName="Default Pattern"&gt;&#xD;
&lt;Entry DisplayName="Public Delegates" Priority="100"&gt;&#xD;
&lt;Entry.Match&gt;&#xD;
&lt;And&gt;&#xD;
&lt;Access Is="Public" /&gt;&#xD;
&lt;Kind Is="Delegate" /&gt;&#xD;
&lt;/And&gt;&#xD;
&lt;/Entry.Match&gt;&#xD;
&#xD;
&lt;Entry.SortBy&gt;&#xD;
&lt;Name /&gt;&#xD;
&lt;/Entry.SortBy&gt;&#xD;
&lt;/Entry&gt;&#xD;
&#xD;
&lt;Entry DisplayName="Public Enums" Priority="100"&gt;&#xD;
&lt;Entry.Match&gt;&#xD;
&lt;And&gt;&#xD;
&lt;Access Is="Public" /&gt;&#xD;
&lt;Kind Is="Enum" /&gt;&#xD;
&lt;/And&gt;&#xD;
&lt;/Entry.Match&gt;&#xD;
&#xD;
&lt;Entry.SortBy&gt;&#xD;
&lt;Name /&gt;&#xD;
&lt;/Entry.SortBy&gt;&#xD;
&lt;/Entry&gt;&#xD;
&#xD;
&lt;Entry DisplayName="Static Fields and Constants"&gt;&#xD;
&lt;Entry.Match&gt;&#xD;
&lt;Or&gt;&#xD;
&lt;Kind Is="Constant" /&gt;&#xD;
&lt;And&gt;&#xD;
&lt;Kind Is="Field" /&gt;&#xD;
&lt;Static /&gt;&#xD;
&lt;/And&gt;&#xD;
&lt;/Or&gt;&#xD;
&lt;/Entry.Match&gt;&#xD;
&#xD;
&lt;Entry.SortBy&gt;&#xD;
&lt;Kind&gt;&#xD;
&lt;Kind.Order&gt;&#xD;
&lt;DeclarationKind&gt;Constant&lt;/DeclarationKind&gt;&#xD;
&lt;DeclarationKind&gt;Field&lt;/DeclarationKind&gt;&#xD;
&lt;/Kind.Order&gt;&#xD;
&lt;/Kind&gt;&#xD;
&lt;/Entry.SortBy&gt;&#xD;
&lt;/Entry&gt;&#xD;
&#xD;
&lt;Entry DisplayName="Fields"&gt;&#xD;
&lt;Entry.Match&gt;&#xD;
&lt;And&gt;&#xD;
&lt;Kind Is="Field" /&gt;&#xD;
&lt;Not&gt;&#xD;
&lt;Static /&gt;&#xD;
&lt;/Not&gt;&#xD;
&lt;/And&gt;&#xD;
&lt;/Entry.Match&gt;&#xD;
&#xD;
&lt;Entry.SortBy&gt;&#xD;
&lt;Readonly /&gt;&#xD;
&lt;Name /&gt;&#xD;
&lt;/Entry.SortBy&gt;&#xD;
&lt;/Entry&gt;&#xD;
&#xD;
&lt;Entry DisplayName="Constructors"&gt;&#xD;
&lt;Entry.Match&gt;&#xD;
&lt;Kind Is="Constructor" /&gt;&#xD;
&lt;/Entry.Match&gt;&#xD;
&#xD;
&lt;Entry.SortBy&gt;&#xD;
&lt;Static/&gt;&#xD;
&lt;/Entry.SortBy&gt;&#xD;
&lt;/Entry&gt;&#xD;
&#xD;
&lt;Entry DisplayName="Properties, Indexers"&gt;&#xD;
&lt;Entry.Match&gt;&#xD;
&lt;Or&gt;&#xD;
&lt;Kind Is="Property" /&gt;&#xD;
&lt;Kind Is="Indexer" /&gt;&#xD;
&lt;/Or&gt;&#xD;
&lt;/Entry.Match&gt;&#xD;
&lt;/Entry&gt;&#xD;
&#xD;
&lt;Entry DisplayName="Interface Implementations" Priority="100"&gt;&#xD;
&lt;Entry.Match&gt;&#xD;
&lt;And&gt;&#xD;
&lt;Kind Is="Member" /&gt;&#xD;
&lt;ImplementsInterface /&gt;&#xD;
&lt;/And&gt;&#xD;
&lt;/Entry.Match&gt;&#xD;
&#xD;
&lt;Entry.SortBy&gt;&#xD;
&lt;ImplementsInterface Immediate="true" /&gt;&#xD;
&lt;/Entry.SortBy&gt;&#xD;
&lt;/Entry&gt;&#xD;
&#xD;
&lt;Entry DisplayName="All other members" /&gt;&#xD;
&#xD;
&lt;Entry DisplayName="Nested Types"&gt;&#xD;
&lt;Entry.Match&gt;&#xD;
&lt;Kind Is="Type" /&gt;&#xD;
&lt;/Entry.Match&gt;&#xD;
&lt;/Entry&gt;&#xD;
&lt;/TypePattern&gt;&#xD;
&lt;/Patterns&gt;&#xD;
</s:String>
<s:String x:Key="/Default/CodeStyle/CSharpMemberOrderPattern/CustomPattern/@EntryValue">&lt;?xml version="1.0" encoding="utf-8" ?&gt;&#xD;
&lt;Patterns xmlns="urn:shemas-jetbrains-com:member-reordering-patterns"&gt;&#xD;
&lt;!--Do not reorder COM interfaces and structs marked by StructLayout attribute--&gt;&#xD;
Expand Down Expand Up @@ -319,7 +482,9 @@ ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF S
<s:Boolean x:Key="/Default/Environment/GenerateMru/GroupByType/=Implementations/@EntryIndexedValue">False</s:Boolean>
<s:Boolean x:Key="/Default/Environment/GenerateMru/SortByName/=Constructor/@EntryIndexedValue">False</s:Boolean>
<s:Boolean x:Key="/Default/Environment/GenerateMru/SortByName/=Implementations/@EntryIndexedValue">False</s:Boolean>
<s:Boolean x:Key="/Default/Environment/SettingsMigration/IsMigratorApplied/=JetBrains_002EReSharper_002EPsi_002ECSharp_002ECodeStyle_002ECSharpFileLayoutPatternsUpgrade/@EntryIndexedValue">True</s:Boolean>
<s:Boolean x:Key="/Default/Environment/SettingsMigration/IsMigratorApplied/=JetBrains_002EReSharper_002EPsi_002ECSharp_002ECodeStyle_002ESettingsUpgrade_002EMigrateBlankLinesAroundFieldToBlankLinesAroundProperty/@EntryIndexedValue">True</s:Boolean>
<s:Boolean x:Key="/Default/Environment/SettingsMigration/IsMigratorApplied/=JetBrains_002EReSharper_002EPsi_002ECSharp_002ECodeStyle_002ESettingsUpgrade_002EMigrateThisQualifierSettings/@EntryIndexedValue">True</s:Boolean>
<s:String x:Key="/Default/Environment/UserInterface/ShortcutSchemeName/@EntryValue">Idea</s:String>
<s:Boolean x:Key="/Default/Housekeeping/GlobalSettingsUpgraded/IsUpgraded/@EntryValue">True</s:Boolean>
<s:Boolean x:Key="/Default/Housekeeping/IntellisenseHousekeeping/HintUsed/@EntryValue">True</s:Boolean>
Expand Down
98 changes: 41 additions & 57 deletions src/app/SharpRaven/Data/SentryRequest.cs
Original file line number Diff line number Diff line change
Expand Up @@ -44,21 +44,22 @@ namespace SharpRaven.Data
/// </summary>
public class SentryRequest
{
internal SentryRequest()
{
// NOTE: We're using dynamic to not require a reference to System.Web.
GetHttpContext();
private static PropertyInfo currentHttpContextProperty;
private readonly dynamic httpContext;

if (!HasHttpContext)
return;

Url = HttpContext.Request.Url.ToString();
Method = HttpContext.Request.HttpMethod;
internal SentryRequest(dynamic httpContext)
{
if (httpContext == null)
throw new ArgumentNullException("httpContext");
this.httpContext = httpContext;
Url = this.httpContext.Request.Url.ToString();
Method = this.httpContext.Request.HttpMethod;
Environment = Convert(x => x.Request.ServerVariables);
Headers = Convert(x => x.Request.Headers);
Cookies = Convert(x => x.Request.Cookies);
Data = Convert(x => x.Request.Form);
QueryString = HttpContext.Request.QueryString.ToString();
QueryString = this.httpContext.Request.QueryString.ToString();
}


Expand Down Expand Up @@ -126,20 +127,6 @@ internal SentryRequest()
[JsonProperty(PropertyName = "url", NullValueHandling = NullValueHandling.Ignore)]
public string Url { get; set; }

/// <summary>
/// Gets or sets the HTTP context.
/// </summary>
/// <value>
/// The HTTP context.
/// </value>
internal static dynamic HttpContext { get; set; }

[JsonIgnore]
private static bool HasHttpContext
{
get { return HttpContext != null; }
}


/// <summary>
/// Gets the request.
Expand All @@ -151,8 +138,8 @@ public static SentryRequest GetRequest()
{
try
{
var request = new SentryRequest();
return HasHttpContext ? request : null;
var httpContext = GetHttpContext();
return httpContext != null ? new SentryRequest(httpContext) : null;
}
catch (Exception exception)
{
Expand All @@ -171,26 +158,20 @@ public static SentryRequest GetRequest()
/// </returns>
public SentryUser GetUser()
{
if (!HasHttpContext)
return null;

return new SentryUser(GetPrincipal())
{
IpAddress = GetIpAddress()
};
}


private static IDictionary<string, string> Convert(Func<dynamic, NameObjectCollectionBase> collectionGetter)
private IDictionary<string, string> Convert(Func<dynamic, NameObjectCollectionBase> collectionGetter)
{
if (!HasHttpContext)
return null;

IDictionary<string, string> dictionary = new Dictionary<string, string>();

try
{
var collection = collectionGetter.Invoke(HttpContext);
var collection = collectionGetter.Invoke(httpContext);
var keys = Enumerable.ToArray(collection.AllKeys);

foreach (object key in keys)
Expand Down Expand Up @@ -237,46 +218,49 @@ private static IDictionary<string, string> Convert(Func<dynamic, NameObjectColle
}


private static void GetHttpContext()
private static PropertyInfo GetHttpContextCurrentProperty()
{
if (HasHttpContext)
return;

try
{
var systemWeb = AppDomain.CurrentDomain
.GetAssemblies()
.FirstOrDefault(assembly => assembly.FullName.StartsWith("System.Web,"));
var systemWeb = AppDomain.CurrentDomain
.GetAssemblies()
.FirstOrDefault(assembly => assembly.FullName.StartsWith("System.Web,"));

if (HasHttpContext || systemWeb == null)
return;
if (systemWeb == null)
return null;

var httpContextType = systemWeb.GetExportedTypes()
.FirstOrDefault(type => type.Name == "HttpContext");
var httpContextType = systemWeb.GetExportedTypes()
.FirstOrDefault(type => type.Name == "HttpContext");

if (HasHttpContext || httpContextType == null)
return;
if (httpContextType == null)
return null;

var currentHttpContextProperty = httpContextType.GetProperty("Current",
BindingFlags.Static | BindingFlags.Public);
return httpContextType.GetProperty("Current", BindingFlags.Static | BindingFlags.Public);
}

if (HasHttpContext || currentHttpContextProperty == null)
return;

HttpContext = currentHttpContextProperty.GetValue(null, null);
private static dynamic GetHttpContext()
{
try
{
if (currentHttpContextProperty == null)
currentHttpContextProperty = GetHttpContextCurrentProperty();

if (currentHttpContextProperty != null)
return currentHttpContextProperty.GetValue(null, null);
}
catch (Exception exception)
{
Console.WriteLine("An error occurred while retrieving the HTTP context: {0}", exception);
}

return null;
}


private static dynamic GetIpAddress()
private dynamic GetIpAddress()
{
try
{
return HttpContext.Request.UserHostAddress;
return this.httpContext.Request.UserHostAddress;
}
catch (Exception exception)
{
Expand All @@ -287,11 +271,11 @@ private static dynamic GetIpAddress()
}


private static IPrincipal GetPrincipal()
private IPrincipal GetPrincipal()
{
try
{
return HttpContext.User as IPrincipal;
return this.httpContext.User as IPrincipal;
}
catch (Exception exception)
{
Expand Down
19 changes: 0 additions & 19 deletions src/tests/SharpRaven.UnitTests/Data/SentryRequestTests.cs
Original file line number Diff line number Diff line change
Expand Up @@ -41,25 +41,6 @@ namespace SharpRaven.UnitTests.Data
[TestFixture]
public class SentryRequestTests
{
#region Setup/Teardown

[SetUp]
public void SetUp()
{
// Set the HTTP Context to null before so tests don't bleed data into each other. @asbjornu
SentryRequest.HttpContext = null;
}


[TearDown]
public void TearDown()
{
// Set the HTTP Context to null before so tests don't bleed data into each other. @asbjornu
SentryRequest.HttpContext = null;
}

#endregion

private static void SimulateHttpRequest(Action<SentryRequest> test)
{
using (var simulator = new HttpSimulator())
Expand Down
Loading

0 comments on commit 5331264

Please sign in to comment.