web-dev-qa-db-ja.com

POST ASP.NET Web Apiアプリケーションへの文字列-nullを返します

クライアントからASP.NET MVC4アプリケーションに文字列を送信しようとしています。

しかし、文字列を受信できません。nullか、postメソッドが見つかりません(404エラー)

文字列を送信するクライアントコード(コンソールアプリケーション):

HttpWebRequest request = (HttpWebRequest)WebRequest.Create("http://localhost:49032/api/test");
request.Credentials = new NetworkCredential("user", "pw");
request.Method = "POST";
string postData = "Short test...";
byte[] byteArray = Encoding.UTF8.GetBytes(postData);
request.ContentType = "application/x-www-form-urlencoded";
request.ContentLength = byteArray.Length;

Stream dataStream = request.GetRequestStream();
dataStream.Write(byteArray, 0, byteArray.Length);
dataStream.Close();

WebResponse response = request.GetResponse();
Console.WriteLine(((HttpWebResponse)response).StatusDescription);
dataStream = response.GetResponseStream();

StreamReader reader = new StreamReader(dataStream);
string responseFromServer = reader.ReadToEnd();
Console.WriteLine(responseFromServer);
reader.Close();
dataStream.Close();
response.Close();
Console.ReadLine();

ASP.NET Web Apiコントローラー:

public class TestController : ApiController
{
    [Authorize]
    public String Post(byte[] value)
    {
        return value.Length.ToString();
    }
}

その場合、「Post」メソッドを呼び出すことができますが、「value」はNULLです。メソッドシグネチャを(文字列値)に変更すると、呼び出されなくなります。

[Authorize]設定を「なし」に設定しても、同じ奇妙な動作になります。 ->したがって、ユーザー認証とは関係ありません。

私が間違っていることは何ですか?私はどんな助けにも感謝しています。

40
user1011394

Web APIコントローラーアクションでいくつかの[Authorize]属性を使用したようですが、これが質問にどのように関連するかわかりません。

それでは、実践しましょう。簡単なWeb APIコントローラーは次のようになります。

public class TestController : ApiController
{
    public string Post([FromBody] string value)
    {
        return value;
    }
}

そしてそれについての消費者:

class Program
{
    static void Main()
    {
        using (var client = new WebClient())
        {
            client.Headers[HttpRequestHeader.ContentType] = "application/x-www-form-urlencoded";
            var data = "=Short test...";
            var result = client.UploadString("http://localhost:52996/api/test", "POST", data);
            Console.WriteLine(result);
        }
    }
}

Web APIコントローラー属性の [FromBody] 装飾と、クライアントのPOST=データの=プレフィックス]に間違いなく気付くでしょう。サイド。 Web APIがどのようにパラメーターバインディングを行うか を読んで、概念をよりよく理解することをお勧めします。

[Authorize]属性に関する限り、これを使用して、認証されたユーザーのみがサーバー上の一部のアクションにアクセスできないようにすることができます。実際、ここで何を達成しようとしているのかははっきりしていません。 ASP.NET Web APIでパラメータバインドがどのように機能するかを理解しようとしていますか(これがあなたの目標である場合はリンクしている記事を読んでください)、または認証および/または承認を実行しようとしていますか? 2番目のケースがあなたの場合であれば、このトピックで書いた following post がおもしろいかもしれません。

そして、私がリンクした資料を読んだ後、あなたは私のようであり、WTFの人に自分自身に言うなら、私がする必要があるのはPOSTサーバー側のエンドポイントへの文字列であり、私は必要です方法はありません。チェックアウト ServiceStack 。Web APIと比較するための優れた基盤が得られます。 、しかし、真剣に、私たちのHTML(Razorを考えてください)とREST stuff?これは深刻なことはできません。

57
Darin Dimitrov

HTTPを使用しているという事実を受け入れれば、Web APIは非常にうまく機能します。乱雑になり始めるのは、ワイヤを介してオブジェクトを送信しているふりをしようとするときです。

 public class TextController : ApiController
    {
        public HttpResponseMessage Post(HttpRequestMessage request) {

            var someText = request.Content.ReadAsStringAsync().Result;
            return new HttpResponseMessage() {Content = new StringContent(someText)};

        }

    }

このコントローラーはHTTP要求を処理し、ペイロードから文字列を読み取り、その文字列を返します。

