Jak wykonywać połączenia do interfejsu API REST za pomocą C #?


335

Oto kod, który mam do tej pory:

using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System;
using System.Net.Http;
using System.Web;
using System.Net;
using System.IO;

namespace ConsoleProgram
{
    public class Class1
    {
        private const string URL = "https://sub.domain.com/objects.json?api_key=123";
        private const string DATA = @"{""object"":{""name"":""Name""}}";

        static void Main(string[] args)
        {
            Class1.CreateObject();
        }

        private static void CreateObject()
        {
            HttpWebRequest request = (HttpWebRequest)WebRequest.Create(URL);
            request.Method = "POST";
            request.ContentType = "application/json"; 
            request.ContentLength = DATA.Length;
            StreamWriter requestWriter = new StreamWriter(request.GetRequestStream(), System.Text.Encoding.ASCII);
            requestWriter.Write(DATA);
            requestWriter.Close();

             try {
                WebResponse webResponse = request.GetResponse();
                Stream webStream = webResponse.GetResponseStream();
                StreamReader responseReader = new StreamReader(webStream);
                string response = responseReader.ReadToEnd();
                Console.Out.WriteLine(response);
                responseReader.Close();
            } catch (Exception e) {
                Console.Out.WriteLine("-----------------");
                Console.Out.WriteLine(e.Message);
            }

        }
    }
}

Problem polega na tym, że myślę, że uruchamiany jest blok wyjątków (ponieważ gdy usuwam try-catch, pojawia się komunikat o błędzie serwera (500). Ale nie widzę konsoli. Linie wstawiam w bloku catch.

Moja konsola:

The thread 'vshost.NotifyLoad' (0x1a20) has exited with code 0 (0x0).
The thread '<No Name>' (0x1988) has exited with code 0 (0x0).
The thread 'vshost.LoadReference' (0x1710) has exited with code 0 (0x0).
'ConsoleApplication1.vshost.exe' (Managed (v4.0.30319)): Loaded 'c:\users\l. preston sego iii\documents\visual studio 11\Projects\ConsoleApplication1\ConsoleApplication1\bin\Debug\ConsoleApplication1.exe', Symbols loaded.
'ConsoleApplication1.vshost.exe' (Managed (v4.0.30319)): Loaded 'C:\Windows\Microsoft.Net\assembly\GAC_MSIL\System.Configuration\v4.0_4.0.0.0__b03f5f7f11d50a3a\System.Configuration.dll', Skipped loading symbols. Module is optimized and the debugger option 'Just My Code' is enabled.
A first chance exception of type 'System.Net.WebException' occurred in System.dll
The thread 'vshost.RunParkingWindow' (0x184c) has exited with code 0 (0x0).
The thread '<No Name>' (0x1810) has exited with code 0 (0x0).
The program '[2780] ConsoleApplication1.vshost.exe: Program Trace' has exited with code 0 (0x0).
The program '[2780] ConsoleApplication1.vshost.exe: Managed (v4.0.30319)' has exited with code 0 (0x0).

Używam Visual Studio 2011 Beta i .NET 4.5 Beta.


Czy umieściłeś tam również punkty przerwania, aby zobaczyć, gdzie dokładnie się wysadza?
NotMe

wynika to z okna wyjściowego, ale nie konsoli
Serj-Tm

5
MSDN miał doskonały artykuł na temat budowania usług RESTful: msdn.microsoft.com/library/dd203052.aspx ... oraz klientów RESTful: msdn.microsoft.com/en-us/magazine/ee309509.aspx
Lynn Crumbling

@ChrisLively co to ma wspólnego z IE? = \ Wysadza w powietrze na żądanie. Linia GetResponse.
NullVoxPopuli

@TheLindyHop; Absolutnie niczego. Źle przeczytałem.
NotMe

Odpowiedzi:


427

Interfejs API sieci Web ASP.Net zastąpił wcześniej wspomniany interfejs API sieci WCF.

Pomyślałem, że opublikuję zaktualizowaną odpowiedź, ponieważ większość tych odpowiedzi pochodzi z początku 2012 r., A ten wątek jest jednym z najlepszych wyników podczas wyszukiwania w Google hasła „zadzwoń do usługi odpoczynku c #”.

Obecne wskazówki od Microsoft to korzystanie z bibliotek klienta Microsoft ASP.NET Web API do korzystania z usługi RESTful. Jest on dostępny jako pakiet NuGet, Microsoft.AspNet.WebApi.Client. Musisz dodać ten pakiet NuGet do swojego rozwiązania.

Oto jak wyglądałby twój przykład po wdrożeniu przy użyciu biblioteki klienta ASP.Net Web API:

using System;
using System.Collections.Generic;
using System.Net.Http;
using System.Net.Http.Headers; 

namespace ConsoleProgram
{
    public class DataObject
    {
        public string Name { get; set; }
    }

    public class Class1
    {
        private const string URL = "https://sub.domain.com/objects.json";
        private string urlParameters = "?api_key=123";

        static void Main(string[] args)
        {
            HttpClient client = new HttpClient();
            client.BaseAddress = new Uri(URL);

            // Add an Accept header for JSON format.
            client.DefaultRequestHeaders.Accept.Add(
            new MediaTypeWithQualityHeaderValue("application/json"));

            // List data response.
            HttpResponseMessage response = client.GetAsync(urlParameters).Result;  // Blocking call! Program will wait here until a response is received or a timeout occurs.
            if (response.IsSuccessStatusCode)
            {
                // Parse the response body.
                var dataObjects = response.Content.ReadAsAsync<IEnumerable<DataObject>>().Result;  //Make sure to add a reference to System.Net.Http.Formatting.dll
                foreach (var d in dataObjects)
                {
                    Console.WriteLine("{0}", d.Name);
                }
            }
            else
            {
                Console.WriteLine("{0} ({1})", (int)response.StatusCode, response.ReasonPhrase);
            }

            //Make any other calls using HttpClient here.

            //Dispose once all HttpClient calls are complete. This is not necessary if the containing object will be disposed of; for example in this case the HttpClient instance will be disposed automatically when the application terminates so the following call is superfluous.
            client.Dispose();
        }
    }
}

Jeśli planujesz składać wiele żądań, powinieneś ponownie użyć instancji HttpClient. Zobacz to pytanie i jego odpowiedzi, aby uzyskać więcej informacji na temat tego, dlaczego w wystąpieniu HttpClient nie użyto instrukcji using: Czy HttpClient i HttpClientHandler muszą zostać usunięte?

Aby uzyskać więcej informacji, w tym inne przykłady, przejdź tutaj: http://www.asp.net/web-api/overview/web-api-clients/calling-a-web-api-from-a-net-client

Ten post na blogu może być również przydatny: http://johnnycode.com/2012/02/23/consuming-your-own-asp-net-web-api-rest-service/


6
Dzięki! Musiałem zainstalować pakiet NuGet klienta WebApi, aby to działało dla mnie: Zainstaluj pakiet Microsoft.AspNet.WebApi.Client
Ev.

3
Jeśli musisz wyśmiewać swoją integrację REST, nawet z bibliotekami klienckimi nadal nie jest to łatwe. Wypróbuj RestSharp?
Rob Church

6
Aby ta odpowiedź była jeszcze lepsza niż jest już wcześniej, należy zawinąć deklarację HttpClient w instrukcję using, aby lepiej zarządzać zasobami :)
Daniel Siebert

