将接口方法作为参数传递

2024-04-10

Note: 这很可能是非常C#特定语言问题,与以下无关WCF or web services at all.

有3方ASMXWeb 服务,用于数据检索。我创建了一个名为的通用方法ExecuteCommand()用于针对 Web 服务的每个请求。该方法的目的是处理cookie会话/异常和其他常见逻辑。对于每个请求,应使用新的信道,以简化未使用资源的处理。

问题是要使用ExecuteCommand()方法 - 我必须每次初始化一个通道,以便能够传递要作为参数执行的方法。抱歉,如果听起来太复杂。这是一个用法示例:

string color = "blue";
var channel = _strategyFactory.CreateChannel<CarServiceSoapChannel>();
var cars = WcfHelper.ExecuteCommand(channel, () => channel.GetCars(color));
// channel is null here. Channel was closed/aborted, depending on Exception type.

After ExecuteCommand()叫做 -channel已经被处理掉了。之所以channel对象之所以需要,就是能够提供一个要执行的方法作为参数! IE。() => channel.GetCars()。为了进一步支持这些话,这里是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
        {
            // init operation context
            using (new OperationContextScope(channel))
            {
                // set the session cookie to header
                if (Cookie != null) {
                    HttpRequestMessageProperty request = new HttpRequestMessageProperty();
                    request.Headers["Cookie"] = cookie.ToString();
                    OperationContext.Current.OutgoingMessageProperties[HttpRequestMessageProperty.Name] = request;  
                }

                // execute method
                var compiledMethod = method.Compile();
                result = compiledMethod.Invoke();
            }
        }
        // do different logic for 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方法本身,同时可以定义在内部执行哪个方法ExecuteCommand对于给定的频道?

我正在尝试完成这样的事情:

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

or even

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

当然,任何其他代码改进建议都是受欢迎的,但不是强制性的。

P.S. ASMX添加为Service reference in Visual Studio。因此,有一些为“CarService”自动生成的实体,例如 -CarServiceSoapChannel界面,CarServiceSoapClient类,当然CarService包含 Web 服务方法的接口。在上面的例子中ChannelFactory用于创建一个通道CarServiceSoapChannel接口,因此,这里是问题名称的来源:Passing an interface method as a parameter。这可能有点误导,但我希望从描述本身可以清楚地看出我想要实现的目标。

更新2018年5月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>();

        // init operation context
        using (new OperationContextScope(channel))
        {
            // set the session cookie to header
            if (Cookie != null)
                Cookie.SetCookieForSession();

            // execute method
            result = method((TInterface)channel);
        }
    }
    catch (Exception)
    {
        throw;
    }
    finally
    {
        CloseOrAbortServiceChannel(channel);
        channel = null;
    }

    return result;
}

这已经达到了最初的目的。然而,这种方法有一个问题。为了调用该方法 - 您必须显式指定该方法的返回参数。

也就是说,如果你想调用该方法 - 写这样是不够的:

var result = WcfHelper.ExecuteCommand<CarServiceSoapChannel>(channel => channel.IsBlue())

您必须具体指定返回类型应为boolean

var result = WcfHelper.ExecuteCommand<CarServiceSoapChannel, bool>(channel => channel.IsBlue())

我个人不介意编写额外的代码,因为它仍然比我最初的方法实现有很大的优势,但是,我想知道在新版本中可以改进吗?

例如,当我只有 1 个泛型时TResult方法中的类型 - 返回类型<TResult>可以省略。有了 2 个泛型,情况就不再是这样了。无论如何,谢谢你@nvoigt!


您的方法签名应该是:

public static TResult ExecuteCommand<TInterface>(Func<TInterface, TResult> method)

然后在你的 WcfHelper 中(可能不应该是static不再因为它需要会员_strategyFactory)您像以前一样创建一个频道:

{
    var channel = _strategyFactory.CreateChannel<CarServiceSoapChannel>();

    return method(channel);
}

显然,您需要再次添加所有奇特的 try/finally 内容。


由于您现在应该拥有实例,并且类中的工厂作为成员,因此您可以将服务契约泛型放入您的类中,以方便用户使用:

public class ConnectionToService<TInterface> : where TInterface : class
{
    public TResult ExecuteCommand<TResult>(Func<TInterface, TResult> method)
    {
        var channel = _strategyFactory.CreateChannel<CarServiceSoapChannel>();

        return method(channel);
    }
}

Usage:

var service = new ConnectionToService<ICarService>();

var color = service.ExecuteCommand(s => s.GetColor());
本文内容由网友自发贡献,版权归原作者所有,本站不承担相应法律责任。如您发现有涉嫌抄袭侵权的内容,请联系:hwhale#tublm.com(使用前将#替换为@)

将接口方法作为参数传递 的相关文章

  • 没有强命名的代码签名是否会让您的应用程序容易被滥用?

    尝试了解authenticode代码签名和强命名 我是否正确地认为 如果我对引用一些 dll 非强命名 的 exe 进行代码签名 恶意用户就可以替换我的 DLL 并以看似由我签名但正在运行的方式分发应用程序他们的代码 假设这是真的 那么您似
  • 以文化中立的方式将字符串拆分为单词

    我提出了下面的方法 旨在将可变长度的文本拆分为单词数组 以进行进一步的全文索引处理 删除停止词 然后进行词干分析 结果似乎不错 但我想听听关于这种实现对于不同语言的文本的可靠性的意见 您会建议使用正则表达式来代替吗 请注意 我选择不使用 S
  • 为什么两个不同的 Base64 字符串的转换会返回相等的字节数组?

    我想知道为什么从 base64 字符串转换会为不同的字符串返回相同的字节数组 const string s1 dg const string s2 dq byte a1 Convert FromBase64String s1 byte a2
  • 在结构中使用 typedef 枚举并避免类型混合警告

    我正在使用 C99 我的编译器是 IAR Embedded workbench 但我认为这个问题对于其他一些编译器也有效 我有一个 typedef 枚举 其中包含一些项目 并且我向该新类型的结构添加了一个元素 typedef enum fo
  • ASP.NET MVC:这个业务逻辑应该放在哪里?

    我正在开发我的第一个真正的 MVC 应用程序 并尝试遵循一般的 OOP 最佳实践 我正在将控制器中的一些简单业务逻辑重构到我的域模型中 我最近一直在阅读一些内容 很明显我应该将逻辑放在域模型实体类中的某个位置 以避免出现 贫血域模型 反模式
  • 使用实体框架模型输入安全密钥

    这是我今天的完美想法 Entity Framework 中的强类型 ID 动机 比较 ModelTypeA ID 和 ModelTypeB ID 总是 至少几乎 错误 为什么编译时不处理它 如果您使用每个请求示例 DbContext 那么很
  • 从Web API同步调用外部api

    我需要从我的 Web API 2 控制器调用外部 api 类似于此处的要求 使用 HttpClient 从 Web API 操作调用外部 HTTP 服务 https stackoverflow com questions 13222998
  • Clang 3.1 + libc++ 编译错误

    我已经构建并安装了 在前缀下 alt LLVM Clang trunk 2012 年 4 月 23 日 在 Ubuntu 12 04 上成功使用 GCC 4 6 然后使用此 Clang 构建的 libc 当我想使用它时我必须同时提供 lc
  • 不同枚举类型的范围和可转换性

    在什么条件下可以从一种枚举类型转换为另一种枚举类型 让我们考虑以下代码 include
  • C# 中通过 Process.Kill() 终止的进程的退出代码

    如果在我的 C 应用程序中 我正在创建一个可以正常终止或开始行为异常的子进程 在这种情况下 我通过调用 Process Kill 来终止它 但是 我想知道该进程是否已退出通常情况下 我知道我可以获得终止进程的错误代码 但是正常的退出代码是什
  • C#中如何移动PictureBox?

    我已经使用此代码来移动图片框pictureBox MouseMove event pictureBox Location new System Drawing Point e Location 但是当我尝试执行时 图片框闪烁并且无法识别确切
  • 如何设计以 char* 指针作为类成员变量的类?

    首先我想介绍一下我的情况 我写了一些类 将 char 指针作为私有类成员 而且这个项目有 GUI 所以当单击按钮时 某些函数可能会执行多次 这些类是设计的单班在项目中 但是其中的某些函数可以执行多次 然后我发现我的项目存在内存泄漏 所以我想
  • 如何序列化/反序列化自定义数据集

    我有一个 winforms 应用程序 它使用强类型的自定义数据集来保存数据进行处理 它由数据库中的数据填充 我有一个用户控件 它接受任何自定义数据集并在数据网格中显示内容 这用于测试和调试 为了使控件可重用 我将自定义数据集视为普通的 Sy
  • 什么时候虚拟继承是一个好的设计? [复制]

    这个问题在这里已经有答案了 EDIT3 请务必在回答之前清楚地了解我要问的内容 有 EDIT2 和很多评论 有 或曾经 有很多答案清楚地表明了对问题的误解 我知道这也是我的错 对此感到抱歉 嗨 我查看了有关虚拟继承的问题 class B p
  • 链接器错误:已定义

    我尝试在 Microsoft Visual Studio 2012 中编译我的 Visual C 项目 使用 MFC 但出现以下错误 error LNK2005 void cdecl operator new unsigned int 2
  • 如何从两个不同的项目中获取文件夹的相对路径

    我有两个项目和一个共享库 用于从此文件夹加载图像 C MainProject Project1 Images 项目1的文件夹 C MainProject Project1 Files Bin x86 Debug 其中有project1 ex
  • C# 成员变量继承

    我对 C 有点陌生 但我在编程方面有相当广泛的背景 我想做的事情 为游戏定义不同的 MapTiles 我已经像这样定义了 MapTile 基类 public class MapTile public Texture2D texture pu
  • C# 模拟VolumeMute按下

    我得到以下代码来模拟音量静音按键 DllImport coredll dll SetLastError true static extern void keybd event byte bVk byte bScan int dwFlags
  • C++ 标准是否指定了编译器的 STL 实现细节?

    在写答案时this https stackoverflow com questions 30909296 can you put a pimpl class inside a vector我遇到了一个有趣的情况 这个问题演示了这样一种情况
  • 对来自流读取器的过滤数据执行小计

    编辑问题未得到解答 我有一个基于 1 个标准的过滤输出 前 3 个数字是 110 210 或 310 给出 3 个不同的组 从流阅读器控制台 问题已编辑 因为第一个答案是我给出的具体示例的字面解决方案 我使用的实际字符串长度为 450 个

