【问题标题】:How to produce XML output using WCF service?如何使用 WCF 服务生成 XML 输出?
【发布时间】:2012-11-12 14:33:05
【问题描述】:

我已经设置了如下界面。

[ServiceContract]
public interface IService1
{
  [OperationContract]
  String Ping();
}

它的实现如下。

public class Service1 : IService1
{
  public string Ping(){ return "Pong"; }
}

根据 VS 中的测试应用程序,它在调用时可以正常工作。我的问题是当我输入 http://localhost:12345/Service1.svc (或者可能是 Service1.svc?PingService.svc/Ping)。它是完全关闭还是我在正确的树上吠叫?

当然,“Pong”最终会是一个 XML 结构。

编辑

@carlosfigueira 在下面的回复中提供的设置为解决方案的建议提供了一个很好的结构,但不幸的是,在我的机器上使用 F5 运行时会出现错误消息。元数据似乎是必需的,端点也是如此。

【问题讨论】:

  • @Adriano 它甚至没有接近那个帖子。要么我看错了,要么你看错了我的。 :)
  • 您需要通过浏览器调用一个函数(可能使用 AJAX?!),对吧?好吧,它说明了如何使用,并为您提供了一个必须使用的 URI 示例(请阅读所有答案)。如果您的结果是 XML/JSON 或纯字符串,那真的没关系。如果您还需要其他内容,请纠正我!
  • 啊,我还没有 WCF 服务(还没有!),也没有设置任何 HTTP 绑定(或者我在不知不觉中?)所以我在 OP 之后放弃了。我的错,我应该多读一些。尽管如此,我仍然不确定我在做什么,@carlosfigueira 发布的内容让我现在想哭。我理解被否决的帖子显然这不是一个完全令人满意的解决方案。
  • carlos 的方法是正确的,您无法逃避以某种方式配置服务(它需要一个端点!)。唯一不需要这样做(不知何故)的情况是,如果您的方法不是独立的 Web 服务而是网站,并且 Ping() 只是从 JavaScript 调用的方法。

标签: c# wcf web-services


【解决方案1】:

我终于得到了完全的采购订单,并开始了全面的业务联系。这是我制作的——它可以在我的机器上运行,我希望这不是本地现象。 :)

IRestService.cs - 声明,即您的代码对联系客户的承诺

[ServiceContract]
public interface IRestService
{
  [OperationContract]
  [WebInvoke(Method = "GET", 
    ResponseFormat = WebMessageFormat.Xml, 
    BodyStyle = WebMessageBodyStyle.Wrapped, 
    UriTemplate = "xml/{id}")]
  String XmlData(String id);

  [OperationContract]
  [WebInvoke(Method = "GET", 
    ResponseFormat = WebMessageFormat.Json, 
    BodyStyle = WebMessageBodyStyle.Wrapped, 
    UriTemplate = "json/{id}")]
  String JsonData(String id);
}

RestService.svc.cs - 实现,您的代码对客户端的实际作用

public class RestService : IRestService
{
  public String XmlData(String id)
  {
    return "Requested XML of id " + id;
  }

  public String JsonData(String id)
  {
    return "Requested JSON of id " + id;
  }
}

Web.config - 配置,您的代码在到达客户端的过程中被处理的方式

<configuration>

  <system.web>
    <compilation debug="true" targetFramework="4.0" />
  </system.web>

  <system.serviceModel>
    <services>
      ...
    </services>
    <behaviors>
    </behaviors>
  </system.serviceModel>

</configuration>

services - 描述服务性质的标签内容

<service name="DemoRest.RestService" 
         behaviorConfiguration="ServiceBehavior">
  <endpoint address="" binding="webHttpBinding" 
            contract="DemoRest.IRestService" 
            behaviorConfiguration="web"></endpoint>
</service>

行为 - 描述服务和端点行为的标签内容

<serviceBehaviors>
  <behavior name="ServiceBehavior">
    <serviceMetadata httpGetEnabled="true"/>
    <serviceDebug includeExceptionDetailInFaults="true"/>
  </behavior>
</serviceBehaviors>

