Làm cách nào để chuyển nhiều tham số cho API Web ASP.Net GET?


136

Tôi đang sử dụng API Web .Net MVC4 để (hy vọng) triển khai api RESTful. Tôi cần truyền một vài tham số cho hệ thống và để nó thực hiện một số hành động, sau đó trả về một danh sách các đối tượng làm kết quả. Cụ thể tôi đang vượt qua trong hai ngày và trả lại hồ sơ rơi giữa họ. Tôi cũng đang theo dõi các hồ sơ được trả lại để các cuộc gọi tiếp theo không được xử lý lại trong hệ thống.

Tôi đã xem xét một vài cách tiếp cận:

  1. Sắp xếp các tham số thành một chuỗi JSON duy nhất và tách nó ra trong API. http://forums.asp.net/t/1807316.aspx/1

  2. Vượt qua các tham số trong chuỗi truy vấn.
    Cách tốt nhất để truyền nhiều tham số truy vấn cho một api yên tĩnh là gì?

  3. Xác định các thông số trong tuyến đường: api / control / date1 / date2

  4. Sử dụng POST vốn đã cho phép tôi vượt qua một đối tượng với params.

  5. Nghiên cứu ODATA vì API Web (hiện tại) hỗ trợ nó. Tôi chưa làm được gì nhiều với điều này nên tôi không quen lắm.

Có vẻ như các thực tiễn REST thích hợp chỉ ra khi dữ liệu được kéo, bạn nên sử dụng GET. Tuy nhiên, GET cũng phải là nullipotent (không tạo ra tác dụng phụ) và tôi tự hỏi liệu việc triển khai cụ thể của tôi có vi phạm điều đó hay không vì tôi đánh dấu các bản ghi trong hệ thống API, do đó tôi đang tạo ra các tác dụng phụ.

Nó cũng dẫn tôi đến câu hỏi hỗ trợ các tham số biến. Nếu danh sách tham số đầu vào thay đổi, sẽ rất tẻ nhạt khi phải xác định lại tuyến đường của bạn cho Lựa chọn 3 nếu điều đó xảy ra nhiều. Và điều gì có thể xảy ra nếu các tham số được xác định vào thời gian chạy ...

Trong mọi trường hợp, đối với việc thực hiện cụ thể của tôi, lựa chọn nào (nếu có) có vẻ tốt nhất?

Câu trả lời:


10

Bản ghi này có ý nghĩa gì? Nếu điều này chỉ được sử dụng cho mục đích ghi nhật ký, tôi sẽ sử dụng GET và vô hiệu hóa tất cả bộ nhớ đệm, vì bạn muốn đăng nhập mọi truy vấn cho tài nguyên này. Nếu đánh dấu hồ sơ có mục đích khác, POST là cách để đi. Người dùng nên biết rằng hành động của mình ảnh hưởng đến hệ thống và phương thức POST là một cảnh báo.


Bằng cách đánh dấu, tôi có nghĩa là chỉ cần theo dõi những bản ghi nào được xử lý và trả lại để các cuộc gọi tiếp theo không lặp lại chúng. Trong trường hợp của tôi, tôi chỉ thực hiện chèn vào một bảng khác để theo dõi được xử lý.
sig606

Ngay bây giờ tôi đã thực hiện nó dưới dạng POST chủ yếu vì lý do bạn nói - hành động xảy ra và người tiêu dùng nhận thức được chúng. Thêm vào đó, có vẻ dễ dàng và linh hoạt nhất đối với việc truyền dữ liệu khác nhau.
sig606

@ sig606: POST là cách phù hợp với tôi, nhưng giao thức của bạn dường như không an toàn. Điều gì xảy ra nếu có gì đó xảy ra và các bản ghi được truy xuất ở phía máy khách, nhưng không được xử lý do lỗi? Bạn sẽ không trả lại cho họ nữa và khách hàng bị mất dữ liệu.
LukLed

Ngay bây giờ API của tôi chỉ trả về các bản ghi sau khi chúng được xử lý. Vì vậy, người tiêu dùng vượt qua API hai ngày. Hồ sơ giữa hai ngày được xử lý và đánh dấu. Sau đó, dữ liệu được trả lại cho người gọi. Tôi cho rằng nếu một cái gì đó xảy ra trong quá trình xử lý hoặc sau khi xử lý trước khi tiếp cận khách hàng, tôi có một vấn đề.
sig606