随机推荐

  • 中缀表示法的有趣行为

    有时 有人试图躲在电脑屏幕后面 试图摆脱女朋友 然而 我发现Scala有时和我的女孩一模一样 这将打印两个列表之间的交集 val boys List Person John Person Kim Person Joe Person Piet
  • MVVM - 分离视图之间的通信

    我试图弄清楚如何执行以下操作 我有一个CustomerListViewModel其中包含一个ObservableCollection
  • 在 Swift 中使用 Tab 键选择下一个 NSTextField

    在 Swift 中 有没有办法通过按键盘上的 Tab 来更改响应者或选择另一个文本字段 笔记 这是填空式申请 我的 VC 创建了一个单词列表 Word 每个单词都有自己的 WordView word wordView WordView 就是
  • Maven 3.5.2 无法将工件部署到 Artifactory,并出现错误 417

    我正在创建简单的pom项目如下
  • 在故事板中使用 UIPageViewController

    有没有一种方法可以在故事板中为 UIPageViewController 配置数据源 委托和视图控制器而无需编写代码 我确实在 UIPageViewController 中看到了数据源和委托的出口 但无法在场景之间建立连接 也无法将额外的控
  • Laravel 5.2:未找到 Imagick 类

    我们正在将 PDF 页面转换为多个单个图像 我们在stackoverflow中找到了一段代码片段 并将其转换为服务类 我们安装了 Imagick 它也显示在 phpinfo 中 然而 在我们的 Laravel 应用程序版本 5 2 中 我们
  • 如何设置 intel_idle.max_cstate=0 来禁用 c 状态?

    我想在我的计算机上禁用 c 状态 我在 BIOS 上禁用了 c state 但没有获得任何结果 不过 我找到了一个解释 大多数较新的 Linux 发行版 在配备 Intel 处理器的系统上 使用 intel idle 驱动程序 可能编译到内
  • 如何从Python列表中的前一个值中减去该值?

    我正在尝试获取列表中的值 例如 1 2 3 并将它们彼此相减 所以它会返回 1 1 因为第一个值是1 2第二个值是2 3 我如何在 python 中实现这一点 我努力了 x y for x y in list 但这会出现 需要多个值才能解包
  • 带有数组赋值的 JavaScript 意外控制台输出;

    在 webkit 浏览器 Chrome 16 0 912 77 和 Safari 5 1 2 7534 52 7 中进行数组分配后 我收到意外的控制台输出 这是我的函数 它演示了该错误 function test var myArray c
  • 即使用户不接受照片,相机意图 onActivityResult 代码也会保存(空白)图像

    当用户单击叉号不接受照片时 它会以与接受拍摄的照片时相同的方式结束意图 它将文件保存到设备库 但它是空白的 单击叉号不应该意味着 resultCode RESULT OK 吗 我还缺少一张支票吗 谢谢 这是代码 等等 我正在保存活动结果之前
  • 如何从 zip 中打开 html 文件?

    有什么方法可以从包含 html 引用的图像的 zip 文件中打开 html 文件吗 我生成带有资源相对路径的 html 但浏览器不会在 zip 文件中找到它们 我必须先将其提取 从拉链打开它是理想的选择 有什么办法可以做到吗 据我所知 只有
  • 创建 Angular/React 应用程序时的 .Net 本地主机服务器

    我正在使用 VS2017 2019 和 NET Core 2 1 来创建Angular or React应用程序 Angular CLI or create react app用于设置一切 以下所有内容都与开发阶段有关 当我们构建 NET
  • 针对数字板难题的优化 CLP(FD) 求解器

    考虑问题从https puzzling stackexchange com questions 20238 explore the square with 100 hops https puzzling stackexchange com
  • let* 和 set 之间的区别?在 Common Lisp 中

    我正在从事一个基因编程爱好项目 我有一个函数 宏设置 当以 setq setf 形式评估时 将生成一个如下所示的列表 setq trees make trees 2 gt x abs x 然后它将绑定到 lambda 函数
  • 如何使用 Swift 在 stderr 上打印?

    我在 Linux 上使用 Swift 2 2 需要在标准错误流上编写一些调试输出 目前 我正在执行以下操作 import Foundation public struct StderrOutputStream OutputStreamTyp
  • 在没有窗口的windows桌面上绘制OpenGL

    我见过这样的事情 我想知道这是否可能 假设我运行我的应用程序 它会显示其下方的渲染结果 所以基本上 在没有窗口的情况下在屏幕上渲染 可能还是谎言 注意 想要在 Windows 和 C 中执行此操作 可以使用您的应用程序在其他应用程序的窗口上
  • Perl 函数中的引用返回值是否更好?

    与返回数组或哈希的引用相比 返回数组或哈希有哪些优缺点 对内存或执行时间有影响吗 两者在功能上有何区别 sub i return an array my a push things in a return a sub i return a
  • cudaMemcpyToSymbol 与 cudaMemcpy [关闭]

    这个问题不太可能对任何未来的访客有帮助 它只与一个较小的地理区域 一个特定的时间点或一个非常狭窄的情况相关 通常不适用于全世界的互联网受众 为了帮助使这个问题更广泛地适用 访问帮助中心 help reopen questions 我试图找出
  • 我应该如何格式化 R mlogit 包的数据?

    我正在使用mlogit与 R 一起打包 使用以下方式导入我的数据后 t lt read csv junk csv header TRUE sep dec 并致电 x lt mlogit data t choice D shape long
  • 将接口方法作为参数传递

    Note 这很可能是非常C 特定语言问题 与以下无关WCF or web services at all 有3方ASMXWeb 服务 用于数据检索 我创建了一个名为的通用方法ExecuteCommand 用于针对 Web 服务的每个请求 该