Przekazywanie parametrów do akcji jest istotną częścią budowania RESTful Web API. ASP.NET Core, który został wydany jako część .NET 5 oferuje wiele sposobów przekazywania parametrów do metod reprezentujących punkty końcowe. Zobaczmy, jakie one są.
Przekazywanie parametrów jako część URL
Podczas przekazywania parametru w adresie URL musisz zdefiniować routing, który zawierałby parametr. Spójrzmy na przykład:
[Route("{daysForward}")] [HttpGet] public IActionResult Get(int daysForward) { var rng = new Random(); return new JsonResult(new WeatherForecast { Date = DateTime.Now.AddDays(daysForward), TemperatureC = rng.Next(-20, 55), Summary = Summaries[rng.Next(Summaries.Length)] }); }
Ta metoda zwraca prognozę pogody dla jednego dnia w przyszłości. Parametr daysForward
określa, ile dni z wyprzedzeniem należy zwrócić prognozę pogody. Zauważ, że daysForward
jest częścią routingu, więc prawidłowy adres URL do tego punktu końcowego będzie wyglądał następująco:
GET: weatherForecast/3
Możemy również użyć atrybutu [FromRoute]
przed deklaracją metody, ale domyślnie będzie również działał w ten sam sposób.
public IActionResult Get([FromRoute] int daysForward)
Przekazywanie parametrów w parametrach żądania
Jest to bardzo powszechna metoda przekazywania dodatkowych parametrów, ponieważ nie wymaga od nas zmiany routingu, więc jest również kompatybilna wstecz. Kompatybilność jest ważna, w przypadku zmiany istniejącego rozwiązania.
Spójrzmy na inną metodę, która zwróciłaby kolekcję prognoz pogody z opcją sortowania.
[HttpGet] public IEnumerable<WeatherForecast> Get([FromQuery]bool sortByTemperature = false) { var rng = new Random(); var forecasts = Enumerable.Range(1, 5).Select(index => new WeatherForecast { Date = DateTime.Now.AddDays(index), TemperatureC = rng.Next(-20, 55), Summary = Summaries[rng.Next(Summaries.Length)] }); if (sortByTemperature) { forecasts = forecasts.OrderByDescending(f => f.TemperatureC); } return forecasts; }
W tym przykładzie przekazujemy parametr sortByTemperature
, który jest opcjonalny. Zauważ, że używamy atrybutu [FromQuery]
, aby wskazać, że jest to zmienna pobrana z parametru zapytania. Adres URL tego punktu końcowego wygląda następująco:
GET: weatherForecast?sortByTemperature=true
Możesz także przekazać więcej parametrów rozdzielając je znakiem &:
GET: weatherForecast?key1=value1&key2=value2&key3=value3
Zwróć uwagę na to, że adres URL musi być odpowiednio zakodowany, aby działał poprawnie. Jeśli chcesz przekazać taki parametr:
https://www.michalbialecki.com/?name=Michał Białecki
To powinien być zakodowany jako:
https://www.michalbialecki.com/?name=Micha%C5%82%20Bia%C5%82ecki
Przekazywanie obiektu w parametrach żądania
Gdy podajesz wiele parametrów zapytania, warto traktować je jako obiekt. Spójrz na poniższy kod:
// GET: weatherForecast/GetFiltered?SortByTemperature=true&City=Poznan [HttpGet("GetFiltered")] public IEnumerable<WeatherForecast> GetFiltered([FromQuery]WeatherForecastFilters filters) { var rng = new Random(); var forecasts = Enumerable.Range(1, 5).Select(index => new WeatherForecast { Date = DateTime.Now.AddDays(index), TemperatureC = rng.Next(-20, 55), Summary = Summaries[rng.Next(Summaries.Length)], City = filters.City }); if (filters.SortByTemperature) { forecasts = forecasts.OrderByDescending(f => f.TemperatureC); } return forecasts; }
Jak widać, przekazuję klasę WeatherForecastFilters
jako parametr zapytania. Zauważ, że używam atrybutu [FromQuery]
przed nazwą klasy.
Klasa WeatherForecastFilters
wygląda następująco:
public class WeatherForecastFilters { public bool SortByTemperature { get; set; } public string City { get; set; } }
Jest to standardowa klasa, bez żadnych dodatkowych atrybutów. Zróbmy teraz zapytanie na poniższy adres URL:
GET: /WeatherForecast/GetFiltered?SortByTemperature=true&City=Poznan
Odpowiedź będzie następująca:
Tak więc parametry mogą być przekazywane według ich nazw, nawet jeśli należą do klasy. Co więcej, są one dostępne tylko po ich nazwach, bez żadnego prefiksu klasy, a to oznacza, że wszystkie właściwości muszą mieć unikalne nazwy.
Oto zrzut ekranu z Visual Studio.
Obsługa parametrów zapytania jako właściwości klasy będzie działać, ale tylko wewnątrz tej klasy. Nie będzie działać z zagnieżdżonymi obiektami – ich właściwości nie będą mapowane. Jest to więc raczje zebranie parametrów w jeden obiekt, a nie przekazywanie skomplikowanego zagnieżdżonego obiektu.
Przekazywanie parametrów w nagłówkach
Przekazywanie parametrów w nagłówkach żądania jest mniej popularne, ale również szeroko stosowane. Nie wyświetla się w adresie URL, więc jest mniej zauważalne przez użytkownika. Typowym scenariuszem przekazywania parametrów w nagłówku byłoby podanie parametrów autoryzacji lub identyfikatora żądania nadrzędnego, aby umożliwić jego śledzenie. Rzućmy okiem na ten przykład:
[HttpPost] public IActionResult Post([FromHeader] string parentRequestId) { Console.WriteLine($"Got a header with parentRequestId: {parentRequestId}!"); return new AcceptedResult(); }
Aby wysłać żądanie POST, musimy skorzystać z jakiegoś narzędzia. Dobrym pomysłem jest wykorzystanie Postman-a:
W zakładce Headers można wprowadzić nagłówki żądania, w tym prypadku parentRequestId
.
Przekazywanie parametrów w treści żądania
Najczęstszym sposobem przekazywania danych jest umieszczenie ich w treści żądania. Możemy dodać nagłówek Content-Type
z wartością application/json
i poinformować odbiorcę, jak interpretować tą treść. Rzućmy okiem na poniższy przykład:
[HttpPost] public IActionResult Post([FromBody] WeatherForecast forecast) { Console.WriteLine($"Got a forecast for data: {forecast.Date}!"); return new AcceptedResult(); }
Używamy atrybutu [FromBody]
, aby wskazać, że prognoza zostanie pobrana z treści żądania. W ASP.NET Core w .NET 5 nie musimy deserializować treści żądania, aby przekształcić z typu JSON w obiekt WeatherForecast
, będzie to zrobione za nas automatycznie. Aby wysłać żądanie POST, użyjmy ponownie Postman-a:
Pamiętaj, że rozmiar treści żądania jest ograniczony przez serwer. Może mieć dowolną maksymalną wartość od 1 MB do 2 GB. W ASP.NET Core 5 domyślny maksymalny rozmiar ciała żądania wynosi około 28 MB, ale można to zmienić. A co jeśli chciałbym wysłać większe pliki, ponad 2 GB? Aby to osiągnąć powinieneś rozważyć wysyłanie treści w postaci strumienia lub wysyłanie jej w częściach.
Przekazywanie parametrów w formularzu
Wysyłanie treści w formularzu nie jest zbyt często stosowane, ale jest to najlepsze rozwiązanie, jeśli chcesz np. przesłać plik. Rzućmy okiem na przykład:
[HttpPost] public IActionResult SaveFile([FromForm] string fileName, [FromForm] IFormFile file) { Console.WriteLine($"Got a file with name: {fileName} and size: {file.Length}"); return new AcceptedResult(); }
Ta metoda tak naprawdę nie wysyła pliku, ale pomyślnie otrzymuje plik z żądania. Interfejs IFormFile
służy specjalnie do obsługi pliku.
Wysyłając żądanie, musimy ustawić Content-Type
na application/x-www-form-urlencoded
i w zakładce Body, musimy wybrać plik:
Zobaczmy, co otrzymamy po zdebugowaniu tego kodu:
Plik został poprawnie odczytany. Ciekawostką jest to, że dzięki IFormFile
otrzymujemy nie tylko dane binarne, ale także typ i nazwę pliku. Możesz więc zapytać, dlaczego wysyłam nazwę pliku osobno? Wynika to z tego, że możesz chcieć inaczej nazwać plik na serwerze, niż ten, który wysyłasz.
Mam nadzieję, że podobał Ci się ten post, możesz rzucić okiem na kod opublikowany tutaj na moim Github: