1

私は 2 つのプロジェクトを持っています。1 つは WCF サービスで、テキスト ボックス内のテキスト/文を読み上げます。

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

次に、2 番目のプロジェクト (asp.net mvc) の _Layout.cshtml ページで ajax を使用して呼び出します。

<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が間違っていると思います。ファイルの構造を見てください。Web 参照は「ServiceReference1」と呼ばれていると思います。 写真

4

1 に答える 1

5

スクリーンショットに示されているように、サービスは Web アプリケーションでホストされていません。このようなサービス (Web アプリケーションの外部でホストされている) にクライアント側から直接アクセスすることはできません。同じオリジン ポリシーの制限に違反しているためです。これは信頼の根底にある概念の 1 つであり、Web セキュリティが基づいています (例: protection aganist XSS )。クロスドメイン AJAX リクエストを送信することはできません。これは基本的に、あるサイト ( などhttps://bank.ny.com) のコンテンツにシステム上のリソースへのアクセス許可が付与されている場合、そのサイトのコンテンツはこれらの許可を共有し、別のサイト ( https://nsa.ny.com) のコンテンツには個別に許可を付与する必要があることを示しています (一般に、 、語源ドメイン名、アプリケーション層プロトコル、およびポート番号を使用して定義されます)。

それにもかかわらず、問題を解決するための解決策が少なくとも 4 つあります。

最初に、ミドル コントローラー レイヤーを介してサービスと対話します。このようにすることは、プロキシ クラスを生成することを意味します ( Visual Studio を使用してサービス参照を追加することによって行ったsvcutil.exeによって)。このクライアントとの通信は次のようになります。

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"(適切な JSON データを AJAX リクエストに渡します。これについては、もう少し詳しく説明します)。

2 番目- サービスに直接話しかけます。サービスと直接通信したい場合は、Web アプリケーションでこのサービスをホストする必要があります。RESTful サービスをサポートするには、正しい WCF 構成に従う必要があります。

<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_ 、構成を使用する必要があります) ( 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. プロジェクトからサービス参照を削除します。ここではミドルコントローラーを使用しないため、必要ありません。

3 番目- JSONP (こちらこちらを参照) を使用して、オリジン ポリシーの制限を克服できます。しかし、JSONP を使用して POST を実行することはできません。JSONPはそのようには機能しないためです。データを取得するための要素が作成<script>されますが、これは GET リクエストを介して行う必要があります。XmlHttpRequestJSONP ソリューションはオブジェクトを使用しないため、標準的な理解の方法では 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>

4番目- CORS。パディング付きの JSON に代わる最新のブラウザーに実装されています。

于 2013-07-05T15:46:17.333 に答える