In WCF, when we call the method on the server, we generally have two considerations: 1. Capture the exception information on the server and record the log; 2. Disable the session channel in time, if the call times out or fails, the session channel is interrupted in time. We usually process it like the following (using calculatorservice as an example ):
Using (Channelfactory <icalculatorservice> channelfactory = New Channelfactory <icalculatorservice> ( "Calculatorservice" ) {Icalculatorservice proxy = channelfactory. createchannel (); var commobj = proxy As Icommunicationobject; Try {Console. writeline ( "X + y = {2} when x = {0} and Y = {1 }" , 1, 2, proxy. Add (1, 2); commobj. Close ();} Catch (Communicationexception) {commobj. Abort ();} Catch (Timeoutexception) {commobj. Abort ();} Catch (Exception ){ // Todo: logs with exceptions Commobj. Abort (); Throw ;}}
The above processing method can fully meet our needs, but there is a problem, each time you call the server method, you need to manually add these exception captureCodeIf the service has many methods, there will inevitably be a lot of code with repeated functions, which is inefficient at reusability. We can refer to the idea of AOP, specifically to intercept server method calls. For. NET applications, custom realproxy is the easiest way to implement method call interception. The following is an example of a custom realproxy:
Public Class Calculatorservicerealproxy: realproxy { Public Calculatorservicerealproxy (): Base ( Typeof (Icalculatorservice )){} Public Override IMessage invoke (iMessage MSG) {imethodreturnmessage methodreturn = Null ; Imethodcallmessage methodcall = (imethodcallmessage) MSG; var client = New Channelfactory <icalculatorservice> ( "Calculatorservice" ); Var channel = client. createchannel ();Try { Object [] Copiedargs = array. createinstance ( Typeof ( Object ), Methodcall. args. length) As Object []; Methodcall. args. copyto (copiedargs, 0 ); Object Returnvalue = methodcall. methodbase. Invoke (Channel, copiedargs); methodreturn = New Returnmessage (returnvalue, copiedargs, copiedargs. length, methodcall. logicalcallcontext, methodcall ); // Todo: Write log } Catch (Exception ex) {var exception = ex; If (EX. innerexception! = Null ) Exception = ex. innerexception; methodreturn = New Returnmessage (exception, methodcall );} Finally {Var commobj = Channel As Icommunicationobject; If (Commobj! = Null ){ Try {Commobj. Close ();} Catch (Communicationexception) {commobj. Abort ();} Catch (Timeoutexception) {commobj. Abort ();} Catch (Exception) {commobj. Abort (); // Todo: logging exception Throw ;}}} Return Methodreturn ;}}
Method call:
static void main ( string [] ARGs) {icalculatorservice proxy = (icalculatorservice) New calculatorservicerealproxy (). gettransparentproxy (); console. writeline ( "x + y = {2} when x = {0} and Y = {1}" , 1, 2, proxy. add (1, 2); console. writeline ( "x-y = {2} when x = {0} and Y = {1}" , 1, 2, proxy. subtract (1, 2); console. writeline ( "x * Y = {2} when x = {0} and Y = {1}" , 1, 2, proxy. multiply (1, 2); console. writeline ( "x/y = {2} when x = {0} and Y = {1}" , 1, 2, proxy. divide (1, 2); console. readkey () ;}
The user-defined realproxy is used to create a transparentproxy for client code calls. For every call through transparentproxy, it is taken over by realproxy, in this way, we can add non-business logic Code such as exception capture and logging to realproxy, which will be called every time the server method is called.
Source code download (Project consolehosting is the server, project client3 is the client)