You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

C#中如何让ExecuteCommand内部创建通道并传递接口方法作为参数?

我的C#代码优化问题

注意:这很可能是一个特定于C#的语言问题,与WCF或web services完全无关。

我现在对接一个第三方的ASMX Web服务做数据检索,已经写了个通用方法ExecuteCommand()来处理所有针对这个服务的请求——它会负责Cookie会话管理、异常处理这些通用逻辑,而且每次请求都会用新通道,这样释放未使用资源更简单。

但现在有个小麻烦:用ExecuteCommand()的时候,必须先自己初始化通道,再把要执行的方法传进去,调用完通道就被释放了。给你们看个使用示例:

string color = "blue"; 
var channel = _strategyFactory.CreateChannel<CarServiceSoapChannel>(); 
var cars = WcfHelper.ExecuteCommand(channel, () => channel.GetCars(color)); 
// 这里channel已经是null了,根据异常类型会被关闭或终止

为了让大家更清楚问题,我把WcfHelper类的内部实现贴出来:

public static class WcfHelper { 
    public static Cookie Cookie { get; set; } 

    public static T ExecuteCommand<T>(IClientChannel channel, Expression<Func<T>> method) { 
        T result = default(T); 
        try { 
            // 初始化操作上下文
            using (new OperationContextScope(channel)) { 
                // 把会话Cookie设置到请求头
                if (Cookie != null) { 
                    HttpRequestMessageProperty request = new HttpRequestMessageProperty(); 
                    request.Headers["Cookie"] = cookie.ToString(); 
                    OperationContext.Current.OutgoingMessageProperties[HttpRequestMessageProperty.Name] = request; 
                } 
                // 执行方法
                var compiledMethod = method.Compile(); 
                result = compiledMethod.Invoke(); 
            } 
        } 
        // 针对FaultException、CommunicationException、TimeoutException做不同处理
        catch (Exception) { 
            throw; 
        } 
        finally { 
            CloseOrAbortServiceChannel(channel); 
            channel = null; 
        } 
        return result; 
    } 

    private static void CloseOrAbortServiceChannel(ICommunicationObject communicationObject) { 
        bool isClosed = false; 
        if (communicationObject == null || communicationObject.State == CommunicationState.Closed) 
            return; 
        try { 
            if (communicationObject.State != CommunicationState.Faulted) { 
                communicationObject.Close(); 
                isClosed = true; 
            } 
        } 
        catch (Exception) { 
            throw; 
        } 
        finally { 
            if (!isClosed) 
                AbortServiceChannel(communicationObject); 
        } 
    } 

    private static void AbortServiceChannel(ICommunicationObject communicationObject) { 
        try { 
            communicationObject.Abort(); 
        } 
        catch (Exception) { 
            throw; 
        } 
    } 
} 

我最关心的核心问题是:能不能把channel的初始化放到ExecuteCommand方法内部去做,同时还能指定要在这个通道上执行的方法?

我理想中的调用方式是这样的:

string color = "blue"; 
var cars = WcfHelper.ExecuteCommand<Car[], CarServiceSoapChannel>(channel => channel.GetCars(color)); 

甚至更简洁一点:

string color = "blue"; 
var cars = WcfHelper.ExecuteCommand<CarServiceSoapChannel>(channel => channel.GetCars(color)); 

当然如果有其他代码改进的建议也欢迎提,但不是必须的。

补充说明一下:这个ASMX服务是我在Visual Studio里通过添加Service reference引入的,所以自动生成了CarService相关的实体,比如CarServiceSoapChannel接口、CarServiceSoapClient类,还有包含Web服务方法的CarService接口。示例里我用ChannelFactory给CarServiceSoapChannel接口创建通道,这也是问题标题“Passing an interface method as a parameter”的由来,可能有点误导,但希望上面的描述能让大家明白我的需求。

2018.05.25更新:我已经采纳了@nvoigt的建议实现了目标,代码如下:

public static TResult ExecuteCommand<TInterface, TResult>(Func<TInterface, TResult> method) where TInterface : IClientChannel { 
    TResult result = default(TResult); 
    IClientChannel channel = null; 
    try { 
        channel = StrategyFactory.CreateChannel<TInterface>(); 
        // 初始化操作上下文
        using (new OperationContextScope(channel)) { 
            // 把会话Cookie设置到请求头
            if (Cookie != null) 
                Cookie.SetCookieForSession(); 
            // 执行方法
            result = method(

内容的提问来源于stack exchange,提问作者Alex

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.05.28 10:17:38