2010-12-16 7 views
2

Der betreffende Code wird von Roboter (CodeSmith) geschrieben und es ist ein Schmerz zu pflegen. Es sieht ein wenig ähnlich:Wie kann ich allgemeine Funktionalität um Methodenaufrufe hinzufügen?

public AddressProgramTemplate GetById(System.Int32 _id) { 
    try { 
     return Service.GetById(_id); 
    } catch (FaultException<ErrorInfo> ex) { 
     throw new ProxyServerBusinessException(ex.Detail); 
    } catch (FaultException) { 
     throw new ProxyServerBusinessException(null); 
    } catch (EndpointNotFoundException ex) { 
     throw new ProxyServerTechnicalException<EndpointNotFoundException>(ex); 
    } catch (CommunicationObjectFaultedException ex) { 
     throw new ProxyServerTechnicalException<CommunicationObjectFaultedException>(ex); 
    } catch (CommunicationException ex) { 
     throw new ProxyServerTechnicalException<CommunicationException>(ex); 
    } catch (ObjectDisposedException ex) { 
     throw new ProxyServerTechnicalException<ObjectDisposedException>(ex); 
    } catch (TimeoutException ex) { 
     throw new ProxyServerTechnicalException<TimeoutException>(ex); 
    } 
} 

Wie Sie sich vorstellen können, es ist eine clientseitige WCF-Proxy-Code und alle diese Linien werden für jeden Service-Methode wiederholt gibt es (und es gibt viele). Was für Roboter gut ist, ist ein Kummer für mich, also habe ich angefangen, es zu refaktorisieren. Zunächst einmal wird die Ausnahmelogik und die Handhabung zu Microsoft Enterprise Library übertragen und gemeinsamen Code Basisklasse migriert:

public TResult WrapServiceMethod<TResult>(Func<TResult> serviceMethod) { 
    TResult result = default(TResult); 
    try { 
     result = serviceMethod(); 
    } catch (Exception ex) { 
     bool rethrow = ExceptionManager.HandleException(ex, ExceptionPolicyNames.ClientRequestPolicy); 
     if (rethrow) throw; 
    } 
    return result; 
} 

So weit so gut, das hässliche try/catch Stapel wird ein ordentlich Einzeiler:

return WrapServiceMethod<AddressProgramTemplate>(() => Service.GetById(_id)); 

Ein wenig Aufwand und leere Methoden abgedeckt. Das Problem kommt, wenn Service-Anrufe out Parameter verwenden:

public void GetPeriod(AddressProgram program, out DateTime startDate, out DateTime endDate){ 
    WrapServiceMethod(() => Service.GetPeriod(program, out startDate, out endDate)); 
} 

Ergebnisse in "nicht ref verwenden oder out-Parameter 'endDate' innerhalb einer anonymen Methode, Lambda-Ausdruck oder Abfrageausdruck" und ich verstehe why.

Was würde ich im Idealfall haben mag, ist eine Möglichkeit, benutzerdefinierte Operator Blöcke wie while() oder mit() zu definieren, so konnte ich

wrapexception { ... } 

schreiben und glücklich leben, aber ich don‘ Ich denke, dieser Trick ist mit .NET möglich. Angenommen, dass das Umschreiben aller Service-Methoden ohne Parameter out der letzte Ausweg ist, habe ich weitere Optionen?

Antwort

2

Klingt, als ob Sie nach einer aspektorientierten Programmierbibliothek wie PostSharp suchen.

Sie können Exception-Handler erstellen, die in Ihren IL nach der Kompilierung basierend auf Regeln eingeführt werden festgelegt, welche Dinge wie fangen Ausnahmen tun können, Protokollierung, Tracing usw.

Der Vorteil davon ist, man den Aspekt einmal schreiben , und wenden Sie es auf mehrere Methoden an. Diese Methoden sind nicht mit Code behaftet, der nichts mit der spezifischen Aufgabe zu tun hat, da die bereichsübergreifenden Belange wie die Ausnahmebehandlung von diesem Aspekt berücksichtigt werden.

Werfen Sie einen Blick auf das Beispiel http://www.sharpcrafters.com/solutions/monitoring#exception-monitoring, das zeigt, wie Ausnahmen behandelt werden.

+0

sieht vielversprechend aus - ein Roboter, Ändert die kompilierte Assembly anstelle des Quellcodes. Sollte in der Tat viel einfacher zu pflegen sein. Gibt es ernsthafte Leistungsnachteile? –

+0

Sollte darauf hinweisen, dass nicht alle AOP-Bibliotheken nach der Kompilierung sind. PostSharp ist, aber andere ändern die kompilierte Assembly nicht. Die Leistung sollte nicht beeinflusst werden, es sei denn, Sie schreiben einen zwielichtigen Aspekt. Wie immer, Profil und Vergleich sicher sein. Spring.NET verwendet Proxy-Objekte, um Methoden-Interzeptoren als ihren Weg zur Implementierung von AOP zu erstellen. –

+0

Ich werde wahrscheinlich mit PolicyInjection von Microsoft Enterprise Library gehen, nur weil es Microsoft (einfach zu verkaufen) und es ist bereits in unserem Projekt (noch einfacher zu verkaufen). –

1

Eine Alternative, die out Signaturen zu ändern (und damit alle Telefonvorwahl ändern zu müssen, die ich bin sicher, dass Sie vermeiden möchten) Sie so etwas tun könnte:

public void GetPeriod(AddressProgram program, out DateTime startDate, out DateTime endDate) 
{ 
    var outs = WrapServiceMethod(() => 
     { 
      DateTime sd; 
      DateTime ed; 
      Service.GetPeriod(program, out sd, out ed)); 
      return new {sd, ed}; 
     } 
    startDate = outs.sd; 
    endDate = outs.ed; 
} 
+1

Ausgezeichneter Tipp, vielen Dank!Machen Sie dies als schnelle Lösung, bis die volle AOP-Implementierung grünes Licht erhält. –