C #: Wie ein Attribut auf ein Verfahren schaffen das Auslösen eines Ereignisses, wenn es aufgerufen wird?
-
03-07-2019 - |
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
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 brauchen eine Art von Aspect orientierten Rahmen. Postsharp wird es tun, als href="http://castleproject.org/container" rel="noreferrer"> Windsor
Im Grunde sie Unterklasse Ihres Objekts und überschreibt diese Methode ... dann wird es: natürlich all dies zu dir verborgen. Alles, was Sie tun müssen, ist Windsor für den Typen fragen, und es wird für Sie das proxying tun. Das Attribut wird eine (benutzerdefinierte) Anlage I in Windsor denken. //proxy
public override void DoSomeStuff()
{
if(MethodHasTriggerAttribute)
Trigger();
_innerClass.DoSomeStuff();
}
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.
Ich glaube nicht, gibt es eine Möglichkeit, es mit nur einem Attribut zu tun, sondern mit
Ein Attribut Informationen gibt, sind sie Metadaten. Ich weiß nicht, von einem Weg, um diese ohne Weiteres zu tun, jemand könnte. Sie können bei Teil Methoden in .NET suchen die Ihnen erlauben, einige leichte Ereignisbehandlung zu tun. Sie die Haken bieten und lassen Sie jemand anderes die Umsetzung behandeln. Wenn die Methode der Compiler nicht implementiert ist einfach ignoriert es.
Sie können einen Blick auf die armen Mannes Lösung nehmen. Siehe Dekorateur Muster