I have a question about events interception with c# and Postsharp.
I would like to cancel the execution of events like BeforeDropDown, RowSelected MouseClick with EventInterceptionAspect in postsharp.
But i can not find a proper place where i can write the code.
example:
i tried something like this:
[Serializable]
class EventInter : EventInterceptionAspect
{
public override bool CompileTimeValidate(System.Reflection.EventInfo targetEvent)
{
return "FormClosed".Equals(targetEvent.Name);
}
public override void OnInvokeHandler(EventInterceptionArgs args)
{
if condition executes method otherwise no
}
}
in the form:
[EventInter]
public partial class Frm_RomperMesa : KryptonForm
But it didn´t work. So i want to know if it is possible to achieve what i want.
Thanks in advace. I hope be clear.
yes, it is possible. The problem is, you're trying to apply an event interception aspect to an event defined in another assembly which you can't do within your code. You can't even override the event because it's setup to be handled using the base Form type in the designer code behind
this.FormClosing += new System.Windows.Forms.FormClosingEventHandler(this.Form1_FormClosing);
you will have to modify the assembly to do this. Use the following aspect and the links to modify your
public class EventAspectProvider : TypeLevelAspect , IAspectProvider
{
public IEnumerable<AspectInstance> ProvideAspects(object targetElement)
{
Type t = (Type)targetElement;
EventInfo e = t.GetEvents().First(c => c.Name.Equals("FormClosing"));
return new List<AspectInstance>() { new AspectInstance(e, new EventInter()) };
}
}
[Serializable]
public class EventInter : EventInterceptionAspect
{
public override void OnInvokeHandler(EventInterceptionArgs args)
{
int x = 0;
if (x > 0) //Do you logic here
{
args.ProceedInvokeHandler();
}
}
}
http://programmersunlimited.wordpress.com/2011/07/27/applying-aspects-to-3rd-party-assemblies-using-postsharp/
http://programmersunlimited.wordpress.com/2011/08/16/exposing-internal-methods-in-3rd-party-assemblies-for-external-use/
Basically it boils down to modifying the System.Windows.Forms.dll which I don't recommend. But if it's some other 3rd party vendor library, then go for it.
A workaround is to do it the other way around: Use an aspect on the method that is hooked to the event and cancel the normal execution of the method if the condition is met. This does not prevent the event form being raised but it prevents your event handling code from being executed.
[EventInter]
private void someForm_FormClosed(object sender, EventArg arg) {}
We use this approach a lot in our project. We have several aspects that apply to event handling methods (exception handling, cursors handling, etc...).
We go a little further, we apply the aspects at the assembly level and we use CompileTimeValide to recognize the signature of an event handling method. In theory, it's not 100% reliable, but we have not found any problems with this approach so far.
Related
I have a method which is called from a 3rd party assembly and serves as our application-entry point. This method raises our event MyEvent. In order to ensure the same event-handler is only registered once and only once, I implemented my own logic for add and remove:
class MyEditorExtension
{
private EventHandler<MyArgs> myEvent
public EventHandler<MyArgs> MyEvent
{
add
{
if(this.myEvent == null || this.myEvent.GetInvocationList().All(x => !x.Equals(value))
this.myEvent += value;
}
remove { this.myEvent -= value; }
}
// this method is called from ArcMap
public void OnCreate()
{
...
MyEvent();
}
}
OnCreate is quite huge and can´t safely be refactored into smaller, testable units. However I want to check if my event-definition really does what it is supposed to do. In order to do so I tried to register the exact same method twice and check if it was executed twice:
[TestFixture]
public class ExtensionTest
{
int numCalls;
[Test]
public void Test_Register_Handler_Twice()
{
var target = new MyExtension();
target.MyEvent += myHandler;
target.MyEvent += myHandler;
target.MyEvent(new MyArgs());
Assert.AreEqual(1, this.numCalls);
}
private void(MyArgs args) { this.numCalls ++; }
}
Of course the above won´t compile because I can´t raise an event outside its class. I´d also like to avoid introducing a RaiseEvent-method solely for the sake of testing the event.
So I wonder if there´s any way to achieve this, e.g. using reflection?
Indeed, it is possible using reflection. However this is quite hacky. In fact this is a common problem when testing legacy-code as this one. This solution was inspired by this post: https://stackoverflow.com/a/12000050/2528063
You have to know that an event is nothing but an add- and remove-method around a private (hidden) delegate-field, just like a property is nothing but a get- and set-method around a private (also hidden) backing-field. Having said this you can access that delegate, which usually has the exact same name as your event:
var delegateField = typeof(MyExtension).GetField("MyEvent", BindingFlags.NonPublic)?.GetValue(target);
In our special case we have our own accessors and therefor the name of the delegate is provided directly within the source-cde of MyExtension. Thus we write this slightly different version:
var delegateField = typeof(MyExtension).GetField("myEvent", BindingFlags.NonPublic)?.GetValue(target);
Now we have our backing delegate, which we can easily invoke:
delegateField?.DynamicInvoke(new MyArgs());
Of course we should add some sanity-checks, e.g. for the case the delegate was renamed and thus couldn´t be found, but I guess you get the point.
Is there a way to call a method to be executed before another method, like a trigger?
Something like an attribute that indicates the method to be executed, like this:
[OnBefore(MethodToBeExecutedBefore)]
public void MethodExecutedNormally()
{
//method code
}
I have a situation that I need to call a check method very often, and most of the time, they are before methods that take too long to execute.
There is no built in way to achieve this result, if you are using a dependency injection mechanism you can use the interception facilities if the DI framework supports this. (Ex: Unity, NInject)
If you want to go low level you can also use Reflection.Emit to create a derived class at runtime, that overrides methods with a particular attribute that invokes any extra functionality you want, but that is more difficult.
What you are talking about is called AOP or Aspect Oriented Programming.
There are no built-in options in C#. While Attributes exists, there is no mechanism to take any actions with them. You always need a piece of code that reads those attributes and then does something. Attributes themselves are only metadata and markers.
As far as external tools go, Postsharp is the de-facto standard AOP postcompiler for .NET, but it's not free (at least not for real use, there is a free version you may want to try, maybe it's enough for your use-case).
I think you should consider an event driven approach.
You could create an interface and some base classes to handle the event, then have your long running classes inherit from it. Subscribe to the event and handle accordingly:
public delegate void BeforeMethodExecutionHandler<TArgs>(ILongRunningWithEvents<TArgs> sender, TArgs args, string caller);
public interface ILongRunningWithEvents<TArgs>
{
event BeforeMethodExecutionHandler<TArgs> OnBeforeMethodExecution;
}
public class LongRunningClass<TArgs> : ILongRunningWithEvents<TArgs>
{
private BeforeMethodExecutionHandler<TArgs> _onBeforeMethodExecution;
public event BeforeMethodExecutionHandler<TArgs> OnBeforeMethodExecution
{
add { _onBeforeMethodExecution += value; }
remove { _onBeforeMethodExecution -= value; }
}
protected void RaiseOnBeforeMethodExecution(TArgs e, [CallerMemberName] string caller = null)
{
_onBeforeMethodExecution?.Invoke(this, e, caller);
}
}
public class ConcreteRunningClass : LongRunningClass<SampleArgs>
{
public void SomeLongRunningMethod()
{
RaiseOnBeforeMethodExecution(new SampleArgs("Starting!"));
//Code for the method here
}
}
public class SampleArgs
{
public SampleArgs(string message)
{
Message = message;
}
public string Message { get; private set; }
}
Sample usage:
public static void TestLongRunning()
{
ConcreteRunningClass concrete = new ConcreteRunningClass();
concrete.OnBeforeMethodExecution += Concrete_OnBeforeMethodExecution;
concrete.SomeLongRunningMethod();
}
private static void Concrete_OnBeforeMethodExecution(ILongRunningWithEvents<SampleArgs> sender, SampleArgs args, string caller)
{
Console.WriteLine("{0}: {1}", caller ?? "unknown", args.Message);
}
The message SomeLongRunningMethod: Starting! will be output before the long-running method executes.
You could add the caller name to the args. I whipped this out real quick to illustrate.
UPDATE: I see you added tags for ASP.NET MVC. The concept still applies to controllers as controllers are just classes.
I have a UserControl on a Form,
when I MouseMove on that UserControl I want to do something in the Form.
How can I make the Form 'listen' for this event?
I am using Visual C#, .Net framework 3.5, winforms
I suppose you're referring to a use control or something like that.
You can add a public event, and trigger it inside your class when detecting the inner class event.
Then you have to subscribe to the published event in the second class.
This is a sample so that you see the sintax:
public class WithEvent
{
// this is the new published event
public EventHandler<EventArgs> NewMouseEvent;
// This handles the original mouse event of the inner class
public void OriginalEventhandler(object sender, EventArgs e)
{
// this raises the published event (if susbcribedby any handler)
if (NewMouseEvent != null)
{
NewMouseEvent(this, e);
}
}
}
public class Subscriber
{
public void Handler(object sender, EventArgs e)
{
// this is the second class handler
}
public void Subscribe()
{
WithEvent we = new WithEvent();
// This is how you subscribe the handler of the second class
we.NewMouseEvent += Handler;
}
}
If you are talking about Windows Forms (it's not clear from the question) you need to define
a new event in the class who recieves the mouse-event. After reciving it raises a new custom-event. Another class is subcribed to that (custom-event) a recieves notification.
For moe information (it's not something that can be presenteed in a couple of lines)
can have alook here:
How to propagate an Event up to the MainForm?
If you are talking about WPF, there are different concept of events: event routing. If your class is UI element present in UI tree of the component that recieves actually mouse-event, it will be propagated to your class too. So no need of more coding.
To expand a little on the answer from JotaBe, there are two scenarios that I could see you having:
a) class A calls a method in class B, and an exception happens. In this case, you don't need to do anything: exception will walk the stack, until it finds a catch statement. So, really, all you need to do is NOT catch an exception, or if you do need to catch it (for logging purposes and such), then rethrow it.
b) if you need to have a code triggered in some unrelated class, as a result of exception, then the best way is to use events. In your class declare:
public class ClassA
{
public static event EventHandler<Exception> OnException;
public void Notify(Exception ex)
{
if (OnException != null)
{
OnException(this, ex);
}
}
}
and then, in order to be notified, all you need is to
ClassA.OnException += (sender, exeption) =>
{
... some GetHashCode ..
};
... I guess JotaBe already added all necessary example code as I was typing
I am trying to create this simple interface. I want it somehow to be able to fire an event.
This is what I have till now (doesn't compile, just my thoughts)
public interface IAsyncSearch<TTermType, TResultsEventType>
where TResultsEventType:delegate
{
event TResultsEventType SearchCompletedEvent;
void SearchAsync(TTermType term);
}
Is something similar even possible? I know that a type is expected in the where statement.
Try this
public interface IAsyncSearch<TData, TArgs>
{
event EventHandler<SpecialDataEventArgs<TArgs>> SearchCompletedEvent;
void SearchAsync(TData term);
}
public class SpecialDataEventArgs<T> : EventArgs
{
public SpecialDataEventArgs(T data)
{
Data = data;
}
public T Data { get; private set; }
}
All event types ought to derive from EventHandler<>, the standard .NET event handler type. Helps anybody that reads your code recognize it quickly. And even more appropriate here, it readily solves your problem:
public interface IAsyncSearch<TTermType, TResultsArgType>
where TResultArgType : EventArgs
{
event EventHandler<TResultsArgType> SearchCompletedEvent;
void SearchAsync(TTermType term);
}
Events work only with delegate types. And there is no way to constrain type parameter to be a delegate in C#. Because of that, I don't think what you want is possible in C#.
According to Jon Skeet, it actually may be possible to do this in CIL, so maybe if you wrote that type in CIL, you could be able to use it from C# the way you want.
EDIT: You can create such type in CIL, but it seems you can't use it property from C#. It seems you can't implement it. And calling the event methods using += doesn't work either. But calling them using the add_SearchCompletedEvent does work.
I'm working on an application that's embedding Mono, and I'd like to raise an event from the C++ layer into the C# layer. Here's what I have:
void* itr(NULL);
MonoEvent* monoEvent;
while(monoEvent= mono_class_get_events(klass, &itr))
{
if(0 == strcmp(eventName, mono_event_get_name(monoEvent)))
raiseMethod = mono_event_get_raise_method(monoEvent);
}
However, raiseMethod always comes back as NULL. Looking at the structure of the MonoEvent, it looks like the add and remove methods were populated, but not the raise? Is there something special I have to do to get this to work?
EDIT: If it matters, here's the (basic) form of the delegate, class, and events I'm using in the C# layer.
public delegate void MyHandler(uint id);
public class SimpleComponent : NativeComponent
{
public event MyHandler OnEnter;
public event MyHandler OnExit;
}
May the event be defined in parent class? If so you need to traverse up the class hierarchy with something like the following:
MonoEvent* monoEvent;
while (klass)
{
void* itr = NULL;
while(monoEvent= mono_class_get_events(klass, &itr))
{
if(0 == strcmp(eventName, mono_event_get_name(monoEvent)))
raiseMethod = mono_event_get_raise_method(monoEvent);
}
klass = mono_class_get_parent(klass);
}
EDIT after comment and re-reading question:
It is normal that the raise method for event is NULL.
This method usually returns null for events declared with the C# event keyword or the Visual Basic Event keyword. This is because the C# and Visual Basic compilers do not generate such a method by default.
(source)
I am afraid it may be hard to fire an event of a class. Because it is actually breaking the concept of events in .NET - which says that the class itself can only fire its own Event. Actually, even from C# it is hard to raise the event of other class.
Conceptually, events are pair of add_handler and remove_handler methods where you specify delegates to be called when event's circumstances occur. It is up to class how it implements events. Technically, it is just a private delegate field, AFAIK.
You may try to locate it.
I am not sure if it is a proper approach, but one of the answers in How do I raise an event via reflection in .NET/C#? describes how to raise event using reflection. You might attempt to convert it into mono_class / mono_field calls, etc.
Krizz's answer is the most complete. This is how I fixed my code to work how I would "expect".
I changed the C# side to:
public delegate void MyHandler(uint aEntityId);
public class SimpleComponent: NativeComponent
{
public event MyHandler OnEnter;
public event MyHandler OnExit;
protected void CallOnEnter(uint aEntityId)
{
if (OnEnter != null)
OnEnter(aEntityId);
}
protected void CallOnExit(uint aEntityId)
{
if (OnExit!= null)
OnExit(aEntityId);
}
}
Then grabbed the mono method with
raiseMethod = mono_class_get_method_from_name(klass, "CallOnEnter", 1);