Suamere
Suamere

Reputation: 6248

Web API won't return object

I have a very simple Web API application. Everything seems to be working with basic types. You won't be finding any fancy authentication or anything, but I can run this on IIS Express with:

When I start this web application, I can point the browser to GetNumber and see 15 in the window. However, when I point to GetObject, I see WebAPI.DemoApp.SampleObject. That doesn't necessarily bother me, except I'm confused why.

I have code (Shown Further Down) that supposedly forces Web API to return JSON. So either the GetNumber or GetObject I would expect to return something like (Pseudocode):

Either way, my Console Application's ReadAsStringAsync produces the same results, and ReadAsAsync produces the error:

My console app is very simple:

static void Main(string[] args)
{

    using (var client = new HttpClient())
    {

        client.BaseAddress = new Uri("http://localhost:25095/");
        client.DefaultRequestHeaders.Accept.Clear();
        client.DefaultRequestHeaders.Accept.Add(new MediaTypeWithQualityHeaderValue("application/json"));

        //HttpResponseMessage response = client.GetAsync("Workbench/GetObject").Result;
        HttpResponseMessage response = client.GetAsync("Workbench/GetNumber").Result;

        //SampleObject getObject = response.Content.ReadAsAsync<SampleObject>().Result;
        var getNumber = response.Content.ReadAsStringAsync().Result;
        Console.WriteLine(getNumber);

        Console.Read();

    }
}

I want to mention that this project began as a generated ASP.Net Web API Project (Without Azure). It has all been downhill from there. I THOUGHT I was forcing Web API to return only JSON, but none of this is working as I would expect.

Literally all code is in the Global.asax.cs file, and I copy/pasted it below:

using System;
using System.Collections.Generic;
using System.Net.Http;
using System.Net.Http.Formatting;
using System.Net.Http.Headers;
using System.Runtime.Serialization;
using System.Web.Http;
using System.Web.Mvc;

namespace WebAPI.DemoApp
{
    public class WebApiApplication : System.Web.HttpApplication
    {
        protected void Application_Start()
        {
            System.Web.Routing.RouteTable.Routes.MapRoute(
                name: "Default",
                url: "{controller}/{action}",
                defaults: new { controller = "Workbench", action = "GetObject", id = UrlParameter.Optional }
            );

            var jsonFormatter = new JsonMediaTypeFormatter();
            GlobalConfiguration.Configuration.Services.Replace(typeof(IContentNegotiator), new JsonContentNegotiator(jsonFormatter));
        }
    }

    public class JsonContentNegotiator : IContentNegotiator
    {
        private readonly JsonMediaTypeFormatter _jsonFormatter;

        public JsonContentNegotiator(JsonMediaTypeFormatter formatter)
        {
            _jsonFormatter = formatter;
        }

        public ContentNegotiationResult Negotiate(Type type, HttpRequestMessage request, IEnumerable<MediaTypeFormatter> formatters)
        {
            var result = new ContentNegotiationResult(_jsonFormatter, new MediaTypeHeaderValue("application/json"));
            return result;
        }
    }

    public class WorkbenchController : Controller
    {
        public SampleObject GetObject()
        {
            return (new SampleObject() { Name = "JoeBob" });
        }
        public int GetNumber()
        {
            return 15;
        }
    }
}

The Web.config is equally as simple:

<?xml version="1.0" encoding="utf-8"?>
<configuration>
  <appSettings></appSettings>
  <system.web>
    <authentication mode="None" />
    <compilation debug="true" targetFramework="4.5"/>
    <httpRuntime targetFramework="4.5" />
  </system.web>
  <runtime>
    <assemblyBinding xmlns="urn:schemas-microsoft-com:asm.v1">
      <dependentAssembly>
        <assemblyIdentity name="Newtonsoft.Json" culture="neutral" publicKeyToken="30ad4fe6b2a6aeed" />
        <bindingRedirect oldVersion="0.0.0.0-6.0.0.0" newVersion="6.0.0.0" />
      </dependentAssembly>
      <dependentAssembly>
        <assemblyIdentity name="System.Web.Helpers" publicKeyToken="31bf3856ad364e35" />
        <bindingRedirect oldVersion="1.0.0.0-3.0.0.0" newVersion="3.0.0.0" />
      </dependentAssembly>
      <dependentAssembly>
        <assemblyIdentity name="System.Web.Mvc" publicKeyToken="31bf3856ad364e35" />
        <bindingRedirect oldVersion="1.0.0.0-5.2.0.0" newVersion="5.2.0.0" />
      </dependentAssembly>
      <dependentAssembly>
        <assemblyIdentity name="System.Web.Optimization" publicKeyToken="31bf3856ad364e35" />
        <bindingRedirect oldVersion="1.0.0.0-1.1.0.0" newVersion="1.1.0.0" />
      </dependentAssembly>
      <dependentAssembly>
        <assemblyIdentity name="System.Web.WebPages" publicKeyToken="31bf3856ad364e35" />
        <bindingRedirect oldVersion="1.0.0.0-3.0.0.0" newVersion="3.0.0.0" />
      </dependentAssembly>
    </assemblyBinding>
  </runtime>
</configuration>

And other than the Stripped-down references (I removed all OWIN References), there is literally nothing else in the project.

My goal is simply to get my object over to my Console Application.

PS: SampleObject lives in a separate DLL that is shared between the two projects.

    [DataContract]
    public class SampleObject
    {
        [DataMember]
        public string Name { get; set; }
    }

Upvotes: 1

Views: 1796

Answers (1)

Suamere
Suamere

Reputation: 6248

Turns out that to return objects, you need to inherit from ApiController, not Controller. Which also means my App_Start has to have:

GlobalConfiguration.Configure(WebApiConfig.Register);

And perform the configuration like you'd see in default Web API App:

public static class WebApiConfig
{
    public static void Register(HttpConfiguration config)
    {
        config.MapHttpAttributeRoutes();

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

Upvotes: 1

Related Questions