【问题标题】:What is the correct url for service reference?服务参考的正确 url 是什么?
【发布时间】:2013-07-03 14:31:54
【问题描述】:

我有两个项目,一个是WCF Service,就是在一个文本框中说出一个文本/句子。

public class Service1 : IService1
{
    public string RunTts(string text)
    {
        using (SpeechSynthesizer synth = new SpeechSynthesizer())
        {
            // Configure the audio output. 
            synth.SetOutputToDefaultAudioDevice();
            synth.Speak(text);
            return "";
        }
    }
}

然后我在第二个项目的_Layout.cshtml页面中用ajax调用,也就是asp.net mvc。

<script type="text/javascript">
    function ttsFunction() {
        serviceUrl = "Service1.svc/RunTts";

        $.ajax({
            type: "POST",
            url: serviceUrl,
            data: '{"text": "' + $('#speak').val() + '"}',
            contentType: "text/xml; charset=utf-8",
            dataType: "text/xml",
            error: function (xhr,status,error) {
                console.log("Status: " + status); // got "error"
                console.log("Error: " + error);   // got "Not Found"
                console.log("xhr: " + xhr.readyState); // got "4"
            },
            statusCode: {
                404: function() {
                    console.log("page not found"); // got 
                }
            }
        });
    }
</script>

因为我收到 404 错误,所以我认为 url 是错误的。请查看文件结构,我猜网络参考称为“ServiceReference1”。

【问题讨论】:

  • 你想建立一个会说话的服务器吗?一旦您在 IIS 中部署此服务,它就不会像我认为的那样做。
  • 不,我不想建立一个会说话的服务器。为什么我在 localhost 中失败了?
  • 我没有响应 WCF 部分,我不明白那里出了什么问题(尽管我猜你编了 URL Service1.svc/RunTts),它是 SOAP 绑定吗?但我的意思是您尝试从 WCF 服务合成语音。这可能适用于您的开发机器,但一旦您将其部署到 IIS,您和您网站的访问者都会听到任何声音。
  • 仅供参考,这是服务参考,不是网络参考。

标签: wcf jquery asp.net-mvc-4


【解决方案1】:

如您的屏幕截图所示,该服务未托管在您的 Web 应用程序中。您不能直接从客户端访问此类服务(托管在您的 Web 应用程序之外),因为您违反了same origin policy 限制。它是信任的基本概念之一,网络安全基于它(例如保护 aganist XSS) - 您不能发送跨域 AJAX 请求。这实质上是说,如果来自一个站点(例如https://bank.ny.com)的内容被授予访问系统上资源的权限,那么来自该站点的任何内容都将共享这些权限,而来自另一个站点(https://nsa.ny.com)的内容必须是分别授予权限(通常,术语origin使用域名、应用层协议和端口号来定义)。

不过,您至少有 4 个解决方案可以解决您的问题:

首先 - 通过中间控制器层与您的服务对话。采用这种方式意味着生成代理类(由 svcutil.exe,您通过使用 Visual Studio 添加服务引用来完成)。与该客户端的通信如下所示:

public class TtsController
{
    public JsonResult RunTts(string text)
    {                        
        using(var client = new ServiceReference1.Service1Client())
        {
            var response = client.RunTts(text);
            return Json(response);
...

JavaScript 端应该使用这样的 URL:var serviceUrl = "/Tts/RunTts"(以及传递给 AJAX 请求的正确 JSON 数据,我将进一步介绍)。

第二 - 直接与服务交谈。如果您想直接与该服务通信,则必须在您的 Web 应用程序中托管该服务。应遵循正确的 WCF 配置以支持 RESTful 服务:

<system.serviceModel>
  <behaviors>
    <endpointBehaviors>
      <behavior name="webby">
        <webHttp />
      </behavior>
    </endpointBehaviors>
    <serviceBehaviors>
      <behavior>
        <serviceMetadata httpGetEnabled="true" />
      </behavior>
    </serviceBehaviors>
  </behaviors>
  <services>
    <service name="Namespace.Service1">
      <endpoint address="" 
                behaviorConfiguration="webby"
                binding="webHttpBinding" 
                contract="Namespace.IService1" />
    </service>
  </services>  
</system.serviceModel>

对于 RESTful 端点,您应该使用的绑定是 WebHttpBinding 以及适当的行为。或者,有许多 RESTful 服务的免配置体验 - WebServiceHostFactory。您的 .svc 文件应如下所示 (MSDN):

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

WebServiceHostFactory 创建WebServiceHost 的实例,并且由于WebServiceHost 将使用WebHttpBinding 和相关行为自动配置端点,因此无需在网络中对此端点进行任何配置.config (当然,如果你需要自定义绑定,你必须使用配置)(MSDN)。

然后使用适当的完整 URL:http://localhost:[port]/Service1.svc/RunTts 或相对 URL:/Service1.svc/RunTts 访问服务。

由于您使用的是 ASP.NET MVC,因此根据您的路由定义,请求将分派到不存在此类操作的某个控制器。你必须告诉 MVC 忽略到你的服务的路由:

routes.IgnoreRoute("{resource}.svc/{*pathInfo}");

(顺便说一句:如果您将 .svc 文件放在应用程序中的不同目录下,请分别修改 URL 和路由以忽略。)

您的代码需要一些额外的修复:

  1. 如果要发送JSON格式的消息,请正确指定dataTypecontentType参数:

    $.ajax({
        url: serviceUrl,
        type: "POST",
        dataType: "json",
        contentType: "application/json; charset=utf-8",
        ...
    
  2. 不要手动构建 JSON 字符串,因为它会导致进一步的解析错误 - 使用转换器,例如:

    var data = new Object();
    data.text = $('#speak').val();
    var jsonString = JSON.stringify(data);
    
    $.ajax({
        ...
        data: jsonString,
        ...
    
  3. 为您的服务提供额外的声明性信息:

    [ServiceContract]
    public interface IService1
    {
        [OperationContract]
        [WebInvoke(Method = "POST", RequestFormat = WebMessageFormat.Json, ResponseFormat = WebMessageFormat.Json, BodyStyle = WebMessageBodyStyle.Wrapped)]        
        string RunTts(string text);
    ...
    
  4. 从项目中删除服务引用。你不需要它,因为这里没有使用中间控制器。

第三个 - JSONP(看herehere)可用于克服来源政策限制。但是您不能使用 JSONP 发布,因为它只是 doesn't work that way - 它创建了一个 &lt;script&gt; 元素来获取数据,这必须通过 GET 请求完成。 JSONP方案没有使用XmlHttpRequest对象,所以不是标准理解方式的AJAX请求,但内容仍然是动态访问的——对最终用户来说没有区别。

$.ajax({
    url: serviceUrl,
    dataType: "jsonp",
    contentType: "application/json; charset=utf-8",
    data: data,
    ...

[OperationContract]         
[WebGet(RequestFormat = WebMessageFormat.Json, ResponseFormat = WebMessageFormat.Json, BodyStyle = WebMessageBodyStyle.Wrapped, UriTemplate="RunTts?text={text}")]
public string RunTts(string text);

允许跨域请求的 RESTful WCF 配置:

<system.serviceModel>
  <bindings>
    <webHttpBinding>
      <binding name="jsonp" crossDomainScriptAccessEnabled="true" />
    </webHttpBinding>
  </bindings>
  <behaviors>
    <endpointBehaviors>
      <behavior name="webby">
        <webHttp />
      </behavior>
    </endpointBehaviors>
    <serviceBehaviors>
      <behavior>
        <serviceMetadata httpGetEnabled="true" />
      </behavior>
    </serviceBehaviors>
  </behaviors>
  <services>
    <service name="Namespace.Service1">
      <endpoint address="" 
                behaviorConfiguration="webby"
                binding="webHttpBinding" 
                bindingConfiguration="jsonp"
                contract="Namespace.IService1" />
    </service>
  </services>
</system.serviceModel>

第四 - CORS。在现代浏览器中实现 alternative 到带有 Padding 的 JSON。

【讨论】:

  • 还是错,全错。我是否应该将 basicHttpsBinding 更改为其他内容。我认为它应该会自动更改,因为我向服务添加了 REST 属性。
  • 您现在遇到什么错误? (顺便说一句,我编辑了答案以添加更多信息。)
  • 让我在我的问题中添加一些要点。请看。好的,我使用了第二种方法。我删除了服务引用并启动了服务项目。然后调试我的mvc项目实例,报错:NetworkError: 400 Bad Request - localhost:55433/Service1.svc/RunTts"。我在两个web.config中都没有找到endpoint。
  • 我认为这个问题可能与违反同源策略限制(en.wikipedia.org/wiki/Same_origin_policy)有关,因为您无法发送跨域 AJAX 请求。 JSONP(SO:stackoverflow.com/questions/2067472/what-is-jsonp-all-about,MSDN:msdn.microsoft.com/en-us/library/ee834511.aspx)可以用来克服这个问题。如果我是你,我现在会尝试完成它,因为我没有其他想法。
  • 服务是我自己创建的,就几行。我没有任何限制,实际上我根本不知道如何添加它们。
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 2010-11-29
  • 2010-12-17
  • 1970-01-01
  • 2017-07-12
  • 2018-03-31
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多