7
Próbowano użyć, ale nie można użyć ReadAsAsync (), pojawia się błąd „HttpContent nie zawiera definicji„ ReadAsAsync ”i żadnej metody rozszerzenia.
Robert Green MBA

7
@RobertGreenMBA: Aby uzyskać metodę rozszerzenia ReadAsAsync(), dodaj odwołanie do System.Net.Http.Formatting.dll. (Intuicyjny, prawda?)
Arin

122

Moją sugestią byłoby użycie RestSharp . Możesz nawiązywać połączenia z usługami REST i zlecać ich rzutowanie na obiekty POCO z bardzo małym kodem wzorcowym, aby faktycznie musiały zostać przeanalizowane przez odpowiedź. To nie rozwiąże konkretnego błędu, ale odpowiada na ogólne pytanie, jak wykonywać połączenia z usługami REST. Konieczność zmiany kodu, aby go używać, powinna się opłacić w łatwości użytkowania i niezawodności. To tylko moje 2 centy

Przykład:

namespace RestSharpThingy
{
    using System;
    using System.Collections.Generic;
    using System.IO;
    using System.Linq;
    using System.Net;
    using System.Reflection;

    using RestSharp;

    public static class Program
    {
        public static void Main()
        {
            Uri baseUrl = new Uri("https://httpbin.org/");
            IRestClient client = new RestClient(baseUrl);
            IRestRequest request = new RestRequest("get", Method.GET) { Credentials = new NetworkCredential("testUser", "P455w0rd") };

            request.AddHeader("Authorization", "Bearer qaPmk9Vw8o7r7UOiX-3b-8Z_6r3w0Iu2pecwJ3x7CngjPp2fN3c61Q_5VU3y0rc-vPpkTKuaOI2eRs3bMyA5ucKKzY1thMFoM0wjnReEYeMGyq3JfZ-OIko1if3NmIj79ZSpNotLL2734ts2jGBjw8-uUgKet7jQAaq-qf5aIDwzUo0bnGosEj_UkFxiJKXPPlF2L4iNJSlBqRYrhw08RK1SzB4tf18Airb80WVy1Kewx2NGq5zCC-SCzvJW-mlOtjIDBAQ5intqaRkwRaSyjJ_MagxJF_CLc4BNUYC3hC2ejQDoTE6HYMWMcg0mbyWghMFpOw3gqyfAGjr6LPJcIly__aJ5__iyt-BTkOnMpDAZLTjzx4qDHMPWeND-TlzKWXjVb5yMv5Q6Jg6UmETWbuxyTdvGTJFzanUg1HWzPr7gSs6GLEv9VDTMiC8a5sNcGyLcHBIJo8mErrZrIssHvbT8ZUPWtyJaujKvdgazqsrad9CO3iRsZWQJ3lpvdQwucCsyjoRVoj_mXYhz3JK3wfOjLff16Gy1NLbj4gmOhBBRb8rJnUXnP7rBHs00FAk59BIpKLIPIyMgYBApDCut8V55AgXtGs4MgFFiJKbuaKxq8cdMYEVBTzDJ-S1IR5d6eiTGusD5aFlUkAs9NV_nFw");
            request.AddParameter("clientId", 123);

            IRestResponse<RootObject> response = client.Execute<RootObject>(request);

            if (response.IsSuccessful)
            {
                response.Data.Write();
            }
            else
            {
                Console.WriteLine(response.ErrorMessage);
            }

            Console.WriteLine();

            string path = Assembly.GetExecutingAssembly().Location;
            string name = Path.GetFileName(path);

            request = new RestRequest("post", Method.POST);
            request.AddFile(name, File.ReadAllBytes(path), name, "application/octet-stream");
            response = client.Execute<RootObject>(request);
            if (response.IsSuccessful)
            {
                response.Data.Write();
            }
            else
            {
                Console.WriteLine(response.ErrorMessage);
            }

            Console.ReadLine();
        }

