14

RESTful WCF サーバーを作成する理由は多数あり (簡単です)、ASP とセキュリティ ボックスを回避できれば (情報を返すための単純な要求だけを行っている場合)、さらに優れています。これを行う方法については、http : //msdn.microsoft.com/en-us/library/ms750530.aspxを参照してください。

私が見つけたのは、AJAX (JQUERY) GET リクエストの処理が簡単だということです。しかし、POST で JSON を処理するのは注意が必要です。

以下は、単純な GET リクエスト コントラクトの例です。

    [OperationContract]
    [WebGet(ResponseFormat = WebMessageFormat.Json)]
    String Version();

そして実装はこちらです(JSONを返します)

    public partial class CatalogService : ICatalogService
{
    public String Version()
    {
        mon.IsActive = true;
        this.BypassCrossDomain();
        ViewModel.myself.TransactionCount++;
        return ViewModel.myself.VersionString;
    }
}

ああ、しかし、JSON を POST したい場合はどうでしょう。スタック オーバーフローに関する多くの記事が見つかります。これだけでよいことがわかります。

    [OperationContract]
    [WebInvoke(Method = "POST", RequestFormat = WebMessageFormat.Json, ResponseFormat = WebMessageFormat.Json)]
    BuildResponse BuildToby(BuildRequest request);

これは JSON メッセージを受け取り、Plain .NET オブジェクト (PONO) にデシリアライズして、それを操作できるようにします。実際、Fiddler でリクエストを作成したとき、これはうまくいきました。

POST /BuildToby HTTP/1.1
User-Agent: Fiddler
Content-Type: application/json
Host: localhost:4326
Content-Length: 1999

ただし、JQUERY 1.8 で次の AJAX を使用すると、驚くべきことがわかります。

「application/json」の content-type を指定することで、www-url で囲まれた投稿メッセージ以外のものを POST できるかどうかを確認するためにブラウザによって開始される「プリフライト」チェックがあることがわかります。(これについては、スタック オーバーフローに注意事項があります)。

    var request = JSON.stringify({ FrameList: ExportData.buildList });
    var jqxhr = $.ajax({
    type: "POST",
    url: "http://localhost:4326/BuildToby",
    data: request,
    contentType: "application/json; charset=utf-8",
    dataType: "json"
});

そして、フィドラーが報告するものは次のとおりです(これは POST メッセージではなく、OPTIONS メッセージであることに注意してください)。

