45

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

しかし、文字列を受信できません。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です。メソッドのシグネチャを(文字列値)に変更すると、呼び出されることはありません。

[承認]設定が「ない」場合でも、同じ奇妙な動作をします。->つまり、ユーザー認証とは何の関係もありません。

私が間違っていることについて何か考えはありますか?助けてくれてありがとう。

4

7 に答える 7

61

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

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

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);
        }
    }
}

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

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

そして、私がリンクした資料を読んだ後、あなたは私のようで、WTFの人、私がする必要があるのはサーバー側のエンドポイントに文字列をPOSTすることだけであり、これをすべて行う必要がありますか?とんでもない。次に、ServiceStackをチェックアウトします。WebAPIと比較するための優れた基盤があります。Microsoftの人物がWebAPIを設計するときに何を考えていたのかはわかりませんが、真剣に言えば、HTML(Razorを考えてください)とRESTのものに別々のベースコントローラーを用意する必要がありますか?これは深刻なことではありません。

于 2012-12-07T21:56:12.650 に答える
36

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

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

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

        }

    }

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

HttpClientを使用して、StringContentのインスタンスを渡すことで呼び出すことができます。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);

    }
于 2012-12-08T01:29:36.073 に答える
4

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

public class YourController : ApiController
{
    [HttpPost]
    public HttpResponseMessage Post()
    {
        string bodyText = this.Request.Content.ReadAsStringAsync().Result;
        //more code here...
    }
}
于 2015-03-27T22:55:28.637 に答える
3

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

/// <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を実行し、Streamを介してバイトを送信する場合、それらはパラメーターとしてアクションに渡されません。サーバー上のストリームを介してバイトを取得する必要があります。

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

     /// <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;
     }
于 2012-12-07T21:26:27.087 に答える
3

ダレルはもちろん彼の反応に正直です。追加する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);

ヘンリック

于 2012-12-09T19:27:13.853 に答える
2

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

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

チャームのように機能します!ご参考までに

于 2015-05-04T10:12:22.113 に答える
-2
([FromBody] IDictionary<string,object> data)
于 2015-10-16T11:16:38.957 に答える