Reputation: 957
I have a hierarchy of TrendProviders
which are used to provide a series of datapoints (trends) from different sources.
I have started with the generic interface:
public interface ITrendProvider<T> where T: TrendResult
{
IEnumerable<T> GetTrends();
}
TrendResult
is a result class with the obtained trend data and operation status code:
public class TrendResult
{
public TrendResult()
{
Points = new Dictionary<DateTimeOffset, decimal>();
}
public TrendResultCode Code { get; set; }
public string Name { get; set; }
public string Identifier { get; set; }
public Dictionary<DateTimeOffset, decimal> Points { get; set; }
}
TrendResultCode
is as follows:
public enum TrendResultCode
{
OK,
DataParseError,
NoData,
UnknownError
}
There are also two types (so far) of more detailed interfaces:
IFileTrendProvider
- used to obtain trends from any files.
IServerTrendProvider
- used to obtain trends from remote servers, using FTP for example.
IFileTrendProvider
goes like this:
public interface IFileTrendProvider : ITrendProvider<TrendResult>
{
IFileReader FileReader {get; set}
FileTrendDiscoveryPattern Pattern {get; set;}
}
IServerTrendProvider
goes like this:
public interface IServerTrendProvider : ITrendProvider<TrendResult>
{
IClient Client { get; set; }
Dictionary<string, string[]> RequestedServerTrendIDs { get; set; }
}
The concrete classes that implements the interfaces are as follows:
One of FileTrend
type:
public class GenericFileTrendProvider : IFileTrendProvider<TrendResult>
{
public GenericFileTrendProvider() { }
public IFileReader FileReader {get; set}
public FileTrendDiscoveryPattern Pattern {get; set;}
public IEnumerable<TrendResult> GetTrends()
{
// Some code to obtain trends from file using FileReader
}
}
And one of the ServerTrend
type:
public class ServerATrendProvider : IServerTrendProvider<TrendResult>
{
public ServerATrendProvider () { }
public IClient Client { get; set; }
public Dictionary<string, string[]> RequestedServerTrendIDs { get; set;}
public IEnumerable<TrendResult> GetTrends()
{
// Some code to obtain trends from remote server using Client
}
}
Now, what I want to achieve and where I need your help and advice:
The IFileReader
introduces its own error codes:
public enum FileReadResultCode
{
OK,
FileAlreadyOpen,
FileNotFound,
UnknownError
}
IClient
also introduces its specific operation error codes:
public enum ClientCode
{
OK,
InvalidCredentials,
ResourceNotFounds,
UnknownError
}
As both: IFileReader
and IClient
also returns its own error codes, how could I intruduce them in the TrendResult
object returned by GetTrends()
method, so that in the end there will be also some information about the "internal" error, not only TrendResult
specific error?
I would need some flexible solution - I was thinking about inheriting from TrendResult
and create a FileTrendResult
and ServerTrendResult
for each of concrete providers, and also define a specific error enumerations for both so that they return its own result type, but can it be done in some other way?
Upvotes: 6
Views: 108
Reputation:
Since IServerTrendProvider will be receiving TrendResults from other computers, you will not be able to use System.Exception in the general case.
In these cirumstances, people fall back to strings - which are always supported regardless of operating system.
public class TrendResult
{
public string[] ErrorMessages; // Error messages - could be the stack trace
public int[] ErrorCodes; // Os-specific error numbers
}
Consider security when sending source-code fragments (e.g. names, stack traces) in error messages, because these could be of use to hackers.
Upvotes: 1
Reputation: 22456
Instead of having a pre-defined list of possible errors in the enumerations (TrendResultCode
, FileReadResultCode
, ClientCode
, ...) you could change the TrendResult
class to store a list of exceptions and get rid of the enumerations:
public class TrendResult
{
// ...
// public TrendResultCode Code { get; set; }
public IEnumerable<Exception> Errors { get; set; }
// ...
}
This way, you can store the complete information of the error including stack trace and other valuable information (or of several errors if there is more than one problem in a single TrendResult
). Even for unexpected errors, you are able to store the details instead of having an unknown error that is hard to track down.
If a TrendResult
does not have any items in the enumeration, there are no problems with it. Otherwise, you can put the information to the log.
The implementation follows the Open/Closed principle, so you don't have to change the implementation that handles the TrendResults
if there are new conditions that lead to an error.
For your business exceptions, e.g. parsing errors, you should create specific exception types so that you are able to analyze these errors later on based on their type.
Upvotes: 3