        private static void Write(this RootObject rootObject)
        {
            Console.WriteLine("clientId: " + rootObject.args.clientId);
            Console.WriteLine("Accept: " + rootObject.headers.Accept);
            Console.WriteLine("AcceptEncoding: " + rootObject.headers.AcceptEncoding);
            Console.WriteLine("AcceptLanguage: " + rootObject.headers.AcceptLanguage);
            Console.WriteLine("Authorization: " + rootObject.headers.Authorization);
            Console.WriteLine("Connection: " + rootObject.headers.Connection);
            Console.WriteLine("Dnt: " + rootObject.headers.Dnt);
            Console.WriteLine("Host: " + rootObject.headers.Host);
            Console.WriteLine("Origin: " + rootObject.headers.Origin);
            Console.WriteLine("Referer: " + rootObject.headers.Referer);
            Console.WriteLine("UserAgent: " + rootObject.headers.UserAgent);
            Console.WriteLine("origin: " + rootObject.origin);
            Console.WriteLine("url: " + rootObject.url);
            Console.WriteLine("data: " + rootObject.data);
            Console.WriteLine("files: ");
            foreach (KeyValuePair<string, string> kvp in rootObject.files ?? Enumerable.Empty<KeyValuePair<string, string>>())
            {
                Console.WriteLine("\t" + kvp.Key + ": " + kvp.Value);
            }
        }
    }

    public class Args
    {
        public string clientId { get; set; }
    }

    public class Headers
    {
        public string Accept { get; set; }

        public string AcceptEncoding { get; set; }

        public string AcceptLanguage { get; set; }

        public string Authorization { get; set; }

        public string Connection { get; set; }

        public string Dnt { get; set; }

        public string Host { get; set; }

        public string Origin { get; set; }

        public string Referer { get; set; }

        public string UserAgent { get; set; }
    }

    public class RootObject
    {
        public Args args { get; set; }

        public Headers headers { get; set; }

        public string origin { get; set; }

        public string url { get; set; }

        public string data { get; set; }

        public Dictionary<string, string> files { get; set; }
    }
}

6
RestSharp i JSON.NET to zdecydowanie najlepsza droga. Zauważyłem, że zestaw narzędzi MS jest brakujący i prawdopodobnie zawiedzie.
cbuteau

