【问题标题】:How do I create a WCF client using only App.config data?如何仅使用 App.config 数据创建 WCF 客户端?
【发布时间】:2014-10-31 04:07:30
【问题描述】:

我必须连接到不响应 svcutil 的 WCF 服务,并且不允许我使用 Visual Studio 中的自动化工具创建服务引用 - 编写/托管 WCF 服务的人非常安全有意识,并且禁用了这些功能(为什么,我不知道)。

我只得到了配置数据。

我的问题是:开发可以向该服务发送 WCF 请求的客户端的下一步是什么?

很抱歉这个开放式问题......我真的很难过,因为这不适合我在在线教程或 TechNet 文档中找到的任何场景。而且我是 WCF 的新手,所以我不知道从哪里开始。

返回类型是键/值对可访问的数据集,但我不确定 C# 数据类型是什么。我得到的文档说 KeyValueOfstringPropertyDto3azeXyb8 之类的。提到了 EntityDto,但我对此并不熟悉(EntityFramework 术语?)。我已获得返回数据集中的列列表,但出于安全原因,我无法直接在问题中发布列名。

服务名称和绑定:
名称 : RecordFindSingle
网址:http://Server01/RecordFindSingle/RecordFindSingle.svc
方法:FindSingleRecord
参数1:来源
参数2:记录编号

<configuration>
  <system.serviceModel>
    <bindings>
      <basicHttpBinding>
        <binding name="BasicHttpBinding_ITwoWayAsync" maxReceivedMessageSize="2147483647">
          <security mode="TransportCredentialOnly">
            <transport clientCredentialType="Windows" />
            <message clientCredentialType="Username" />
          </security>
        </binding>
       </basicHttpBinding>
    </bindings>
    <client>
      <endpoint address="http://Server02/RecordFindSingle/RecordFindSingle.svc"
          binding="basicHttpBinding" bindingConfiguration="BasicHttpBinding_ITwoWayAsync"
          contract="RecordFindSingle.RecordFindSingle" name="BasicHttpBinding_ITwoWayAsync" />
    </client>
  </system.serviceModel>
</configuration>