141

Tôi nghĩ cách dễ nhất là sử dụng đơn giản AttributeRouting.

Rõ ràng trong bộ điều khiển của bạn, tại sao bạn lại muốn điều này trong WebApiConfigtệp Toàn cầu của mình ?

Thí dụ:

    [Route("api/YOURCONTROLLER/{paramOne}/{paramTwo}")]
    public string Get(int paramOne, int paramTwo)
    {
        return "The [Route] with multiple params worked";
    }

Các {}tên cần phải phù hợp với các thông số của bạn.

Đơn giản như vậy, bây giờ bạn có một phần riêng GETxử lý nhiều thông số trong trường hợp này.


12
Điều đó thật tuyệt. Hầu hết mọi người khuyên bạn nên thiết lập tuyến đường trong WebApiConfigtệp, nhưng điều này thực sự đẹp hơn.
rhyek

4
Thật vậy, chúng tôi (hầu hết mọi người) khuyên bạn nên có một khu vực quản lý tập trung cho cấu hình của bạn. Trong trường hợp API Web (Microsoft hoặc cách khác), các mẫu tập trung cho REST là khóa. Định tuyến thuộc tính là dễ thương, nhưng nó làm cho ngoại lệ một lần trở nên quá hấp dẫn.
David Betz

3
Đồng ý, tôi cần cập nhật câu trả lời của tôi thực sự. Có nhiều cách tốt hơn để thực hiện nhiều tham số với GET. Đã đăng bài này khi tôi mới hơn lên WebAPI, bây giờ tôi không sử dụng AttributionRouting (trừ khi tôi không muốn tạo Trình điều khiển mới) và vượt qua tất cả các Thông số trong QueryString, chúng sẽ tự động ánh xạ. Cập nhật khi tôi có cơ hội để mọi người không sử dụng phương pháp cũ hơn này
Mark Pieszak - Trilon.io

Có cách nào để đặt một Routetham số được đặt tên (ví dụ: tham số truy vấn) không?
Shimmy Weitzhandler

1
Nếu tên phương thức hành động là bắt buộc, điều này có thể được sửa đổi để phù hợp với điều đó. [Tuyến đường ("api / YOUCONTROLLER / Get / {paramOne} / {paramTwo}")] chuỗi công khai Get (int paramOne, int paramTwo) {return "Something"; }
Dash

49

Chỉ cần thêm một tuyến đường mới cho các WebApiConfigmục.

Chẳng hạn, để gọi:

