質問をすることでしか得られない、回答やアドバイスがある。

15分調べてもわからないことは、質問しよう!

新規登録して質問してみよう
ただいま回答率
85.48%
HTTP

HTTP(Hypertext Transfer Protocol)とはweb上でHTML等のコンテンツを交換するために使われるアプリケーション層の通信プロトコルです。

POST

POSTはHTTPプロトコルのリクエストメソッドです。ファイルをアップロードしたときや入力フォームが送信されたときなど、クライアントがデータをサーバに送る際に利用されます。

Windows Forms

Windows Forms(WinForms)はMicrosoft .NET フレームワークに含まれる視覚的なアプリケーションのプログラミングインターフェイス(API)です。WinFormsは管理されているコードの既存のWindowsのAPIをラップすることで元のMicrosoft Windowsのインターフェイスのエレメントにアクセスすることができます。

ASP.NET Web API

ASP.NET Web APIはブラウザやモバイル機器のようなクライアント向けのHTTPサービスを構築するフレームワークです。Microsoft .NET Frameworkがベースになっており、RESTfulサービスを構築するには理想的です。

Q&A

解決済

2回答

18011閲覧

ASP.NET WebApi を HttpClient の PostAsyncメソッドで呼び出し

skippanther

総合スコア13

HTTP

HTTP(Hypertext Transfer Protocol)とはweb上でHTML等のコンテンツを交換するために使われるアプリケーション層の通信プロトコルです。

POST

POSTはHTTPプロトコルのリクエストメソッドです。ファイルをアップロードしたときや入力フォームが送信されたときなど、クライアントがデータをサーバに送る際に利用されます。

Windows Forms

Windows Forms(WinForms)はMicrosoft .NET フレームワークに含まれる視覚的なアプリケーションのプログラミングインターフェイス(API)です。WinFormsは管理されているコードの既存のWindowsのAPIをラップすることで元のMicrosoft Windowsのインターフェイスのエレメントにアクセスすることができます。

ASP.NET Web API

ASP.NET Web APIはブラウザやモバイル機器のようなクライアント向けのHTTPサービスを構築するフレームワークです。Microsoft .NET Frameworkがベースになっており、RESTfulサービスを構築するには理想的です。

0グッド

1クリップ

投稿2015/10/10 13:50

編集2015/10/14 10:30

