using System;
using System.Collections.Generic;
using System.Diagnostics;
using System.Reflection;
using System.Threading;
using System.Web;
using Exceptron.Client.Configuration;
using Exceptron.Client.Message;
namespace Exceptron.Client
{
public class ExceptronClient : IExceptronClient
{
internal IRestClient RestClient { private get; set; }
///
/// Version of Client
///
public string ClientVersion
{
get { return Assembly.GetExecutingAssembly().GetName().Version.ToString(); }
}
///
/// Name of Client
///
public string ClientName
{
get { return "Official .NET"; }
}
///
/// Client Configuration
///
public ExceptronConfiguration Configuration { get; private set; }
///
/// Framework Type of the Host Application (.Net/mono)
///
public string FrameworkType { get; set; }
///
/// Creates a new instance of
/// Loads from application config file.
///
/// Version of the currently running application
public ExceptronClient(Version applicationVersion)
: this(ExceptronConfiguration.ReadConfig(), applicationVersion)
{
FrameworkType = ".Net";
}
private readonly string _applicationVersion;
private readonly string _maxFrameworkVersion;
/// exceptron client configuration
///
public ExceptronClient(ExceptronConfiguration exceptronConfiguration, Version applicationVersion)
{
if (exceptronConfiguration == null)
throw new ArgumentNullException("exceptronConfiguration");
if (applicationVersion == null)
throw new ArgumentNullException("applicationVersion");
if (string.IsNullOrEmpty(exceptronConfiguration.ApiKey))
throw new ArgumentException("An API Key was not provided");
Configuration = exceptronConfiguration;
RestClient = new RestClient();
_applicationVersion = applicationVersion.ToString();
_maxFrameworkVersion = GetMaximumFrameworkVersion();
FrameworkType = ".Net";
}
///
/// Submit an exception to exceptron Servers.
///
/// Exception that is being reported
/// Component that experienced this exception.
/// Severity of the exception being reported
/// Any message that should be attached to this exceptions
/// ID that will uniquely identify the user
/// in which the exception occurred. If no is provided
/// will try to get the current from
///
public ExceptionResponse SubmitException(Exception exception, string component, ExceptionSeverity severity = ExceptionSeverity.None, string message = null, string userId = null, HttpContext httpContext = null)
{
var exceptionData = new ExceptionData
{
Exception = exception,
Component = component,
Severity = severity,
Message = message,
UserId = userId,
HttpContext = httpContext
};
return SubmitException(exceptionData);
}
///
/// Submit an exception to exceptron Servers.
///
/// Exception data to be reported to the server
public ExceptionResponse SubmitException(ExceptionData exceptionData)
{
try
{
ValidateState(exceptionData);
var report = new ExceptionReport();
report.ap = Configuration.ApiKey;
report.dn = ClientName;
report.dv = ClientVersion;
report.aver = _applicationVersion;
report.ext = exceptionData.Exception.GetType().FullName;
report.stk = ConvertToFrames(exceptionData.Exception);
report.exm = exceptionData.Exception.Message;
report.cmp = exceptionData.Component;
report.uid = exceptionData.UserId;
report.msg = exceptionData.Message;
report.sv = (int)exceptionData.Severity;
report.fv = _maxFrameworkVersion;
report.ft = FrameworkType;
SetHttpInfo(exceptionData, report);
SetEnviromentInfo(report);
return RestClient.Put(Configuration.Host, report);
}
catch (Exception e)
{
Trace.WriteLine("Unable to submit exception to exceptron. ", e.ToString());
if (Configuration.ThrowExceptions)
{
throw;
}
return new ExceptionResponse { Exception = e };
}
}
private void ValidateState(ExceptionData exceptionData)
{
if (string.IsNullOrEmpty(Configuration.ApiKey))
throw new InvalidOperationException("ApiKey has not been provided for this client.");
if (exceptionData == null)
throw new ArgumentNullException("exceptionData");
if (exceptionData.Exception == null)
throw new ArgumentException("ExceptionData.Exception Cannot be null.", "exceptionData");
}
private void SetEnviromentInfo(ExceptionReport report)
{
report.cul = Thread.CurrentThread.CurrentCulture.Name;
try
{
report.os = Environment.OSVersion.VersionString;
}
catch (Exception)
{
if (Configuration.ThrowExceptions) throw;
}
if (Configuration.IncludeMachineName)
{
try
{
report.hn = Environment.MachineName;
}
catch (Exception)
{
if (Configuration.ThrowExceptions) throw;
}
}
}
private void SetHttpInfo(ExceptionData exceptionData, ExceptionReport report)
{
if (exceptionData.HttpContext == null && HttpContext.Current == null)
return;
if (exceptionData.HttpContext == null)
{
exceptionData.HttpContext = HttpContext.Current;
}
try
{
report.hm = exceptionData.HttpContext.Request.HttpMethod;
//TODO:find proper way to find http status code.
/*
var httpException = exceptionData.Exception as HttpException;
if (httpException != null)
{
report.sc = httpException.GetHttpCode();
}*/
report.url = exceptionData.HttpContext.Request.Url.ToString();
report.ua = exceptionData.HttpContext.Request.UserAgent;
}
catch (Exception)
{
if (Configuration.ThrowExceptions) throw;
}
}
internal static List ConvertToFrames(Exception exception)
{
if (exception == null) return null;
var stackTrace = new StackTrace(exception, true);
var frames = stackTrace.GetFrames();
if (frames == null) return null;
var result = new List();
for (int index = 0; index < frames.Length; index++)
{
var frame = frames[index];
var method = frame.GetMethod();
var declaringType = method.DeclaringType;
var fileName = frame.GetFileName();
var currentFrame = new Frame
{
i = index,
fn = fileName,
ln = frame.GetFileLineNumber(),
m = method.ToString(),
};
currentFrame.m = currentFrame.m.Substring(currentFrame.m.IndexOf(' ')).Trim();
if (declaringType != null)
{
currentFrame.c = declaringType.FullName;
}
result.Add(currentFrame);
}
return result;
}
private string GetMaximumFrameworkVersion()
{
var clrVersion = Environment.Version;
if (clrVersion.Major == 2)
{
//Check if 2.0 or 3.5
try
{
Assembly.Load("System.Core, Version=3.5.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089");
return "3.5";
}
catch (Exception)
{
}
return "2.0";
}
if (clrVersion.Major == 4)
{
//Check if 4.0 or 4.5
try
{
Assembly.Load("System.Threading.Tasks.Parallel, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b03f5f7f11d50a3a");
return "4.5";
}
catch (Exception)
{
}
return "4.0";
}
return "Unknown";
}
}
}