2
Kolejny głos na RestSharp, ponieważ możesz wyśmiewać go do testowania znacznie, znacznie łatwiej niż biblioteki klienta WebApi.
Rob Church

1
dla użytkowników mono - RestSharp wydaje się korzystać z apletu System.Net WebRequest - co z mojego doświadczenia nie jest tak niezawodne jak implementacje .net. („losowy” zawiesza się)
Tom

3
Przydałby się przykład w tej odpowiedzi.
Caltor

2
Brak przykładu sprawia, że ​​ten post nie jest pomocny!
smac2020

39

Niepowiązane, jestem pewien, ale owiń IDisposableobiekty w usingbloki, aby zapewnić właściwą utylizację:

using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System;
using System.Web;
using System.Net;
using System.IO;

namespace ConsoleProgram
{
    public class Class1
    {
        private const string URL = "https://sub.domain.com/objects.json?api_key=123";
        private const string DATA = @"{""object"":{""name"":""Name""}}";

        static void Main(string[] args)
        {
            Class1.CreateObject();
        }

        private static void CreateObject()
        {
            HttpWebRequest request = (HttpWebRequest)WebRequest.Create(URL);
            request.Method = "POST";
            request.ContentType = "application/json";
            request.ContentLength = DATA.Length;
            using (Stream webStream = request.GetRequestStream())
            using (StreamWriter requestWriter = new StreamWriter(webStream, System.Text.Encoding.ASCII))
            {
                requestWriter.Write(DATA);
            }

            try
            {
                WebResponse webResponse = request.GetResponse();
                using (Stream webStream = webResponse.GetResponseStream() ?? Stream.Null)
                using (StreamReader responseReader = new StreamReader(webStream))
                {
                    string response = responseReader.ReadToEnd();
                    Console.Out.WriteLine(response);
                }
            }
            catch (Exception e)
            {
                Console.Out.WriteLine("-----------------");
                Console.Out.WriteLine(e.Message);
            }

        }
    }
}

4
Dobra odpowiedź, która nie korzysta z żadnych dodatkowych pakietów poza zwykłym środowiskiem .NET.
palswim

@Jesse C. Slicer.. dlaczego trafiłem na błąd 404 w WebResponse webResponse = request.GetResponse ();
Goh Han

2
Ponieważ nie znaleziono zasobu? Istnieje wiele WIELU powodów, aby zdobyć 404.
Jesse C. Slicer

1
To świetne rozwiązanie @ JesseC.Slicer. Jestem w stanie zastosować ten kod, aby pobrać token i zobaczyć go z konsoli. Czy masz jakieś wskazówki, które pozwolą mi wziąć ten token do uwierzytelnienia / logowania? Chcę użyć polecenia GET do pobrania niektórych danych, ale tylko wtedy, gdy jestem zalogowany. Gdzie mogę dowiedzieć się więcej na ten temat? Dzięki!
Paul Laguna

18

Oto kilka różnych sposobów wywoływania zewnętrznego interfejsu API w języku C # (aktualizacja 2019).

Wbudowane sposoby .NET:

  • WebRequest i WebClient - pełne interfejsy API i dokumentacja Microsoft nie są łatwe do naśladowania
  • HttpClient - najnowsze dziecko .NET w bloku i znacznie prostsze w użyciu niż powyżej.

Darmowe pakiety NuGet typu open source , które szczerze mówiąc mają znacznie lepsze wrażenia programistyczne niż wbudowani klienci .NET:

  • ServiceStack.Text (1k github stars, 7m pobrania Nuget) (*) - szybki, lekki i odporny.
  • RestSharp (6 tys. Gwiazdek github, 23 mln pobrań Nuget) (*) - prosty klient REST i HTTP API
  • Flurl (1,7 tys. Gwiazd github, 3m pobrania Nuget) (*) - płynna, przenośna, testowalna biblioteka klienta HTTP

Wszystkie powyższe pakiety zapewniają doskonałe wrażenia programistyczne (tj. Zwięzłe, łatwe API) i są dobrze utrzymane.

(*) na sierpień 2019 r

Przykład: pobieranie elementu czynności do wykonania z interfejsu API fałszywego odpoczynku za pomocą ServiceStack.Text. Pozostałe biblioteki mają bardzo podobną składnię.

class Program
{
    static void Main(string[] args)
    {
        // fake rest API
        string url = "https://jsonplaceholder.typicode.com/todos/1";

        // GET data from api & map to Poco
        var todo =  url.GetJsonFromUrl().FromJson<Todo>();

        // print result to screen
        todo.PrintDump();
    }
    public class Todo
    {
        public int UserId { get; set; }
        public int Id { get; set; }
        public string Title { get; set; }
        public bool Completed { get; set; }
    }

}

