简体   繁体   中英

How to get object on ASP.NET Web API?

This is my Web API and it works fine, I mean when i enter this URL on my browser:

http://localhost:18207/api/values/GetMyClass

I retrieve this result:

<MyClass>
<A>a</A>
<b>b</b>
</MyClass>

My codes:

public class MyClass
{
    public MyClass()
    {
        this.A = "a";
        this.b = "b";
    }
    public string A { get; set; }
    public string b { get; set; }
}


public class ValuesController : ApiController
{
    public MyClass GetMyClass()
    {
        return new MyClass();
    }
}

I have another console application to use my Web API and want to know, How can i have a complex or object type of MyClass?

Codes on my Console are below but it returns string type

 static void Main(string[] args)
    {
        var cts = new CancellationTokenSource();
        MainAsync(args, cts.Token).Wait();
    }

    static async Task MainAsync(string[] args, CancellationToken token)
    {
        string baseAddress = "http://localhost:18207/api/values/GetMyClass";

        using (var httpClient = new HttpClient())
        {
            string response = await httpClient.GetStringAsync(baseAddress);
        }
    }

Your response is probably coming to your console application as JSON (the reason your browser receives it as XML is because of different Accept headers, you can learn about that if you look at Content Negotiation ). So what you need to do is parse the JSON and have it deserialize it into your object. There's quite a few libraries that can do that for you.

First make sure that your MyClass is defined in a Class Library project that both your Web API project and your Console project are referencing. This allows us to reuse the class definition without needing to have a separate copy in both projects.

Next, you need a JSON parsing library. There's one built into .NET, but there's a 3rd party one called Json.NET that is the gold standard. My answer will use that one since I'm more familiar with it. Install the Newtonsoft.Json package into your console app.

Then, change your console app as follows:

using Newtonsoft.Json; // at the top of your file

static void Main(string[] args)
{
    var cts = new CancellationTokenSource();
    MainAsync(args, cts.Token).Wait();
}

static async Task MainAsync(string[] args, CancellationToken token)
{
    string baseAddress = "http://localhost:18207/api/values/GetMyClass";

    using (var httpClient = new HttpClient())
    {
        string json = await httpClient.GetStringAsync(baseAddress);
        MyClass instance = JsonConvert.DeserializeObject<MyClass>(json);
    }
}

The JsonConvert class handles serializing and deserializing the JSON. When deserializing, we just tell is which class to deserialize to and it will attempt to convert the JSON to an instance of that class and return it.

Here is the full solution end-to-end. We are hosting a Web Api that returns MyClass and then we are calling the API and getting data formatted as XML through a console application.

First, we have MyClass annotated as a DataContract :

[DataContract]
public class MyClass
{
    public MyClass()
    {
        this.A = "a";
        this.b = "b";
    }
    [DataMember]
    public string A { get; set; }
    [DataMember]
    public string b { get; set; }
}

The MyClass Web API:

[AllowAnonymous]
public class MyClassController : ApiController
{
    public MyClass Get()
    {
        return new MyClass();
    }
}

and a Console app that uses HttpWebRequest to call the Web Api.

Here's that code (the bottom half is from my original post):

static void Main(string[] args)
    {
        // this is my Web API Endpoint
        var req = (HttpWebRequest)WebRequest.Create("http://localhost:17512/api/MyClass");
        // default is JSON, but you can request XML
        req.Accept = "application/xml";
        req.ContentType = "application/xml";

        var resp = req.GetResponse();
        var sr = new StreamReader(resp.GetResponseStream());
        // read the response stream as Text.
        var xml = sr.ReadToEnd();
        var ms = new MemoryStream(Encoding.UTF8.GetBytes(xml));

        // Deserialize
        var ser = new XmlSerializer(typeof(MyClass));
        var instance = (MyClass)ser.Deserialize(ms);
        Console.WriteLine(instance.A);
        Console.WriteLine(instance.b);

        var final = Console.ReadLine();
    }

NOTE: You'll need to figure out if you want to share a reference to MyClass between the two assemblies or if you just want to have a copy of the code file in each project.

You can use method "GetAsync" which will return object of class "HttpResponseMessage" and then you can call "ReadAsAsync" on Content property. Please see below code:

public class MyClass
{
    public MyClass()
    {
        this.A = "a";
        this.b = "b";
    }
    public string A { get; set; }
    public string b { get; set; }
}

static void Main(string[] args)
    {
        var cts = new CancellationTokenSource();
        MainAsync(args, cts.Token).Wait();
    }

    static async Task MainAsync(string[] args, CancellationToken token)
    {
        string baseAddress = "http://localhost:18207/api/values/GetMyClass";

        using (var httpClient = new HttpClient())
        {

            HttpResponseMessage response = await httpClient.GetAsync(baseAddress);
            response.EnsureSuccessStatusCode();
             MyClass result = await response.Content.ReadAsAsync< MyClass>();

        }
    }

You could just remove XML Formatter inside your WebApiConfig.cs

public static class WebApiConfig
{
    public static void Register(HttpConfiguration config)
    {
        // Removing XML
        config.Formatters.Remove(config.Formatters.XmlFormatter);

        // Allows us to map routes using [Route()] and [RoutePrefix()]
        config.MapHttpAttributeRoutes();

        config.Routes.MapHttpRoute(
            name: "DefaultApi",
            routeTemplate: "api/{controller}/{id}",
            defaults: new { id = RouteParameter.Optional }
        );
    }
}

Then in your controller you would return just like in your example:

public class ValuesController : ApiController
{
    public MyClass GetMyClass()
    {
        return new MyClass();
    }
}

UPDATE 1: I did my answer become more consistent with the question

When making a Request from a Console Application, you could use RestSharp .

var client = new RestClient("http://localhost:18207/");

var request = new RestRequest("api/values/GetMyClass", Method.GET);
var response = client.Execute<MyClass>(request);  
if(response.StatusCode == HttpStatusCode.OK)
  var responseData = response.Data;    

When you execute client.Execute<MyClass>(request) it will deserialize the response into an object of that class. If field names match it should work.

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM