locked
Call webapi return list of object but can not cast to base type of object? RRS feed

  • Question

  • User281273049 posted

    I have some class:

    public class Base
    {
        public string Name;
    }

    public class AClass : Base
    {
        public string AAtribute;
    }

    public class BClass : Base
    {
        public string BAtribute;
    }

    I create WebApi with ApiController' class:

    public class TestController : ApiController
    {
        [HttpGet]
        public IHttpActionResult GetAll()
        {
            var d = new List<Base>{
                new AClass() { Name = "A", AAtribute = "A1" },
                new BClass() { Name = "B", AAtribute = "B1" },
                new BClass() { Name = "B", AAtribute = "B2" },
                new BClass() { Name = "B", AAtribute = "B3" },
                new AClass() { Name = "A", AAtribute = "A2" }
            };
            
            return Ok(d);
        }
    }

    Class to call WebApi:

    public class RestClient<T> : IDisposable where T : class
    {
        private readonly string _baseAddress;

        public RestClient(string baseAddress)
        {
            _baseAddress = baseAddress;
        }

        private void SetupClient(System.Net.Http.HttpClient client, string contentType)
        {
            client.BaseAddress = new Uri(_baseAddress);
            client.DefaultRequestHeaders.Accept.Clear();
            client.DefaultRequestHeaders.Accept.Add(new MediaTypeWithQualityHeaderValue(contentType));
        }
        
        public async Task<IEnumerable<T>> GetItems(string actionName, string contentType)
        {
            IEnumerable<T> r = null;

            using (var client = new System.Net.Http.HttpClient())
            {
                SetupClient(client, contentType);

                var response = await client.GetAsync(actionName);

                response.EnsureSuccessStatusCode();

                if (response.IsSuccessStatusCode)
                {
                    r = await response.Content.ReadAsAsync<IEnumerable<T>>();
                }
            }

            return r;
        }
    }

    Unit test to call WebApi:

    var d = List<Base>();

    using (var client = new RestClient<Base>("http://xxx"))
    {
        try
        {
            var r = client.GetItems("api/Test/GetAll", "application/json");

            var d = r.Result;

            foreach (var m in d)
            {
                var name = m.Name;

                Base x;
                if (name == "A") x = (AClass) m;
                if (name == "B") x = (BClass) m;
                if (x == null) continue;
                
                d.Add(x);
            }
        }
        catch (Exception ex)
        {
        }
    }

    When i run unit test but exception cast Base to AClass or BClass. How do fix it????

    Thanks.

    Wednesday, March 15, 2017 4:17 PM

All replies

  • User753101303 posted

    Hi,

    This is the other way round ie you can cast from a child type to a base type (because the base type is guaranteed to support as well all features exposed by the child type) but you can't cast from a real base type to a child type (the base type doesn't have AAtribute or BAtribute).

    From my search, it seems you should be able to use https://kirmir.com/2014/05/16/polymorphic-serialization-using-newton-json-net-in-httpcontent/ which add a $type value that can then be used during the deserialization process.

    Still make sure to have a reason for doing that.

    Wednesday, March 15, 2017 4:59 PM
  • User281273049 posted

    Hi PatriceSc,

    I add this code in WebApiConfig.cs like following code:

    public static class WebApiConfig
    {
        public static void Register(HttpConfiguration config)
        {
            // Web API configuration and services
            config.Formatters.JsonFormatter.SerializerSettings.TypeNameHandling = TypeNameHandling.Auto;
    
            // Web API routes
            config.MapHttpAttributeRoutes();
    
            config.Routes.MapHttpRoute(
                name: "DefaultApi",
                routeTemplate: "api/{controller}/{action}/{id}",
                defaults: new { id = RouteParameter.Optional }
            );
        }
    }

    When i test again but the same error. Can you help me???

    Thursday, March 16, 2017 2:49 PM
  • User-2057865890 posted

    Hi Tuan_Tu,

    PatriceSc given a suitable way. You can try it by yourself.

    You need to create a new HttpResponseMessage and contains the config.

    [HttpGet]
    public HttpResponseMessage GetAvailableVehicles()
    {
        var dto = new AvailableVehiclesDto
        {
        };
    
         var config = new HttpConfiguration();
         config.Formatters.JsonFormatter.SerializerSettings.TypeNameHandling = TypeNameHandling.Auto;
         return Request.CreateResponse(HttpStatusCode.OK, dto, config);
    }
    
    

    Client:

    var response = await _serviceClient.GetAsync( "");
    response.EnsureSuccessStatusCode();
    var formatter = new JsonMediaTypeFormatter
    {
        SerializerSettings = { TypeNameHandling = TypeNameHandling.Auto }
    };
    var dto = await response.Content.ReadAsAsync<AvailableVehiclesDto>(
        new List<MediaTypeFormatter> { formatter });
    

    Then, you can according the type to Convert your Objects.

    Best Regards,

    Chris

    Saturday, April 1, 2017 6:18 AM