{"id":26562881,"url":"https://github.com/aelfproject/aopexceptionmodule","last_synced_at":"2026-01-29T03:34:04.513Z","repository":{"id":257816350,"uuid":"869284578","full_name":"AElfProject/AOPExceptionModule","owner":"AElfProject","description":null,"archived":false,"fork":false,"pushed_at":"2024-10-29T10:30:30.000Z","size":79,"stargazers_count":0,"open_issues_count":4,"forks_count":0,"subscribers_count":3,"default_branch":"master","last_synced_at":"2025-10-11T02:09:33.038Z","etag":null,"topics":[],"latest_commit_sha":null,"homepage":null,"language":"C#","has_issues":true,"has_wiki":null,"has_pages":null,"mirror_url":null,"source_name":null,"license":"mit","status":null,"scm":"git","pull_requests_enabled":true,"icon_url":"https://github.com/AElfProject.png","metadata":{"files":{"readme":"README.md","changelog":null,"contributing":null,"funding":null,"license":"LICENSE","code_of_conduct":".github/CODE_OF_CONDUCT.md","threat_model":null,"audit":null,"citation":null,"codeowners":null,"security":null,"support":null,"governance":null,"roadmap":null,"authors":null,"dei":null,"publiccode":null,"codemeta":null}},"created_at":"2024-10-08T03:24:18.000Z","updated_at":"2024-10-29T10:29:52.000Z","dependencies_parsed_at":null,"dependency_job_id":"ce6b94ed-9fe1-4d65-9dba-6fc66c8278a6","html_url":"https://github.com/AElfProject/AOPExceptionModule","commit_stats":null,"previous_names":["aelfproject/aopexceptionmodule"],"tags_count":15,"template":false,"template_full_name":null,"purl":"pkg:github/AElfProject/AOPExceptionModule","repository_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/AElfProject%2FAOPExceptionModule","tags_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/AElfProject%2FAOPExceptionModule/tags","releases_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/AElfProject%2FAOPExceptionModule/releases","manifests_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/AElfProject%2FAOPExceptionModule/manifests","owner_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners/AElfProject","download_url":"https://codeload.github.com/AElfProject/AOPExceptionModule/tar.gz/refs/heads/master","sbom_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/AElfProject%2FAOPExceptionModule/sbom","scorecard":null,"host":{"name":"GitHub","url":"https://github.com","kind":"github","repositories_count":286080680,"owners_count":28862125,"icon_url":"https://github.com/github.png","version":null,"created_at":"2022-05-30T11:31:42.601Z","updated_at":"2026-01-28T22:56:21.783Z","status":"online","status_checked_at":"2026-01-29T02:00:06.714Z","response_time":59,"last_error":null,"robots_txt_status":"success","robots_txt_updated_at":"2025-07-24T06:49:26.215Z","robots_txt_url":"https://github.com/robots.txt","online":true,"can_crawl_api":true,"host_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub","repositories_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories","repository_names_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repository_names","owners_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners"}},"keywords":[],"created_at":"2025-03-22T15:29:05.038Z","updated_at":"2026-01-29T03:34:04.498Z","avatar_url":"https://github.com/AElfProject.png","language":"C#","funding_links":[],"categories":[],"sub_categories":[],"readme":"# AOP Exception Module\n\nA demo of AOP Exception Handling.\n\n- [About The Project](#about-the-project)\n- [Getting Started](#getting-started)\n  - [Usage](#usage)\n  - [Exception Handling Strategies](#exception-handling-strategies)\n  - [Multiple Exception Handling](#multiple-exception-handling)\n  - [Callback Method](#callback-method)\n  - [Finally](#finally)\n  - [Logging](#logging)\n  - [Message](#message)\n  - [Return Value](#return-value)\n  - [Logging Method Parameters](#logging-method-parameters)\n  - [Return Type Exception](#return-type-exception)\n- [Limitations](#limitations)\n- [Examples](#examples)\n- [Contributing](#contributing)\n- [License](#license)\n\n## About The Project\n\nThis is a C# class named ExceptionHandler which is an aspect designed to handle exceptions in methods through PostSharp's OnMethodBoundaryAspect. It intercepts methods when they throw an exception and allows for custom exception handling logic. The code leverages aspects to capture method execution and provides a strategy to deal with specific types of exceptions.\n\n### Key Components\n1. Inheritance from OnMethodBoundaryAspect of PostSharp:  \n   The ExceptionHandler class extends OnMethodBoundaryAspect, which allows intercepting the method execution at predefined points, specifically when exceptions are thrown (OnException method).\n\n2. Attributes and Fields:\n  - TargetType, MethodName, and Exception define the target method and exception type to handle.\n\n3. Asynchronous Methods:\n   Able to catch exceptions from nested asynchronous methods and supports TPL.\n\n### Pros and Cons\nPros:\n1. Separation of Concerns:\n  - Exception handling logic is decoupled from the business logic, improving code readability and maintainability.\n\n2. Reusability:\n  - The aspect can be reused across multiple methods and classes, making it a scalable solution for consistent exception handling.\n\n3. Dynamic Method Invocation:\n  - The code uses reflection and expression trees to invoke any method dynamically, allowing for flexibility in how exceptions are handled.\n\n4. Aspect-Oriented Approach:\n  - Reduces code duplication related to exception handling by centralizing the logic in one place.\n\n5. Quicker Onboarding:\n  - The learning cost is reduced because exception handling is encapsulated in one place without the need to learn PostSharp and reflection related code.\n\nCons:\n1. Performance Overhead:\n  - Reflection and dynamic invocation introduce some performance overhead, which might be noticeable in high-throughput systems.\n\n2. Limited Compile-time Safety:\n  - Errors related to method names or parameter mismatches will only be detected at runtime, increasing the potential for runtime exceptions.\n\n## Getting Started\n\n### Usage\n1. Define a Method Returning `FlowBehavior`:\n   Create a method in your target class that handles exceptions and returns a Task\u003cExceptionHandlingStrategy\u003e. The strategy will dictate how the flow of the program should behave (e.g., return, rethrow, throw).\n\n```csharp\npublic class ExceptionHandlingService\n{\n    public static async Task\u003cFlowBehavior\u003e HandleException(Exception ex, int i)\n    {\n        Console.WriteLine($\"Handled exception: {ex.Message}\");\n        await Task.Delay(100);\n        return new FlowBehavior\n        {\n            ExceptionHandlingStrategy = ExceptionHandlingStrategy.Return,\n            ReturnValue = true\n        }\n    }\n}\n```\n\n2. Apply the Aspect to Your Methods:\n   Use the ExceptionHandler aspect on the methods where you want to handle exceptions.\n\n```csharp\n[ExceptionHandler(typeof(ArgumentNullException), TargetType = typeof(ExceptionHandlingService), MethodName = nameof(ExceptionHandlingService.HandleException))]\nprotected virtual Task SomeMethod(int i)\n{\n    // Business logic that may throw exceptions\n}\n```\n\nAll methods with the ExceptionHandler attribute have 2 requirements:\n1. The method must return a Task.\n2. The method must be virtual or abstract.\n\n### Exception Handling Strategies\nThere are 3 ways to return the exception through the Flow Behavior:\n1. Return: The method will return the ReturnValue implemented.\n```csharp\npublic async Task\u003cFlowBehavior\u003e HandleException(Exception ex, string message)\n {\n     return new FlowBehavior\n     {\n         ExceptionHandlingStrategy = ExceptionHandlingStrategy.Return,\n         ReturnValue = true\n     }\n  }\n```\n2. Rethrow: The method will rethrow the exception.\n```csharp\npublic async Task\u003cFlowBehavior\u003e HandleException(Exception ex, string message)\n{\n   return new FlowBehavior\n   {\n        ExceptionHandlingStrategy = ExceptionHandlingStrategy.Rethrow\n   }\n}\n```\n3. Throw: The method will throw a new exception based on the ReturnValue implemented.\n```csharp\npublic async Task\u003cFlowBehavior\u003e HandleException(Exception ex, string message)\n{\n   return new FlowBehavior\n   {\n        ExceptionHandlingStrategy = ExceptionHandlingStrategy.Throw,\n        ReturnValue = new Exception(\"New Exception\")\n   }\n}\n```\n4. Continue: The method will continue to the next exception specified or rethrow if there are no other exceptions.\n```csharp\npublic async Task\u003cFlowBehavior\u003e HandleException(Exception ex, string message)\n{\n   return new FlowBehavior\n   {\n        ExceptionHandlingStrategy = ExceptionHandlingStrategy.Continue\n   }\n}\n```\n\n### Multiple Exception Handling\nYou can stack multiple ExceptionHandler attributes on a method to handle multiple exceptions.\n```csharp\n[ExceptionHandler([typeof(InvalidOperationException), typeof(ArgumentException)], TargetType = typeof(BookAppService), MethodName = nameof(HandleSpecificException))]\n[ExceptionHandler(typeof(Exception), TargetType = typeof(BookAppService), MethodName = nameof(HandleException))]\npublic async Task\u003cBookDto\u003e CreateAsync(CreateBookInput input)\n{\n    // Business logic that may throw exceptions\n}\n```\nFrom the example above, the method CreateAsync will handle InvalidOperationException and ArgumentException with the HandleSpecificException method and handle any other exceptions with the HandleException method.\n\n### Callback Method\nSignature of the callback method can be either of the following:\n1. The callback method must have the same parameter as the method that an exception is thrown from with an addition leading Exception parameter.\n```csharp\npublic async Task\u003cFlowBehavior\u003e HandleSpecificException(Exception ex, CreateBookInput message)\n{\n    return new FlowBehavior\n    {\n        ExceptionHandlingStrategy = ExceptionHandlingStrategy.Return,\n        ReturnValue = new BookDto()\n    };\n}\n```\n2. The callback method must have only the Exception parameter.\n```csharp\npublic async Task\u003cFlowBehavior\u003e HandleException(Exception ex)\n{\n    return new FlowBehavior\n    {\n        ExceptionHandlingStrategy = ExceptionHandlingStrategy.Return,\n        ReturnValue = new BookDto()\n    };\n}\n```\n\n### Finally\nThe Finally method is called after the method execution is completed. The method signature should follow the same signature as the method that an exception was thrown from with a return type of Task instead.\n```csharp\n[ExceptionHandler(typeof(Exception), TargetType = typeof(BookAppService), MethodName = nameof(HandleException), \n                    FinallyTargetType = typeof(BookAppService), FinallyMethodName = nameof(Finally))]\npublic async Task\u003cBookDto\u003e CreateAsync(CreateBookInput input)\n{\n    // Business logic that may throw exceptions\n}\n\npublic async Task Finally(CreateBookInput message)\n{\n    // cleanup code\n    Console.WriteLine(\"Finally block\");\n}\n```\n\n### Logging\nThe `LogOnly` attribute is used to log exceptions without handling them. This will result in a rethrow. All logs are logged by `ILogger`. If `LogOnly` is set to `false`, the exception will still be logged and will continue to handle the exception through the assigned method. By default, `LogOnly = false`.\n```csharp\n[ExceptionHandler(typeof(Exception), LogOnly = true)]\nprotected virtual async Task\u003cbool\u003e SomeMethod(string message)\n{\n    throw new Exception(\"boo!\");\n    return false;\n}\n```\n\nYou may also set the LogLevel for the output of the exception. For example:\n```csharp\n[ExceptionHandler(typeof(Exception), \n    LogLevel = LogLevel.Information, \n    TargetType = typeof(BookAppService), \n    MethodName = nameof(HandleException))]\nprotected virtual async Task\u003cbool\u003e SomeMethod(string message)\n{\n    throw new Exception(\"boo!\");\n    return false;\n}\n```\n\n### Message\n\nYou may set customised message for the exception. For example:\n```csharp\n[ExceptionHandler(typeof(Exception), \n    Message = \"Customised message\", \n    TargetType = typeof(BookAppService), \n    MethodName = nameof(HandleException))]\nprotected virtual async Task\u003cbool\u003e SomeMethod(string message)\n{\n    throw new Exception(\"boo!\");\n    return false;\n}\n```\nThis would output \"Customised message\" along with the exception message.\n\n### Return Value\n\nInstead of a callback method, you may set ReturnValue directly in the attribute through ReturnDefault property. For example:\n```csharp\n[ExceptionHandler([typeof(InvalidOperationException)], ReturnDefault = ReturnDefault.New)]\npublic override async Task\u003cPagedResultDto\u003cBookDto\u003e\u003e GetListAsync(PagedAndSortedResultRequestDto input)\n{\n    var thrown = await ShouldThrowInvalidOperationException();\n    return await base.GetListAsync(input);\n}\n```\nThe above demonstrates how to return a new instance of the return type of the method.\n\nThe ReturnDefault property can be set to the following:\n1. New: Returns a new instance of the return type.\n2. Default: Returns the default value of the return type (i.e. default(T)).\n3. None: Indicates not to use the ReturnDefault property.\n\n### Logging Method Parameters\n\nYou may log the method parameters by specifying through the `LogTargets`. For example:\n```csharp\n[ExceptionHandler(typeof(Exception), \n    ReturnDefault = ReturnDefault.Default, \n    LogTargets = [\"i\", \"dummy\"])]\nprotected virtual async Task\u003cdecimal\u003e Boo(int i, Dummy dummy, string name = \"some name\")\n{\n    throw new Exception(\"boo!\");\n    return 10;\n}\n```\nThe above will log the values of i and dummy when the exception is thrown.\n\n### Return Type Exception\n\nThe program will throw a `ReturnTypeMismatchException` when the return type specified in your `FlowBehavior.ReturnValue` is not the corresponding return type to the method that has thrown.\n\n## Limitations\n1. The method must return a Task.\n2. The method must be virtual or abstract.\n3. Unit Test class methods are not supported.\n4. `internal` methods are not supported.\n\n## Examples\n\nExample with multiple exception handler:\n```csharp\n[ExceptionHandler(typeof(InvalidOperationException), TargetType = typeof(ExceptionHandlingService), MethodName = nameof(ExceptionHandlingService.HandleException))]\n[ExceptionHandler(typeof(ArgumentNullException), TargetType = typeof(ExceptionHandlingService), MethodName = nameof(ExceptionHandlingService.HandleException))]\npublic virtual Task SomeMethod(int i)\n{\n    // Business logic that may throw exceptions\n}\n```\n\nOr you can have multiple Exceptions:\n```csharp\n[ExceptionHandler([typeof(ArgumentNullException), typeof(InvalidOperationException)], TargetType = typeof(ExceptionHandlingService), MethodName = nameof(ExceptionHandlingService.HandleException))]\npublic virtual Task SomeMethod(int i)\n{\n    // Business logic that may throw exceptions\n}\n```\n\n## Contributing\n\nIf you encounter a bug or have a feature request, please use the [Issue Tracker](https://github.com/AElfProject/aelf-dapp-factory/issues/new). The project is also open to contributions, so feel free to fork the project and open pull requests.\n\n## License\n\nDistributed under the Apache License. See [License](LICENSE) for more information.\nDistributed under the MIT License. See [License](LICENSE) for more information.\n","project_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Faelfproject%2Faopexceptionmodule","html_url":"https://awesome.ecosyste.ms/projects/github.com%2Faelfproject%2Faopexceptionmodule","lists_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Faelfproject%2Faopexceptionmodule/lists"}