pamidur / aspect-injector

AOP framework for .NET (c#, vb, etc)
Apache License 2.0
745 stars 112 forks source link

Error handling features #129

Closed KKacer closed 4 years ago

KKacer commented 4 years ago

Hello, As an old Postsharp user, I believe it is a nice piece of software. Was watching the growth of this project in the past months, now want to try it. Before the beginning, have 2 simple questions:

  1. Does it support error-handling? Something like: [CatchErrors] or [LogErrors]

  2. Can we use dashes in the aspect names? [Catch-Errors] ?

Something to note: The Mixin Effect page in your Docs section doesn't exist anymore. Sorry if you already explained them somewhere in your code or manual,

Regards, Kasra

pamidur commented 4 years ago

Hi @KKacer ,

  1. Aspect-Injector is framework that allows you to create your own crosscutting features like error handling. You can find examples here and here. Of course you can modify them to behave the way you need. Log exceptions, mute them, implement retry features etc.

  2. The name restrictions are enforced by csharp compiler, so there is little we can do. So no dashes possible importunately, you might want to use underscores instead.

KKacer commented 4 years ago

Think those 2 links could be useful on this case, and will look and study them. Anyway a simple official sample will put any new user in the correct path. Thanks for the reply and guidance,

Regards.

pamidur commented 4 years ago

Good point, we'll need to make more samples that are plug and play like Cache for example, so you can get it from Nuget. However the last one I mentioned in comment above, is official sample,. The reason it is not released as Nuget package is that there are too many ways to deal with exceptions. It is like when you say "handle exception" what exactly you mean? Log them or mute them or retry call method again with the same args?

I'd like to know more about your use cases and your expectations on what [CatchErrors] should do? It might help us to create generic error handlers for everyone to use out of the box.

KKacer commented 4 years ago

You can provide the very basic usage and most common ones, That was also one of the very first Postsharp examples as well.

I guess catching errors and log them could be called a very basic scenario.

Regards.

pamidur commented 4 years ago

Very basic one would be like this:

    [Injection(typeof(CatchErrorsAttribute))]
    [Aspect(Scope.Global)]
    public class CatchErrorsAttribute : Attribute
    {
        [Advice(Kind.Around)]
        public object Around(
            [Argument(Source.Arguments)] object[] args,
            [Argument(Source.Target)] Func<object[], object> target)
        {
            try
            {
                return target(args);
            }
            catch (Exception e)
            {
                Console.WriteLine(e.Message);
                throw;
            }
        }
    }

Usage

    [CatchErrors] //you may apply it do method directly 
    public class TestClass
    {
        public void Do() { }
    }
pamidur commented 4 years ago

Please let me know if it helps, and if it does, where would you expect to find this information? On this page, precompiled in nuget package or in readme file that opens ones you install the aspect-injector, or some other place?

KKacer commented 4 years ago

Sure, will try it. Thanks for the example.

KKacer commented 4 years ago

Hello, Back to this question, cause of my current scenario:

In the current provided sample:

  1. How can I find that what was the type of the target (the attribute consumer, was that a method or property or a class) ?
  2. If that was a method, how to find out the method name? Should we add more arguments, like the below line? :

[Argument(Source.Name)] string name, ...

Can you please change the sample you provided earlier targeting this?

pamidur commented 4 years ago

It is easy, use Source.Metadata. It will give you MethodBase object from which you can get name, and if it was property setter or event. Alternatively, you may have separate advice for Methods and Properties. It is done by [Advice(... Target=Properties)] I'll try to make you a good example one's I get to computer

KKacer commented 4 years ago

Thanks, guess I know the second approach, but prefer to see the example about the first one once you were able to, appreciate it.

KKacer commented 4 years ago

I thought you still wanted to add something here. I added these:

            catch (Exception e)
            {
                Log.Information($"Source.Name: {Source.Name}");
                Log.Information($"Source.Metadata: {Source.Metadata.GetType().ToString()}");

which seems wrong, I may need to use them in the Arguments section, right? Argument(Source.Name)] // not sure if it will give the caller method's name.

pamidur commented 4 years ago

Performant way

        [Advice(Kind.Before, Targets = Target.AnyAccess | Target.AnyScope | Target.Setter | Target.Getter)]
        public void BeforeProperties()
        {
            Console.WriteLine("This is property");
        }

        [Advice(Kind.Before, Targets = Target.AnyAccess | Target.AnyScope | Target.Method)]
        public void BeforeMethod()
        {
            Console.WriteLine("This is regular methods");
        }

All in one way

        [Advice(Kind.Before)]
        public void BeforeEverything([Argument(Source.Metadata)] MethodBase metadata)
        {
            if (metadata.IsSpecialName)
            {
                var prop = metadata.DeclaringType.GetProperty(metadata.Name.Substring(4),
                       BindingFlags.NonPublic | BindingFlags.Public | BindingFlags.Instance);

                if (prop != null)
                    Console.WriteLine("This is property");
                else
                    Console.WriteLine("This is probably event, you need additional checks though to be sure");
            }
            else
            {
                Console.WriteLine("This is regular methods");
            }            
        }
KKacer commented 4 years ago

Thanks @pamidur , great help. Like the second approach more. Have 1,2 questions more which may ask in new tickets.