2008-10-22 26 views
33

¿Hay alguna manera en C# o .NET en general de crear un atributo en un método que desencadena un evento cuando se invoca un método? Idealmente, podría ejecutar acciones personalizadas antes y después de la invocación del método.C# Atributo para desencadenar un evento al invocar un método

quiero decir algo como esto:

[TriggersMyCustomAction()] 
public void DoSomeStuff() 
{ 
} 

estoy totalmente idea de cómo hacerlo o si es posible en absoluto, pero System.Diagnostic.ConditionalAttribute podría hacer algo similar en el fondo. No estoy seguro sin embargo.

EDIT: Olvidé mencionar que debido a las circunstancias de mi caso específico, el rendimiento no es realmente un problema.

+0

La respuesta corta es: sí, acompañado por: No sé cómo. Lo que quiere hacer es manipular IL en el momento de la compilación para inyectar una devolución de llamada en la primera y última línea de su método. El ensamblado MS.VB tiene un atributo que realiza alguna manipulación IL (para hacer que una clase sea un singleton no estático). – cfeduke

+0

@Tamas: Sé que su pregunta fue hecha hace mucho tiempo, pero se me ocurrió una respuesta. Espero que te ayude :-) – Matt

Respuesta

14

La única forma en que sé cómo hacerlo es con PostSharp. Post-procesa tu IL y puede hacer cosas como lo que pediste.

+0

He votado esta respuesta porque también es mi pensamiento: vas a necesitar alguna herramienta para ejecutar después de la compilación para analizar tu IL, buscar los métodos con tu atributo e inyectar alguna lógica de evento. –

+0

Acabo de enterarme de PostSharp y fui a buscar esta pregunta para publicarla como respuesta. – cfeduke

0

No creo que haya una manera de hacerlo con solo un atributo, pero usando proxy classes y reflexión podría tener una clase que sepa interceptar instancias de las clases en las que tiene métodos atribuidos.

Luego, la clase de proxy puede desencadenar un evento cada vez que se invocan los métodos atribuidos.

0

Un atributo proporciona información, son metadatos. No sé de una manera de hacerlo de forma espontánea, alguien podría.

Puede ver los métodos parciales en .NET que le permiten hacer un poco de manejo de eventos livianos. Proporciona los ganchos y deja que otra persona maneje la implementación. Si el método no está implementado, el compilador simplemente lo ignora.

http://msdn.microsoft.com/en-us/library/wa80x488.aspx

8

se necesita algún tipo de marco orientado aspecto. PostSharp lo hará, al igual que Windsor.

Básicamente, subclase de su objeto y reemplazar este método ...

entonces se convierte en:

//proxy 
public override void DoSomeStuff() 
{ 
    if(MethodHasTriggerAttribute) 
     Trigger(); 

    _innerClass.DoSomeStuff(); 
} 

, por supuesto, todo esto se oculta en su caso. Todo lo que tiene que hacer es preguntarle a Windsor por el tipo, y lo hará por usted. El atributo se convierte en una instalación (personalizada), creo que en Windsor.

15

Este concepto se usa en las aplicaciones web MVC.

El .NET 4.x Marco proporciona varios atributos que desencadenan acciones, por ejemplo .: ExceptionFilterAttribute (Manejo de excepciones), AuthorizeAttribute (autorización de tramitación). Ambos se definen en System.Web.Http.Filters.

Se podría, por ejemplo, definir su propio atributo de autorización como sigue:

public class myAuthorizationAttribute : AuthorizeAttribute 
{ 
    protected override bool IsAuthorized(HttpActionContext actionContext) 
    { 
     // do any stuff here 
     // it will be invoked when the decorated method is called 
     if (CheckAuthorization(actionContext)) 
      return true; // authorized 
     else 
      return false; // not authorized 
    } 

} 

Luego, en su controlador clase decorar los métodos que se supone que usar su autorización como sigue:

[myAuthorization] 
public HttpResponseMessage Post(string id) 
{ 
    // ... your code goes here 
    response = new HttpResponseMessage(HttpStatusCode.OK); // return OK status 
    return response; 
} 

Cuando se invoca el método Post, llamará al método IsAuthorized dentro del myAuthorization Atributo antes se ejecuta el código dentro del método Post.

Si devuelve false en el método IsAuthorized, indica que no se concede la autorización y se cancela la ejecución del método Post.


Para entender cómo funciona esto, vamos a ver en el ExceptionFilter, que permite excepciones de filtrado mediante el uso de atributos, tal como se muestra anteriormente para el AuthorizeAttribute.

Se utiliza la interfaz IExceptionFilter internamente como un contrato:

namespace System.Web.Http.Filters 
{ 
    public interface IExceptionFilter : IFilter 
    { 
     // Executes an asynchronous exception filter. 
     // Returns: An asynchronous exception filter. 
     Task ExecuteExceptionFilterAsync(
        HttpActionExecutedContext actionExecutedContext, 
        CancellationToken cancellationToken); 
    } 
} 

El ExceptionFilterAttribute misma se define de la siguiente manera:

namespace System.Web.Http.Filters 
{ 
    // Represents the attributes for the exception filter. 
    [AttributeUsage(AttributeTargets.Class | AttributeTargets.Method, 
      Inherited = true, AllowMultiple = true)] 
    public abstract class ExceptionFilterAttribute : FilterAttribute, 
      IExceptionFilter, IFilter 
    { 
     // Raises the exception event. 
     // actionExecutedContext: The context for the action.</param> 
     public virtual void OnException(
      HttpActionExecutedContext actionExecutedContext) 
     { 
     } 
     // Asynchronously executes the exception filter. 
     // Returns: The result of the execution. 
     Task IExceptionFilter.ExecuteExceptionFilterAsync(
      HttpActionExecutedContext actionExecutedContext, 
      CancellationToken cancellationToken) 
     { 
      if (actionExecutedContext == null) 
      { 
       throw Error.ArgumentNull("actionExecutedContext"); 
      } 
      this.OnException(actionExecutedContext); 
      return TaskHelpers.Completed(); 
     } 
    } 
} 

Dentro ExecuteExceptionFilterAsync, el método se llama OnException. Puede usarlo de manera análoga como se mostró anteriormente para el AuthorizeAttribute: Cree su propia clase, heredando desde ExceptionFilterAttribute, y anule el método OnException.


Existe también un producto comercial disponible como se mencionó en la respuesta de OwenP, PostSharp, lo que le permite hacer tan fácilmente. Here es un ejemplo de cómo puede hacerlo con PostSharp. Tenga en cuenta que hay una edición Express disponible que puede usar gratis incluso para proyectos comerciales.

Cuestiones relacionadas