享受无止境 - 改进版WCF Client

在之前的文章“让WCF客户端的“调用”成为一种‘享受’”中,分别用Func与Action实现了WCF客户端调用接口。

Func实现的调用方式:

WcfClient.UseService((IUserService userService) => (userService.GetUser(userId)));

缺点:

1. 需要用匿名方法传递参数,写起来比较麻烦。

2. 不支持无返回值的ServiceContract。

Action实现的调用方式:

List<ZzkDocument> docs = null;
WcfClient.UseService<IZzkDocumentService>(
s =>
{
docs = s.GetZzkDocuments("0", 30).ToList();
});

缺点:

虽然支持了无返回值的ServiceContract,但需要在Lambda表达式中获取返回值。这样还造成了无法使用类型判断,也就是不能使用var docs。

用Action“享受”了很多次的过程中,总是有那么一点点“不爽”萦绕在心头,挥之不去。。。

 

2011即将过去,2012即将到来,在这辞旧换新之际,也把那一点点“不爽”辞去吧。

今天下午,借助.NET世界中一个强大的武器完成了这个小小的心愿,它就是表达式树 —— Expression<Func<TService, TReturn>> operation

先一睹调用改进版WCF Client的风采:

var client = new WcfClient<IZzkDocumentService>();
var docs = client.UseService(s => s.GetZzkDocuments("0", 10));

然后看看WcfClient的实现代码:

public class WcfClient<TService> where TService : class
{
public TReturn UseService<TReturn>(Expression<Func<TService, TReturn>> operation)
{
var channelFactory = new ChannelFactory<TService>("*");
TService channel = channelFactory.CreateChannel();
var client = (IClientChannel)channel;
client.Open();
TReturn result = operation.Compile().Invoke(channel);
try
{
if (client.State != CommunicationState.Faulted)
{
client.Close();
}
}
catch
{
client.Abort();
}
return result;
}
}

对于Expression<Func<TService, TReturn>> operation,我的理解是:请你告诉我,如果给你一段代码(TService),你如何给我一个改变了的世界(TReturn)。我不关心给你的是什么代码,也不关心改变后的世界是什么样子,我只关心你如何改变世界。

 

享受无止境,但真正让人成长与快乐的不是得到那个享受,而是这个追求享受的过程。现实世界如此,代码世界也是如此。

祝大家2012年在代码世界享受更多快乐!

 

参考文章:

Explaining Expression

标签: WCF
posted @ 2011-12-31 16:46 dudu 阅读(2123) 评论(18) 编辑 收藏

 回复 引用 查看   
#1楼 2011-12-31 16:52 今昭      
happy new year~
 回复 引用 查看   
#2楼 2011-12-31 16:53 Fibo      
要放假了,dudu还这么忙,顶个!
 回复 引用 查看   
#3楼 2011-12-31 16:58 Steven Chen      


额 即使是示例代码,也不应该有这样的错误啊~

 回复 引用 查看   
#4楼 2011-12-31 17:00 Jianqiang Bao      
老大新年快乐
 回复 引用 查看   
#5楼[楼主] 2011-12-31 17:03 dudu      
@Steven Chen
这是下面的代码的精简版:
try
{
    ...
    client.Close();
}
catch (CommunicationException e)
{
    ...
    client.Abort();
}
catch (TimeoutException e)
{
    ...
    client.Abort();
}
catch (Exception e)
{
    ...
    client.Abort();
    throw;
}

 回复 引用 查看   
#6楼 2011-12-31 17:05 Steven Chen      
牛!
 回复 引用 查看   
#7楼 2011-12-31 17:37 dreamhappy      
为什么说wcf是支持xml的,服务端实现一个方法返回字符串,客户端调用服务的方法也是返回字符串,怎么解释这个呢
 回复 引用 查看   
#8楼 2011-12-31 17:40 南京.王清培      
学习了。嘟嘟新年好。呵呵
 回复 引用 查看   
#9楼 2011-12-31 18:42 artwl      
console.log("Happy new year");
 回复 引用 查看   
#10楼 2011-12-31 19:23 Artech      
ChannelFactory<TChannel>最好进行缓存!
 回复 引用 查看   
#11楼 2011-12-31 20:41 斯克迪亚      
老大,博问登不上账户了,怎么回事?反复登录都显示未登录。~~昨天还好好的呢
 回复 引用 查看   
#12楼[楼主] 2011-12-31 22:21 dudu      
@斯克迪亚
现在好了

 回复 引用 查看   