Uruchomienie powyższego przykładu w aplikacji .NET Core Console daje następujące wyniki.

wprowadź opis zdjęcia tutaj

Zainstaluj te pakiety za pomocą NuGet

Install-Package ServiceStack.Text, or

Install-Package RestSharp, or

Install-Package Flurl.Http

17

Użyj poniższego kodu do żądania interfejsu API REST

using System;
using System.Collections.Generic;
using System.IO;
using System.Linq;
using System.Net;
using System.Net.Http;
using System.Text;
using System.Json;

namespace ConsoleApplication2
{
    class Program
    {
        private const string URL = "https://XXXX/rest/api/2/component";
        private const string DATA = @"{
    ""name"": ""Component 2"",
    ""description"": ""This is a JIRA component"",
    ""leadUserName"": ""xx"",
    ""assigneeType"": ""PROJECT_LEAD"",
    ""isAssigneeTypeValid"": false,
    ""project"": ""TP""}";

        static void Main(string[] args)
        {
            AddComponent();
        }

        private static void AddComponent()
        {
            System.Net.Http.HttpClient client = new System.Net.Http.HttpClient();
            client.BaseAddress = new System.Uri(URL);
            byte[] cred = UTF8Encoding.UTF8.GetBytes("username:password");
            client.DefaultRequestHeaders.Authorization = new System.Net.Http.Headers.AuthenticationHeaderValue("Basic", Convert.ToBase64String(cred));
            client.DefaultRequestHeaders.Accept.Add(new System.Net.Http.Headers.MediaTypeWithQualityHeaderValue("application/json"));

            System.Net.Http.HttpContent content = new StringContent(DATA, UTF8Encoding.UTF8, "application/json");
            HttpResponseMessage messge = client.PostAsync(URL, content).Result;
            string description = string.Empty;
            if (messge.IsSuccessStatusCode)
            {
                string result = messge.Content.ReadAsStringAsync().Result;
                description = result;
            }
        }
    }
}

-1: .net jest platformą zarządzaną, ale HttpClient nie jest zarządzany (co oznacza, że ​​MUSISZ użyć, aby powiedzieć mu, kiedy może pozbyć się tych niezarządzanych wskaźników). Bez niego Twój kod nie będzie skalowany do kilku użytkowników (i tak, jest to ważne, tak ważne, że język ma określone słowo kluczowe, aby sobie z tym poradzić).
JCKödel,

5
@ JCKödel - Nie jesteś absolutnie w tym miejscu i powinieneś przeczytać ten stackoverflow.com/a/22561368 - HttpClient został zaprojektowany do ponownego wykorzystania dla wielu połączeń
hB0

1
Tak @ JCKödel, przeczytaj ten artykuł stackoverflow.com/questions/15705092/…
Nathan

11

Chciałbym udostępnić moje rozwiązanie w programie ASP.NET Core

using Newtonsoft.Json;
using System;
using System.Net.Http;
using System.Text;
using System.Threading.Tasks;
using System.Configuration;

namespace WebApp
{
    public static class HttpHelper
    {
        // In my case this is https://localhost:44366/
        private static readonly string apiBasicUri = ConfigurationManager.AppSettings["apiBasicUri"];

        public static async Task Post<T>(string url, T contentValue)
        {
            using (var client = new HttpClient())
            {
                client.BaseAddress = new Uri(apiBasicUri);
                var content = new StringContent(JsonConvert.SerializeObject(contentValue), Encoding.UTF8, "application/json");
                var result = await client.PostAsync(url, content);
                result.EnsureSuccessStatusCode();
            }
        }

        public static async Task Put<T>(string url, T stringValue)
        {
            using (var client = new HttpClient())
            {
                client.BaseAddress = new Uri(apiBasicUri);
                var content = new StringContent(JsonConvert.SerializeObject(stringValue), Encoding.UTF8, "application/json");
                var result = await client.PutAsync(url, content);
                result.EnsureSuccessStatusCode();
            }
        }

        public static async Task<T> Get<T>(string url)
        {
            using (var client = new HttpClient())
            {
                client.BaseAddress = new Uri(apiBasicUri);
                var result = await client.GetAsync(url);
                result.EnsureSuccessStatusCode();
                string resultContentString = await result.Content.ReadAsStringAsync();
                T resultContent = JsonConvert.DeserializeObject<T>(resultContentString);
                return resultContent;
            }
        }

