2012-11-05 44 views
30

tôi có phương pháp Web API sau trong một lớp ApiController:Bắt dữ liệu POST liệu từ phương pháp Web API

public HttpResponseMessage Post([FromBody]byte[] incomingData) 
{ 
    ... 
} 

Tôi muốn incomingData là nội dung thô của POST. Nhưng có vẻ như ngăn xếp API Web cố gắng phân tích cú pháp dữ liệu đến với trình định dạng JSON và điều này khiến mã sau ở phía máy khách thất bại:

new WebClient().UploadData("http://localhost:15134/api/Foo", new byte[] { 1, 2, 3 }); 

Có cách giải quyết đơn giản không?

Trả lời

39

Đối với bất cứ ai khác chạy vào vấn đề này, giải pháp là để xác định phương thức POST không có tham số, và truy cập các dữ liệu thô qua Request.Content:

+3

tôi cần một cái gì đó tương tự nhưng đối với chuỗi, và đảm bảo không có tham số trong phương thức POST rốt cuộc là cần thiết để bằng cách sử dụng 'ReadAsStringAsync' tương đương, nó không có gì khác. –

+0

Đây là cách dễ nhất để làm điều này tôi đã tìm thấy. Các đối tác của chúng tôi tiếp tục thêm các trường không có giấy tờ mới mà họ muốn chúng tôi sử dụng và chúng tôi không bao giờ biết chính xác cách họ đánh vần/định dạng chúng. Cảm ơn! – MvcCmsJon

+0

Cảm ơn vì điều này. Trong MVC6 để có được toàn thân, tôi phải loại bỏ các tham số và đọc 'Request.Body' theo cách thủ công. – joe

3

Trong MVC 6 Yêu cầu dường như không có một Thuộc tính 'Nội dung'. Đây là những gì tôi đã kết thúc thực hiện:

[HttpPost] 
public async Task<string> Post() 
{ 
    string content = await new StreamReader(Request.Body).ReadToEndAsync(); 
    return "SUCCESS"; 
} 
19

Nếu bạn cần đầu vào nguyên liệu, thêm vào các tham số mô hình để truy cập dễ dàng hơn, bạn có thể sử dụng như sau:

using (var contentStream = await this.Request.Content.ReadAsStreamAsync()) 
{ 
    contentStream.Seek(0, SeekOrigin.Begin); 
    using (var sr = new StreamReader(contentStream)) 
    { 
     string rawContent = sr.ReadToEnd(); 
     // use raw content here 
    } 
} 

Bí mật đang sử dụng stream.Seek(0, SeekOrigin.Begin) để thiết lập lại luồng trước khi cố gắng đọc dữ liệu.

+0

Cảm ơn vì điều này, tôi đã đăng một câu trả lời dựa trên mã của bạn, nếu bạn muốn kết hợp nó cảm thấy tự do và tôi sẽ xóa câu trả lời của tôi. – Rocklan

10

Các câu trả lời khác đề xuất xóa thông số đầu vào, nhưng điều đó sẽ phá vỡ tất cả mã hiện tại của bạn. Để trả lời những câu hỏi đúng, một giải pháp dễ dàng hơn là tạo ra một chức năng mà trông như thế này (Nhờ Christoph dưới đây để biết mã này):

private async Task<String> getRawPostData() 
{ 
    using (var contentStream = await this.Request.Content.ReadAsStreamAsync()) 
    { 
     contentStream.Seek(0, SeekOrigin.Begin); 
     using (var sr = new StreamReader(contentStream)) 
     { 
      return sr.ReadToEnd(); 
     } 
    } 
} 

và sau đó nhận được liệu đăng tải dữ liệu bên trong gọi api web của bạn như sau:

public HttpResponseMessage Post ([FromBody]byte[] incomingData) 
{ 
    string rawData = getRawPostData().Result; 

    // log it or whatever 

    return Request.CreateResponse(HttpStatusCode.OK); 
} 
+1

Làm tốt lắm, cảm ơn bạn! Tôi đang thêm một câu trả lời mà regurgitates của bạn như là một lớp tiện ích với một phương pháp tĩnh. –

+3

lol, bây giờ chúng tôi là ba cấp độ sâu. – Rocklan

+0

Nếu bạn truy cập vào tác vụ . Thuộc tính sở hữu như vậy, bạn sẽ ngay lập tức chờ đợi trên chuỗi. Có lợi ích gì khi sử dụng Nhiệm vụ ở đây không? – codinglifestyle

3

Tôi lấy câu trả lời của LachlanB và đặt nó vào một lớp tiện ích với một phương pháp tĩnh duy nhất mà tôi có thể sử dụng trong tất cả các bộ điều khiển của mình.

public class RawContentReader 
{ 
    public static async Task<string> Read(HttpRequestMessage req) 
    { 
     using (var contentStream = await req.Content.ReadAsStreamAsync()) 
     { 
      contentStream.Seek(0, SeekOrigin.Begin); 
      using (var sr = new StreamReader(contentStream)) 
      { 
       return sr.ReadToEnd(); 
      } 
     } 
    } 
} 

Sau đó, tôi có thể gọi nó từ bất kỳ các phương pháp ApiController tôi theo cách này:

Các vấn đề liên quan