【问题讨论】:

  • “已禁用这些功能(为什么,我不知道)” - 您将这个问题的答案放在句子的第一部分:“编写/托管 WCF 服务的人是非常有安全意识”。乍一看,他们似乎禁用了 WSDL 的发布,这将阻止其他方通过简单地通过 URL 引用 WSDL 来创建代理。我会问他们是否可以为您提供 WSDL - 如果可以,您可以使用 add reference 或 svcutil 来生成代理。
  • @Tim 有道理。如果有安全隐患,他们不会为我改变任何政策——即使是暂时的。正如我所提到的,我找不到任何好的教程来展示如何仅使用此信息将客户端连接到服务。如果您愿意提供一个简短的代码示例作为答案,可以让我朝着正确的方向前进,我会接受这个答案。我整天都在阅读 HttpWebRequest ,但我仍然完全不知道它是如何发挥作用的...... :( Microsoft 文档失败。
  • 只有一个配置文件,如果可能的话,它可能会很棘手。让我炒一会,看看我的想法。
  • 你知道FindSingleRecord的参数和返回类型吗?
  • @brz 我刚刚编辑了我的问题以包含输入参数。返回类型是可通过键/值对访问的数据集,但我不确定 .NET 数据类型是什么。它说类似 KeyValueOfstringPropertyDto3azeXyb8。我已获得返回数据集中的列列表,但出于安全原因,我无法直接在问题中发布列名。

标签: c# wcf web-config app-config


【解决方案1】:

您必须创建一个接口和相关的DataContracts 来定义服务合同。例如,如果您有一个Contract,它定义了一个返回Record 实例的FindSingleRecord 方法:

[DataContract]
public class Record
{
    [DataMember]
    public string Property1 {get;set;}
    [DataMember]
    public string Property2 {get;set;}

    // Continue listing all properties ...
}

[ServiceContract]
public interface RecordFindSingle
{
    [OperationContract]
    Record FindSingleRecord(string Source , int RecordNo);
}

然后使用通道工厂调用它:

var httpBinding = new BasicHttpBinding()
{
    Security = new BasicHttpSecurity()
    {
        Mode = BasicHttpSecurityMode.TransportCredentialOnly,
        Message = new BasicHttpMessageSecurity() { ClientCredentialType = BasicHttpMessageCredentialType.UserName },
        Transport = new HttpTransportSecurity() { ClientCredentialType = HttpClientCredentialType.Windows }
    }
};
ChannelFactory<RecordFindSingle> factory = new ChannelFactory<RecordFindSingle>(httpBinding, new EndpointAddress("http://Server02/RecordFindSingle/RecordFindSingle.svc"));
var channel = factory.CreateChannel();
Record result = channel.FindSingleRecord();

【讨论】:

  • 这看起来不错。让我修改一下,看看我能不能让它工作。
  • 参数为Source(必填,字符串)和RecordNumber(必填,整数)。你能告诉我这将如何发挥作用吗?我可以将void FindSingleRecord(string Source, int RecordNumber) 放在 RecordFindSingle 界面中吗?
  • @Giffyguy 是的,返回类型也很重要。
  • 我试图对我得到的模糊文档做出正面或反面。文档建议返回类型是 1 个或多个 EntityDto 的集合。这是一个 EntityFramework 术语吗?这是否应该指向接口内方法的返回类型?
  • @Giffyguy DTO(Data Transfer Object) 是一个在进程之间承载数据的对象。您必须知道 DTO 具有哪些属性,并在客户端应用程序中创建一个表示该 DTO 的类。请参阅编辑后的答案。
【解决方案2】:

您可以使用 HttpWebRequest 在运行时调用 Web 服务。为此,您不必在解决方案或项目中添加任何服务引用。在我的一个应用程序中,我使用此功能从 MVC 4 Web API 项目调用 WCF Web 服务。

实际上,您可以直接将 SOAP 发送到 WCF 服务,而无需创建代理类。只需创建一个 WebClient 对象并设置“Content-Type”和“SOAPAction”标头,然后将 SOAP 消息上传到服务。代码如下:

using (var client = new WebClient())
{
    var data = CreateSoapsEnvelope();
    client.Headers.Add("Content-Type", "text/xml;charset=utf-8");
    client.Headers.Add("SOAPAction", "\"tempuri.org/IMyService/MyOperation\"");
    var response = client.UploadString("localhost:1234/MyService.svc", data);
    Console.WriteLine(response);
}

CreateSoapsEnvelope() 是创建 Soap Envelope 的函数,其中包含调用 Web 服务的输入参数

<s:Envelope xmlns:s="schemas.xmlsoap.org/soap/envelope/">;
    <s:Body> <OperationName xmlns="tempuri.org/">;
        <Inputparam1>Maged</Inputparam1> <Inputparam2>maged@mail.com</Inputparam2>
</OperationName> </s:Body> </s:Envelope>

【讨论】:

  • 谢谢 Piyush。如果您愿意提供一个代码示例来帮助您更容易理解,我将不胜感激。我整天都在阅读 HttpWebRequest ,但它对我来说仍然没有任何意义。 :(
  • 实际上您可以直接将 SOAP 发送到 WCF 服务,而无需创建代理类。只需创建一个 WebClient 对象并设置“Content-Type”和“SOAPAction”标头,然后将 SOAP 消息上传到服务。代码如下所示:- using (var client = new WebClient()) { var data = CreateSoapsEnvelope(); client.Headers.Add("Content-Type", "text/xml;charset=utf-8"); client.Headers.Add("SOAPAction", "\"tempuri.org/IMyService/MyOperation\""); var response = client.UploadString("localhost:1234/MyService.svc", data); Console.WriteLine(响应); }
  • 其中 CreateSoapsEnvelope() 是创建 Soap Envelope 的函数,就像它包含调用 web 服务的输入参数一样 schemas.xmlsoap.org/soap/envelope"> tempuri.org"> Magedmaged@mail.com
  • 这对你有用吗,还是帮你解决问题
  • 可能,我正在与我工作的其他一些开发人员一起工作。我会让你知道结果如何。
猜你喜欢
  • 2011-09-06
  • 2013-07-04
  • 1970-01-01
  • 1970-01-01
  • 2023-03-10
  • 2011-12-03
  • 1970-01-01
  • 2011-12-03
相关资源
最近更新 更多