        public static async Task Delete(string url)
        {
            using (var client = new HttpClient())
            {
                client.BaseAddress = new Uri(apiBasicUri);
                var result = await client.DeleteAsync(url);
                result.EnsureSuccessStatusCode();
            }
        }
    }
}

Aby opublikować, użyj czegoś takiego:

await HttpHelper.Post<Setting>($"/api/values/{id}", setting);

Przykład usunięcia:

await HttpHelper.Delete($"/api/values/{id}");

Przykład, aby uzyskać listę:

List<ClaimTerm> claimTerms = await HttpHelper.Get<List<ClaimTerm>>("/api/values/");

Przykład uzyskania tylko jednego:

ClaimTerm processedClaimImage = await HttpHelper.Get<ClaimTerm>($"/api/values/{id}");

2
To naprawdę niezły kawałek kodu, chociaż nie powinieneś używać httpclient wewnątrz bloku używającego. zobacz aspnetmonsters.com/2016/08/2016-08-27-httpclientwrong
Myke Black

9

Aktualizacja do wywoływania interfejsu API REST podczas korzystania z .NET 4.5 lub .NET Core

Sugerowałbym DalSoft.RestClient (zastrzeżenie, że go stworzyłem). Ponieważ używa dynamicznego pisania, możesz wszystko zawrzeć w jednym płynnym wywołaniu, w tym serializacji / deserializacji. Poniżej znajduje się działający przykład PUT:

dynamic client = new RestClient("http://jsonplaceholder.typicode.com");

var post = new Post { title = "foo", body = "bar", userId = 10 };

var result = await client.Posts(1).Put(post);

5

DOSTAĆ:

// GET JSON Response
public WeatherResponseModel GET(string url) {
    WeatherResponseModel model = new WeatherResponseModel();
    HttpWebRequest request = (HttpWebRequest)WebRequest.Create(url);
    try {
        WebResponse response = request.GetResponse();
        using(Stream responseStream = response.GetResponseStream()) {
            StreamReader reader = new StreamReader(responseStream, Encoding.UTF8);
            model = JsonConvert.DeserializeObject < WeatherResponseModel > (reader.ReadToEnd());
        }
    } catch (WebException ex) {
        WebResponse errorResponse = ex.Response;
        using(Stream responseStream = errorResponse.GetResponseStream()) {
            StreamReader reader = new StreamReader(responseStream, Encoding.GetEncoding("utf-8"));
            String errorText = reader.ReadToEnd();
            // log errorText
        }
        throw;
    }

    return model;
}

POCZTA:

// POST a JSON string
void POST(string url, string jsonContent) {
    HttpWebRequest request = (HttpWebRequest)WebRequest.Create(url);
    request.Method = "POST";

    System.Text.UTF8Encoding encoding = new System.Text.UTF8Encoding();
    Byte[]byteArray = encoding.GetBytes(jsonContent);

    request.ContentLength = byteArray.Length;
    request.ContentType =  @ "application/json";

    using(Stream dataStream = request.GetRequestStream()) {
        dataStream.Write(byteArray, 0, byteArray.Length);
    }
    long length = 0;
    try {
        using(HttpWebResponse response = (HttpWebResponse)request.GetResponse()) {
            // got response
            length = response.ContentLength;
        }
    } catch (WebException ex) {
        WebResponse errorResponse = ex.Response;
        using(Stream responseStream = errorResponse.GetResponseStream()) {
            StreamReader reader = new StreamReader(responseStream, Encoding.GetEncoding("utf-8"));
            String errorText = reader.ReadToEnd();
            // log errorText
        }
        throw;
    }
}

Uwaga: Do serializacji i pragnienia JSON użyłem pakietu Newtonsoft.Json NuGet.


4

Sprawdź Refit do nawiązywania połączeń z usługami odpoczynku z .net. Uważam, że jest bardzo łatwy w użyciu: https://github.com/paulcbetts/refit

Remont: Automatyczna biblioteka REST bezpieczna dla typów .NET Core, Xamarin i .NET

Refit to biblioteka silnie zainspirowana biblioteką Square Retrofit, która zmienia interfejs API REST w interfejs na żywo:

public interface IGitHubApi {
        [Get("/users/{user}")]
        Task<User> GetUser(string user); } The RestService class generates an implementation of IGitHubApi that uses HttpClient to make its calls:

var gitHubApi = RestService.For<IGitHubApi>("https://api.github.com");

var octocat = await gitHubApi.GetUser("octocat");

