为相当模糊的标题道歉,但我想要实现的目标可能在代码中更好地说明。
我有一个WCF客户端。当我调用方法时,我想将每个调用包装在一些错误处理代码中。因此,我没有直接公开方法,而是在客户端类上创建了以下辅助函数:
public T HandleServiceCall<T>(Func<IApplicationService, T> serviceMethod)
{
try
{
return serviceMethod(decorator);
}
[...]
}
客户端代码使用它如下:
service.HandleServiceCall(channel => channel.Ping("Hello"));
对Ping的调用很好地包含在一些试图处理任何错误的逻辑中。
这很好用,除了我现在需要知道在服务上实际调用哪些方法。最初,我希望只使用表达式树来检查Func<IApplicationService, T>
但是没有走得太远。
最后,我选择了装饰模式:
public T HandleServiceCall<T>(Func<IApplicationService, T> serviceMethod)
{
var decorator = new ServiceCallDecorator(client.ServiceChannel);
try
{
return serviceMethod(decorator);
}
[...]
finally
{
if (decorator.PingWasCalled)
{
Console.Writeline("I know that Ping was called")
}
}
}
装饰者本身:
private class ServiceCallDecorator : IApplicationService
{
private readonly IApplicationService service;
public ServiceCallDecorator(IApplicationService service)
{
this.service = service;
this.PingWasCalled = new Nullable<bool>();
}
public bool? PingWasCalled
{
get;
private set;
}
public ServiceResponse<bool> Ping(string message)
{
PingWasCalled = true;
return service.Ping(message);
}
}
它真的很笨重而且代码很多。 有更优雅的方式吗?
答案 0 :(得分:3)
您可以使用表情,然后检查身体。
像
这样的东西public T HandleServiceCall<T>(Expression<Func<IApplicationService, T>> serviceMethod)
{
try
{
var func = serviceMethod.Compile();
string body = serviceMethod.Body.ToString();
return func(new ConcreteAppService());
}
catch(Exception ex)
{
...
}
}
答案 1 :(得分:2)
您是否考虑过使用面向方法?听起来就像你需要的那样。
包装异常和其他“元方法”功能可以写成与您的serviceMethods所做的“正交”方面。
关于AOP的一些一般信息:AOP in wikipedia
带容器的潜在解决方案:AOP with Windsor Castle
答案 2 :(得分:1)
以下是使用表达式树的简单示例:
public T HandleServiceCall<T>(Expression<Func<T>> serviceMethod)
{
try
{
return serviceMethod();
}
finally
{
var serviceMethodInfo = ((MethodCallExpression)serviceMethod.Body).Method;
Console.WriteLine("The '{0}' service method was called", serviceMethodInfo.Name);
}
}
请注意,此示例假定serviceMethod
表达式始终包含方法调用。
相关资源:
答案 3 :(得分:0)
是的,我相信您的代码已经过时了。
在为常见的安全处理代理包装代码方面,请查看here以获得一个不错的实现。使用它很容易:
using (var client = new Proxy().Wrap()) {
client.BaseObject.SomeMethod();
}
现在您还需要访问方法名称 - 为此只需使用Environment.StackTrace
。你需要在Marc Gravell的Wrap
中添加堆栈。