ASP.NET WebApiのPost処理(C#)を、Windowsフォームアプリ(C#)から、HttpClient の PostAsyncメソッドを使って呼ぼうとしているのですが、どうもうまくいきません。
###発生している問題・エラーメッセージ
以下が返されて、対象のPostメソッドは呼ばれません。
The requested resource does not support http method 'GET'.

###ソースコード
まず、WebApiの記述です。

C#

1 [RoutePrefix("api/GateApi")] 2 public class GateApiController : ApiController 3 { 4 // パラメータ用のクラス定義 5 public class para 6 { 7 public int GateNo { get; set; } 8 } 9 10 // Post処理 11 [Route("TestPost")] 12 [HttpPost] 13 public string TestPost(para data) 14 { 15 return "Post呼ばれたよ"; 16 } 17 } 18

試しに、同じサイト内のページに埋め込んだ、以下のJavascriptでPOSTしてみましたが、これは正常に処理されます。
値も正常に渡るし、戻り値も返っています。

JavaScript

1 function testPost() { 2 $.ajax( 3 "/api/GateApi/TestPost/", 4 { 5 type: "POST", 6 data: { GateNo: 333 }, 7 success: function (data) { 8 alert(data); 9 }, 10 error: function (e) { 11 alert("エラー"); 12 } 13 }); 14 }

以下が、Windows Formのソースの一部です。
ボタンをクリックするとレスポンスがラベルに表示されます。

C#

1 private void button_Click(object sender, EventArgs e) 2 { 3 PostWebPageAsync(); 4 } 5 6 private async void PostWebPageAsync() 7 { 8 this.label1.Text = "Post取得中"; 9 10 string uri = "http://localhost:12345/api/GateApi/TestPost/"; 11 12 // "Message":"The requested resource does not support http method 'GET'. が返されます。 13 this.label1.Text = await Post(uri, 14 new Dictionary<string, string> {{ "GateNo", "123" }}); 15 } 16 17 // Post呼び出し処理 18 private async Task<string> Post(string url, Dictionary<string, string> param) 19 { 20 string result = ""; 21 22 try 23 { 24 HttpClient httpClient = new HttpClient(); 25 httpClient.MaxResponseContentBufferSize = int.MaxValue; 26 HttpContent content = new FormUrlEncodedContent(param); 27 var response = await httpClient.PostAsync(url, content); 28 String text = await response.Content.ReadAsStringAsync(); 29 30 result = text; 31 } 32 catch (Exception Err) 33 { 34 result = "ERROR: " + Err.Message; 35 } 36 37 return result; 38 }

例外は発生していないようですが、ラベルには、
** "Message":"The requested resource does not support http method 'GET'. **
が表示されます。
response.StatusCode は MethodNotAllowed が返されます。

何か、ヘッダなど必要な情報があるんでしょうが、よくわかりません。
###補足情報
サーバー側もクライアント側も、.NETのバージョンは 4.5.1

IISのログの抜粋です

■うまくいくとき → ChromeのRest Client で呼び出し
2015-10-13 03:06:50 ::1 POST /api/GateApi/TestPost - 12345 - ::1 Mozilla/5.0+(Windows+NT+6.1;+WOW64)+AppleWebKit/537.36+(KHTML,+like+Gecko)+Chrome/45.0.2454.101+Safari/537.36 - 200 0 0 2620

■うまくいかないとき → WindowsForm で呼び出し
2015-10-13 03:09:21 ::1 POST /api/GateApi/TestPost/ - 12345 - ::1 - - 302 0 0 13
2015-10-13 03:09:21 ::1 GET /api/GateApi/TestPost/ AspxAutoDetectCookieSupport=1 53903 - ::1 - - 405 0 0 266

上記ログ(うまくいかないほう)とソースの対応を調べたのですが、
1行目: var response = await httpClient.PostAsync(url, content); → POST
2行目: String text = await response.Content.ReadAsStringAsync(); → GET
ということでした。
1行目の処理で、エラーが帰りそのため2行目のGETがうまくいかないということのようです。

1行目POST時の戻り値の内容を一部抜粋

IsSuccessStatusCode: false ReasonPhrase: "Method Not Allowed" RequestMessage: {Method: POST, RequestUri: 'http://localhost:12345/api/GateApi/TestPost/?AspxAutoDetectCookieSupport=1', Version: 1.1, Content: System.Net.Http.FormUrlEncodedContent, Headers:

{
Content-Type: application/x-www-form-urlencoded
Content-Length: 10
}}


###[その後の調査]

eripong さん

貴重な情報ありがとうございます。
セッションIDの受渡のために、クッキーを使うかどうかの設定の話だと思うんですが、私の知識では、いまいち細かいしくみがわかりません。ただ、これを機に多少とも勉強させていただきます。

最低限の私の知識で理解できる範囲で、以下いろいろやってみました。

■まず、cookieless の設定による実行結果です。(○がPOST成功)
× UseUri
○ UseCookies
× AutoDetect
○ UseDeviceProfile

おっしゃるように、UseCookiesだとうまくいくようで、UseDeviceProfileでも大丈夫みたいです。

つまり、設定としては、

  • <sessionState mode="Off" />
  • <sessionState cookieless="UseCookies"/>
  • <sessionState cookieless="UseDeviceProfile"/>

のいずれかだとうまくいくということになります。

■次に、Chromeのクッキーの状態を見てみました。
イメージ説明
AspxAutoDetectCookieSupportの値が1として保存されているようです。

試しに、これを削除して、JavascriptやREST ClientツールでGETしてみると、見事にエラーになります。
ただ、このときに再度AspxAutoDetectCookieSupport=1 が保存され、2回目以降はエラーにならないようです。

■REST Client でのPOST実行結果
各処理のリクエストの内容を細かく調べる方法がわからないので、とりあえず情報として載せておきます。

以下は、REST Client でPOSTに失敗した時の状況です。
イメージ説明
POST時に、AspxAutoDetectCookieSupport=1にリダイレクトしてるということでしょうか。その結果「405 Method Not Allowed」が返されています。そして、その後、GETしようとしてエラー返されているようです。

最後に、REST Client でPOSTに成功した時の状況です。
イメージ説明

気になる質問をクリップする

クリップした質問は、後からいつでもMYページで確認できます。

またクリップした質問に回答があった際、通知やメールを受け取ることができます。

バッドをするには、ログインかつ

こちらの条件を満たす必要があります。

退会済みユーザー

退会済みユーザー

2015/10/11 07:13 編集

IISが使用しているポート番号が正しく設定されていますでしょうか? IISはデフォルトでは通常の80や8080ポートではなく乱数であいているポートを使用していたと思うのでそうなっていないか確認してみてください。
skippanther

2015/10/12 23:51

とりあえずはVSのデバッグモードで実行しています。つまり、実行環境としてはデバッグ時に起動されるドメインとポート番号を指定しているということです。 ためしに、Chromeの拡張ツール Advanced Rest Clientで、ちゃんとこのメソッドが呼ばれることを確認しました。
skippanther

2015/10/13 00:25

ちなみに、ポートが間違っている場合は、 "ERROR: 無効な URI: 無効なポートが指定されています。" が返されました。
eripong

2015/10/13 02:48

IISのログはどうなっていますか?POSTできているかや、うまく行く場合との差分の確認はできませんか?
guest

回答2

0

恐らくですが,POSTの引数の型解釈が出来なくてエラーが出ているのが根本的な原因ではないでしょうか。

ここに対策として,引数に[FromBody]属性を書く方法が載っています。javascriptの対処の方は以下の例ではクエリパラメータでリクエストを渡しているので今回は参考にしなくても大丈夫です。

以下の資料によれば,POSTメソッドの引数指定は文字列から変換できる型のみに限定されるようです。恐らく独自定義クラスだとキャストを定義する,インターフェースを継承する必要があるのではないかと思います。[FromBody]属性を付けるとリクエストを引数をbodyから受け取るようにして空のリクエストも引数有りにするのだと思います。(javascriptで正しく動いていることからURIに引数がないから怒られている可能性もあります。)

また,POSTリクエストをDictionary型で渡しているところも怪しいので文字列に変換してからリクエストしてみてはいかがでしょうか。

WebApi2 Requested resource does not support post

何が解決策になるか解りませんがいずれかの方法で解決するように思います。

追記:session offで解決するとのことなのでもしかすると,ASP.NETではリクエストヘッダかボディにデフォルトでセッションに使うパラメータが入っていて,それが引数の型で解釈できないせいでエラーが出ている可能性もあります。

投稿2015/10/13 06:17

編集2015/10/13 06:48
退会済みユーザー

退会済みユーザー

総合スコア0

バッドをするには、ログインかつ

こちらの条件を満たす必要があります。

skippanther

2015/10/13 07:26

たしかに「FromBody をつけろ」というのは、あちこちのサイトにありましたね。 public string TestPost([FromBody] para data) でも、これをつけても効果はありませんでした。 PostAsyncの第2引数についても、渡し方をいろいろ変えてみましたが、やり方が悪いのか、状況は変わらないようです。 時間があるときにさらに調べてみるつもりではいますが、今回は Session を OFF にすることで、解決とさせていただきます。
退会済みユーザー

退会済みユーザー

2015/11/10 02:48 編集

いろいろ試していただいたあとなのですね。 こちらも色々勉強になりました。 URIに付加されてることからやはりcookieを処理するメソッドがないのが原因で,デフォルトでcookieが付加されてしまうのが原因の可能性が高そうです。
guest

0

ベストアンサー

調べ切れていませんが、セッションの実現のための仕組みのようです。
rest - asp.net web api and aspxautodetectcookiesupport - Stack Overflow
では、セッションをoffにする事で現象が解消したとありますが、
セッションは使用されているでしょうか?offにすることはできますか?

問題が発生する仕組みについて

まず、POSTした後に、クエリストリングにAspxAutoDetectCookieSupport=1を付けて
GETしているようなのは、sessionStateのcookielessがAutoDetectの場合に発生する様です。

今回の場合、最初のPOSTは、以下に述べるセッションのための処理を行うために、
ASP.NETによって処理され、二番目に来るGETを関数TestPostに振り分けようとして、
POSTにしか対応していないのでエラー、ということだと思います。

同じサイト内のページに埋め込んだJavascriptやChromeのRest Clientでうまくいったのは、
既に今回のアプリケーションにアクセスしており、リクエストにクッキーが載っていたためではないかと
予想しています。
(確認できれば、確認していただければと思います。)

セッションIDをクッキーに保存するかURLに埋め込むかを決めるために、
クッキーが使えるクライアントか、そうでないかを判定するために、
AspxAutoDetectCookieSupport=1にリダイレクトしています。
以下のページに詳しい判定方法が載っています。
Understand How the ASP.NET Cookieless Feature Works

また、SessionStateSection.Cookieless プロパティを見ると、
cookielessのデフォルトはAutoDetectの様なので、こちらをUseCookiesにすれば、
現象が解消する可能性はあります。
その場合、HttpClientでCookieが有効になる様にする必要があります。
ただ、UseCookiesにすればリダイレクトがなくなるかどうかについては、
今のところ有効な資料を見つけられておらず、また検証する環境もないので、
うまく行くかは未知数です。

UseUriは、セッションID付きのURLへのリダイレクトを伴うと思いますので、
いずれにしてもリダイレクトした場合にGETリクエストになって同じエラーになるかと思います。
(こちらも検証していないので予想です。)

セッション自体をなくしてしまえば、これらの仕組みが動かなくなるので、
セッションをoffにすれば改善するだろうと思って回答しました。

投稿2015/10/13 04:27

編集2015/10/13 08:43
eripong

総合スコア1546

バッドをするには、ログインかつ

こちらの条件を満たす必要があります。

eripong

2015/10/13 04:36

もう少しまとまったら、回答を更新します。
skippanther

2015/10/13 06:02 編集

ありがとうございました。 Web.Config で、セッションをOFFにすることで解決しました。 <sessionState mode="Off" /> よく理由がわからないんですが、、、 ※同じ HttpClient のメソッドの GetAsync() はセッションに関係なくうま くいきます。
eripong

2015/10/13 08:28 編集

セッションoffでうまくいく理由を追記しました。 HttpClient のメソッドの GetAsync() がうまくいく、 というのは、呼び出し先のメソッドをHttpPostでなくHttpGetにした ということでしょうか? リダイレクトされるとGETリクエストになるので、 呼び出し先のメソッドがGETリクエストに対応していれば、 うまく動くだろうと思います。
eripong

2015/10/14 09:22

色々な検証結果の共有、ありがとうございます。 予想した流れは大体合っていたようで、良かったです。 > POST時に、AspxAutoDetectCookieSupport=1にリダイレクトしてるということでしょうか。その結果「405 Method Not Allowed」が返されています。そして、その後、GETしようとしてエラー返されているようです。 この部分は、ちょっと違うと思います。 POST時に、302応答が返り、リダイレクト先として、AspxAutoDetectCookieSupport=1が指定される。その後、リダイレクト先へのGETを行い、405応答が返る。 という流れと思います。
skippanther

2015/10/14 12:43

ご指摘ありがとうございます。 Webの開発は難しいですね。後々のことを考えると、やはりその都度ちきんと検証していないとなかなかスキルが身につかないですね。
eripong

2015/10/15 06:41

そうですね。 原理を理解することと、その理解を検証して確認することで、 身になる気がします。 > JavascriptやREST ClientツールでGETしてみると、見事にエラーになります。 の部分は、POSTでもエラーにならないですか?
skippanther

2015/10/19 10:53

すいません レスを見逃していました。 >> JavascriptやREST ClientツールでGETしてみると、見事にエラーになります。 の部分は、POSTでもエラーにならないですか? エラーになるのは、GET、POST 両方です。
eripong

2015/10/19 11:42

返信ありがとうございます。 両方であれば、納得です。
guest

あなたの回答

tips

太字

斜体

打ち消し線

見出し

引用テキストの挿入

コードの挿入

リンクの挿入

リストの挿入

番号リストの挿入

表の挿入

水平線の挿入

プレビュー

15分調べてもわからないことは
teratailで質問しよう!

ただいまの回答率
85.48%

質問をまとめることで
思考を整理して素早く解決

テンプレート機能で
簡単に質問をまとめる

質問する

関連した質問