Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Aspect Injection throws AI_ERR0 with inner NotSupportedException on compilation #123

Closed
backfromexile opened this issue Feb 17, 2020 · 2 comments

Comments

@backfromexile
Copy link

backfromexile commented Feb 17, 2020

The following code is part of an ASP.NET Core application and throws this error:

1>AspectInjector|2.3.0: Found 1 aspects, 2 injections
1>AspectInjector|2.3.0 : error AI_ERR0: Processing failure: System.NotSupportedException: No instruction for ValueType
1>   at FluentIL.Arrays.GetStoreOpcode(TypeReference elementType)
1>   at FluentIL.Arrays.SetByIndex(Cut pc, TypeReference elementType, Int32 index, PointCut value)
1>   at FluentIL.Arrays.CreateArray(Cut pc, TypeReference elementType, PointCut[] elements)
1>   at FluentIL.Values.AttributeArgument(Cut pc, CustomAttributeArgument argument)
1>   at FluentIL.Values.Value(Cut pc, Object value)
1>   at AspectInjector.Core.Advice.Weavers.Processes.AdviceWeaveProcessBase`1.<>c__DisplayClass16_0.<LoadInjectionsArgument>b__2(Cut ilc)
1>   at FluentIL.Cut.Here(PointCut pc)
1>   at FluentIL.Statements.Call(Cut cut, MethodReference method, PointCut args)
1>   at AspectInjector.Core.Advice.Weavers.Processes.AdviceWeaveProcessBase`1.<>c__DisplayClass16_0.<LoadInjectionsArgument>b__1(Cut il)
1>   at FluentIL.Cut.Here(PointCut pc)
1>   at FluentIL.Arrays.SetByIndex(Cut pc, TypeReference elementType, Int32 index, PointCut value)
1>   at FluentIL.Arrays.CreateArray(Cut pc, TypeReference elementType, PointCut[] elements)
1>   at AspectInjector.Core.Advice.Weavers.Processes.AdviceWeaveProcessBase`1.LoadInjectionsArgument(Cut pc, AdviceArgument parameter)
1>   at AspectInjector.Core.Advice.Weavers.Processes.AdviceWeaveProcessBase`1.LoadAdviceArgs(Cut cut)
1>   at FluentIL.Cut.Here(PointCut pc)
1>   at FluentIL.Statements.Call(Cut cut, MethodReference method, PointCut args)
1>   at AspectInjector.Core.Advice.Weavers.Processes.AdviceBeforeProcess.<Execute>b__1_0(Cut e)
1>   at FluentIL.Cut.Here(PointCut pc)
1>   at FluentIL.MethodEditor.BeforeInstruction(MethodBody body, Instruction instruction, PointCut action)
1>   at AspectInjector.Core.Processor.PatchAssembly(AssemblyDefinition assembly, Boolean optimize, Boolean verbose)
1>   at FluentIL.PatcherBase.Process(String assemblyFile, IAssemblyResolver resolver, Boolean optimize, Boolean verbose)
1>   at AspectInjector.Compiler.Execute(String filename, IReadOnlyList`1 references, Boolean optimize, Boolean verbose). Please submit an issue to https://github.com/pamidur/aspect-injector
1>AspectInjector : error AI_FAIL: Aspect Injector processing has failed. See other errors.

This is the code:

public enum UserRole
    {
        Guest,
        Normal,
        Admin,
    }

    public class User
    {
        public IReadOnlyList<UserRole> Roles { get; }

        public User(params UserRole[] roles)
        {
            Roles = new ReadOnlyCollection<UserRole>(roles);
        }

        public bool HasRole(UserRole role)
        {
            return Roles.Contains(role);
        }
    }

    public static class Context
    {
        public static AsyncLocal<User> User { get; } = new AsyncLocal<User>();
    }

    public class HomeController : Controller
    {
        public async Task<IActionResult> Index()
        {
            User user = new User(UserRole.Admin);
            Context.User.Value = user;

            await SomeIOOperation();

            await ActionOnlyAdminsCanDo();

            return View();
        }

        [CheckPrivileges(UserRole.Admin)]
        private async Task ActionOnlyAdminsCanDo()
        {
            await Task.Delay(100);
        }

        [CheckPrivileges(UserRole.Guest)]
        private async Task ActionEverybodyCanDo()
        {
            await Task.Delay(0);
        }


        public async Task<IActionResult> Privacy()
        {
            User user = new User(UserRole.Guest);
            Context.User.Value = user;

            await SomeIOOperation();

            return View();
        }

        private async Task SomeIOOperation()
        {
            await Task.Factory.StartNew(async () => { await Task.Delay(1000); }, TaskCreationOptions.LongRunning);
        }
    }

    [Injection(typeof(CheckPrivilegesAspect))]
    [AttributeUsage(AttributeTargets.Method)]
    public sealed class CheckPrivileges : Attribute
    {
        public UserRole[] Roles { get; }

        public CheckPrivileges(params UserRole[] roles)
        {
            Roles = roles;
        }
    }

    [Aspect(Scope.PerInstance)]
    public class CheckPrivilegesAspect
    {
        [Advice(Kind.Before)]
        public void Before([Argument(Source.Triggers)] Attribute[] attributes)
        {
            CheckPrivileges attr = attributes.OfType<CheckPrivileges>().FirstOrDefault();

            if (attr.Roles.Any(role => !Context.User.Value.HasRole(role)))
                throw new MissingPrivilegesException();
        }
    }

    [Serializable]
    internal class MissingPrivilegesException : Exception
    {
        public MissingPrivilegesException()
        {
        }

        public MissingPrivilegesException(string message) : base(message)
        {
        }

        public MissingPrivilegesException(string message, Exception innerException) : base(message, innerException)
        {
        }

        protected MissingPrivilegesException(SerializationInfo info, StreamingContext context) : base(info, context)
        {
        }
    }

Am I doing something wrong here or can't I inject values into the attributes?
Also is there a reason I have to create two different classes for aspect and attribute if I want the attribute to have a not empty constructor?

@pamidur
Copy link
Owner

pamidur commented Feb 18, 2020

Hi @backfromexile , thank you for the report!
Issue should be fixed in 2.3.1

@pamidur
Copy link
Owner

pamidur commented Feb 18, 2020

FYI the issue was that when one uses params with enums the compiler creates an array of int instead of array of enums(value types), this totally makes sense however we haven't tested this scenario before

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

No branches or pull requests

2 participants