Czy wiesz, czy Refit używa refleksji, aby to osiągnąć? Nigdzie nie mogę znaleźć informacji.
tfrascaroli

przepraszam @tfrascaroli Nie jestem pewien, czy jest pod ręką.
patrickbadley,

2

To jest przykładowy kod, który na pewno działa. Zajęło mi dzień, aby to zrobić, aby odczytać zestaw obiektów z usługi Rest:

RootObject to typ obiektu, który czytam z usługi rest.

string url = @"http://restcountries.eu/rest/v1";
DataContractJsonSerializer serializer = new DataContractJsonSerializer(typeof(IEnumerable<RootObject>));
WebClient syncClient = new WebClient();
string content = syncClient.DownloadString(url);

using (MemoryStream memo = new MemoryStream(Encoding.Unicode.GetBytes(content)))
{
    IEnumerable<RootObject> countries = (IEnumerable<RootObject>)serializer.ReadObject(memo);    
}

Console.Read();

1
    var TakingRequset = WebRequest.Create("http://xxx.acv.com/MethodName/Get");
    TakingRequset.Method = "POST";
    TakingRequset.ContentType = "text/xml;charset=utf-8";
    TakingRequset.PreAuthenticate = true;

    //---Serving Request path query
     var PAQ = TakingRequset.RequestUri.PathAndQuery;

    //---creating your xml as per the host reqirement
    string xmlroot=@"<root><childnodes>passing parameters</childnodes></root>";
    string xmlroot2=@"<root><childnodes>passing parameters</childnodes></root>";

    //---Adding Headers as requested by host 
    xmlroot2 = (xmlroot2 + "XXX---");
    //---Adding Headers Value as requested by host 
  //  var RequestheaderVales = Method(xmlroot2);

    WebProxy proxy = new WebProxy("XXXXX-----llll", 8080);
    proxy.Credentials = new NetworkCredential("XXX---uuuu", "XXX----", "XXXX----");
    System.Net.WebRequest.DefaultWebProxy = proxy;


    // Adding The Request into Headers
    TakingRequset.Headers.Add("xxx", "Any Request Variable ");
    TakingRequset.Headers.Add("xxx", "Any Request Variable");

    byte[] byteData = Encoding.UTF8.GetBytes(xmlroot);
    TakingRequset.ContentLength = byteData.Length;

    using (Stream postStream = TakingRequset.GetRequestStream())
    {
        postStream.Write(byteData, 0, byteData.Length);
        postStream.Close();
    }



    StreamReader stredr = new StreamReader(TakingRequset.GetResponse().GetResponseStream());
    string response = stredr.ReadToEnd();

1

Zrobiłem to w prosty sposób, dzięki web Api 2.0. Możesz usunąć UseDefaultCredentials.I użyłem go do moich własnych przypadków użycia.

            List<YourObject> listObjects = new List<YourObject>();


            string response = "";
            using (var client = new WebClient() { UseDefaultCredentials = true })
            {
                 response = client.DownloadString(apiUrl);
            }

            listObjects = JsonConvert.DeserializeObject<List<YourObject>>(response);
            return listObjects ;


0

Zaznaczona tutaj odpowiedź sugeruje użycie HttpClient bezpośrednio i usunięcie go. To może działać, ale dość łatwo wpaść w problemy z HttpClient, jeśli nie używasz go poprawnie. Jeśli zamierzasz używać HttpClient, lepiej oddać tworzenie / usuwanie HttpClients bibliotece innej firmy, która używa wzorca fabrycznego. RestClient.Net jest jedną z takich bibliotek.

Ma bardzo podstawową fabrykę HttpClient, dzięki czemu nie napotykasz problemu wyczerpania gniazda,

public class DefaultHttpClientFactory : IHttpClientFactory, IDisposable
{
    #region Fields
    private bool disposed;
    private readonly ConcurrentDictionary<string, Lazy<HttpClient>> _httpClients;
    private readonly Func<string, Lazy<HttpClient>> _createClientFunc;
    #endregion

    #region Constructor
    public DefaultHttpClientFactory() : this(null)
    {
    }

    public DefaultHttpClientFactory(Func<string, Lazy<HttpClient>> createClientFunc)
    {
        _createClientFunc = createClientFunc;
        _httpClients = new ConcurrentDictionary<string, Lazy<HttpClient>>();

        if (_createClientFunc != null) return;
        _createClientFunc = name =>
        {
            return new Lazy<HttpClient>(() => new HttpClient(), LazyThreadSafetyMode.ExecutionAndPublication);
        };
    }
    #endregion

