aktualisieren
So Ihre Code- und Remo ausgezeichneten Punkt mit über die Aktionsmethoden benötigen in einem leeren Standardkonstruktor zu virtuellen und setzen (nur dynamische Proxy zu besänftigen, halten Ihren anderen Konstruktor noch) I haben sowohl den Aktionsfilter als auch den Interception-Ansatz.
Ich würde sagen, dass, wie es aussieht, Ihr Code potenziell unerwünschte Methoden auf dem ApiController abfangen wird, so dass Sie wahrscheinlich auch etwas Code an Ort und Stelle setzen müssen, um diese herauszufiltern, z. ExecuteAsync und Dispose.
Mein einziger anderer Punkt ist die Leistung. Enormer Disclaimer Dies sind nur sehr grundlegende Tests (mit dem Action Filter Ansatz jedes Mal, um die Statistiken zu protokollieren), ich lade Sie zu Ihrer eigenen (!) ... aber mit dem DynamicProxy Interceptor bekam ich eine Zeit von etwa 4 Millisekunden pro Erhaltungs-Anforderungs
[Execution of Get took 00:00:00.0046615.]
[Execution of Get took 00:00:00.0041988.]
[Execution of Get took 00:00:00.0039383.]
den Interception Code kommentierte und einen Aktionsfilter I Sub-Millisekunden-Leistung wurde immer:
[Execution of Get took 00:00:00.0001146.]
[Execution of Get took 00:00:00.0001116.]
[Execution of Get took 00:00:00.0001364.]
Es liegt an Ihnen, ob dies tatsächlich ein Problem oder ein Anliegen ist, aber ich Ich dachte, ich würde darauf hinweisen.
Zurück Antwort
Haben rulled Sie ActionFilters mit aus? Dies ist der natürliche Erweiterungspunkt für AOP bei einer MVC-Aktion.
Wenn Sie andere Methoden als die eigentliche Aktion auf dem Controller interessiert waren, dann würde ich verstehen, aber ich dachte, ich würde einen Vorschlag trotzdem posten.
Inspiriert von Are ActionFilterAttributes reused across threads? How does that work? und Measure Time Invoking ASP.NET MVC Controller Actions.
Aktualisiert, um den Ausschluss des Timers anzuzeigen, wenn die Methode markiert wurde. Inspiration aus Kern WebAPI Rahmen speziell AllowAnonymousAttribute und AuthorizeAttribute
Register global dies so, dass alle Aktionen, die von dieser überwacht werden:
GlobalConfiguration.Configuration.Filters.Add(new TimingActionFilter());
Dann:
public class TimingActionFilter : ActionFilterAttribute
{
private const string Key = "__action_duration__";
public override void OnActionExecuting(HttpActionContext actionContext)
{
if (SkipLogging(actionContext))
{
return;
}
var stopWatch = new Stopwatch();
actionContext.Request.Properties[Key] = stopWatch;
stopWatch.Start();
}
public override void OnActionExecuted(HttpActionExecutedContext actionExecutedContext)
{
if (!actionExecutedContext.Request.Properties.ContainsKey(Key))
{
return;
}
var stopWatch = actionExecutedContext.Request.Properties[Key] as Stopwatch;
if(stopWatch != null)
{
stopWatch.Stop();
var actionName = actionExecutedContext.ActionContext.ActionDescriptor.ActionName;
Debug.Print(string.Format("[Execution of {0} took {1}.]", actionName, stopWatch.Elapsed));
}
}
private static bool SkipLogging(HttpActionContext actionContext)
{
return actionContext.ActionDescriptor.GetCustomAttributes<NoLogAttribute>().Any() ||
actionContext.ControllerContext.ControllerDescriptor.GetCustomAttributes<NoLogAttribute>().Any();
}
}
Und
[AttributeUsage(AttributeTargets.Method | AttributeTargets.Class, Inherited = true)]
public class NoLogAttribute : Attribute
{
}
Jetzt Sie können den globalen Filter ausschließen mit:
public class ExampleController : ApiController
{
// GET api/example
[NoLog]
public Example Get()
{
//
}
}
Vielleicht ist dieser Vorschlag eine zu große Verschiebung im Design, aber wenn Sie alle Geschäftsvorgänge hinter einer generischen Abstraktion abstrahieren und diese in die Controller injizieren, könnten Sie diese Abstraktionen leicht schmücken oder abfangen, um übergreifende Bedenken hinzuzufügen wie dein Timing-Aspekt. Schauen Sie sich das [command/handler pattern] (http://www.cuttingedge.it/blogs/steven/pivot/entry.php?id=91) an, um eine Idee zu bekommen, wovon ich spreche. – Steven
Haben Sie einen zusätzlichen parameterlosen Konstruktor und sind alle Aktionsmethoden virtuell? –
Danke Remo, ich habe die Aktionsmethode virtuell hinzugefügt, aber für den parameterlosen Konstruktor habe ich ein Problem, weil unser Dienstobjekt dort injiziert und im Controller verwendet wird. Mit einem parameterlosen Konstruktor ist das Serviceobjekt null. Wie kommst du um dieses Problem herum? Danke vielmals! –