Is there a right way to handle exceptions in using block? C#

Shervan360 1,521 Reputation points
2023-09-22T02:56:03.88+00:00

Hello,

Is there a right way to handle exceptions in using block?

public class Answer
{
     static void Main()
     {
          const string fileName = "TestFile.txt";

          string path = Path.Combine(Environment.CurrentDirectory, fileName, "!");
          try // is there a right way?
          {
               using StreamReader sr = File.OpenText(path); // not found 
               while (!sr.EndOfStream)
               {
                    Console.WriteLine(sr.ReadLine());
               }
          }
          catch (DirectoryNotFoundException ex) // is there a right way?
          {
               Console.WriteLine("In exception"); 
          }

     }

}


C#
C#
An object-oriented and type-safe programming language that has its roots in the C family of languages and includes support for component-oriented programming.
10,843 questions
0 comments No comments
{count} votes

Accepted answer
  1. Jiale Xue - MSFT 44,501 Reputation points Microsoft Vendor
    2023-09-22T04:01:52.3566667+00:00

    Hi @Shervan360 , Welcome to Microsoft Q&A,

    First read the documentation on the official website: Exception and try-catch

    Before using try catch, you need to understand what your purpose is?

    Without a try-catch block, the program may crash when an unhandled exception occurs. Using try-catch, you can catch exceptions and take appropriate action, such as logging the error, providing a friendly error message to the user, or reverting to a known safe state.

    You can first use Exception to get the type of possible errors, and then handle them in detail.

    catch (Exception ex)
    {
         Console.WriteLine($"An error occurred: {ex.Message}");
    }
    

    Sometimes some errors may not be urgent to handle at the moment, and you can use catch to record them on the stack. Add finally// code that will be executed regardless of whether an exception occurs or not

    It is generally not advisable to use large blocks of code in try.

    Regarding TRY-catch you can also check out these: Why is try {...} finally {...} good; try {...} catch{} bad? Why catch and rethrow an exception in C#? How using try catch for exception handling is best practice

    Regarding using with using, everyone has different habits: try/catch + using, right syntax

    In my daily usage I usually use when creating a resource, make sure it is released

    using (var resource = new SomeDisposableResource())
    {
         try
         {
             //Code to use resources
         }
         catch (Exception ex)
         {
             // Handle possible exceptions
             Console.WriteLine($"Exception occurred: {ex.Message}");
         }
    } // Here, use the using statement to ensure that the resource is released, and the resource cleanup operation will be performed even if an exception occurs.
    

    Hope it can give you some help.

    Best Regards,

    Jiale


    If the answer is the right solution, please click "Accept Answer" and kindly upvote it. If you have extra questions about this answer, please click "Comment". 

    Note: Please follow the steps in our documentation to enable e-mail notifications if you want to receive the related email notification for this thread.

    0 comments No comments

2 additional answers