OPTIONS http://localhost:4326/BuildToby HTTP/1.1
Host: localhost:4326
User-Agent: Mozilla/5.0 (Windows NT 6.1; WOW64; rv:19.0) Gecko/20100101 Firefox/19.0
Accept: text/html,application/xhtml+xml,application/xml;q=0.9,*/*;q=0.8
Accept-Language: en-US,en;q=0.5
Accept-Encoding: gzip, deflate
Origin: http://ysg4206
Access-Control-Request-Method: POST
Access-Control-Request-Headers: content-type
Connection: keep-alive
Pragma: no-cache
Cache-Control: no-cache

ブラウザ (この場合は Firefox) は、(このコンテンツ タイプの) POST が許可されているかどうかを確認するために、OPTIONS HTTP メッセージを使用してサーバーに追加の呼び出しを行う必要があります。

これを修正するためのすべての記事は、GLOBAL.ASAX の編集に関するもので、ASP.NET を使用している場合は問題ありませんが、セルフホスト WCF を使用している場合は役に立ちません。

これで質問が表示されました (長くなって申し訳ありませんが、他の人が結果を追跡できるように、これを完全な記事にしたかったのです)。

4

4 に答える 4

27

さて、解決策を書いた実際の MSDN の第一人者がいますが、私はそれらを理解できません: http://blogs.msdn.com/b/carlosfigueira/archive/2012/05/15/implementing-cors-support -in-wcf.aspx

しかし、私は簡単な解決策を思いつきました。少なくとも WCF 4.5 では、OPTIONS 要求を処理するために独自の OperationContract を追加できます。

    [OperationContract]
    [WebInvoke(Method = "OPTIONS", UriTemplate = "*")]
    void GetOptions();

メソッド シグネチャは無効であり、引数がないことに注意してください。これが最初に呼び出され、次に POST メッセージが呼び出されます。

GetOptions の実装は次のとおりです。

    public partial class CatalogService : ICatalogService
{
    public void GetOptions()
    {
        mon.IsActive = true;
        WebOperationContext.Current.OutgoingResponse.Headers.Add("Access-Control-Allow-Origin", "*");
        WebOperationContext.Current.OutgoingResponse.Headers.Add("Access-Control-Allow-Methods", "POST, GET, OPTIONS");
        WebOperationContext.Current.OutgoingResponse.Headers.Add("Access-Control-Allow-Headers", "Content-Type");
    }
}

そして、それは本当にあなたがしなければならないすべてです。

大きな JSON をシリアル化できるように、この属性をサービス クラスに追加することもできます。

//This defines the base behavior of the CatalogService. All other files are partial classes that extend the service
[ServiceBehavior(MaxItemsInObjectGraph = 2147483647)]       // Allows serialization of very large json structures
public partial class CatalogService : ICatalogService
{
    PgSqlMonitor mon = new PgSqlMonitor();

    private void BypassCrossDomain()
    {
        WebOperationContext.Current.OutgoingResponse.Headers.Add("Access-Control-Allow-Origin", "*");
    }
}

BypassCrossDomain() という小さなヘルパー メソッドがあり、これをすべての POST メソッドと GET メソッドで呼び出して、クロス ドメイン呼び出しを処理できることに注意してください。

私はここ (MSDN フォーラム、スタック オーバーフロー、ブログ) で多くの調査に時間を費やしました。

于 2013-03-12T18:56:25.603 に答える
3

Dr.YSG の回答にもう 1 つ追加します。個々の ID に POSTS を送信するエンドポイントで OPTIONS メソッドをサポートする必要がある場合は、複数の GetOptions メソッドを実装する必要があります。

    [WebInvoke(Method = "OPTIONS", UriTemplate = "")]
    void GetOptions();
    [WebInvoke(Method = "OPTIONS", UriTemplate = "{id}")]
    void GetOptions(string id);

WCF/Microsoft がエンドポイントの署名に基づいて適切な OPTIONS 応答を自動的に生成できないことは本当に残念ですが、少なくとも手動で処理することはできます。

于 2014-03-17T16:51:46.337 に答える
0

それについて何日も検索し、多くの投稿と提案された解決策を読んだ後、YSG博士によるこの質問は、angular/wcf/post/CORSなどの問題を理解して解決するための最良のリソースであると思います.

しかし、私にとって本当にうまくいったのはこれでした:

protected void Application_BeginRequest(object sender, EventArgs e)
{
    if (Request.HttpMethod == "OPTIONS")
    {
        Response.End();
    }
}

私はglobal.asaxを使用しており、考えられるシナリオが非常に多いため、完全な(または美しい)ソリューションではないことを理解していますが、最終的に他の誰かを助ける可能性があるため、この代替案を共有したいだけです.

(ヘッダーの追加に加えて)

于 2016-09-09T11:26:45.083 に答える
0

Dr.YSG が回答として挙げたものに加えて、リダイレクトが発生しているという Firefox の通知と、「405 メソッドは許可されていません」というエラーが表示されることがわかりました。追加する

WebOperationContext.Current.OutgoingResponse.Headers.Add("Access-Control-Allow-Origin", "*");
WebOperationContext.Current.OutgoingResponse.Headers.Add("Access-Control-Max-Age", "1728000");

GetOptions クラスに追加すると、問題が解決されたようです。

于 2013-11-05T18:05:54.137 に答える