<endpointBehaviors>
  <behavior name="web">
    <webHttp/>
  </behavior>
</endpointBehaviors>

Index.html - 执行者,你的代码可以叫什么

<html>
  <head>
    <script>
      ...
    </script>
    <style>
      ...
    </style>
  </head>
  <body>
    ...
  </body>
</html>

script - 在 JavaScript 中描述可执行文件的标签内容

window.onload = function () {
  document.getElementById("xhr").onclick = function () {
    var xhr = new XMLHttpRequest();
    xhr.onload = function () { alert(xhr.responseText); }
    xhr.open("GET", "RestService.svc/xml/Viltersten");
    xhr.send();
  }
}

style - 描述外观的标签内容

.clickable
{
  text-decoration: underline;
  color: #0000ff;
}

body - 描述标记结构的标签内容

<ul>
  <li>XML output <a href="RestService.svc/xml/123">
    <span class="clickable">here</span></a></li>
  <li>JSON output <a href="RestService.svc/json/123">
    <span class="clickable">here</span></a></li>
  <li>XHR output <span id="xhr" class="clickable">here</span></li>

所有内容都存储在名为DemoRest 的项目中。我为服务的声明和实现创建了自己的文件,删除了默认文件。由于篇幅原因,using 的指令以及 XML 版本声明被省略。

现在可以使用以下 URL 检索响应。

localhost:12345/RestService.svc/xml/Konrad
localhost:12345/RestService.svc/json/Viltersten
  1. 还有其他人让它工作吗?
  2. 有什么改进或澄清的建议吗?

【讨论】:

  • 问题是关于 WCF 的;使用 HttpContext 在 WCF 中并非在所有情况下都有效(如果 AspNetCompatibilityMode 被禁用则无效;如果自托管则无效)
  • 嗯...从来没有遇到过这些问题(我猜是幸运的我)。那有什么办法呢?
  • 看我的回答。使用 Web 端点将返回 XML(或 JSON,考虑到 OP 的评论他想使用XMLHttpRequest,这似乎更合适)。
  • @carlosfigueira 我试过你的方法。它不适用于我的配置。我对元数据有些唠叨。并不是说你的建议是错误的——我总是愿意适应改进新的方法,但在这一点上(在我的机器上)我的解决方案有效,你的无效。有什么明显的我失踪了吗?当然,我会用谷歌搜索一段时间,但如果您有其他指示,请不要害羞。 :)
  • 关于元数据的错误是什么? For web endpoints there is no metadata,所以如果你想启用它,你不应该那样做。另外,我会用一个完整的例子来更新我的答案。
【解决方案2】:

如果您将服务端点定义为 WebHttp 端点(也称为 REST 端点),您将得到您想要的。最简单的方法是在 svc 文件中使用 WebServiceHostFactory

Service1.svc.

<%@ ServiceHost Language="C#" Debug="true" Service="YourNamespace.Service1"
                Factory="System.ServiceModel.Activation.WebServiceHostFactory" %>

或者您可以定义没有工厂的端点,通过定义它将使用webHttpBinding 并具有&lt;webHttp/&gt; 行为:

<system.serviceModel>
  <behaviors>
    <endpointBehaviors>
      <behavior name="MyBehavior">
        <webHttp/>
      </behavior>
    </endpointBehaviors>
  </behaviors>
  <services>
    <service name="YourNamespace.Service1">
      <endpoint address=""
                behaviorConfiguration="MyBehavior"
                binding="webHttpBinding"
                contract="YourNamespace.IService1" />
    </service>
  </services>
</system.serviceModel>

更新:由于有些人有问题,我写了一个完整的例子,使用XMLHttpRequest 与上面列出的服务对话。代码可以在https://github.com/carlosfigueira/WCFQuickSamples/tree/master/WCFForums/QuickWebCode1 找到(查找 StackOverflow_13345557),并且大部分都在此处列出。

服务代码(请注意,我使用 JSON 作为响应,但 XML 也可以):

namespace StackOverflow_13345557
{
    [ServiceContract]
    public interface IService1
    {
        [WebGet(ResponseFormat = WebMessageFormat.Json)]
        string Ping();
        [WebGet(ResponseFormat = WebMessageFormat.Json)]
        string PingWithParameters(int a, string b);
    }

