Technique for centralized web service authentication, logging, etc.

R

rshekhtm

Hi everyone,

I would like to get your opinion on a technique I came up with when
faced with the problem of redundant code in every web method
(authentication, logging, exception handling). Normally, my web methods
would look something like this:

[WebMethod][SoapHeader("AuthHeader")]
public ReturnType GetSomeData(SomeType param1)
{
try
{
// Authentication

// Implementation
}
catch(Exception ex)
{
// Exception handling and logging
}
finally
{
// Request logging
}
}

[WebMethod][SoapHeader("AuthHeader")]
public ReturnTypeArray GetMoreData(Type1 param1, Type2 param2, Type3
param3)
{
try
{
// Authentication

// Implementation
}
catch(Exception ex)
{
// Exception handling and logging
}
finally
{
// Request logging
}
}

It gets rather tiresome to copy-paste all this non-implementation code,
never mind the fact that the DRY principle (Don't Repeat Yourself) is
violated. The only suggestions to avoid this that I have seen include
writing HTTP handlers or SOAP extensions. Yikes - very ugly, IMHO.

I have come up with a method that uses delegates coupled with a
centralized ExecuteRequest function that takes care of this
non-implementation functionality and works with any number of
parameters (FYI - in my case, web methods always return a value, but
I'm sure it wouldn't be too hard to make void methods work).

It reminds me of the Template Method pattern, except instead of
overridden methods, we have delegates to perform the work inside of a
method that provides the code template. Have a look:

private delegate ReturnType GetSomeDataImplDelegate(SomeType param1);
private delegate ReturnTypeArray GetMoreDataImplDelegate(Type1 param1,
Type2 param2, Type3 param3);
private MulticastDelegate _func;

[WebMethod][SoapHeader("AuthHeader")]
public ReturnType GetSomeData(SomeType param1)
{
_func = new GetSomeDataImplDelegate(GetSomeDataImpl);
return (ReturnType)ExecuteRequest(param1);
}

[WebMethod][SoapHeader("AuthHeader")]
public ReturnTypeArray GetMoreData(Type1 param1, Type2 param2, Type3
param3)
{
_func = new GetMoreDataImplDelegate(GetMoreDataImpl);
return (ReturnTypeArray)ExecuteRequest(param1, param2, param3);
}

private ReturnType GetSomeDataImpl(SomeType param1)
{
// Implementation
}

private ReturnTypeArray GetMoreDataImpl(Type1 param1, Type2 param2,
Type3 param3)
{
// Implementation
}

private object ExecuteRequest(params object[] parameters)
{
try
{
// Authentication

// Invoke the implementation function
return _func.DynamicInvoke(parameters);
}
catch(Exception ex)
{
// Exceptions thrown withing the implementation function are
// wrapped in TargetInvocationException. Unwrap before logging.
if (ex is System.Reflection.TargetInvocationException)
ex = ex.InnerException;

// Exception handling and logging
}
finally
{
// Request logging
}
}


What do you think? I don't believe I've seen this technique anywhere
else...
 

Ask a Question

Want to reply to this thread or ask your own question?

You'll need to choose a username for the site, which only take a couple of moments. After that, you can post your question and our members will help you out.

Ask a Question

Members online

No members online now.

Forum statistics

Threads
473,755
Messages
2,569,536
Members
45,007
Latest member
obedient dusk

Latest Threads

Top