Search code examples
c#exceptiondesign-patternsdtousing-statement

How to transfer exceptions between layers?


I have a project divided in 3 layers. In the Business Logic Layer, are two classes that read and write a CSV file. In a using statement, I need to handle the IOException and I find that I can do that with DTO and "send" to UI Layer the problem description, but I don't know how. You can explain me, please? Or maybe is another good way to transfer the information between layers.

The write method:

public void WriteCustomers(string filePath, IEnumerable<Customer> customers)
    {
        try
        {
            using (var streamWriter = new StreamWriter(filePath))
            {
                var csvWriter = new CsvWriter(streamWriter);
                csvWriter.Configuration.RegisterClassMap<CustomerMap>();
                csvWriter.WriteRecords(customers);
            }
        }
        catch (IOException)
        {

        }
    }

An approach of the solution:

public void WriteCustomers(string filePath, IEnumerable<Customer> customers)
        {
            if (!File.Exists(filePath))
                throw new IOException("The output file path is not valid.");
            using (var streamWriter = new StreamWriter(filePath))
            {
                var csvWriter = new CsvWriter(streamWriter);
                csvWriter.Configuration.RegisterClassMap<CustomerMap>();
                csvWriter.WriteRecords(customers);
            }
        }

Solution

  • The description of an error will naturally bubble up to the UI layer where you are calling it from, so you can catch and handle the error by displaying a message there. Below is a pseudo code example which might help explain what I mean:

    namespace My.UiLayer
    {
        public class MyUiClass
        {
            try
            {
                BusinessLogicClass blc = new BusinessLogicClass();
                blc.WriteCustomers(string filePath, IEnumerable<Customer> customers);
            }
            catch (IOException e)
            {
              // Read from 'e' and display description in your UI here
            }
        }
    }
    

    Note you may want to change the above to catch all Exceptions with Exception, rather than just IOException in the above, depending on what you may want to display to the user

    If you want specific message from different procedures classes then you could do something like the following:

    public void WriteCustomers(string filePath, IEnumerable<Customer> customers)
        {
            try
            {
               // Code
            }
            catch (IOException e)
            {
                throw new IOException("Error in write customers", ex);
            }
        }
    
    
    public void WriteSomethingElse(string filePath, IEnumerable<Something> s)
        {
            try
            {
               // Code
            }
            catch (IOException e)
            {
                throw new IOException("Error in something else", ex);
            }
        }
    

    And these will be caught in the calling UI layer with the message you have specified. There are a variety of ways you may want to capture/handle the errors but the key point is that the error will pass up the layer; you don't need a data transfer object (DTO) to send that information.