How to create user-defined exceptions with localized exception messages

In this article, you will learn how to create user-defined exceptions that are inherited from the base Exception class with localized exception messages using satellite assemblies.

Create custom exceptions

.NET contains many different exceptions that you can use. However, in some cases when none of them meets your needs, you can create your own custom exceptions.

Let's assume you want to create a StudentNotFoundException that contains a StudentName property. To create a custom exception, follow these steps:

  1. Create a serializable class that inherits from Exception. The class name should end in "Exception":

    [Serializable]
    public class StudentNotFoundException : Exception { }
    
    <Serializable>
    Public Class StudentNotFoundException
        Inherits Exception
    End Class
    
  2. Add the default constructors:

    [Serializable]
    public class StudentNotFoundException : Exception
    {
        public StudentNotFoundException() { }
    
        public StudentNotFoundException(string message)
            : base(message) { }
    
        public StudentNotFoundException(string message, Exception inner)
            : base(message, inner) { }
    }
    
    <Serializable>
    Public Class StudentNotFoundException
        Inherits Exception
    
        Public Sub New()
        End Sub
    
        Public Sub New(message As String)
            MyBase.New(message)
        End Sub
    
        Public Sub New(message As String, inner As Exception)
            MyBase.New(message, inner)
        End Sub
    End Class
    
  3. Define any additional properties and constructors:

    [Serializable]
    public class StudentNotFoundException : Exception
    {
        public string StudentName { get; }
    
        public StudentNotFoundException() { }
    
        public StudentNotFoundException(string message)
            : base(message) { }
    
        public StudentNotFoundException(string message, Exception inner)
            : base(message, inner) { }
    
        public StudentNotFoundException(string message, string studentName)
            : this(message)
        {
            StudentName = studentName;
        }
    }
    
    <Serializable>
    Public Class StudentNotFoundException
        Inherits Exception
    
        Public ReadOnly Property StudentName As String
    
        Public Sub New()
        End Sub
    
        Public Sub New(message As String)
            MyBase.New(message)
        End Sub
    
        Public Sub New(message As String, inner As Exception)
            MyBase.New(message, inner)
        End Sub
    
        Public Sub New(message As String, studentName As String)
            Me.New(message)
            StudentName = studentName
        End Sub
    End Class
    

Create localized exception messages

You have created a custom exception, and you can throw it anywhere with code like the following:

throw new StudentNotFoundException("The student cannot be found.", "John");
Throw New StudentNotFoundException("The student cannot be found.", "John")

The problem with the previous line is that "The student cannot be found." is just a constant string. In a localized application, you want to have different messages depending on user culture. Satellite assemblies are a good way to do that. A satellite assembly is a .dll that contains resources for a specific language. When you ask for a specific resources at run time, the CLR finds that resource depending on user culture. If no satellite assembly is found for that culture, the resources of the default culture are used.

To create the localized exception messages:

  1. Create a new folder named Resources to hold the resource files.

  2. Add a new resource file to it. To do that in Visual Studio, right-click the folder in Solution Explorer, and select Add > New Item > Resources File. Name the file ExceptionMessages.resx. This is the default resources file.

  3. Add a name/value pair for your exception message, like the following image shows:

    Add resources to the default culture

  4. Add a new resource file for French. Name it ExceptionMessages.fr-FR.resx.

  5. Add a name/value pair for the exception message again, but with a French value:

    Add resources to the fr-FR culture

  6. After you build the project, the build output folder should contain the fr-FR folder with a .dll file, which is the satellite assembly.

  7. You throw the exception with code like the following:

    var resourceManager = new ResourceManager("FULLY_QUALIFIED_NAME_OF_RESOURCE_FILE", Assembly.GetExecutingAssembly());
    throw new StudentNotFoundException(resourceManager.GetString("StudentNotFound"), "John");
    
    Dim resourceManager As New ResourceManager("FULLY_QUALIFIED_NAME_OF_RESOURCE_FILE", Assembly.GetExecutingAssembly())
    Throw New StudentNotFoundException(resourceManager.GetString("StudentNotFound"), "John")
    

    Note

    If the project name is TestProject and the resource file ExceptionMessages.resx resides in the Resources folder of the project, the fully qualified name of the resource file is TestProject.Resources.ExceptionMessages.

See also