using System ;
using System.Collections.Generic ;
using System.Diagnostics ;
using System.IO ;
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 ; }
/// <summary>
/// Version of Client
/// </summary>
public string ClientVersion
{
get { return Assembly . GetExecutingAssembly ( ) . GetName ( ) . Version . ToString ( ) ; }
}
/// <summary>
/// Name of Client
/// </summary>
public string ClientName
{
get { return "Official .NET" ; }
}
/// <summary>
/// Client Configuration
/// </summary>
public ExceptronConfiguration Configuration { get ; private set ; }
/// <summary>
/// Framework Type of the Host Application (.Net/mono)
/// </summary>
public string FrameworkType { get ; set ; }
/// <summary>
/// Creates a new instance of <see cref="ExceptronClient"/>
/// Loads <see cref="ExceptronConfiguration"/> from application config file.
/// </summary>
/// <param name="applicationVersion">Version of the currently running application</param>
public ExceptronClient ( Version applicationVersion )
: this ( ExceptronConfiguration . ReadConfig ( ) , applicationVersion )
{
FrameworkType = ".Net" ;
}
private readonly string _applicationVersion ;
private readonly string _maxFrameworkVersion ;
/// <param name="exceptronConfiguration">exceptron client configuration</param>
/// <param name="applicationVersion"> </param>
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" ;
}
/// <summary>
/// Submit an exception to exceptron Servers.
/// </summary>
/// <param name="exception">Exception that is being reported</param>
/// <param name="component"
/// example="DataAccess, Configuration, Registration, etc."
/// remarks="It is common to use the logger name that was used to log the exception as the component.">Component that experienced this exception.</param>
/// <param name="severity">Severity of the exception being reported</param>
/// <param name="message"
/// example="Something went wrong while checking for application updates.">Any message that should be attached to this exceptions</param>
/// <param name="userId"
/// remarks="This Id does not have to be tied to the user's identity.
/// You can use a system generated unique ID such as GUID.
/// This field is used to report how many unique users are experiencing an error."
/// example="
/// 62E5C8EF-0CA2-43AB-B278-FC6994F776ED
/// Timmy@aol.com
/// 26437
/// ">ID that will uniquely identify the user</param>
/// <param name="httpContext"><see cref="System.Web.HttpContext"/> in which the exception occurred. If no <see cref="System.Web.HttpContext"/> is provided
/// <see cref="ExceptronClient"/> will try to get the current <see cref="System.Web.HttpContext"/> from <see cref="System.Web.HttpContext.Current"/></param>
/// <returns></returns>
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 ) ;
}
/// <summary>
/// Submit an exception to exceptron Servers.
/// </summary>
/// <param name="exceptionData">Exception data to be reported to the server</param>
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 < ExceptionResponse > ( 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 < Frame > 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 < Frame > ( ) ;
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" ;
}
}
}