C #: Wie ein Attribut auf ein Verfahren schaffen das Auslösen eines Ereignisses, wenn es aufgerufen wird?

StackOverflow https://stackoverflow.com/questions/226420

Frage

Gibt es eine Möglichkeit in C # oder .NET in der Regel ein Attribut auf ein Verfahren zu schaffen, die ein Ereignis auslöst, wenn die Methode aufgerufen wird? Im Idealfall würde ich in der Lage sein, benutzerdefinierte Aktionen vor und nach dem Aufruf der Methode ausgeführt werden.

Ich meine etwas wie folgt aus:

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

Ich bin völlig ratlos, wie es zu tun, oder wenn es überhaupt möglich, aber System.Diagnostic.ConditionalAttribute könnte eine ähnliche Sache im Hintergrund tun. Ich bin allerdings nicht sicher.

Bearbeiten :. Ich habe vergessen zu erwähnen, dass aufgrund der Umstände von meinem speziellen Fall, ist die Leistung nicht wirklich ein Problem

War es hilfreich?

Lösung

Der einzige Weg, ich weiß, wie dies zu tun ist mit Postsharp . Es Post-Prozesse Ihre IL und können Dinge tun, wie das, was Sie gefragt.

Andere Tipps

Dieses Konzept wird in MVC Web-Anwendungen.

Das .NET Framework 4.x bietet verschiedene Attribute, die Aktionen auslösen, z.B .: ExceptionFilterAttribute (Umgang mit Ausnahmen), AuthorizeAttribute (Umgang mit Genehmigung). Beide sind in System.Web.Http.Filters definiert.

Sie können zum Beispiel definieren Sie Ihre eigene Berechtigungs Attribut wie folgt:

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
    }

}

Dann in der Controller Klasse dekorieren Sie die Methoden, die angeblich Ihre Berechtigung wie folgt verwenden:

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

Jedes Mal, wenn die Post Methode aufgerufen wird, wird es die IsAuthorized Methode innerhalb des myAuthorization Attribut aufrufen vor der Code innerhalb der Post Verfahren ausgeführt wird.

Wenn Sie false im IsAuthorized Methode zurückzukehren, signalisieren Sie, dass eine Genehmigung nicht erteilt wird und die Durchführung des Verfahrens Post abgebrochen wird.


Um zu verstehen, wie dies funktioniert, lassen Sie uns in ein anderes Beispiel aussehen: Die ExceptionFilter , die durch Filterung Ausnahmen erlaubt Attribute verwenden, die Nutzung ist ähnlich wie oben für die AuthorizeAttribute gezeigt (Sie können ein mehr finden detaillierte Beschreibung über ihre Nutzung hier ).

Um es zu nutzen, leitet die DivideByZeroExceptionFilter Klasse aus dem ExceptionFilterAttribute wie dargestellt hier , und überschreiben Sie die Methode OnException:

public class DivideByZeroExceptionFilter : ExceptionFilterAttribute
{
    public override void OnException(HttpActionExecutedContext actionExecutedContext)
    {
        if (actionExecutedContext.Exception is DivideByZeroException)
        {
            actionExecutedContext.Response = new HttpResponseMessage() { 
                Content = new StringContent("An error occured within the application.",
                                System.Text.Encoding.UTF8, "text/plain"), 
                StatusCode = System.Net.HttpStatusCode.InternalServerError
                };
        }
    }
}

Dann verwenden Sie den folgenden Demo-Code es auslösen:

[DivideByZeroExceptionFilter]
public void Delete(int id)
{
    // causes the DivideByZeroExceptionFilter attribute to be triggered:
    throw new DivideByZeroException(); 
}

Jetzt, da wir wissen, wie es verwendet wird, ich bei der Umsetzung in erster Linie interessiert sind. Der folgende Code ist aus dem .NET Framework. Es nutzt die Schnittstelle IExceptionFilter intern als Vertrag:

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);
    }
}

Die ExceptionFilterAttribute selbst ist wie folgt definiert:

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();
        }
    }
}

Innerhalb ExecuteExceptionFilterAsync wird das Verfahren OnException genannt. Weil Sie es außer Kraft gesetzt haben, wie zuvor gezeigt, kann der Fehler nun durch Ihren eigenen Code behandelt werden.


Es gibt auch ein kommerzielles Produkt zur Verfügung, wie in OwenP Antwort erwähnt, Postsharp , das Ihnen erlaubt, zu tun dass leicht. Hier ist ein Beispiel, wie Sie das mit Postsharp tun können. Beachten Sie, dass es eine Express-Edition zur Verfügung, die Sie kostenlos auch für kommerzielle Projekte verwenden können.

Postsharp Beispiel (den Link oben für die vollständige Beschreibung):

public class CustomerService
{
    [RetryOnException(MaxRetries = 5)]
    public void Save(Customer customer)
    {
        // Database or web-service call.
    }
}

Hier wird das Attribut gibt an, dass die Save Methode zu 5-mal aufgerufen, wenn eine Ausnahme auftritt. Der folgende Code definiert dieses benutzerdefinierte Attribut:

[PSerializable]
public class RetryOnExceptionAttribute : MethodInterceptionAspect
{
    public RetryOnExceptionAttribute()
    {
        this.MaxRetries = 3;
    }

    public int MaxRetries { get; set; }

    public override void OnInvoke(MethodInterceptionArgs args)
    {
        int retriesCounter = 0;

        while (true)
        {
            try
            {
                args.Proceed();
                return;
            }
            catch (Exception e)
            {
                retriesCounter++;
                if (retriesCounter > this.MaxRetries) throw;

                Console.WriteLine(
                    "Exception during attempt {0} of calling method {1}.{2}: {3}",
                    retriesCounter, args.Method.DeclaringType, args.Method.Name, e.Message);
            }
        }
    }
}

Sie können Context und IMessageSink verwenden. Siehe http://msdn.microsoft.com/nb- no / Magazin / cc301356 (en-us) aspx

Seien Sie gewarnt, dass dieser Ansatz eine schwere Auswirkungen auf die Leistung hat im Vergleich zu einem direkten Methodenaufruf.

Lizenziert unter: CC-BY-SA mit Zuschreibung
Nicht verbunden mit StackOverflow
scroll top