StringContentのインスタンスを渡すことにより、HttpClientを使用して呼び出すことができます。 StringContentは、デフォルトでメディアタイプとしてtext/plainを使用します。まさにあなたが渡そうとしているものです。

    [Fact]
    public void PostAString()
    {

        var client = new HttpClient();

        var content = new StringContent("Some text");
        var response = client.PostAsync("http://Oak:9999/api/text", content).Result;

        Assert.Equal("Some text",response.Content.ReadAsStringAsync().Result);

    }
35
Darrel Miller

もちろん、Darrelは彼の反応を正しく理解しています。追加する1つのことは、「hello」のような単一のトークンを含むボディにバインドしようとする理由です。

uRL形式でエンコードされたデータではないということです。このように前に「=」を追加することにより:

=hello

空の名前と値「hello」を持つ単一のキー値ペアのURL形式エンコードになります。

ただし、より良い解決策は、文字列をアップロードするときにapplication/jsonを使用することです。

POST /api/sample HTTP/1.1
Content-Type: application/json; charset=utf-8
Host: Host:8080
Content-Length: 7

"Hello"

HttpClientを使用すると、次のように実行できます。

HttpClient client = new HttpClient();
HttpResponseMessage response = await client.PostAsJsonAsync(_baseAddress + "api/json", "Hello");
string result = await response.Content.ReadAsStringAsync();
Console.WriteLine(result);

ヘンリク

このコードを使用して、HttpRequestを投稿します。

/// <summary>
        /// Post this message.
        /// </summary>
        /// <param name="url">URL of the document.</param>
        /// <param name="bytes">The bytes.</param>
        public T Post<T>(string url, byte[] bytes)
    {
        T item;
        var request = WritePost(url, bytes);

        using (var response = request.GetResponse() as HttpWebResponse)
        {
            item = DeserializeResponse<T>(response);
            response.Close();
        }

        return item;
    }

    /// <summary>
    /// Writes the post.
    /// </summary>
    /// <param name="url">The URL.</param>
    /// <param name="bytes">The bytes.</param>
    /// <returns></returns>
    private static HttpWebRequest WritePost(string url, byte[] bytes)
    {
        ServicePointManager.ServerCertificateValidationCallback = (sender, certificate, chain, errors) => true;

        HttpWebRequest request = (HttpWebRequest) WebRequest.Create(url);
        Stream stream = null;
        try
        {
            request.Headers.Clear();
            request.PreAuthenticate = true;
            request.Connection = null;
            request.Expect = null;
            request.KeepAlive = false;
            request.ContentLength = bytes.Length;
            request.Timeout = -1;
            request.Method = "POST";
            stream = request.GetRequestStream();
            stream.Write(bytes, 0, bytes.Length);
        }
        catch (Exception e)
        {
            GetErrorResponse(url, e);
        }
        finally
        {
            if (stream != null)
            {
                stream.Flush();
                stream.Close();
            }
        }
        return request;
    }

コードに関しては、content.Type(request.ContentType = "application/x-www-form-urlencoded";

更新

問題は、値を取得する方法にあると考えています。 POSTを実行し、ストリームを介してバイトを送信する場合、それらはパラメーターとしてアクションに渡されません。サーバー上のストリームを介してバイトを取得する必要があります。

サーバーで、ストリームからバイトを取得してください。次のコードは私が使用するものです。

     /// <summary> Gets the body. </summary>
     /// <returns> The body. </returns>
     protected byte[] GetBytes()
     {
       byte[] bytes;
        using (var binaryReader = new BinaryReader(Request.InputStream))
        {
            bytes = binaryReader.ReadBytes(Request.ContentLength);
        }

         return bytes;
     }
3
Chuck Conway

WebAPIの場合、特別な[FromBody]バインディングを経由せずに本文テキストを取得するコードを次に示します。

public class YourController : ApiController
{
    [HttpPost]
    public HttpResponseMessage Post()
    {
        string bodyText = this.Request.Content.ReadAsStringAsync().Result;
        //more code here...
    }
}
2
Jeson Martajaya

私はこの問題に出会い、この記事を見つけます。 http://www.jasonwatmore.com/post/2014/04/18/Post-a-simple-string-value-from-AngularJS-to-NET-Web-API.aspx

私が見つけた解決策は、あなたのjs投稿で文字列値を二重引用符で囲むだけでした

魅力のように機能します!ご参考までに

2
Bill.Zhuang