Sort by: Most helpful
  1. Bruce (SqlWork.com) 64,161 Reputation points
    2023-09-22T03:41:37.0266667+00:00

    your example is correct.

    0 comments No comments

  2. Karen Payne MVP 35,401 Reputation points
    2023-09-22T09:37:32.4933333+00:00

    Its better to use assertion, in this case check if the file exists first.

    And return, in this case, success, line from the file and if there is an exception pass it back where the caller deconstructs the data returned.

    public class Answer
    {
        public static (bool success, string lines, Exception exception) Read(string fileName)
        {
    
            StringBuilder sb = new();
            try
            {
                using StreamReader sr = File.OpenText(fileName);
    
                while (!sr.EndOfStream)
                {
                    sb.AppendLine(sr.ReadLine());
                }
    
                return (true, sb.ToString(), null);
    
            }
            catch (Exception ex)
            {
                return (false, ex.ToString(), ex);
            }
        }
    }
    

    Usage

    string fileName = Path.Combine(Environment.CurrentDirectory, "TestFile.txt", "!");
    if (File.Exists(fileName))
    {
        var (success, lines, exception) = Answer.Read(fileName);
        Console.WriteLine(success ? 
            lines : 
            exception.Message);
    }
    

    And if this is not about StreamReader.

    public class Answer
    {
        public static (bool success, string lines, Exception exception) Read(string fileName)
        {
            try
            {
                var result = File.ReadAllText(fileName);
    
                return (true, result, null);
    
            }
            catch (Exception ex)
            {
                return (false, null, ex);
            }
        }
    }
    

    Logging

    Most novice never consider logging their exceptions. An easy way is to install SeriLog (see this repository for how to log with SeriLog).

    Setup SeriLog, see also ModuleInitializer

    public class SetupLogging 
    {
        [ModuleInitializer]
        public static void Init()
        {
            Initialize();
        }
        public static void Initialize()
        {
    
            Log.Logger = new LoggerConfiguration()
                .MinimumLevel.Verbose()
                .WriteTo.File(Path.Combine(AppDomain.CurrentDomain.BaseDirectory, "LogFiles", $"{Now.Year}-{Now.Month}-{Now.Day}", "Log.txt"),
                    rollingInterval: RollingInterval.Infinite,
                    outputTemplate: "[{Timestamp:yyyy-MM-dd HH:mm:ss.fff} [{Level}] {Message}{NewLine}{Exception}")
                .CreateLogger();
        }
    }
    

    Usage

    public class Answer
    {
        public static (bool success, string lines, Exception exception) Read(string fileName)
        {
            try
            {
                var result = File.ReadAllText(fileName);
    
                return (true, result, null);
    
            }
            catch (Exception ex)
            {
                Log.Error(ex, "Failed reading file");
                return (false, null, ex);
            }
        }
    }
    

    When invoking Log.Error the first time, in the Debug folder a folder is created, LogFiles, then a folder for today's date followed by creating log.txt and logs the exception, other log entries are added. Then for other days the process is repeated.

    SeriLog packages

    Double click the project name in solution explorer, add the following and save.

    <ItemGroup>
        <PackageReference Include="Serilog" Version="3.0.1" />
        <PackageReference Include="Serilog.Sinks.File" Version="5.0.0" />
    </ItemGroup>
    

    Sample log entry

    [2023-09-22 02:33:43.538 [Error] Foo
    System.IO.DirectoryNotFoundException: Could not find a part of the path 'C:\OED\DotnetLand\VS2022\Code\WinFormsApp1\bin\Debug\net7.0-windows\TestFile.txt\!'.
       at Microsoft.Win32.SafeHandles.SafeFileHandle.CreateFile(String fullPath, FileMode mode, FileAccess access, FileShare share, FileOptions options)
       at Microsoft.Win32.SafeHandles.SafeFileHandle.Open(String fullPath, FileMode mode, FileAccess access, FileShare share, FileOptions options, Int64 preallocationSize, Nullable`1 unixCreateMode)
       at System.IO.Strategies.OSFileStreamStrategy..ctor(String path, FileMode mode, FileAccess access, FileShare share, FileOptions options, Int64 preallocationSize, Nullable`1 unixCreateMode)
       at System.IO.Strategies.FileStreamHelpers.ChooseStrategyCore(String path, FileMode mode, FileAccess access, FileShare share, FileOptions options, Int64 preallocationSize, Nullable`1 unixCreateMode)
       at System.IO.StreamReader.ValidateArgsAndOpenPath(String path, Encoding encoding, Int32 bufferSize)
       at System.IO.File.ReadAllText(String path, Encoding encoding)
       at WinFormsApp1.Form1.button2_Click(Object sender, EventArgs e) in ./Form1.cs:line 41
    

    Note that in the last line ./Form1.cs:line 41 has no path, that is from me adding the following to the project file which strips the path to the project as we know this already.

    <PropertyGroup>
       <PathMap>$([System.IO.Path]::GetFullPath('$(MSBuildThisFileDirectory)'))=./</PathMap>
    </PropertyGroup>
    
    0 comments No comments

Your answer

Answers can be marked as Accepted Answers by the question author, which helps users to know the answer solved the author's problem.