Generic result class with C#
Summary
In this post, I discuss a way to create a result class that
can be used for method calls across multiple layers in your application. I
discuss the need for such an approach and my take on the solution. I welcome recommendations
to make this solution better.
Introduction
It has become the norm that when one starts creating a .net
solution, one follows a layered approach. Following the standard n-layered
architecture, one creates a number of class libraries to represent the layers.
Often times, I have come across the problem of getting the results from the
lowest layer to the topmost layer. So, for example, I write a method that gets
data from the database and populate an object and I need to return this object
to the UI, the norm is to create a method signature that returns the object
type. An issue arise when errors happen, how do I get to send these errors to
the upper layers?
The following sections look at a solution I came to like and
have been using in most of my solutions. Let’s assume I am writing an
application to read manage student details. I will define some methods to
manage this data and describe a way to use a generic result class I can use in
all my methods. I will also describe a caveat to this solution and a work
around.
IStudentRepository
public interface IStudentRepository
{
long AddStudent(Student newStudent);
Student GetStudent(long studentId);
bool UpdateStudent(Student updatedStudent);
}
Note that all my methods return a different data type. How
should I handle errors that occur when trying to access my persistence layer?
The solution I use id to create a generic result class that has the capability
to carry errors as well as my results and any other piece of information. I
also use a couple of other classes to help manage this.
Generic result
[DataContract]
public class Result
{
public Result()
{
IsValid = true;
Errors = new List<Error>();
}
[DataMember]
public T Value { get; set; }
[DataMember]
public bool IsValid { get; set; }
[DataMember]
public List<Error> Errors { get; set; }
[DataMember]
public List<string> InfoMessages { get; set; }
}
[DataContract]
public class Error
{
[DataMember]
public string ErrorCode { get; set; }
[DataMember]
public string ErrorMessage { get; set; }
[DataMember]
public ErrorType Severity { get; set; }
}
The DataContract attibutes have been added allow this to
be serialized in WCF for example. Now using this class, here is how I define
the same interface above
public interface IStudentRepository
{
Result<long> AddStudent(Student newStudent);
Result<Student> GetStudent(long studentId);
Result<bool> UpdateStudent(Student updatedStudent);
}
Using this approach,
in my code I first check if the result is valid, if it is, I can access the
strongly typed Value property to get the results and pontentially any InfoMessages
I can use for notifications. If the result is invalid, I can access the list of
errors to get more information on what went wrong.
Caveat L
With this solution,
you will realize that it will not work when your result type is a string, a
work around is to wrap your string value in an object
I hope you find this
useful in your solutions too.
No comments:
Post a Comment