public IEnumerable<SampleObject> Get(int pageNumber, int pageSize) { ..

thêm vào:

config.Routes.MapHttpRoute(
    name: "GetPagedData",
    routeTemplate: "api/{controller}/{pageNumber}/{pageSize}"
);

Sau đó thêm các tham số vào cuộc gọi HTTP:

GET //<service address>/Api/Data/2/10 

10
Đây dường như là câu trả lời duy nhất liệt kê tất cả các phần. Tôi ước rằng ai đó mô tả tốt hơn cách sử dụng api/controller?start=date1&end=date2URI kiểu.
Hot Licks

@Hot Licks Câu trả lời của Andrew Veriga hoạt động tốt với các đối số chuỗi truy vấn. Về cơ bản, bạn liên kết các tên chuỗi truy vấn với các thuộc tính lớp và chuyển chúng vào phương thức của bạn. Phương thức của bạn sẽ lấy một đối số lớp duy nhất được đánh dấu bằng thuộc tính [FromUri] và sẽ có các đối số chuỗi truy vấn của bạn làm thuộc tính của nó.
David Peterson

Công cụ tuyệt vời. Cảm ơn!
Hugo Nava Kopp

xin chào @HotLicks và GrahamWright bạn có nghĩ mình có thể trả lời câu hỏi này không? Cảm ơn, stackoverflow.com/questions/57565318/ từ

45

Tôi chỉ phải thực hiện một api RESTfull nơi tôi cần truyền tham số. Tôi đã làm điều này bằng cách chuyển các tham số trong chuỗi truy vấn theo cùng kiểu như được mô tả bởi ví dụ đầu tiên của Mark "api / control? Start = date1 & end = date2"

Trong bộ điều khiển tôi đã sử dụng một mẹo từ phân tách URL trong C #?

// uri: /api/courses
public IEnumerable<Course> Get()
{
    NameValueCollection nvc = HttpUtility.ParseQueryString(Request.RequestUri.Query);
    var system = nvc["System"];
    // BL comes here
    return _courses;
}

Trong trường hợp của tôi, tôi đã gọi WebApi qua Ajax giống như:

$.ajax({
        url: '/api/DbMetaData',
        type: 'GET',
        data: { system : 'My System',
                searchString: '123' },
        dataType: 'json',
        success: function (data) {
                  $.each(data, function (index, v) {
                  alert(index + ': ' + v.name);
                  });
         },
         statusCode: {
                  404: function () {
                       alert('Failed');
                       }
        }
   });

Tôi hi vọng cái này giúp được...


2
Tôi đoán bạn không sử dụng WebApi vì ParameterBinding sẽ ánh xạ chuỗi truy vấn của bạn tới các tham số phương thức api của bạn một cách tự động ...
emp

1
Có, cách tốt hơn là sử dụng và thuộc tính như [Tuyến đường ("api / DbMetaData / {system} / {searchString}")] và sau đó thêm các tham số vào Get (hệ thống chuỗi, chuỗi searchString) và sau đó gọi bằng " ... api / DbMetaData / mysystem / mysearchopes "
Nigel Findlater

Tôi đã sử dụng ví dụ của anh ấy trong C # MVC WebApi của tôi và nó hoạt động tốt. +1 chẳng hạn
Si8

38

Tôi tìm thấy giải pháp tuyệt vời trên http://habrahabr.ru/post/164945/

public class ResourceQuery
{
   public string Param1 { get; set; }
   public int OptionalParam2 { get; set; }
}

public class SampleResourceController : ApiController
{
    public SampleResourceModel Get([FromUri] ResourceQuery query)
    {
        // action
    }
}

5
Manh mối ở đây là [FromUri]
tranceporter

2
Mặc dù bài viết bằng tiếng Nga, @tranceporter đã đúng. "FromUri" trông giống như một cách tuyệt vời để lấy các tham số từ url. Một bài viết khác có thể hữu ích: asp.net/web-api/overview/formats-and-model-binding/ ám
Greg

Đây là những gì tôi đã làm được một thời gian và nó đã hoạt động rất tốt! Tôi cũng muốn giới thiệu giải pháp này.
David Peterson

Nếu bạn gọi vào một phương thức trợ giúp khác (không phải Get), bạn vẫn có thể sử dụng [FromUri]chứ? Tôi dường như không thể làm cho nó hoạt động.
vui vẻ

8

Sử dụng NHẬN hoặc POST được giải thích rõ ràng bởi @LukLed . Về cách bạn có thể vượt qua các tham số tôi sẽ đề xuất theo cách tiếp cận thứ hai (tôi không biết nhiều về ODATA ).

1.Serialize các params thành một chuỗi JSON duy nhất và chọn nó trong API. http://forums.asp.net/t/1807316.aspx/1

Đây không phải là người dùng thân thiệnSEO thân thiện

2.Pass các params trong chuỗi truy vấn. Cách tốt nhất để truyền nhiều tham số truy vấn cho một api yên tĩnh là gì?

Đây là cách tiếp cận thông thường thích hợp hơn.

3. Xác định các thông số trong tuyến đường: api / control / date1 / date2

Đây chắc chắn không phải là một cách tiếp cận tốt. Điều này làm cho cảm thấy một số date2là một tài nguyên phụ date1và đó không phải là trường hợp. Cả hai date1date2là các tham số truy vấn và có cùng cấp độ.

Trong trường hợp đơn giản, tôi sẽ đề xuất một URI như thế này,

api/controller?start=date1&end=date2

Nhưng cá nhân tôi thích mẫu URI dưới đây nhưng trong trường hợp này chúng ta phải viết một số mã tùy chỉnh để ánh xạ các tham số.

api/controller/date1,date2

Trên thực tế, đó là những lời giải thích nguồn gốc của tôi. Tôi nghĩ LukLed đã tạo ra các thẻ và liên kết URL của tôi.
sig606

Theo như SEO, trong trường hợp này nó sẽ không áp dụng. Mã này sẽ là "máy chủ đến máy chủ", vì vậy tôi sẽ không quan tâm nếu thế giới bên ngoài đã phát hiện ra nó. Trong thực tế, tôi phải đảm bảo các bước bảo mật thích hợp được thực hiện để tránh truy cập ngẫu nhiên. Tôi đã phải thực hiện tuần tự hóa JSON cho một phần khác của hệ thống (dường như là một lỗi khi cố gắng POST các danh sách lớn của obj vì vậy tôi phải tuần tự hóa thành chuỗi), vì vậy trong trường hợp này sẽ không kéo dài quá nhiều .
sig606

1
Tôi hy vọng bạn đã có câu trả lời sau đó tại sao bạn đang đặt câu hỏi?
VJAI

2
Xin lỗi vì phản hồi muộn này, Mark. Tôi đã thử một vài giải pháp nhưng không chắc đó là giải pháp tốt nhất và đang cố gắng tuân thủ các phương pháp tiếp cận tiêu chuẩn công nghiệp, vì vậy tôi đã đăng ở đây tại SO.
sig606

1
@Mark Một cái gì đó giống như tiếp theo: stackoverflow.com/questions/9681658/ cấp ?
RredCat


3
 [Route("api/controller/{one}/{two}")]
    public string Get(int One, int Two)
    {
        return "both params of the root link({one},{two}) and Get function parameters (one, two)  should be same ";
    }

Cả hai tham số của liên kết gốc ({one}, {hai}) và Nhận tham số hàm (một, hai) phải giống nhau


2

Tôi biết điều này thực sự cũ, nhưng tôi muốn điều tương tự gần đây và đây là những gì tôi tìm thấy ...

    public HttpResponseMessage Get([FromUri] string var, [FromUri] string test) {
        var retStr = new HttpResponseMessage(HttpStatusCode.OK);
        if (var.ToLower() == "getnew" && test.ToLower() == "test") {
            retStr.Content = new StringContent("Found Test", System.Text.Encoding.UTF8, "text/plain");
        } else {
            retStr.Content = new StringContent("Couldn't Find that test", System.Text.Encoding.UTF8, "text/plain");
        }

        return retStr;
    }

Vì vậy, bây giờ trong địa chỉ của bạn / URI / ...

http (s): // myURL / api / myControll /? var = getnew & test = test

Kết quả: "Tìm thấy thử nghiệm"


http (s): // myURL / api / myControll /? var = getnew & test = anything

Kết quả: "Không thể tìm thấy bài kiểm tra đó"


Cá nhân tôi thích phong cách này trong C #, vì tôi có thể thay đổi chữ ký của phương thức ban đầu và quá tải chính xác những gì tôi đang cố gắng thực hiện mà không cần điều chỉnh các cấu hình định tuyến. Hy vọng nó sẽ giúp những người khác đã quen với cách tiếp cận (có thể là cổ xưa) này trong việc đưa ra yêu cầu GET.
Rick Riggs

1
Tôi đã phải tạo một API sự kiện được sử dụng bởi ứng dụng lịch của bên thứ ba, sử dụng phương pháp này. Tôi rất vui vì đã tìm thấy câu trả lời này!
đất sét Ngày


0
    public HttpResponseMessage Get(int id,string numb)
    {
        //this will differ according to your entity name
        using (MarketEntities entities = new MarketEntities())
        {
          var ent=  entities.Api_For_Test.FirstOrDefault(e => e.ID == id && e.IDNO.ToString()== numb);
            if (ent != null)
            {
                return Request.CreateResponse(HttpStatusCode.OK, ent);
            }
            else
            {
                return Request.CreateErrorResponse(HttpStatusCode.NotFound, "Applicant with ID " + id.ToString() + " not found in the system");
            }
        }
    }
Khi sử dụng trang web của chúng tôi, bạn xác nhận rằng bạn đã đọc và hiểu Chính sách cookieChính sách bảo mật của chúng tôi.
Licensed under cc by-sa 3.0 with attribution required.