Closed zejji closed 3 years ago
Hi @zejji , as of now there is no such possibility. I will make this issue to be FeatureRequest.
Could you please give some info?
Is IRequiresPermissionCheck
in your control and you can modify it? Like
[Injection(typeof(ApplyPermissionCheckAttribute))] //won't do anything now, but shows possible implementation approach
public interface IRequiresPermissionCheck
{
public void CheckPermissions();
}
with v2.5.0-pre1 you could try something like the following
Please note:
PropagationFilter
or additional check in your advice to avoid StackOverflow calling CheckPermissions->CheckPermissions->CheckPermissions...[Aspect(Scope.Global)]
public class ApplyPermissionCheck
{
[Advice(Kind.Before, Targets = Target.Method)]
public void BeforeMethod([Argument(Source.Instance)] object instance, [Argument(Source.Metadata)] MethodBase metadata)
{
//Alternative to ProragationFilter
//if (metadata.Name.Contains(nameof(IRequiresPermissionCheck.CheckPermissions)))
// return;
((IRequiresPermissionCheck)instance).CheckPermissions();
}
}
[Injection(typeof(ApplyPermissionCheck), PropagationFilter = "^(?=.)((?!" + nameof(CheckPermissions) + ").)*$")]
public interface IRequiresPermissionCheck
{
void CheckPermissions();
}
public class TestClass : IRequiresPermissionCheck
{
public void CheckPermissions()
{
Console.WriteLine("Allowed");
}
public void Do()
{
Console.WriteLine("Done");
}
}
class Program
{
static void Main(string[] args)
{
new TestClass().Do();
}
}
I'd like to hear feedback. Please let me know how it works, is it convenient or not
@pamidur - Many thanks for getting back to me - much appreciated!
I tried the approach you suggested (using the metadata check on the basis that it is more readable) and can confirm it works successfully.
In terms of design, I wonder whether the CompileTimeValidate
approach used by PostSharp might be cleaner? I had four specific thoughts regarding the implementation in your post above, some of which are related to use of AspectInjector in a team:
TestClass
in your example) might hide the intended behaviour for team members not familiar with AspectInjector. In contrast, most people will know e.g. the concept of ASP.NET Core's Authorize
attribute, so use of an attribute will likely be instantly recognizable. However, using the interface trigger approach does have the significant advantage that it prevents users from implementing the IRequiresPermissionCheck
interface but forgetting to apply the attribute. This was something I realised I had forgotten to do on one class I was in the middle of writing!So in fact I understood you wrong from the very beginning. It might be because I was thinking about InterfaceTriggers long before :)
What you need is -> Aspect injection is still triggered by an Attribute. However it is only applied if a target has specific Interface implementation. Why not simply ignore other targets?
if (instance is IRequiresPermissionCheck rc)
{
rc.CheckPermissions();
}
// simply ignore everything else
For InterfaceTriggers feature:
CompileTimeValidate
is executed in compile time, which I'd like to avoid in AspectInjector because:
CompileTimeValidate
validate method should be compatible and I cannot enforce it.CompileTimeValidate
basically allows to execute arbitrary code on your devs computers@pamidur - Thanks for your reply. The reason I though it preferable not just to ignore other targets that don't implement IRequiresPermissionCheck
is that I would prefer to catch any inappropriate usage of the attribute at compile-time rather than runtime if possible. However, I completely understand your issues with the CompileTimeValidate
idea.
One final thought - although I haven't had a chance to investigate the source code in details, some validation appears to done currently at compile time. Perhaps there could be an additional parameter to the Injection
attribute which specifies a required interface to be implemented by the target class? Just an idea - I don't know whether this is either (i) possible or (ii) would be helpful enough for other users to consider implementing.
I was thinking about additional Propagation options to allows only certain types, like PropagateToTypes=[typeof(IRequiresPermissionCheck)]
. This should work for methods too, restricting by return type. But it won't throw compile time error, it will just ignore incorrect attribute assignment attempts.
So for restricting targets I think it is possible (won't break anything) to add new field to InjectionAttribute
- RestrictToTypes=[typeof(IRequiresPermissionCheck)]
, combining that with your regular AttributeUsage(Class)
might fulfill your requirements.
Please feel free to contribute)
Released in 2.5.0
Great - thanks for the heads-up. Will give this a try!
Consider the following interface:
By creating the following aspect, it is possible to automatically call the
CheckPermissions()
method prior to any method call within a class that implementsIRequiresPermissionCheck
:Is it possible to restrict an aspect so that it can only be applied to classes implementing a certain interface, i.e. a via a compile-time check rather than throwing a runtime exception?
Update: While googling I noticed a similar feature referenced in the PostSharp documentation: https://doc.postsharp.net/aspect-validation