How do I make calls to a REST api using c#?

2019-01-01 01:26发布

问题:

This is the code I have so far:

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

        }
    }
}

The problem is that I think the exception block is being triggered (because when I remove the try-catch, I get a server error (500) message. But I don\'t see the Console.Out lines I put in the catch block.

My Console:

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).

I\'m using Visual Studio 2011 Beta, and .NET 4.5 Beta.

回答1:

The ASP.Net Web API has replaced the WCF Web API previously mentioned.

I thought I\'d post an updated answer since most of these responses are from early 2012, and this thread is one of the top results when doing a Google search for \"call restful service c#\".

Current guidance from Microsoft is to use the Microsoft ASP.NET Web API Client Libraries to consume a RESTful service. This is available as a NuGet package, Microsoft.AspNet.WebApi.Client. You will need to add this NuGet package to your solution.

Here\'s how your example would look when implemented using the ASP.Net Web API Client Library:

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

If you plan on making multiple requests, you should re-use your HttpClient instance. See this question and its answers for more details on why a using statement was not used on the HttpClient instance in this case: Do HttpClient and HttpClientHandler have to be disposed?

For more details, including other examples, go here: http://www.asp.net/web-api/overview/web-api-clients/calling-a-web-api-from-a-net-client

This blog post may also be useful: http://johnnycode.com/2012/02/23/consuming-your-own-asp-net-web-api-rest-service/



回答2:

My suggestion would be to use RestSharp. You can make calls to REST services and have them cast into POCO objects with very little boilerplate code to actually have to parse through the response. This will not solve your particular error, but answers your overall question of how to make calls to REST services. Having to change your code to use it should pay off in the ease of use and robustness moving forward. That is just my 2 cents though



回答3:

Unrelated, I\'m sure, but do wrap your IDisposable objects in using blocks to ensure proper disposal:

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:

Please use below code for your REST api request

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


回答5:

Update for calling a REST API when using .NET 4.5 or .NET Core

I would suggest DalSoft.RestClient (caveat I created it). The reason being because it uses dynamic typing you can wrap everything up in one fluent call including serialization/de-serialization. Below is a working PUT example:

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


回答6:

Check out Refit for making calls to rest services from .net. I\'ve found it very easy to use: https://github.com/paulcbetts/refit

Refit: The automatic type-safe REST library for .NET Core, Xamarin and .NET

Refit is a library heavily inspired by Square\'s Retrofit library, and it turns your REST API into a live interface:

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\");


回答7:

GET:

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

POST:

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

Note: To serialize and desirialze JSON I used Newtonsoft.Json NuGet package.



回答8:

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


回答9:

This is an example code that works for sure. It took me a day to make this to read a set of object from Rest service:

RootObject is the type of the object Im reading from the rest service.

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


回答10:

Since you are using Visual Studio 11 Beta you will want to use the latest and greatest. The new Web Api contains classes for this.

See HttpClient: http://wcf.codeplex.com/wikipage?title=WCF%20HTTP



回答11:

I did It in this simple way, with web Api 2.0. You can remove UseDefaultCredentials.I used it for my own use cases.

            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 ;


回答12:

first step is create the helper class for the http client.

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

    }
}

Then you can use this class in your code.

this is an example of how you call the rest api without bearer using the above class.

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

this an example of how you can call the rest api that require bearer.

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

you can also refer to below repo if you want to see the working example of how it work.

https://github.com/mokh223/callApi



标签: c# api rest