// Copyright 2009-2022 Josh Close
// This file is a part of CsvHelper and is dual licensed under MS-PL and Apache 2.0.
// See LICENSE.txt for details or visit http://www.opensource.org/licenses/ms-pl.html for MS-PL and http://opensource.org/licenses/Apache-2.0 for Apache 2.0.
// https://github.com/JoshClose/CsvHelper
using CsvHelper.Configuration;
using System;
using System.Text;
namespace CsvHelper
{
///
/// Represents errors that occur in CsvHelper.
///
[Serializable]
public class CsvHelperException : Exception
{
[NonSerialized]
private readonly CsvContext context;
///
/// Gets the context.
///
public CsvContext Context => context;
///
/// Initializes a new instance of the CsvHelperException class.
///
internal protected CsvHelperException() : base() { }
///
/// Initializes a new instance of the CsvHelperException class.
///
/// The message that describes the error.
internal protected CsvHelperException(string message) : base(message) { }
///
/// Initializes a new instance of the CsvHelperException class.
///
/// The error message that explains the reason for the exception.
/// The exception that is the cause of the current exception, or a null reference (Nothing in Visual Basic) if no inner exception is specified.
internal protected CsvHelperException(string message, Exception innerException) : base(message, innerException) { }
///
/// Initializes a new instance of the class.
///
public CsvHelperException(CsvContext context)
{
this.context = context;
}
///
/// Initializes a new instance of the class
/// with a specified error message.
///
/// The context.
/// The message that describes the error.
public CsvHelperException(CsvContext context, string message) : base(AddDetails(message, context))
{
this.context = context;
}
///
/// Initializes a new instance of the class
/// with a specified error message and a reference to the inner exception that
/// is the cause of this exception.
///
/// The context.
/// The error message that explains the reason for the exception.
/// The exception that is the cause of the current exception, or a null reference (Nothing in Visual Basic) if no inner exception is specified.
public CsvHelperException(CsvContext context, string message, Exception innerException) : base(AddDetails(message, context), innerException)
{
this.context = context;
}
private static string AddDetails(string message, CsvContext context)
{
var indent = new string(' ', 3);
var details = new StringBuilder();
if (context.Reader != null)
{
details.AppendLine($"{nameof(IReader)} state:");
details.AppendLine($"{indent}{nameof(IReader.ColumnCount)}: {context.Reader.ColumnCount}");
details.AppendLine($"{indent}{nameof(IReader.CurrentIndex)}: {context.Reader.CurrentIndex}");
try
{
var record = new StringBuilder();
if (context.Reader.HeaderRecord != null)
{
record.Append("[\"");
record.Append(string.Join("\",\"", context.Reader.HeaderRecord));
record.Append("\"]");
}
details.AppendLine($"{indent}{nameof(IReader.HeaderRecord)}:{Environment.NewLine}{record}");
}
catch { }
}
if (context.Parser != null)
{
details.AppendLine($"{nameof(IParser)} state:");
details.AppendLine($"{indent}{nameof(IParser.ByteCount)}: {context.Parser.ByteCount}");
details.AppendLine($"{indent}{nameof(IParser.CharCount)}: {context.Parser.CharCount}");
details.AppendLine($"{indent}{nameof(IParser.Row)}: {context.Parser.Row}");
details.AppendLine($"{indent}{nameof(IParser.RawRow)}: {context.Parser.RawRow}");
details.AppendLine($"{indent}{nameof(IParser.Count)}: {context.Parser.Count}");
try
{
var rawRecord = context.Configuration.ExceptionMessagesContainRawData
? context.Parser.RawRecord
: $"Hidden because {nameof(IParserConfiguration.ExceptionMessagesContainRawData)} is false.";
details.AppendLine($"{indent}{nameof(IParser.RawRecord)}:{Environment.NewLine}{rawRecord}");
}
catch { }
}
if (context.Writer != null)
{
details.AppendLine($"{nameof(IWriter)} state:");
details.AppendLine($"{indent}{nameof(IWriter.Row)}: {context.Writer.Row}");
details.AppendLine($"{indent}{nameof(IWriter.Index)}: {context.Writer.Index}");
var record = new StringBuilder();
if (context.Writer.HeaderRecord != null)
{
record.Append("[");
if (context.Writer.HeaderRecord.Length > 0)
{
record.Append("\"");
record.Append(string.Join("\",\"", context.Writer.HeaderRecord));
record.Append("\"");
}
record.Append("]");
}
details.AppendLine($"{indent}{nameof(IWriter.HeaderRecord)}:{Environment.NewLine}{context.Writer.Row}");
}
return $"{message}{Environment.NewLine}{details}";
}
}
}