Interception ordering - TylerBrinks/Snap GitHub Wiki

The .NET framework has a quirk in that using reflection to read attributes does not preserve the order in which they are decorated. In other words, the following are all exactly the same:

[A] [B] void Method(){…}

[B] [A] void Method(){…}

[A, B]void Method(){…}

[B, A]void Method(){…}

Even if .NET did preserve the order, there are situations in which you need to control the order in which your interceptors execute. For example, if you’re using one attribute to handle exceptions and another to wrap methods in transactions, you may want the transaction to attempt to roll back before the error handler interceptor catches an error.

In any case, Snap has two mechanisms for ordering invocation order. Attributes have an optional order parameter. Also, interceptor bindings can be ordered using fluent configuration.

Note that attributes with a defined order always supersede a conflicting configured order.

An example of ordered attributes:

[First]
[Second]
public void RunInOrder()
{
    // These run in alphabetical order; first, then second.  You'd probably expect as much.
}
[Second]
[First]
public void RunInOrder()
{
    // These also run in alphabetical order also; first, then second.  It's a .NET's quirk
}
[First(Order=2)]
[Second(Order=1)]
public void RunInOrder()
{
    // These run in order; second, then first!
}

This is extremely useful in scenarios where order of operations is important.

You can also use a global configuration keeping in mind that Snap always observes attribute order before configuration order:

SnapConfiguration.For<StructureMapAspectContainer>(c =>
{
    c.IncludeNamespaceRoot("Snap.Tests");
    c.Bind<SecondInterceptor>().To<SecondAttribute>().Order(2);
    c.Bind<FirstInterceptor>().To<FirstAttribute>().Order(3);
    c.Bind<ThirdInterceptor>().To<ThirdAttribute>().Order(1);
});

This tells Snap to invoke Third, Second, and then First (unless the attributes have an overriding Order).

Happy coding!

⚠️ **GitHub.com Fallback** ⚠️