#13楼 2012-01-02 00:13 magic_evan      
这种方式还是未支持ref或者out的参数哦....
 回复 引用 查看   
#14楼 2012-01-04 08:36 LiangHu      
和我的好像哦~~来一个我的:
 /// <summary>
    /// 抽象安全客户端基类
    /// </summary>
    /// <typeparam name="I"></typeparam>
    public abstract class AbstractSecurityClientBase<I>:ClientBase<I>
        where I:class
    {
        /// <summary>
        /// 构造函数
        /// </summary>
        /// <param name="endpointConfigurationName">服务配置</param>
        public AbstractSecurityClientBase(string endpointConfigurationName)
            :base(endpointConfigurationName)
        {
            this.ClientCredentials.UserName.UserName = Global.UserName;
            this.ClientCredentials.UserName.Password = Global.PassWord;

            //启用服务发现
            if (Global.DiscoveryService)
            {

            }
        }

        /// <summary>
        /// 安全调用
        /// </summary>
        /// <param name="func">Func</param>
        /// <returns>服务结果</returns>
        public ServiceResult SafeInvoke(Func<I,ServiceResult> func)
        {
            ServiceResult result = new ServiceResult();
            I proxy = this.ChannelFactory.CreateChannel();
            try
            {
                result = func(proxy);
            }
            catch (TimeoutException)
            {
                result.Successed = false;
                result.Error = ErrorCode.TimeOut;
            }
            catch (MessageSecurityException)
            {
                result.Successed = false;
                result.Error = ErrorCode.SecurityException;
            }
            catch (SecurityAccessDeniedException)
            {
                result.Successed = false;
                result.Error = ErrorCode.AccessDenied;
            }
            catch (CommunicationException)
            {
                result.Successed = false;
                result.Error = ErrorCode.CommunicationException;
            }
            finally
            {
                SafeClose(proxy);
            }
            return result;
        }
        
        /// <summary>
        /// 安全调用
        /// </summary>
        /// <typeparam name="M">ServiceResult泛型结果类型</typeparam>
        /// <param name="func">Func</param>
        /// <returns>包含泛型类型结果的服务结果</returns>
        public ServiceResult<M> SafeInvoke<M>(Func<I, ServiceResult<M>> func)
        {
            ServiceResult<M> result = new ServiceResult<M>();
            I proxy = this.ChannelFactory.CreateChannel();
            try
            {
                result = func(proxy);
            }
            catch (TimeoutException)
            {
                result.Successed = false;
                result.Error = ErrorCode.TimeOut;
            }
            catch (MessageSecurityException)
            {
                result.Successed = false;
                result.Error = ErrorCode.SecurityException;
            }
            catch (SecurityAccessDeniedException)
            {
                result.Successed = false;
                result.Error = ErrorCode.AccessDenied;
            }
            catch (CommunicationException)
            {
                result.Successed = false;
                result.Error = ErrorCode.CommunicationException;
            }
            finally
            {
                SafeClose(proxy);
            }
            return result;
        }

        /// <summary>
        /// 安全关闭
        /// </summary>
        void SafeClose(I proxy)
        {
            ICommunicationObject comm = proxy as ICommunicationObject;
            if (comm != null)
            {
                try
                {
                    if (comm.State != CommunicationState.Faulted)
                        comm.Close();
                    else
                        comm.Abort();
                }
                catch (Exception)
                {
                    comm.Abort();
                }
            }
        }
    }

 回复 引用 查看   
#15楼 2012-01-07 10:23 darjuan      
拜读....
 回复 引用 查看   
#16楼 2012-02-09 23:02 永远的阿哲      
本人愚钝,除了用了表达式树的新技术,没看出来解决了什么问题.
旧的Action版本还是要的吧,新的Expression版本应该是来代替旧的Func版本的.但是
1.新的Expression版本还是不能使用无返回值的ServiceContract呀,
2.至于写的麻烦,我看只不过是把匿名函数的参数类型从匿名函数内移到了外面去了,没什么区别啊.
望指教!

 回复 引用 查看   
#17楼[楼主] 2012-02-11 21:30 dudu      
@永远的阿哲
1.是的,无返回值的ServiceContract还是要用Action版本;
2.是没什么区别,只是代码写起来舒服些。

 回复 引用 查看   
#18楼 2012-02-19 17:23 饭饭-1      
如果返回类型是Void方法怎么用!?本人愚钝不知道