    #region Implementation
    public HttpClient CreateClient(string name)
    {
        if (name == null)
        {
            throw new ArgumentNullException(nameof(name));
        }

        return _httpClients.GetOrAdd(name, _createClientFunc).Value;
    }

    public void Dispose()
    {
        if (disposed) return;
        disposed = true;

        foreach (var name in _httpClients.Keys)
        {
            _httpClients[name].Value.Dispose();
        }
    }
    #endregion
}

Ale implementacja Microsoft IHttpClientFactory może być również używana do najnowszych i najlepszych:

    var serviceCollection = new ServiceCollection();
    var baseUri = new Uri("http://www.test.com");
    serviceCollection.AddSingleton(typeof(ISerializationAdapter), typeof(NewtonsoftSerializationAdapter));
    serviceCollection.AddSingleton(typeof(ILogger), typeof(ConsoleLogger));
    serviceCollection.AddSingleton(typeof(IClient), typeof(Client));
    serviceCollection.AddDependencyInjectionMapping();
    serviceCollection.AddTransient<TestHandler>();

    //Make sure the HttpClient is named the same as the Rest Client
    serviceCollection.AddSingleton<IClient>(x => new Client(name: clientName, httpClientFactory: x.GetRequiredService<IHttpClientFactory>()));
    serviceCollection.AddHttpClient(clientName, (c) => { c.BaseAddress = baseUri; })
        .AddHttpMessageHandler<TestHandler>();

    var serviceProvider = serviceCollection.BuildServiceProvider();
    var client = serviceProvider.GetService<IClient>();
    await client.GetAsync<object>();

RestClient.Net bierze pod uwagę wstrzykiwanie zależności konta, kpiny, kontenery IoC, testowanie jednostek, a przede wszystkim jest szybkie. Polowałem wokoło, a jedynym innym klientem, który wydaje się działać z podobną wydajnością, jest Flurl


-2

pierwszym krokiem jest utworzenie klasy pomocniczej dla klienta http.

using System;
using System.Collections.Generic;
using System.Linq;
using System.Net.Http;
using System.Net.Http.Headers;
using System.Threading.Tasks;

namespace callApi.Helpers
{
    public class CallApi
    {
        private readonly Uri BaseUrlUri;
        private HttpClient client = new HttpClient();

        public CallApi(string baseUrl)
        {
            BaseUrlUri = new Uri(baseUrl);
            client.BaseAddress = BaseUrlUri;
            client.DefaultRequestHeaders.Accept.Clear();
            client.DefaultRequestHeaders.Accept.Add(
                new MediaTypeWithQualityHeaderValue("application/json"));

        }

        public HttpClient getClient()
        {
            return client;
        }

        public HttpClient getClientWithBearer(string token)
        {
            client.DefaultRequestHeaders.Authorization = new AuthenticationHeaderValue("Bearer", token);
            return client;
        }

    }
}

Następnie możesz użyć tej klasy w swoim kodzie.

jest to przykład tego, jak wywołać resztę interfejsu API bez nośnika przy użyciu powyższej klasy.

// GET api/values
[HttpGet]
public async Task<ActionResult<string>> postNoBearerAsync(string email, string password,string baseUrl, string action)
{
    var request = new LoginRequest
    {
        email = email,
        password = password
    };

    var callApi = new CallApi(baseUrl);
    var client = callApi.getClient();
    HttpResponseMessage response = await client.PostAsJsonAsync(action, request);
    if (response.IsSuccessStatusCode)
        return Ok(await response.Content.ReadAsAsync<string>());
    else
        return NotFound();
}

jest to przykład tego, jak można wywołać pozostałe API, które wymagają okaziciela.

// GET api/values
[HttpGet]
public async Task<ActionResult<string>> getUseBearerAsync(string token, string baseUrl, string action)
{
    var callApi = new CallApi(baseUrl);
    var client = callApi.getClient();
    client.DefaultRequestHeaders.Authorization = new AuthenticationHeaderValue("Bearer", token);
    HttpResponseMessage response = await client.GetAsync(action);
    if (response.IsSuccessStatusCode)
    {
        return Ok(await response.Content.ReadAsStringAsync());

    }
    else
        return NotFound();
}

możesz również zapoznać się z poniższym repozytorium, jeśli chcesz zobaczyć działający przykład jego działania.

https://github.com/mokh223/callApi

Korzystając z naszej strony potwierdzasz, że przeczytałeś(-aś) i rozumiesz nasze zasady używania plików cookie i zasady ochrony prywatności.
Licensed under cc by-sa 3.0 with attribution required.