    public class Service1 : IService1
    {
        public string Ping()
        {
            return "Hello";
        }

        public string PingWithParameters(int a, string b)
        {
            return string.Format("Hello {0} - {1}", a, b);
        }
    }
}

.SVC 文件 - 注意没有使用 Factory 属性,因为我通过配置定义端点:

<%@ ServiceHost Language="C#" Debug="true" Service="StackOverflow_13345557.Service1"
                CodeBehind="StackOverflow_13345557.svc.cs" %>

web.config

<system.serviceModel>
  <services>
    <service name="StackOverflow_13345557.Service1">
      <endpoint address=""
                behaviorConfiguration="WithWebHttp"
                binding="webHttpBinding"
                bindingConfiguration="WithJSONP"
                contract="StackOverflow_13345557.IService1" />
    </service>
  </services>
  <behaviors>
    <endpointBehaviors>
      <behavior name="WithWebHttp">
        <webHttp/>
      </behavior>
    </endpointBehaviors>
  </behaviors>
  <bindings>
    <webHttpBinding>
      <binding name="WithJSONP" crossDomainScriptAccessEnabled="true" />
    </webHttpBinding>
  </bindings>
</system.serviceModel>

HTML 页面访问服务(仅正文):

<body>
    <script type="text/javascript">
        function StackOverflow_13345557_Test(passParameters) {
            var baseUrl = "/StackOverflow_13345557.svc";
            var cacheBuster = new Date().getTime(); // to prevent cached response; development only
            var url;
            if (passParameters) {
                url = baseUrl + "/PingWithParameters?a=123&b=john+doe&_=" + cacheBuster;
            } else {
                url = baseUrl + "/Ping?_=" + cacheBuster;
            }
            var xhr = new XMLHttpRequest();
            xhr.onreadystatechange = function () {
                if (xhr.readyState == 4) {
                    document.getElementById("result").innerText = xhr.responseText;
                }
            }

            xhr.open('GET', url, true);
            xhr.send();
        }
    </script>
    <input type="button" value="StackOverflow 13345557 (no params)" onclick="StackOverflow_13345557_Test(false);" /><br />
    <input type="button" value="StackOverflow 13345557 (with params)" onclick="StackOverflow_13345557_Test(true);" /><br />
    <div id='result'></div>
</body>

另一个更新:在https://skydrive.live.com/redir?resid=99984BBBEC66D789!6355添加了一个独立的最小项目,上面列出了代码。

【讨论】:

  • 哦,这让菜鸟感到困惑...我将把 XML 暴露给在另一台服务器上运行的 JS 驱动的XmlHttpRequest。由于 CORS 问题,我可能还需要设置标题。实现这一目标的最简单方法是什么?
  • 如果您只是发出 GET 请求(似乎是这样,因为您想使用浏览器调用服务),您应该考虑使用 JSONP 而不是原始 XMLHttpRequest。 WCF 中的 CORS 并不是最容易完成的事情,而 JSONP 支持是内置的。举个例子,你可以看看codeproject.com/Articles/259832/…
  • 我相信我的困惑是由于我没有看到您的建议中的哪个位置(1)我正在调用的服务中的方法和(2)我'想通过。这可能是非常直接的事情,但对于以前从未这样做过的人来说,它看起来像魔法,像十一月的夜晚一样黑暗。
  • 他有错别字。我已经纠正了。这是您问题的部分,但可能还有更多,哈哈。
  • 我已经完全按照你说的做了(除了我将StackOverflow_13345557 更改为WcfService2)。其余的就像你展示的那样。我可以看到什么东西做了哪个部分,很清楚。唯一的问题是它不起作用。当我按 F5 时,我会看到一个进度条,当它达到大约 50% 时,我会收到以下错误消息。 “错误:无法从 localhost:52850/Service1.svc 获取元数据如果这是您有权访问的 Windows (R) Communication Foundation 服务,请检查您是否已启用元数据发布...”。该怎么办?我已将完整信息粘贴到您的回复中。
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多