diff --git a/AssemblyVersionInfo.cs b/AssemblyVersionInfo.cs index 86489ac0..a28f2cb5 100644 --- a/AssemblyVersionInfo.cs +++ b/AssemblyVersionInfo.cs @@ -10,5 +10,5 @@ // You can specify all the values or you can default the Build and Revision Numbers // by using the '*' as shown below: // [assembly: AssemblyVersion("1.0.*")] -[assembly: AssemblyVersion("5.10.2.0")] -[assembly: AssemblyFileVersion("5.10.2.0")] +[assembly: AssemblyVersion("5.11.0.0")] +[assembly: AssemblyFileVersion("5.11.0.0")] diff --git a/Mindscape.Raygun4Net.ClientProfile.Tests/RaygunClientTests.cs b/Mindscape.Raygun4Net.ClientProfile.Tests/RaygunClientTests.cs index 5428cc54..1e0cadca 100644 --- a/Mindscape.Raygun4Net.ClientProfile.Tests/RaygunClientTests.cs +++ b/Mindscape.Raygun4Net.ClientProfile.Tests/RaygunClientTests.cs @@ -297,7 +297,7 @@ public void UserCustomData() [Test] public void NoHandlerSendsAll() { - Assert.IsTrue(_client.ExposeOnSendingMessage(_client.ExposeBuildMessage(_exception))); + Assert.IsTrue(_client.ExposeOnSendingMessage(_client.ExposeBuildMessage(_exception), _exception)); } [Test] @@ -310,7 +310,7 @@ public void HandlerIsChecked() filterCalled = true; e.Cancel = true; }; - Assert.IsFalse(_client.ExposeOnSendingMessage(_client.ExposeBuildMessage(_exception))); + Assert.IsFalse(_client.ExposeOnSendingMessage(_client.ExposeBuildMessage(_exception), _exception)); Assert.IsTrue(filterCalled); } @@ -321,7 +321,7 @@ public void HandlerCanAllowSend() { // Allow send by not setting e.Cancel }; - Assert.IsTrue(_client.ExposeOnSendingMessage(_client.ExposeBuildMessage(_exception))); + Assert.IsTrue(_client.ExposeOnSendingMessage(_client.ExposeBuildMessage(_exception), _exception)); } [Test] @@ -341,7 +341,7 @@ public void AllHandlersAreChecked() filter2Called = true; e.Cancel = true; }; - Assert.IsFalse(_client.ExposeOnSendingMessage(_client.ExposeBuildMessage(_exception))); + Assert.IsFalse(_client.ExposeOnSendingMessage(_client.ExposeBuildMessage(_exception), _exception)); Assert.IsTrue(filter1Called); Assert.IsTrue(filter2Called); } @@ -357,7 +357,7 @@ public void DontSendIfFirstHandlerCancels() { // Allow send by not setting e.Cancel }; - Assert.IsFalse(_client.ExposeOnSendingMessage(_client.ExposeBuildMessage(_exception))); + Assert.IsFalse(_client.ExposeOnSendingMessage(_client.ExposeBuildMessage(_exception), _exception)); } [Test] @@ -371,7 +371,7 @@ public void DontSendIfSecondHandlerCancels() { e.Cancel = true; }; - Assert.IsFalse(_client.ExposeOnSendingMessage(_client.ExposeBuildMessage(_exception))); + Assert.IsFalse(_client.ExposeOnSendingMessage(_client.ExposeBuildMessage(_exception), _exception)); } [Test] @@ -385,7 +385,7 @@ public void AllowSendIfNoHandlerCancels() { // Allow send by not setting e.Cancel }; - Assert.IsTrue(_client.ExposeOnSendingMessage(_client.ExposeBuildMessage(_exception))); + Assert.IsTrue(_client.ExposeOnSendingMessage(_client.ExposeBuildMessage(_exception), _exception)); } [Test] @@ -399,7 +399,7 @@ public void HandlerCanModifyMessage() e.Message.Details.Error.Message = "Custom error message"; }; - Assert.IsTrue(_client.ExposeOnSendingMessage(message)); + Assert.IsTrue(_client.ExposeOnSendingMessage(message, _exception)); Assert.AreEqual("Custom error message", message.Details.Error.Message); } diff --git a/Mindscape.Raygun4Net.ClientProfile/RaygunClient.cs b/Mindscape.Raygun4Net.ClientProfile/RaygunClient.cs index 21358125..097cac3d 100644 --- a/Mindscape.Raygun4Net.ClientProfile/RaygunClient.cs +++ b/Mindscape.Raygun4Net.ClientProfile/RaygunClient.cs @@ -93,7 +93,7 @@ public void RemoveWrapperExceptions(params Type[] wrapperExceptions) _wrapperExceptions.Remove(wrapper); } } - + /// /// Transmits an exception to Raygun.io synchronously, using the version number of the originating assembly. /// @@ -140,7 +140,7 @@ public void Send(Exception exception, IList tags, IDictionary userCustom { if (CanSend(exception)) { - Send(BuildMessage(exception, tags, userCustomData, userInfo, null)); + Send(BuildMessage(exception, tags, userCustomData, userInfo, null), exception); FlagAsSent(exception); } } @@ -191,7 +191,7 @@ public void SendInBackground(Exception exception, IList tags, IDictionar { try { - Send(BuildMessage(exception, tags, userCustomData, userInfo, currentTime)); + Send(BuildMessage(exception, tags, userCustomData, userInfo, currentTime), exception); } catch (Exception) { @@ -212,9 +212,10 @@ public void SendInBackground(Exception exception, IList tags, IDictionar /// /// The RaygunMessage to send. This needs its OccurredOn property /// set to a valid DateTime and as much of the Details property as is available. - public void SendInBackground(RaygunMessage raygunMessage) + /// The original exception that generated the RaygunMessage + public void SendInBackground(RaygunMessage raygunMessage, Exception exception) { - ThreadPool.QueueUserWorkItem(c => Send(raygunMessage)); + ThreadPool.QueueUserWorkItem(c => Send(raygunMessage, exception)); } protected RaygunMessage BuildMessage(Exception exception, IList tags, IDictionary userCustomData) @@ -266,9 +267,10 @@ private Exception StripWrapperExceptions(Exception exception) /// /// The RaygunMessage to send. This needs its OccurredOn property /// set to a valid DateTime and as much of the Details property as is available. - public override void Send(RaygunMessage raygunMessage) + /// The original exception that generated the RaygunMessage + public override void Send(RaygunMessage raygunMessage, Exception exception = null) { - bool canSend = OnSendingMessage(raygunMessage); + bool canSend = OnSendingMessage(raygunMessage, exception); if (canSend) { string message = null; diff --git a/Mindscape.Raygun4Net.Core.Signed.nuspec b/Mindscape.Raygun4Net.Core.Signed.nuspec index 86bf2f40..2001d7b0 100644 --- a/Mindscape.Raygun4Net.Core.Signed.nuspec +++ b/Mindscape.Raygun4Net.Core.Signed.nuspec @@ -2,7 +2,7 @@ Mindscape.Raygun4Net.Core.Signed - 5.10.2 + 5.11.0 <authors>Raygun</authors> <owners /> diff --git a/Mindscape.Raygun4Net.Core.nuspec b/Mindscape.Raygun4Net.Core.nuspec index bb07f560..d74c42a4 100644 --- a/Mindscape.Raygun4Net.Core.nuspec +++ b/Mindscape.Raygun4Net.Core.nuspec @@ -2,7 +2,7 @@ <package xmlns="http://schemas.microsoft.com/packaging/2010/07/nuspec.xsd"> <metadata minClientVersion="2.5"> <id>Mindscape.Raygun4Net.Core</id> - <version>5.10.2</version> + <version>5.11.0</version> <title /> <authors>Raygun</authors> <owners /> diff --git a/Mindscape.Raygun4Net.Core/Mindscape.Raygun4Net.Core.csproj b/Mindscape.Raygun4Net.Core/Mindscape.Raygun4Net.Core.csproj index 5590a09b..a3c28c13 100644 --- a/Mindscape.Raygun4Net.Core/Mindscape.Raygun4Net.Core.csproj +++ b/Mindscape.Raygun4Net.Core/Mindscape.Raygun4Net.Core.csproj @@ -60,9 +60,6 @@ <Reference Include="System.Xml" /> </ItemGroup> <ItemGroup> - <Compile Include="..\AssemblyVersionInfo.cs"> - <Link>Properties\AssemblyVersionInfo.cs</Link> - </Compile> <Compile Include="..\Mindscape.Raygun4Net\Attributes\DoNotProfileAttribute.cs"> <Link>Attributes\DoNotProfileAttribute.cs</Link> </Compile> @@ -135,6 +132,7 @@ <Compile Include="..\Mindscape.Raygun4Net\Filters\RaygunKeyValuePairDataFilter.cs"> <Link>Filters\RaygunKeyValuePairDataFilter.cs</Link> </Compile> + <Compile Include="Properties\AssemblyVersionInfo.cs" /> </ItemGroup> <ItemGroup> <Folder Include="Filters\" /> diff --git a/Mindscape.Raygun4Net.Core/Properties/AssemblyVersionInfo.cs b/Mindscape.Raygun4Net.Core/Properties/AssemblyVersionInfo.cs new file mode 100644 index 00000000..a28f2cb5 --- /dev/null +++ b/Mindscape.Raygun4Net.Core/Properties/AssemblyVersionInfo.cs @@ -0,0 +1,14 @@ +using System.Reflection; + +// Version information for an assembly consists of the following four values: +// +// Major Version +// Minor Version +// Build Number +// Revision +// +// You can specify all the values or you can default the Build and Revision Numbers +// by using the '*' as shown below: +// [assembly: AssemblyVersion("1.0.*")] +[assembly: AssemblyVersion("5.11.0.0")] +[assembly: AssemblyFileVersion("5.11.0.0")] diff --git a/Mindscape.Raygun4Net.Mvc.Signed.nuspec b/Mindscape.Raygun4Net.Mvc.Signed.nuspec index e62d9243..c74ebcca 100644 --- a/Mindscape.Raygun4Net.Mvc.Signed.nuspec +++ b/Mindscape.Raygun4Net.Mvc.Signed.nuspec @@ -2,7 +2,7 @@ <package xmlns="http://schemas.microsoft.com/packaging/2010/07/nuspec.xsd"> <metadata minClientVersion="2.5"> <id>Mindscape.Raygun4Net.Mvc.Signed</id> - <version>5.10.3</version> + <version>5.11.0</version> <title /> <authors>Raygun</authors> <owners /> @@ -12,7 +12,7 @@ <projectUrl>https://github.com/MindscapeHQ/raygun4net</projectUrl> <licenseUrl>https://raw.github.com/MindscapeHQ/raygun4net/master/LICENSE</licenseUrl> <dependencies> - <dependency id="Mindscape.Raygun4Net.Core.Signed" version="5.10.2" /> + <dependency id="Mindscape.Raygun4Net.Core.Signed" version="5.11.0" /> </dependencies> </metadata> <files> diff --git a/Mindscape.Raygun4Net.Mvc.nuspec b/Mindscape.Raygun4Net.Mvc.nuspec index 68d8074f..12fbf73a 100644 --- a/Mindscape.Raygun4Net.Mvc.nuspec +++ b/Mindscape.Raygun4Net.Mvc.nuspec @@ -2,7 +2,7 @@ <package xmlns="http://schemas.microsoft.com/packaging/2010/07/nuspec.xsd"> <metadata minClientVersion="2.5"> <id>Mindscape.Raygun4Net.Mvc</id> - <version>5.10.3</version> + <version>5.11.0</version> <title /> <authors>Raygun</authors> <owners /> @@ -12,7 +12,7 @@ <projectUrl>https://github.com/MindscapeHQ/raygun4net</projectUrl> <licenseUrl>https://raw.github.com/MindscapeHQ/raygun4net/master/LICENSE</licenseUrl> <dependencies> - <dependency id="Mindscape.Raygun4Net.Core" version="5.10.2" /> + <dependency id="Mindscape.Raygun4Net.Core" version="5.11.0" /> </dependencies> </metadata> <files> diff --git a/Mindscape.Raygun4Net.Mvc/Properties/AssemblyVersionInfo.cs b/Mindscape.Raygun4Net.Mvc/Properties/AssemblyVersionInfo.cs index 6af10067..a28f2cb5 100644 --- a/Mindscape.Raygun4Net.Mvc/Properties/AssemblyVersionInfo.cs +++ b/Mindscape.Raygun4Net.Mvc/Properties/AssemblyVersionInfo.cs @@ -10,5 +10,5 @@ // You can specify all the values or you can default the Build and Revision Numbers // by using the '*' as shown below: // [assembly: AssemblyVersion("1.0.*")] -[assembly: AssemblyVersion("5.10.3.0")] -[assembly: AssemblyFileVersion("5.10.3.0")] +[assembly: AssemblyVersion("5.11.0.0")] +[assembly: AssemblyFileVersion("5.11.0.0")] diff --git a/Mindscape.Raygun4Net.NetCore/Mindscape.Raygun4Net.NetCore.csproj b/Mindscape.Raygun4Net.NetCore/Mindscape.Raygun4Net.NetCore.csproj index 861d53f7..b4f237f4 100644 --- a/Mindscape.Raygun4Net.NetCore/Mindscape.Raygun4Net.NetCore.csproj +++ b/Mindscape.Raygun4Net.NetCore/Mindscape.Raygun4Net.NetCore.csproj @@ -4,7 +4,6 @@ <AssemblyName>Mindscape.Raygun4Net.NetCore</AssemblyName> <EnableDefaultCompileItems>false</EnableDefaultCompileItems> <TargetFrameworks>netstandard1.6;netstandard2.0</TargetFrameworks> - <TargetFrameworkIdentifier>.NETStandard</TargetFrameworkIdentifier> <GenerateAssemblyInfo>false</GenerateAssemblyInfo> <Configurations>Debug;Release;Sign</Configurations> <Platforms>AnyCPU</Platforms> diff --git a/Mindscape.Raygun4Net.Signed.nuspec b/Mindscape.Raygun4Net.Signed.nuspec index ca25415f..019a6220 100644 --- a/Mindscape.Raygun4Net.Signed.nuspec +++ b/Mindscape.Raygun4Net.Signed.nuspec @@ -2,7 +2,7 @@ <package xmlns="http://schemas.microsoft.com/packaging/2010/07/nuspec.xsd"> <metadata minClientVersion="2.5"> <id>Mindscape.Raygun4Net.Signed</id> - <version>5.10.2</version> + <version>5.11.0</version> <title /> <authors>Raygun</authors> <owners /> diff --git a/Mindscape.Raygun4Net.Tests/Model/FakeRaygunClient.cs b/Mindscape.Raygun4Net.Tests/Model/FakeRaygunClient.cs index 06ef46e8..437ce9a1 100644 --- a/Mindscape.Raygun4Net.Tests/Model/FakeRaygunClient.cs +++ b/Mindscape.Raygun4Net.Tests/Model/FakeRaygunClient.cs @@ -33,9 +33,9 @@ public bool ExposeValidateApiKey() return ValidateApiKey(); } - public bool ExposeOnSendingMessage(RaygunMessage raygunMessage) + public bool ExposeOnSendingMessage(RaygunMessage raygunMessage, Exception exception) { - return OnSendingMessage(raygunMessage); + return OnSendingMessage(raygunMessage, exception); } public bool ExposeCanSend(Exception exception) diff --git a/Mindscape.Raygun4Net.Tests/RaygunClientBaseTests.cs b/Mindscape.Raygun4Net.Tests/RaygunClientBaseTests.cs index 3a4e3b11..4ffc8bc8 100644 --- a/Mindscape.Raygun4Net.Tests/RaygunClientBaseTests.cs +++ b/Mindscape.Raygun4Net.Tests/RaygunClientBaseTests.cs @@ -55,8 +55,8 @@ public void ExceptionInsideSendingMessageHAndlerDoesNotCrash() throw new Exception("Oops..."); }; - Assert.That(() => client.ExposeOnSendingMessage(new RaygunMessage()), Throws.Nothing); - Assert.IsTrue(client.ExposeOnSendingMessage(new RaygunMessage())); + Assert.That(() => client.ExposeOnSendingMessage(new RaygunMessage(), new Exception()), Throws.Nothing); + Assert.IsTrue(client.ExposeOnSendingMessage(new RaygunMessage(), new Exception())); } } } diff --git a/Mindscape.Raygun4Net.Tests/RaygunClientTests.cs b/Mindscape.Raygun4Net.Tests/RaygunClientTests.cs index 584bde45..ce0f4562 100644 --- a/Mindscape.Raygun4Net.Tests/RaygunClientTests.cs +++ b/Mindscape.Raygun4Net.Tests/RaygunClientTests.cs @@ -305,7 +305,7 @@ public void UserCustomData() [Test] public void NoHandlerSendsAll() { - Assert.IsTrue(_client.ExposeOnSendingMessage(_client.ExposeBuildMessage(_exception))); + Assert.IsTrue(_client.ExposeOnSendingMessage(_client.ExposeBuildMessage(_exception), _exception)); } [Test] @@ -318,7 +318,7 @@ public void HandlerIsChecked() filterCalled = true; e.Cancel = true; }; - Assert.IsFalse(_client.ExposeOnSendingMessage(_client.ExposeBuildMessage(_exception))); + Assert.IsFalse(_client.ExposeOnSendingMessage(_client.ExposeBuildMessage(_exception), _exception)); Assert.IsTrue(filterCalled); } @@ -329,7 +329,7 @@ public void HandlerCanAllowSend() { // Allow send by not setting e.Cancel }; - Assert.IsTrue(_client.ExposeOnSendingMessage(_client.ExposeBuildMessage(_exception))); + Assert.IsTrue(_client.ExposeOnSendingMessage(_client.ExposeBuildMessage(_exception), _exception)); } [Test] @@ -349,7 +349,7 @@ public void AllHandlersAreChecked() filter2Called = true; e.Cancel = true; }; - Assert.IsFalse(_client.ExposeOnSendingMessage(_client.ExposeBuildMessage(_exception))); + Assert.IsFalse(_client.ExposeOnSendingMessage(_client.ExposeBuildMessage(_exception), _exception)); Assert.IsTrue(filter1Called); Assert.IsTrue(filter2Called); } @@ -365,7 +365,7 @@ public void DontSendIfFirstHandlerCancels() { // Allow send by not setting e.Cancel }; - Assert.IsFalse(_client.ExposeOnSendingMessage(_client.ExposeBuildMessage(_exception))); + Assert.IsFalse(_client.ExposeOnSendingMessage(_client.ExposeBuildMessage(_exception), _exception)); } [Test] @@ -379,7 +379,7 @@ public void DontSendIfSecondHandlerCancels() { e.Cancel = true; }; - Assert.IsFalse(_client.ExposeOnSendingMessage(_client.ExposeBuildMessage(_exception))); + Assert.IsFalse(_client.ExposeOnSendingMessage(_client.ExposeBuildMessage(_exception), _exception)); } [Test] @@ -393,7 +393,7 @@ public void AllowSendIfNoHandlerCancels() { // Allow send by not setting e.Cancel }; - Assert.IsTrue(_client.ExposeOnSendingMessage(_client.ExposeBuildMessage(_exception))); + Assert.IsTrue(_client.ExposeOnSendingMessage(_client.ExposeBuildMessage(_exception), _exception)); } [Test] @@ -407,7 +407,7 @@ public void HandlerCanModifyMessage() e.Message.Details.Error.Message = "Custom error message"; }; - Assert.IsTrue(_client.ExposeOnSendingMessage(message)); + Assert.IsTrue(_client.ExposeOnSendingMessage(message, _exception)); Assert.AreEqual("Custom error message", message.Details.Error.Message); } diff --git a/Mindscape.Raygun4Net.WebApi.Signed.nuspec b/Mindscape.Raygun4Net.WebApi.Signed.nuspec index 0d086bc9..c97105ed 100644 --- a/Mindscape.Raygun4Net.WebApi.Signed.nuspec +++ b/Mindscape.Raygun4Net.WebApi.Signed.nuspec @@ -2,7 +2,7 @@ <package xmlns="http://schemas.microsoft.com/packaging/2010/07/nuspec.xsd"> <metadata minClientVersion="2.5"> <id>Mindscape.Raygun4Net.WebApi.Signed</id> - <version>5.10.3</version> + <version>5.11.0</version> <title>Raygun for ASP.NET Web API Raygun @@ -13,7 +13,7 @@ https://github.com/MindscapeHQ/raygun4net https://raw.github.com/MindscapeHQ/raygun4net/master/LICENSE - + diff --git a/Mindscape.Raygun4Net.WebApi.nuspec b/Mindscape.Raygun4Net.WebApi.nuspec index f6ff375a..0a3e88a2 100644 --- a/Mindscape.Raygun4Net.WebApi.nuspec +++ b/Mindscape.Raygun4Net.WebApi.nuspec @@ -2,7 +2,7 @@ Mindscape.Raygun4Net.WebApi - 5.10.3 + 5.11.0 Raygun for ASP.NET Web API Raygun @@ -13,7 +13,7 @@ https://github.com/MindscapeHQ/raygun4net https://raw.github.com/MindscapeHQ/raygun4net/master/LICENSE - + diff --git a/Mindscape.Raygun4Net.WebApi/Properties/AssemblyVersionInfo.cs b/Mindscape.Raygun4Net.WebApi/Properties/AssemblyVersionInfo.cs index 6af10067..a28f2cb5 100644 --- a/Mindscape.Raygun4Net.WebApi/Properties/AssemblyVersionInfo.cs +++ b/Mindscape.Raygun4Net.WebApi/Properties/AssemblyVersionInfo.cs @@ -10,5 +10,5 @@ // You can specify all the values or you can default the Build and Revision Numbers // by using the '*' as shown below: // [assembly: AssemblyVersion("1.0.*")] -[assembly: AssemblyVersion("5.10.3.0")] -[assembly: AssemblyFileVersion("5.10.3.0")] +[assembly: AssemblyVersion("5.11.0.0")] +[assembly: AssemblyFileVersion("5.11.0.0")] diff --git a/Mindscape.Raygun4Net.WebApi/RaygunWebApiClient.cs b/Mindscape.Raygun4Net.WebApi/RaygunWebApiClient.cs index 730d2a07..ff020543 100644 --- a/Mindscape.Raygun4Net.WebApi/RaygunWebApiClient.cs +++ b/Mindscape.Raygun4Net.WebApi/RaygunWebApiClient.cs @@ -19,19 +19,19 @@ namespace Mindscape.Raygun4Net.WebApi public class RaygunWebApiClient : RaygunClientBase { internal const string UnhandledExceptionTag = "UnhandledException"; - + protected readonly RaygunRequestMessageOptions _requestMessageOptions = new RaygunRequestMessageOptions(); private readonly List _wrapperExceptions = new List(); private readonly ThreadLocal _currentWebRequest = new ThreadLocal(() => null); private readonly ThreadLocal _currentRequestMessage = new ThreadLocal(() => null); - + private readonly string _apiKey; private static RaygunWebApiExceptionFilter _exceptionFilter; private static RaygunWebApiActionFilter _actionFilter; private static RaygunWebApiDelegatingHandler _delegatingHandler; - + /// /// Initializes a new instance of the class. /// Uses the ApiKey specified in the config file. @@ -59,7 +59,7 @@ public RaygunWebApiClient() public RaygunWebApiClient(string apiKey) { _apiKey = apiKey; - + ApplicationVersion = RaygunSettings.Settings.ApplicationVersion; if (string.IsNullOrEmpty(ApplicationVersion)) { @@ -68,7 +68,7 @@ public RaygunWebApiClient(string apiKey) // or else we will not be getting the user's library but our own Raygun4Net library. ApplicationVersion = Assembly.GetCallingAssembly()?.GetName()?.Version?.ToString(); } - + Init(); } @@ -86,7 +86,7 @@ public static void Attach(HttpConfiguration config) // or else we will not be getting the user's library but our own Raygun4Net library. appVersion = Assembly.GetCallingAssembly()?.GetName()?.Version?.ToString(); } - + AttachInternal(config, null, appVersion); } @@ -105,7 +105,7 @@ public static void Attach(HttpConfiguration config, Func gen // or else we will not be getting the user's library but our own Raygun4Net library. appVersion = Assembly.GetCallingAssembly()?.GetName()?.Version?.ToString(); } - + if (generateRaygunClient != null) { AttachInternal(config, message => generateRaygunClient(), appVersion); @@ -145,7 +145,7 @@ private static void AttachInternal( string appVersion) { Detach(config); - + if (RaygunSettings.Settings.IsRawDataIgnored == false) { _delegatingHandler = new RaygunWebApiDelegatingHandler(); @@ -220,9 +220,9 @@ public static void Detach(HttpConfiguration config) _actionFilter = null; } } - + /// - /// + /// /// /// The API key. /// The application version. @@ -444,7 +444,7 @@ public bool UseKeyValuePairRawDataFilter /// /// Add an implementation to be used when capturing the raw data - /// of a HTTP request. This filter will be passed the request raw data and is expected to remove + /// of a HTTP request. This filter will be passed the request raw data and is expected to remove /// or replace values whose keys are found in the list supplied to the Filter method. /// /// Custom raw data filter implementation. @@ -540,9 +540,10 @@ public void SendInBackground(Exception exception, IList tags, IDictionar /// /// The RaygunMessage to send. This needs its OccurredOn property /// set to a valid DateTime and as much of the Details property as is available. - public void SendInBackground(RaygunMessage raygunMessage) + /// The original exception used to generate the RaygunMessage + public void SendInBackground(RaygunMessage raygunMessage, Exception exception = null) { - ThreadPool.QueueUserWorkItem(c => Send(raygunMessage)); + ThreadPool.QueueUserWorkItem(c => Send(raygunMessage, exception)); } internal void FlagExceptionAsSent(Exception exception) @@ -596,7 +597,7 @@ private void StripAndSend(Exception exception, IList tags, IDictionary u { foreach (Exception e in StripWrapperExceptions(exception)) { - Send(BuildMessage(e, tags, userCustomData, currentTime)); + Send(BuildMessage(e, tags, userCustomData, currentTime), exception); } } @@ -659,11 +660,12 @@ protected IEnumerable StripWrapperExceptions(Exception exception) /// /// The RaygunMessage to send. This needs its OccurredOn property /// set to a valid DateTime and as much of the Details property as is available. - public override void Send(RaygunMessage raygunMessage) + /// The original exception used to generate the RaygunMessage + public override void Send(RaygunMessage raygunMessage, Exception exception = null) { try { - bool canSend = OnSendingMessage(raygunMessage) && CanSend(raygunMessage); + bool canSend = OnSendingMessage(raygunMessage, exception) && CanSend(raygunMessage); if (canSend) { var message = SimpleJson.SerializeObject(raygunMessage); diff --git a/Mindscape.Raygun4Net.WinRT.Tests/Model/FakeRaygunClient.cs b/Mindscape.Raygun4Net.WinRT.Tests/Model/FakeRaygunClient.cs index 1ce31e2e..c450907c 100644 --- a/Mindscape.Raygun4Net.WinRT.Tests/Model/FakeRaygunClient.cs +++ b/Mindscape.Raygun4Net.WinRT.Tests/Model/FakeRaygunClient.cs @@ -23,9 +23,9 @@ public RaygunMessage ExposeBuildMessage(Exception exception, [Optional] IList ExposeStripWrapperExceptions(Exception exception) diff --git a/Mindscape.Raygun4Net.WinRT.Tests/RaygunClientTests.cs b/Mindscape.Raygun4Net.WinRT.Tests/RaygunClientTests.cs index caf0b8a4..67e5aa37 100644 --- a/Mindscape.Raygun4Net.WinRT.Tests/RaygunClientTests.cs +++ b/Mindscape.Raygun4Net.WinRT.Tests/RaygunClientTests.cs @@ -22,7 +22,7 @@ public void SetUp() [Test] public void NoHandlerSendsAll() { - Assert.IsTrue(_client.ExposeOnSendingMessage(_client.ExposeBuildMessage(_exception))); + Assert.IsTrue(_client.ExposeOnSendingMessage(_client.ExposeBuildMessage(_exception), _exception)); } [Test] @@ -35,7 +35,7 @@ public void HandlerIsChecked() filterCalled = true; e.Cancel = true; }; - Assert.IsFalse(_client.ExposeOnSendingMessage(_client.ExposeBuildMessage(_exception))); + Assert.IsFalse(_client.ExposeOnSendingMessage(_client.ExposeBuildMessage(_exception), _exception)); Assert.IsTrue(filterCalled); } @@ -46,7 +46,7 @@ public void HandlerCanAllowSend() { // Allow send by not setting e.Cancel }; - Assert.IsTrue(_client.ExposeOnSendingMessage(_client.ExposeBuildMessage(_exception))); + Assert.IsTrue(_client.ExposeOnSendingMessage(_client.ExposeBuildMessage(_exception), _exception)); } [Test] @@ -66,7 +66,7 @@ public void AllHandlersAreChecked() filter2Called = true; e.Cancel = true; }; - Assert.IsFalse(_client.ExposeOnSendingMessage(_client.ExposeBuildMessage(_exception))); + Assert.IsFalse(_client.ExposeOnSendingMessage(_client.ExposeBuildMessage(_exception), _exception)); Assert.IsTrue(filter1Called); Assert.IsTrue(filter2Called); } @@ -82,7 +82,7 @@ public void DontSendIfFirstHandlerCancels() { // Allow send by not setting e.Cancel }; - Assert.IsFalse(_client.ExposeOnSendingMessage(_client.ExposeBuildMessage(_exception))); + Assert.IsFalse(_client.ExposeOnSendingMessage(_client.ExposeBuildMessage(_exception), _exception)); } [Test] @@ -96,7 +96,7 @@ public void DontSendIfSecondHandlerCancels() { e.Cancel = true; }; - Assert.IsFalse(_client.ExposeOnSendingMessage(_client.ExposeBuildMessage(_exception))); + Assert.IsFalse(_client.ExposeOnSendingMessage(_client.ExposeBuildMessage(_exception), _exception)); } [Test] @@ -110,7 +110,7 @@ public void AllowSendIfNoHandlerCancels() { // Allow send by not setting e.Cancel }; - Assert.IsTrue(_client.ExposeOnSendingMessage(_client.ExposeBuildMessage(_exception))); + Assert.IsTrue(_client.ExposeOnSendingMessage(_client.ExposeBuildMessage(_exception), _exception)); } [Test] @@ -124,7 +124,7 @@ public void HandlerCanModifyMessage() e.Message.Details.Error.Message = "Custom error message"; }; - Assert.IsTrue(_client.ExposeOnSendingMessage(message)); + Assert.IsTrue(_client.ExposeOnSendingMessage(message, _exception)); Assert.AreEqual("Custom error message", message.Details.Error.Message); } diff --git a/Mindscape.Raygun4Net.WinRT/RaygunClient.cs b/Mindscape.Raygun4Net.WinRT/RaygunClient.cs index c135f7e6..859bb9b3 100644 --- a/Mindscape.Raygun4Net.WinRT/RaygunClient.cs +++ b/Mindscape.Raygun4Net.WinRT/RaygunClient.cs @@ -53,16 +53,18 @@ private bool ValidateApiKey() private bool _handlingRecursiveErrorSending; // Returns true if the message can be sent, false if the sending is canceled. - protected bool OnSendingMessage(RaygunMessage raygunMessage) + protected bool OnSendingMessage(RaygunMessage raygunMessage, Exception exception = null) { bool result = true; if (!_handlingRecursiveErrorSending) { EventHandler handler = SendingMessage; + if (handler != null) { - RaygunSendingMessageEventArgs args = new RaygunSendingMessageEventArgs(raygunMessage); + RaygunSendingMessageEventArgs args = new RaygunSendingMessageEventArgs(raygunMessage, exception); + try { handler(this, args); @@ -232,11 +234,11 @@ public void Send(Exception exception, [Optional] IList tags, [Optional] StripAndSend(exception, tags, userCustomData); } - public async void Send(RaygunMessage raygunMessage) + public async void Send(RaygunMessage raygunMessage, Exception exception = null) { if (ValidateApiKey()) { - bool canSend = OnSendingMessage(raygunMessage); + bool canSend = OnSendingMessage(raygunMessage, exception); if (canSend) { HttpClientHandler handler = new HttpClientHandler {UseDefaultCredentials = true}; diff --git a/Mindscape.Raygun4Net.WindowsStore.Tests/Model/FakeRaygunClient.cs b/Mindscape.Raygun4Net.WindowsStore.Tests/Model/FakeRaygunClient.cs index f902d016..5e724fa6 100644 --- a/Mindscape.Raygun4Net.WindowsStore.Tests/Model/FakeRaygunClient.cs +++ b/Mindscape.Raygun4Net.WindowsStore.Tests/Model/FakeRaygunClient.cs @@ -23,9 +23,9 @@ public RaygunMessage ExposeBuildMessage(Exception exception, [Optional] IList ExposeStripWrapperExceptions(Exception exception) diff --git a/Mindscape.Raygun4Net.WindowsStore/RaygunClient.cs b/Mindscape.Raygun4Net.WindowsStore/RaygunClient.cs index 4a73ff73..6ea6febf 100644 --- a/Mindscape.Raygun4Net.WindowsStore/RaygunClient.cs +++ b/Mindscape.Raygun4Net.WindowsStore/RaygunClient.cs @@ -71,7 +71,7 @@ private bool ValidateApiKey() private bool _handlingRecursiveErrorSending; // Returns true if the message can be sent, false if the sending is canceled. - protected bool OnSendingMessage(RaygunMessage raygunMessage) + protected bool OnSendingMessage(RaygunMessage raygunMessage, Exception exception = null) { bool result = true; @@ -80,7 +80,7 @@ protected bool OnSendingMessage(RaygunMessage raygunMessage) EventHandler handler = SendingMessage; if (handler != null) { - RaygunSendingMessageEventArgs args = new RaygunSendingMessageEventArgs(raygunMessage); + RaygunSendingMessageEventArgs args = new RaygunSendingMessageEventArgs(raygunMessage, exception); try { handler(this, args); @@ -279,9 +279,10 @@ public async Task SendAsync(Exception exception, IList tags, IDictionary /// /// The RaygunMessage to send. This needs its OccurredOn property /// set to a valid DateTime and as much of the Details property as is available. - public async Task SendAsync(RaygunMessage raygunMessage) + /// The original exception object that the is based upon. + public async Task SendAsync(RaygunMessage raygunMessage, Exception exception = null) { - await SendOrSave(raygunMessage); + await SendOrSave(raygunMessage, exception); } /// @@ -329,9 +330,10 @@ public void Send(Exception exception, IList tags, IDictionary userCustom /// /// The RaygunMessage to send. This needs its OccurredOn property /// set to a valid DateTime and as much of the Details property as is available. - public void Send(RaygunMessage raygunMessage) + /// The original exception object that the is based upon. + public void Send(RaygunMessage raygunMessage, Exception exception = null) { - SendOrSave(raygunMessage).Wait(3000); + SendOrSave(raygunMessage, exception).Wait(3000); } private bool InternetAvailable() @@ -345,11 +347,11 @@ private bool InternetAvailable() return internetAvailable; } - private async Task SendOrSave(RaygunMessage raygunMessage) + private async Task SendOrSave(RaygunMessage raygunMessage, Exception exception) { if (ValidateApiKey()) { - bool canSend = OnSendingMessage(raygunMessage); + bool canSend = OnSendingMessage(raygunMessage, exception); if (canSend) { try @@ -551,7 +553,7 @@ private void StripAndSend(Exception exception, IList tags, IDictionary u var currentTime = DateTime.UtcNow; foreach (Exception e in StripWrapperExceptions(exception)) { - Send(BuildMessage(e, tags, userCustomData, currentTime)); + Send(BuildMessage(e, tags, userCustomData, currentTime), exception); } } @@ -561,7 +563,7 @@ private async Task StripAndSendAsync(Exception exception, IList tags, ID var currentTime = DateTime.UtcNow; foreach (Exception e in StripWrapperExceptions(exception)) { - tasks.Add(SendAsync(BuildMessage(e, tags, userCustomData, currentTime))); + tasks.Add(SendAsync(BuildMessage(e, tags, userCustomData, currentTime), exception)); } await Task.WhenAll(tasks); } diff --git a/Mindscape.Raygun4Net.Xamarin.Android/Mindscape.Raygun4Net.Xamarin.Android.csproj b/Mindscape.Raygun4Net.Xamarin.Android/Mindscape.Raygun4Net.Xamarin.Android.csproj index 723785bf..4e9c7432 100644 --- a/Mindscape.Raygun4Net.Xamarin.Android/Mindscape.Raygun4Net.Xamarin.Android.csproj +++ b/Mindscape.Raygun4Net.Xamarin.Android/Mindscape.Raygun4Net.Xamarin.Android.csproj @@ -78,15 +78,9 @@ Messages\RaygunMessage.cs - - RaygunClientBase.cs - RaygunCustomGroupingKeyEventArgs.cs - - RaygunSendingMessageEventArgs.cs - SimpleJson.cs @@ -114,6 +108,8 @@ + + diff --git a/Mindscape.Raygun4Net.Xamarin.Android/RaygunClientBase.cs b/Mindscape.Raygun4Net.Xamarin.Android/RaygunClientBase.cs new file mode 100644 index 00000000..5b85fb32 --- /dev/null +++ b/Mindscape.Raygun4Net.Xamarin.Android/RaygunClientBase.cs @@ -0,0 +1,140 @@ +using System; +using System.Net; +using Mindscape.Raygun4Net.Messages; + +namespace Mindscape.Raygun4Net +{ + public abstract class RaygunClientBase + { + protected internal const string SentKey = "AlreadySentByRaygun"; + + /// + /// Gets or sets the user identity string. + /// + public virtual string User { get; set; } + + /// + /// Gets or sets information about the user including the identity string. + /// + public virtual RaygunIdentifierMessage UserInfo { get; set; } + + /// + /// Gets or sets the context identifier defining a scope under which errors are related + /// + public string ContextId { get; set; } + + /// + /// Gets or sets a custom application version identifier for all error messages sent to the Raygun endpoint. + /// + public string ApplicationVersion { get; set; } + + protected virtual bool CanSend(Exception exception) + { + return exception == null || exception.Data == null || !exception.Data.Contains(SentKey) || false.Equals(exception.Data[SentKey]); + } + + protected void FlagAsSent(Exception exception) + { + if (exception != null && exception.Data != null) + { + try + { + Type[] genericTypes = exception.Data.GetType().GetGenericArguments(); + if (genericTypes.Length == 0 || genericTypes[0].IsAssignableFrom(typeof(string))) + { + exception.Data[SentKey] = true; + } + } + catch (Exception ex) + { + System.Diagnostics.Debug.WriteLine(String.Format("Failed to flag exception as sent: {0}", ex.Message)); + } + } + } + + /// + /// Raised just before a message is sent. This can be used to make final adjustments to the , or to cancel the send. + /// + public event EventHandler SendingMessage; + + private bool _handlingRecursiveErrorSending; + + // Returns true if the message can be sent, false if the sending is canceled. + protected bool OnSendingMessage(RaygunMessage raygunMessage) + { + bool result = true; + + if (!_handlingRecursiveErrorSending) + { + EventHandler handler = SendingMessage; + + if (handler != null) + { + RaygunSendingMessageEventArgs args = new RaygunSendingMessageEventArgs(raygunMessage); + + try + { + handler(this, args); + } + catch (Exception e) + { + // Catch and send exceptions that occur in the SendingMessage event handler. + // Set the _handlingRecursiveErrorSending flag to prevent infinite errors. + _handlingRecursiveErrorSending = true; + Send(e); + _handlingRecursiveErrorSending = false; + } + + result = !args.Cancel; + } + } + + return result; + } + + /// + /// Raised before a message is sent. This can be used to add a custom grouping key to a RaygunMessage before sending it to the Raygun service. + /// + public event EventHandler CustomGroupingKey; + + private bool _handlingRecursiveGrouping; + protected string OnCustomGroupingKey(Exception exception, RaygunMessage message) + { + string result = null; + if(!_handlingRecursiveGrouping) + { + var handler = CustomGroupingKey; + if(handler != null) + { + var args = new RaygunCustomGroupingKeyEventArgs(exception, message); + try + { + handler(this, args); + } + catch (Exception e) + { + _handlingRecursiveGrouping = true; + Send(e); + _handlingRecursiveGrouping = false; + } + result = args.CustomGroupingKey; + } + } + return result; + } + + /// + /// Transmits an exception to Raygun.io synchronously. + /// + /// The exception to deliver. + public abstract void Send(Exception exception); + + /// + /// Posts a RaygunMessage to the Raygun.io api endpoint. + /// + /// The RaygunMessage to send. This needs its OccurredOn property + /// set to a valid DateTime and as much of the Details property as is available. + /// The original exception used to generate the RaygunMessage + public abstract void Send(RaygunMessage raygunMessage); + } +} diff --git a/Mindscape.Raygun4Net.Xamarin.Android/RaygunSendingMessageEventArgs.cs b/Mindscape.Raygun4Net.Xamarin.Android/RaygunSendingMessageEventArgs.cs new file mode 100644 index 00000000..49378c29 --- /dev/null +++ b/Mindscape.Raygun4Net.Xamarin.Android/RaygunSendingMessageEventArgs.cs @@ -0,0 +1,24 @@ +using System; +using System.ComponentModel; +using Mindscape.Raygun4Net.Messages; + +namespace Mindscape.Raygun4Net +{ + /// + /// Can be used to modify the message before sending, or to cancel the send operation. + /// + public class RaygunSendingMessageEventArgs : CancelEventArgs + { + private RaygunMessage _raygunMessage; + + public RaygunSendingMessageEventArgs(RaygunMessage message) + { + _raygunMessage = message; + } + + public RaygunMessage Message + { + get { return _raygunMessage; } + } + } +} diff --git a/Mindscape.Raygun4Net.Xamarin.Mac.Unified/Mindscape.Raygun4Net.Xamarin.Mac.Unified.csproj b/Mindscape.Raygun4Net.Xamarin.Mac.Unified/Mindscape.Raygun4Net.Xamarin.Mac.Unified.csproj index adf65018..c3454319 100644 --- a/Mindscape.Raygun4Net.Xamarin.Mac.Unified/Mindscape.Raygun4Net.Xamarin.Mac.Unified.csproj +++ b/Mindscape.Raygun4Net.Xamarin.Mac.Unified/Mindscape.Raygun4Net.Xamarin.Mac.Unified.csproj @@ -71,12 +71,6 @@ IRaygunMessageBuilder.cs - - RaygunClientBase.cs - - - RaygunSendingMessageEventArgs.cs - SimpleJson.cs @@ -116,6 +110,12 @@ RaygunCustomGroupingKeyEventArgs.cs + + RaygunClientBase.cs + + + RaygunSendingMessageEventArgs.cs + diff --git a/Mindscape.Raygun4Net.Xamarin.Mac/Mindscape.Raygun4Net.Xamarin.Mac.csproj b/Mindscape.Raygun4Net.Xamarin.Mac/Mindscape.Raygun4Net.Xamarin.Mac.csproj index e0b80c4b..c233521f 100644 --- a/Mindscape.Raygun4Net.Xamarin.Mac/Mindscape.Raygun4Net.Xamarin.Mac.csproj +++ b/Mindscape.Raygun4Net.Xamarin.Mac/Mindscape.Raygun4Net.Xamarin.Mac.csproj @@ -84,9 +84,6 @@ - - RaygunSendingMessageEventArgs.cs - Builders\RaygunErrorMessageBuilderBase.cs @@ -107,15 +104,14 @@ Messages\RaygunMessageDetails.cs - - RaygunClientBase.cs - Messages\RaygunErrorMessage.cs RaygunCustomGroupingKeyEventArgs.cs + + diff --git a/Mindscape.Raygun4Net.Xamarin.Mac/RaygunClientBase.cs b/Mindscape.Raygun4Net.Xamarin.Mac/RaygunClientBase.cs new file mode 100644 index 00000000..5b85fb32 --- /dev/null +++ b/Mindscape.Raygun4Net.Xamarin.Mac/RaygunClientBase.cs @@ -0,0 +1,140 @@ +using System; +using System.Net; +using Mindscape.Raygun4Net.Messages; + +namespace Mindscape.Raygun4Net +{ + public abstract class RaygunClientBase + { + protected internal const string SentKey = "AlreadySentByRaygun"; + + /// + /// Gets or sets the user identity string. + /// + public virtual string User { get; set; } + + /// + /// Gets or sets information about the user including the identity string. + /// + public virtual RaygunIdentifierMessage UserInfo { get; set; } + + /// + /// Gets or sets the context identifier defining a scope under which errors are related + /// + public string ContextId { get; set; } + + /// + /// Gets or sets a custom application version identifier for all error messages sent to the Raygun endpoint. + /// + public string ApplicationVersion { get; set; } + + protected virtual bool CanSend(Exception exception) + { + return exception == null || exception.Data == null || !exception.Data.Contains(SentKey) || false.Equals(exception.Data[SentKey]); + } + + protected void FlagAsSent(Exception exception) + { + if (exception != null && exception.Data != null) + { + try + { + Type[] genericTypes = exception.Data.GetType().GetGenericArguments(); + if (genericTypes.Length == 0 || genericTypes[0].IsAssignableFrom(typeof(string))) + { + exception.Data[SentKey] = true; + } + } + catch (Exception ex) + { + System.Diagnostics.Debug.WriteLine(String.Format("Failed to flag exception as sent: {0}", ex.Message)); + } + } + } + + /// + /// Raised just before a message is sent. This can be used to make final adjustments to the , or to cancel the send. + /// + public event EventHandler SendingMessage; + + private bool _handlingRecursiveErrorSending; + + // Returns true if the message can be sent, false if the sending is canceled. + protected bool OnSendingMessage(RaygunMessage raygunMessage) + { + bool result = true; + + if (!_handlingRecursiveErrorSending) + { + EventHandler handler = SendingMessage; + + if (handler != null) + { + RaygunSendingMessageEventArgs args = new RaygunSendingMessageEventArgs(raygunMessage); + + try + { + handler(this, args); + } + catch (Exception e) + { + // Catch and send exceptions that occur in the SendingMessage event handler. + // Set the _handlingRecursiveErrorSending flag to prevent infinite errors. + _handlingRecursiveErrorSending = true; + Send(e); + _handlingRecursiveErrorSending = false; + } + + result = !args.Cancel; + } + } + + return result; + } + + /// + /// Raised before a message is sent. This can be used to add a custom grouping key to a RaygunMessage before sending it to the Raygun service. + /// + public event EventHandler CustomGroupingKey; + + private bool _handlingRecursiveGrouping; + protected string OnCustomGroupingKey(Exception exception, RaygunMessage message) + { + string result = null; + if(!_handlingRecursiveGrouping) + { + var handler = CustomGroupingKey; + if(handler != null) + { + var args = new RaygunCustomGroupingKeyEventArgs(exception, message); + try + { + handler(this, args); + } + catch (Exception e) + { + _handlingRecursiveGrouping = true; + Send(e); + _handlingRecursiveGrouping = false; + } + result = args.CustomGroupingKey; + } + } + return result; + } + + /// + /// Transmits an exception to Raygun.io synchronously. + /// + /// The exception to deliver. + public abstract void Send(Exception exception); + + /// + /// Posts a RaygunMessage to the Raygun.io api endpoint. + /// + /// The RaygunMessage to send. This needs its OccurredOn property + /// set to a valid DateTime and as much of the Details property as is available. + /// The original exception used to generate the RaygunMessage + public abstract void Send(RaygunMessage raygunMessage); + } +} diff --git a/Mindscape.Raygun4Net.Xamarin.Mac/RaygunSendingMessageEventArgs.cs b/Mindscape.Raygun4Net.Xamarin.Mac/RaygunSendingMessageEventArgs.cs new file mode 100644 index 00000000..49378c29 --- /dev/null +++ b/Mindscape.Raygun4Net.Xamarin.Mac/RaygunSendingMessageEventArgs.cs @@ -0,0 +1,24 @@ +using System; +using System.ComponentModel; +using Mindscape.Raygun4Net.Messages; + +namespace Mindscape.Raygun4Net +{ + /// + /// Can be used to modify the message before sending, or to cancel the send operation. + /// + public class RaygunSendingMessageEventArgs : CancelEventArgs + { + private RaygunMessage _raygunMessage; + + public RaygunSendingMessageEventArgs(RaygunMessage message) + { + _raygunMessage = message; + } + + public RaygunMessage Message + { + get { return _raygunMessage; } + } + } +} diff --git a/Mindscape.Raygun4Net.Xamarin.iOS.Unified/Mindscape.Raygun4Net.Xamarin.iOS.Unified.csproj b/Mindscape.Raygun4Net.Xamarin.iOS.Unified/Mindscape.Raygun4Net.Xamarin.iOS.Unified.csproj index 3ec9d140..dd9c33e1 100644 --- a/Mindscape.Raygun4Net.Xamarin.iOS.Unified/Mindscape.Raygun4Net.Xamarin.iOS.Unified.csproj +++ b/Mindscape.Raygun4Net.Xamarin.iOS.Unified/Mindscape.Raygun4Net.Xamarin.iOS.Unified.csproj @@ -125,12 +125,6 @@ IRaygunMessageBuilder.cs - - RaygunClientBase.cs - - - RaygunSendingMessageEventArgs.cs - Messages\RaygunClientMessage.cs @@ -159,6 +153,9 @@ Messages\RaygunMessageDetails.cs + + RaygunClientBase.cs + RaygunClient.cs @@ -204,6 +201,9 @@ + + RaygunSendingMessageEventArgs.cs + diff --git a/Mindscape.Raygun4Net.Xamarin.iOS/RaygunClientBase.cs b/Mindscape.Raygun4Net.Xamarin.iOS/RaygunClientBase.cs new file mode 100644 index 00000000..5b85fb32 --- /dev/null +++ b/Mindscape.Raygun4Net.Xamarin.iOS/RaygunClientBase.cs @@ -0,0 +1,140 @@ +using System; +using System.Net; +using Mindscape.Raygun4Net.Messages; + +namespace Mindscape.Raygun4Net +{ + public abstract class RaygunClientBase + { + protected internal const string SentKey = "AlreadySentByRaygun"; + + /// + /// Gets or sets the user identity string. + /// + public virtual string User { get; set; } + + /// + /// Gets or sets information about the user including the identity string. + /// + public virtual RaygunIdentifierMessage UserInfo { get; set; } + + /// + /// Gets or sets the context identifier defining a scope under which errors are related + /// + public string ContextId { get; set; } + + /// + /// Gets or sets a custom application version identifier for all error messages sent to the Raygun endpoint. + /// + public string ApplicationVersion { get; set; } + + protected virtual bool CanSend(Exception exception) + { + return exception == null || exception.Data == null || !exception.Data.Contains(SentKey) || false.Equals(exception.Data[SentKey]); + } + + protected void FlagAsSent(Exception exception) + { + if (exception != null && exception.Data != null) + { + try + { + Type[] genericTypes = exception.Data.GetType().GetGenericArguments(); + if (genericTypes.Length == 0 || genericTypes[0].IsAssignableFrom(typeof(string))) + { + exception.Data[SentKey] = true; + } + } + catch (Exception ex) + { + System.Diagnostics.Debug.WriteLine(String.Format("Failed to flag exception as sent: {0}", ex.Message)); + } + } + } + + /// + /// Raised just before a message is sent. This can be used to make final adjustments to the , or to cancel the send. + /// + public event EventHandler SendingMessage; + + private bool _handlingRecursiveErrorSending; + + // Returns true if the message can be sent, false if the sending is canceled. + protected bool OnSendingMessage(RaygunMessage raygunMessage) + { + bool result = true; + + if (!_handlingRecursiveErrorSending) + { + EventHandler handler = SendingMessage; + + if (handler != null) + { + RaygunSendingMessageEventArgs args = new RaygunSendingMessageEventArgs(raygunMessage); + + try + { + handler(this, args); + } + catch (Exception e) + { + // Catch and send exceptions that occur in the SendingMessage event handler. + // Set the _handlingRecursiveErrorSending flag to prevent infinite errors. + _handlingRecursiveErrorSending = true; + Send(e); + _handlingRecursiveErrorSending = false; + } + + result = !args.Cancel; + } + } + + return result; + } + + /// + /// Raised before a message is sent. This can be used to add a custom grouping key to a RaygunMessage before sending it to the Raygun service. + /// + public event EventHandler CustomGroupingKey; + + private bool _handlingRecursiveGrouping; + protected string OnCustomGroupingKey(Exception exception, RaygunMessage message) + { + string result = null; + if(!_handlingRecursiveGrouping) + { + var handler = CustomGroupingKey; + if(handler != null) + { + var args = new RaygunCustomGroupingKeyEventArgs(exception, message); + try + { + handler(this, args); + } + catch (Exception e) + { + _handlingRecursiveGrouping = true; + Send(e); + _handlingRecursiveGrouping = false; + } + result = args.CustomGroupingKey; + } + } + return result; + } + + /// + /// Transmits an exception to Raygun.io synchronously. + /// + /// The exception to deliver. + public abstract void Send(Exception exception); + + /// + /// Posts a RaygunMessage to the Raygun.io api endpoint. + /// + /// The RaygunMessage to send. This needs its OccurredOn property + /// set to a valid DateTime and as much of the Details property as is available. + /// The original exception used to generate the RaygunMessage + public abstract void Send(RaygunMessage raygunMessage); + } +} diff --git a/Mindscape.Raygun4Net.Xamarin.iOS/RaygunSendingMessageEventArgs.cs b/Mindscape.Raygun4Net.Xamarin.iOS/RaygunSendingMessageEventArgs.cs new file mode 100644 index 00000000..49378c29 --- /dev/null +++ b/Mindscape.Raygun4Net.Xamarin.iOS/RaygunSendingMessageEventArgs.cs @@ -0,0 +1,24 @@ +using System; +using System.ComponentModel; +using Mindscape.Raygun4Net.Messages; + +namespace Mindscape.Raygun4Net +{ + /// + /// Can be used to modify the message before sending, or to cancel the send operation. + /// + public class RaygunSendingMessageEventArgs : CancelEventArgs + { + private RaygunMessage _raygunMessage; + + public RaygunSendingMessageEventArgs(RaygunMessage message) + { + _raygunMessage = message; + } + + public RaygunMessage Message + { + get { return _raygunMessage; } + } + } +} diff --git a/Mindscape.Raygun4Net.nuspec b/Mindscape.Raygun4Net.nuspec index 0e197ea8..984ed1c4 100644 --- a/Mindscape.Raygun4Net.nuspec +++ b/Mindscape.Raygun4Net.nuspec @@ -2,7 +2,7 @@ Mindscape.Raygun4Net - 5.10.2 + 5.11.0 <authors>Raygun</authors> <owners /> diff --git a/Mindscape.Raygun4Net/RaygunClient.cs b/Mindscape.Raygun4Net/RaygunClient.cs index 9f0a22c9..0e53ef9b 100644 --- a/Mindscape.Raygun4Net/RaygunClient.cs +++ b/Mindscape.Raygun4Net/RaygunClient.cs @@ -251,7 +251,7 @@ public void Send(Exception exception, IList<string> tags, IDictionary userCustom { _currentRequestMessage = BuildRequestMessage(); - Send(BuildMessage(exception, tags, userCustomData, userInfo, null)); + Send(BuildMessage(exception, tags, userCustomData, userInfo, null), exception); FlagAsSent(exception); } } @@ -301,13 +301,13 @@ public void SendInBackground(Exception exception, IList<string> tags, IDictionar // otherwise it will be disposed while we are using it on the other thread. RaygunRequestMessage currentRequestMessage = BuildRequestMessage(); DateTime currentTime = DateTime.UtcNow; - + ThreadPool.QueueUserWorkItem(c => { try { _currentRequestMessage = currentRequestMessage; - Send(BuildMessage(exception, tags, userCustomData, userInfo, currentTime)); + Send(BuildMessage(exception, tags, userCustomData, userInfo, currentTime), exception); } catch (Exception) { @@ -328,9 +328,10 @@ public void SendInBackground(Exception exception, IList<string> tags, IDictionar /// </summary> /// <param name="raygunMessage">The RaygunMessage to send. This needs its OccurredOn property /// set to a valid DateTime and as much of the Details property as is available.</param> - public void SendInBackground(RaygunMessage raygunMessage) + /// <param name="exception">The original exception object that the <paramref name="raygunMessage"/> is based upon.</param> + public void SendInBackground(RaygunMessage raygunMessage, Exception exception = null) { - ThreadPool.QueueUserWorkItem(c => Send(raygunMessage)); + ThreadPool.QueueUserWorkItem(c => Send(raygunMessage, exception)); } private RaygunRequestMessage BuildRequestMessage() @@ -409,9 +410,10 @@ private Exception StripWrapperExceptions(Exception exception) /// </summary> /// <param name="raygunMessage">The RaygunMessage to send. This needs its OccurredOn property /// set to a valid DateTime and as much of the Details property as is available.</param> - public override void Send(RaygunMessage raygunMessage) + /// <param name="exception">The original exception that generated the RaygunMessage</param> + public override void Send(RaygunMessage raygunMessage, Exception exception = null) { - bool canSend = OnSendingMessage(raygunMessage); + bool canSend = OnSendingMessage(raygunMessage, exception); if (canSend) { string message = null; diff --git a/Mindscape.Raygun4Net/RaygunClientBase.cs b/Mindscape.Raygun4Net/RaygunClientBase.cs index 4bf0633c..d08445a0 100644 --- a/Mindscape.Raygun4Net/RaygunClientBase.cs +++ b/Mindscape.Raygun4Net/RaygunClientBase.cs @@ -60,16 +60,18 @@ protected void FlagAsSent(Exception exception) private bool _handlingRecursiveErrorSending; // Returns true if the message can be sent, false if the sending is canceled. - protected bool OnSendingMessage(RaygunMessage raygunMessage) + protected bool OnSendingMessage(RaygunMessage raygunMessage, Exception exception) { bool result = true; if (!_handlingRecursiveErrorSending) { EventHandler<RaygunSendingMessageEventArgs> handler = SendingMessage; + if (handler != null) { - RaygunSendingMessageEventArgs args = new RaygunSendingMessageEventArgs(raygunMessage); + RaygunSendingMessageEventArgs args = new RaygunSendingMessageEventArgs(raygunMessage, exception); + try { handler(this, args); @@ -82,6 +84,7 @@ protected bool OnSendingMessage(RaygunMessage raygunMessage) Send(e); _handlingRecursiveErrorSending = false; } + result = !args.Cancel; } } @@ -131,6 +134,7 @@ protected string OnCustomGroupingKey(Exception exception, RaygunMessage message) /// </summary> /// <param name="raygunMessage">The RaygunMessage to send. This needs its OccurredOn property /// set to a valid DateTime and as much of the Details property as is available.</param> - public abstract void Send(RaygunMessage raygunMessage); + /// <param name="exception">The original exception used to generate the RaygunMessage</param> + public abstract void Send(RaygunMessage raygunMessage, Exception exception = null); } } diff --git a/Mindscape.Raygun4Net/RaygunSendingMessageEventArgs.cs b/Mindscape.Raygun4Net/RaygunSendingMessageEventArgs.cs index f28e83e6..28d2665b 100644 --- a/Mindscape.Raygun4Net/RaygunSendingMessageEventArgs.cs +++ b/Mindscape.Raygun4Net/RaygunSendingMessageEventArgs.cs @@ -9,11 +9,28 @@ namespace Mindscape.Raygun4Net /// </summary> public class RaygunSendingMessageEventArgs : CancelEventArgs { + private RaygunMessage _raygunMessage; + private Exception _exception; + public RaygunSendingMessageEventArgs(RaygunMessage message) + : this(message, null) + { + } + + public RaygunSendingMessageEventArgs(RaygunMessage message, Exception exception) { - Message = message; + _raygunMessage = message; + _exception = exception; } - public RaygunMessage Message { get; private set; } + public RaygunMessage Message + { + get { return _raygunMessage; } + } + + public Exception Exception + { + get { return _exception; } + } } } diff --git a/Mindscape.Raygun4Net2.Tests/Model/FakeRaygunClient.cs b/Mindscape.Raygun4Net2.Tests/Model/FakeRaygunClient.cs index 280ea2a5..24130cfc 100644 --- a/Mindscape.Raygun4Net2.Tests/Model/FakeRaygunClient.cs +++ b/Mindscape.Raygun4Net2.Tests/Model/FakeRaygunClient.cs @@ -25,9 +25,9 @@ public bool ExposeValidateApiKey() return ValidateApiKey(); } - public bool ExposeOnSendingMessage(RaygunMessage message) + public bool ExposeOnSendingMessage(RaygunMessage message, Exception exception) { - return OnSendingMessage(message); + return OnSendingMessage(message, exception); } } } diff --git a/Mindscape.Raygun4Net2.Tests/RaygunClientTests.cs b/Mindscape.Raygun4Net2.Tests/RaygunClientTests.cs index 8dea569e..c47159ec 100644 --- a/Mindscape.Raygun4Net2.Tests/RaygunClientTests.cs +++ b/Mindscape.Raygun4Net2.Tests/RaygunClientTests.cs @@ -258,7 +258,7 @@ public void UserCustomData() [Test] public void NoHandlerSendsAll() { - Assert.IsTrue(_client.ExposeOnSendingMessage(_client.ExposeBuildMessage(_exception))); + Assert.IsTrue(_client.ExposeOnSendingMessage(_client.ExposeBuildMessage(_exception), _exception)); } [Test] @@ -271,7 +271,7 @@ public void HandlerIsChecked() filterCalled = true; e.Cancel = true; }; - Assert.IsFalse(_client.ExposeOnSendingMessage(_client.ExposeBuildMessage(_exception))); + Assert.IsFalse(_client.ExposeOnSendingMessage(_client.ExposeBuildMessage(_exception), _exception)); Assert.IsTrue(filterCalled); } @@ -282,7 +282,7 @@ public void HandlerCanAllowSend() { // Allow send by not setting e.Cancel }; - Assert.IsTrue(_client.ExposeOnSendingMessage(_client.ExposeBuildMessage(_exception))); + Assert.IsTrue(_client.ExposeOnSendingMessage(_client.ExposeBuildMessage(_exception), _exception)); } [Test] @@ -302,7 +302,7 @@ public void AllHandlersAreChecked() filter2Called = true; e.Cancel = true; }; - Assert.IsFalse(_client.ExposeOnSendingMessage(_client.ExposeBuildMessage(_exception))); + Assert.IsFalse(_client.ExposeOnSendingMessage(_client.ExposeBuildMessage(_exception), _exception)); Assert.IsTrue(filter1Called); Assert.IsTrue(filter2Called); } @@ -318,7 +318,7 @@ public void DontSendIfFirstHandlerCancels() { // Allow send by not setting e.Cancel }; - Assert.IsFalse(_client.ExposeOnSendingMessage(_client.ExposeBuildMessage(_exception))); + Assert.IsFalse(_client.ExposeOnSendingMessage(_client.ExposeBuildMessage(_exception), _exception)); } [Test] @@ -332,7 +332,7 @@ public void DontSendIfSecondHandlerCancels() { e.Cancel = true; }; - Assert.IsFalse(_client.ExposeOnSendingMessage(_client.ExposeBuildMessage(_exception))); + Assert.IsFalse(_client.ExposeOnSendingMessage(_client.ExposeBuildMessage(_exception), _exception)); } [Test] @@ -346,7 +346,7 @@ public void AllowSendIfNoHandlerCancels() { // Allow send by not setting e.Cancel }; - Assert.IsTrue(_client.ExposeOnSendingMessage(_client.ExposeBuildMessage(_exception))); + Assert.IsTrue(_client.ExposeOnSendingMessage(_client.ExposeBuildMessage(_exception), _exception)); } [Test] @@ -360,7 +360,7 @@ public void HandlerCanModifyMessage() e.Message.Details.Error.Message = "Custom error message"; }; - Assert.IsTrue(_client.ExposeOnSendingMessage(message)); + Assert.IsTrue(_client.ExposeOnSendingMessage(message, _exception)); Assert.AreEqual("Custom error message", message.Details.Error.Message); } } diff --git a/Mindscape.Raygun4Net2/RaygunClient.cs b/Mindscape.Raygun4Net2/RaygunClient.cs index 2f7bed78..b1afe93d 100644 --- a/Mindscape.Raygun4Net2/RaygunClient.cs +++ b/Mindscape.Raygun4Net2/RaygunClient.cs @@ -201,7 +201,7 @@ public void Send(Exception exception, IList<string> tags, IDictionary userCustom { _currentRequestMessage = BuildRequestMessage(); - Send(BuildMessage(exception, tags, userCustomData, null)); + Send(BuildMessage(exception, tags, userCustomData, null), exception); } /// <summary> @@ -238,7 +238,7 @@ public void SendInBackground(Exception exception, IList<string> tags, IDictionar DateTime? currentTime = DateTime.UtcNow; ThreadPool.QueueUserWorkItem(c => { _currentRequestMessage = currentRequestMessage; - Send(BuildMessage(exception, tags, userCustomData, currentTime)); + Send(BuildMessage(exception, tags, userCustomData, currentTime), exception); }); } @@ -247,9 +247,10 @@ public void SendInBackground(Exception exception, IList<string> tags, IDictionar /// </summary> /// <param name="raygunMessage">The RaygunMessage to send. This needs its OccurredOn property /// set to a valid DateTime and as much of the Details property as is available.</param> - public void SendInBackground(RaygunMessage raygunMessage) + /// <param name="exception">The original exception that gernerated the RaygunMessage</param> + public void SendInBackground(RaygunMessage raygunMessage, Exception exception = null) { - ThreadPool.QueueUserWorkItem(c => Send(raygunMessage)); + ThreadPool.QueueUserWorkItem(c => Send(raygunMessage, exception)); } private RaygunRequestMessage BuildRequestMessage() @@ -320,11 +321,12 @@ private Exception StripWrapperExceptions(Exception exception) /// </summary> /// <param name="raygunMessage">The RaygunMessage to send. This needs its OccurredOn property /// set to a valid DateTime and as much of the Details property as is available.</param> - public override void Send(RaygunMessage raygunMessage) + ///<param name="exception">The original exception that generated the RaygunMessage</param> + public override void Send(RaygunMessage raygunMessage, Exception exception = null) { if (ValidateApiKey()) { - bool canSend = OnSendingMessage(raygunMessage); + bool canSend = OnSendingMessage(raygunMessage, exception); if (canSend) { string message = null; diff --git a/Mindscape.Raygun4Net4.ClientProfile/RaygunClient.cs b/Mindscape.Raygun4Net4.ClientProfile/RaygunClient.cs index b708d266..b8fab232 100644 --- a/Mindscape.Raygun4Net4.ClientProfile/RaygunClient.cs +++ b/Mindscape.Raygun4Net4.ClientProfile/RaygunClient.cs @@ -212,9 +212,10 @@ public void SendInBackground(Exception exception, IList<string> tags, IDictionar /// </summary> /// <param name="raygunMessage">The RaygunMessage to send. This needs its OccurredOn property /// set to a valid DateTime and as much of the Details property as is available.</param> - public void SendInBackground(RaygunMessage raygunMessage) + /// <param name="exception">The original exception that generated the RaygunMessage</param> + public void SendInBackground(RaygunMessage raygunMessage, Exception exception) { - ThreadPool.QueueUserWorkItem(c => Send(raygunMessage)); + ThreadPool.QueueUserWorkItem(c => Send(raygunMessage, exception)); } protected RaygunMessage BuildMessage(Exception exception, IList<string> tags, IDictionary userCustomData) @@ -247,7 +248,7 @@ private void StripAndSend(Exception exception, IList<string> tags, IDictionary u { foreach (Exception e in StripWrapperExceptions(exception)) { - Send(BuildMessage(e, tags, userCustomData, userInfo, currentTime)); + Send(BuildMessage(e, tags, userCustomData, userInfo, currentTime), exception); } } @@ -285,9 +286,10 @@ protected IEnumerable<Exception> StripWrapperExceptions(Exception exception) /// </summary> /// <param name="raygunMessage">The RaygunMessage to send. This needs its OccurredOn property /// set to a valid DateTime and as much of the Details property as is available.</param> - public override void Send(RaygunMessage raygunMessage) + /// <param name="exception">The original exception that generated the RaygunMessage</param> + public override void Send(RaygunMessage raygunMessage, Exception exception = null) { - bool canSend = OnSendingMessage(raygunMessage); + bool canSend = OnSendingMessage(raygunMessage, exception); if (canSend) { string message = null; diff --git a/Mindscape.Raygun4Net4/RaygunClient.cs b/Mindscape.Raygun4Net4/RaygunClient.cs index 27c699cc..ec565091 100644 --- a/Mindscape.Raygun4Net4/RaygunClient.cs +++ b/Mindscape.Raygun4Net4/RaygunClient.cs @@ -259,7 +259,7 @@ public bool UseKeyValuePairRawDataFilter /// <summary> /// Add an <see cref="IRaygunDataFilter"/> implementation to be used when capturing the raw data - /// of a HTTP request. This filter will be passed the request raw data and is expected to remove + /// of a HTTP request. This filter will be passed the request raw data and is expected to remove /// or replace values whose keys are found in the list supplied to the Filter method. /// </summary> /// <param name="filter">Custom raw data filter implementation.</param> @@ -450,9 +450,10 @@ public void SendInBackground(Exception exception, IList<string> tags, IDictionar /// </summary> /// <param name="raygunMessage">The RaygunMessage to send. This needs its OccurredOn property /// set to a valid DateTime and as much of the Details property as is available.</param> - public void SendInBackground(RaygunMessage raygunMessage) + /// <param name="exception">The original exception that generated the RaygunMessage</param> + public void SendInBackground(RaygunMessage raygunMessage, Exception exception = null) { - ThreadPool.QueueUserWorkItem(c => Send(raygunMessage)); + ThreadPool.QueueUserWorkItem(c => Send(raygunMessage, exception)); } private RaygunRequestMessage BuildRequestMessage() @@ -522,7 +523,7 @@ private void StripAndSend(Exception exception, IList<string> tags, IDictionary u { foreach (Exception e in StripWrapperExceptions(exception)) { - Send(BuildMessage(e, tags, userCustomData, userInfo, currentTime)); + Send(BuildMessage(e, tags, userCustomData, userInfo, currentTime), exception); } } @@ -585,10 +586,10 @@ protected IEnumerable<Exception> StripWrapperExceptions(Exception exception) /// </summary> /// <param name="raygunMessage">The RaygunMessage to send. This needs its OccurredOn property /// set to a valid DateTime and as much of the Details property as is available.</param> - public override void Send(RaygunMessage raygunMessage) + /// <param name="exception">The original exception used to generate the RaygunMessage</param> + public override void Send(RaygunMessage raygunMessage, Exception exception = null) { - bool canSend = OnSendingMessage(raygunMessage); - if (canSend) + if (OnSendingMessage(raygunMessage, exception)) { string message = null; try @@ -613,7 +614,7 @@ public override void Send(RaygunMessage raygunMessage) { WebClientHelper.WebProxy = WebProxy; } - + WebClientHelper.Send(message, _apiKey, ProxyCredentials); } catch (Exception sendMessageException) @@ -621,7 +622,7 @@ public override void Send(RaygunMessage raygunMessage) try { System.Diagnostics.Trace.WriteLine($"Error sending exception to Raygun.io due to: {sendMessageException}"); - + // Attempt to store the message in isolated storage. SaveMessage(message); } @@ -714,7 +715,7 @@ private void SendStoredMessages() System.Diagnostics.Debug.WriteLine("ApiKey has not been provided, skipping sending stored Raygun messages"); return; } - + try { using (IsolatedStorageFile isolatedStorage = GetIsolatedStorageScope()) @@ -735,7 +736,7 @@ private void SendStoredMessages() { WebClientHelper.WebProxy = WebProxy; } - + WebClientHelper.Send(text, _apiKey, ProxyCredentials); } catch