PostSharp OnMethodBoundaryAspect OnEntry Not Executing - c#

I am running a .NET 4.0 Web Application (not web site) and PostSharp 1.5. I cannot get the OnEntry override method to execute using the OnMethodBoundaryAspect base class. Here is some relevant code:
public sealed class MonitorAttribute : OnMethodBoundaryAspect {
public string[] SomeValue { get; protected set; }
public MonitorAttribute (params string[] someValue){
SomeValue = someValue;
}
public override void OnEntry(MethodExecutionEventArgs eventArgs){
// do Something here
base.OnEntry(eventArgs);
}
}
public sealed class MyUsageClass : IMyUsageClass {
[Monitor(new string[]{ 'Test' })
public void SomeMethod {
// Do something else in here
}
}
Am I missing something? It never hits the OnEntry method. I also tried replacing my PostSharp.dll and PostSharp.Laos.dll dependencies with the new 2.0 version. If it makes any difference MyUsageClass is instantiated by StructureMap.

Yes, every dev will need to have PostSharp installed. If you're just using the starter edition then it's all free.
Posting this as an answer to show you the code. My test code
class Program
{
[Monitor]
static void Main(string[] args)
{
}
}
[Serializable]
public class MonitorAttribute : OnMethodBoundaryAspect
{
public override void OnEntry(MethodExecutionArgs args)
{
Console.WriteLine("OnEntry");
}
}
The code after compilation
internal class Program
{
[CompilerGenerated, DebuggerNonUserCode]
internal sealed class <>z__Aspects
{
internal static MethodBase m1 = MethodBase.GetMethodFromHandle(ldtoken(Main()));
internal static readonly MonitorAttribute a0 = (MonitorAttribute)<>z__AspectsImplementationDetails.aspects1[0];
}
private static void Main(string[] args)
{
Program.<>z__Aspects.a0.OnEntry(null);
}
}

Related

How to access the first base class in C#?

I'm having a base class defined in my app
Something like,
using System;
public class BaseClass
{
public virtual void Method2() {Console.WriteLine("base2");}
public virtual void Method1() {Console.WriteLine("base1");}
}
public class Derived1 : BaseClass
{
public override void Method2() {Console.WriteLine("derived1-2");}
public override void Method1() {Console.WriteLine("derived1-1");}
}
public class Derived2 : Derived1
{
public override void Method1() {Console.WriteLine("derived2-2");}
}
public class Program
{
public static void Main()
{
var obj = new Derived2();
((BaseClass)obj).Method2();
Console.WriteLine("Hello World");
}
}
Say I need to access the Method2() of my very first BaseClass. Even after typecasting it to ((BaseClass)obj).Method2(), I'm still getting derived1-2 while I'm expecting base2'.
How do I do that ?
I completely agree with the comments: it sounds like the behaviour that you require would need you to re-think your classes - possibly inheritance is not the best solution in this case. It depends what you're trying to do; you could obviously just do this:
var obj = new BaseClass();
((BaseClass)obj).Method2();
Console.WriteLine("Hello World");
My guess would be that what you actually want here is some form of injection; for example:
public class BaseClass
{
private readonly IFunctionality1 functionality1;
public virtual void Method2() { Console.WriteLine("base2"); }
public virtual void Method1() { this.functionality1.Method1(); }
public BaseClass(IFunctionality1 functionality1)
{
this.functionality1 = functionality1;
}
}
public class Derived1 : BaseClass
{
public Derived1(IFunctionality1 functionality1) : base (functionality1)
{
}
}
In this case, you might find that inheritance isn't even required anymore.

Force property on method parameter before excecution (using PostSharp?)

I have a method like this
public void MyMethod(MyType parameter) { /* ... */ }
I'd like to force a value into one of parameter's public property before the method gets excecuted.
It must happen before method excecution because some postSharp OnMethodBoundaryAspect.OnEntry depends on this property's value.
An ideal solution could looks like this:
[SetPropertyBeforeEntry(0 /* Argument's index*/, nameof(MyType.MyProperty) /* Property to set */, 1234 /* Value */)]
public void MyMethod(MyType parameter) { /* ... */ }
You have two options - OnMethodBoundaryAspect and MethodInterceptionAspect, but in both cases you need to use aspect dependencies to make sure you have proper order (PostSharp would produce warnings if the order is not specified).
PostSharp provides various ways to specify dependencies between aspects. You can find more here.
The following demonstrates changing of the parameter's property before (without the specific logic for argument type, property or index.
class Program
{
static void Main(string[] args)
{
new TestClass().Foo(new TestData());
}
}
public class TestClass
{
[ObservingAspect]
[ArgumentChangingAspect]
public int Foo(TestData data)
{
Console.WriteLine("Method observed: {0}", data.Property);
return data.Property;
}
}
public class TestData
{
public int Property { get; set; }
}
[AspectTypeDependency(AspectDependencyAction.Order, AspectDependencyPosition.Before, typeof(ObservingAspect))]
[PSerializable]
public class ArgumentChangingAspect : OnMethodBoundaryAspect
{
public override void OnEntry(MethodExecutionArgs args)
{
((TestData) args.Arguments[0]).Property = 42;
}
}
[PSerializable]
public class ObservingAspect : OnMethodBoundaryAspect
{
public override void OnEntry(MethodExecutionArgs args)
{
Console.WriteLine("Aspect observed: {0}", ((TestData)args.Arguments[0]).Property);
}
}

How to override a method in a custom library class

I have two projects: ClientProj and ServerProj, which both share a SharedLibrary containing the basics of my game.
Inside this library I have the class GameObject which is the base class from which many other game items inherit.
Inside GameObject is a SetPosition() method.
Here's my problem: When I run SetPosition() on the client, I wish to add some additional code / override the method completely. The code I wish to add however relates to classes that are only present in the ClientProj namespace, which the SharedLibrary knows nothing about.
Is there any clean way to override or extend the library methods?
Updated: Note that the instances of GameObject and all things that inherit it are defined, contained and handled all within the SharedLibrary namespace. For the most part the ClientProj and ServerProj only handle networking, users and input/output.
You can use the Proxy pattern and have the game objects inherit from the proxy class instead of the real class:
SharedLibrary:
public class GameObject
{
public virtual void SetPosition() { ... }
}
public class DelegatingGameObject : GameObject
{
public GameObject Inner;
public override void SetPosition() { Inner.SetPosition(); }
}
public class Tree : DelegatingGameObject
{
}
ClientLibrary:
class ClientGameObject : GameObject
{
public override void SetPosition()
{
if (isMonday) base.SetPosition();
}
}
var tree = new Tree { Inner = new ClientGameObject() };
tree.SetPosition();
SharedLibrary:
public class GameObject
{
public virtual void SetPosition() { Console.WriteLine("GameObject.SetPosition"); }
public static event Func<GameObject> Factory;
internal static GameObject CreateBase() { var factory = Factory; return (factory != null) ? factory() : new GameObject(); }
}
internal class GameObjectBase : GameObject
{
private readonly GameObject baseGameObject;
protected GameObjectBase() { baseGameObject = GameObject.CreateBase(); }
public override void SetPosition() { baseGameObject.SetPosition(); }
}
internal class Tree : GameObjectBase
{
public override void SetPosition()
{
Console.WriteLine("Tree.SetPosition");
base.SetPosition();
}
}
public static class Game
{
public static void Start()
{
new Tree().SetPosition();
}
}
ClientLibrary:
internal class ClientGameObject : GameObject
{
public override void SetPosition()
{
Console.WriteLine("ClientGameObject.SetPosition Before");
base.SetPosition();
Console.WriteLine("ClientGameObject.SetPosition After");
}
}
internal static class Program
{
static void Main(string[] args)
{
GameObject.Factory += () => new ClientGameObject();
Game.Start();
}
}
Make SetPosition method virtual and use override keyword to override its behaviour in ClientProj.
You can do it virtual in base class, override in derived, and in overriden method call your methods and after base class method.
A psudocode can look like this:
public class GameObject
{
public virtual void SetPosition()
{
//do something here
}
}
public class Derived: GameObject
{
public override void SetPosition()
{
// do something specific to Derived
base.SetPosition(); // CALL BASE CLASS METHOD AFTER
}
}

Clean code which version is correct?

When the only code in there is for a class how would you code it adding public to the default class like so
namespace HW2_2_Spaceship
{
public class Spaceship //added public to the default class
{
static void Main(string[] args)
{
}
or
namespace HW2_1_Book
{
class Book
{
static void Main(string[] args)
{
}
public class Book // added a new class with in the default class
{
In general, each class should have their own file.
Main should be in Program.cs
There are usecases where you can use Inner classes, see Using Inner classes in C#.
//Program.cs, if u use visual studio then ensure you add
// the public access modifier yourself
namespace HW2_2_Spaceship
{
public class Program
{
public static void Main(string[] args)
{
//Do something here
}
}
}
//Book.cs, add the public modifier to the class
namespace HW2_2_Spaceship
{
public class Book
{
//add method and properties here
}
}

Whats wrong with this aspect

I only want this invoked when a property is set. Why is this not working?
[DirtyTrackingAttribute(AttributeTargetElements =
PostSharp.Extensibility.MulticastTargets.Property)]
class Program
{
public static string Test { get; set; }
static void Main(string[] args)
{
TestIt();
Test = "foo";
Console.ReadKey();
}
private static void TestIt()
{
Console.WriteLine("Real method called");
}
}
[Serializable]
public class DirtyTrackingAttribute : OnMethodInvocationAspect
{
public override void OnInvocation(MethodInvocationEventArgs eventArgs)
{
Console.WriteLine("Property invoked");
eventArgs.Proceed();
}
}
If you want the aspect to be applied on property setters only, you can filter the method name with the expression "set_*":
[DirtyTrackingAttribute(AttributeTargetMembers="set_*")]
PostSharp 1.* does not support explicitely properties; property accessors are considered as plain methods.

Categories

Resources