QA@IT

Restfull PUT送信について

5420 PV

c# vs2012です。

asp.net restfulでwebとwindowsフォーム間でやり取りをし、
PUTで更新したいのですが、Windowsフォームから下記のようにPUT送信すると
WEB側の[FromBody]string valueがnullとなり受け取れません。

テストはローカルで行っていますが、WEB側のpc_nameはきちんと取れています。
原因、対処方法など教授いただけないでしょうか。

Windowsフォーム

string uri2 = "http://localhost:4291/api/distcheck/" + str_pcname;
var request = (HttpWebRequest)WebRequest.Create(uri2);
var buffer = Encoding.UTF8.GetBytes("pc_name=" + str_pcname + "&cpu_temp=16");
request.Method = "PUT";
request.ContentType = "application/x-www-form-urlencoded";
request.ContentLength = buffer.Length;
request.CookieContainer = new CookieContainer();

var requestStream = request.GetRequestStream();
requestStream.Write(buffer, 0, buffer.Length);
requestStream.Flush();
requestStream.Close();  

WEB側

public void Put(string pc_name, [FromBody]string value)
{



}

回答

通常のapplication/x-www-form-urlencoded においては、クエリ文字列の様に 名前=値&名前=値&...で渡せますが、WebApiに送る際、Request Bodyは=内容 の形になる必要があります。

イコールで始まり一つの値を送ることになります。
つまり以下の様にする必要があります。

var buffer = Encoding.UTF8.GetBytes("=" + pc_name);
// サーバー側のvalue引数の値は pc_nameの値と同じになる

もし以下のようにした場合最初の値のみ有効です

var buffer = Encoding.UTF8.GetBytes("=" + pc_name + "&cpu_id=16");
// サーバー側のvalue引数の値は pc_nameの値と同じになり、&以降は無視される

複数の値をおくりたくてこれでは問題がある場合は、他の形式で送りサーバー側で分割することを検討してください。

例えば Content-typeを application/json にした場合は以下のように渡せます。

var buffer = Encoding.UTF8.GetBytes("\"" + pc_name + "&cpu_id=16\"");
~中略~
request.ContentType = "application/json";

この結果サーバー側では前後の引用符の無い文字列が受け取れます。
仮にpc_nameaaaなら以下if文は成り立ちます。

public void Put(string pc_serial, [FromBody]string value) {
  if("aaa&cpu_id=16" == value) Debug.Print("出力される");
}

なお、jsonと指定していますが実際に受け取れるのはただの文字列でありオブジェクトではありません。

編集 履歴 (1)
  • 無事取得することができました。

    丁寧に解説頂きありがとうございます。
    とても勉強になりました。

    -

失礼致しました。環境は以下の通りです。

OS Windows8
.NET Framework4
iisはまだ立てておらず、
ローカルの開発環境でテストを行っています。

asp.net restful とは何ですか? ASP.NET MVC 4 で追加された Web API のことですか?

 はい。おっしゃる通りWeb APIです。
 
現状は、同一PC内でwebアプリと、windowsアプリの両方を起動させ
デバックにて値の確認を行っています。

1.WEB側のPUTメソッド内にブレークポイントを設定、
2.Windows側のボタンクリックでPUT送信、
3.WEB側のイベント内に入ることを確認し、ウォッチパネルなどで値の確認を行っています。

windowsフォーム側

private void button1_Click(object sender, EventArgs e)
        {

            string uri2 = "http://localhost:4291/api/distcheck/" + "test_pc";
            var request = (HttpWebRequest)WebRequest.Create(uri2);
            var buffer = Encoding.UTF8.GetBytes("pc_name=" + pc_name + "&cpu_temp=16");
            request.Method = "PUT";
            request.ContentType = "application/x-www-form-urlencoded";
            request.ContentLength = buffer.Length;
            request.CookieContainer = new CookieContainer();

            var requestStream = request.GetRequestStream();
            requestStream.Write(buffer, 0, buffer.Length);
            requestStream.Flush();
            requestStream.Close();  

        }

WEB側

app_start

public static class WebApiConfig
    {
        public static void Register(HttpConfiguration configuration)
        {


            configuration.Routes.MapHttpRoute(
                name: "distcheck",
                routeTemplate: "api/distcheck/{pc_serial}",
                defaults: new { controller = "distcheck", pc_serial = RouteParameter.Optional }
            );



        }
    }

コントローラ

 public class distcheckController : ApiController
    {

        public IEnumerable<string> Get()
        {
            return new string[] { "" };
        }

        public IEnumerable<string> Get(string pc_serial)
        {
            return new string[] { "" }; 

        }

        public void Post([FromBody]string value)
        {


        }

        public void Put(string pc_serial, [FromBody]string value)
        {
            Debug.WriteLine(pc_serial + ":" + value); 
        }

        public void Delete(int id)
        {

        }
    }

宜しくお願い致します。

編集 履歴 (2)
  • MVC 4 の Web API プラットフォームですと検証する手段を持ってないのでお手上げです(Visual Studio 2010 MVC 3 なら OK ですが)。すみませんが他の方の回答をお待ちください。 -

質問の際には、まず最初に、ご自分の環境(OS, .NET, IIS のバージョンなど)、ASP.NET のプラットフォームなどの情報を書いていただけませんか?

asp.net restful とは何ですか? ASP.NET MVC 4 で追加された Web API のことですか?

Web アプリの実装を、呼び出すメソッドだけでなく、もう少し全体が分かるように書けませんか?

編集 履歴 (0)
ウォッチ

この質問への回答やコメントをメールでお知らせします。