1

I've got data from an API, deserializing it to work with my model, but when I try to add that data to my database its only stores a blank object.I've tried passing through CrdResponse but that provides an exception that I can't get around.

public async Task <ActionResult> InsertCard(Card card)
        {

            List<Card> CardsInfo = new List<Card>();

            var getUrl = System.Web.HttpContext.Current.Request.Url.AbsoluteUri;

            var test = new Uri(getUrl);

            var id = test.Segments.Last();

            SingleResult += id;


            using (var client = new HttpClient())
            {
                //passing service baseurl 
                client.BaseAddress = new Uri(SingleResult);

                client.DefaultRequestHeaders.Clear();

                //Define request data format
                client.DefaultRequestHeaders.Accept.Add(new MediaTypeWithQualityHeaderValue("application/json"));

                //Sending request to find web api REST service resource Getallcards using HTTPClient
                HttpResponseMessage Res = await client.GetAsync(SingleResult);

                //Checking the response is successful or not which is sent using HttpClient  

                if (Res.IsSuccessStatusCode)
                {
                    //Storing the response details received from web api

                    var CrdResponse = Res.Content.ReadAsStringAsync().Result;


                    //Deserializing the response recieved from web api and storing in to the card list
                    CardsInfo = JsonConvert.DeserializeObject<List<Card>>(CrdResponse);

                    _context.Cards.Add(card);

                    _context.SaveChanges();
                }

            }

            return RedirectToAction("Index", "API");
        }

and my Model

 public class Card
    {
        public int Id { get; set; }
        public string Name { get; set; }
        public int? Atk { get; set; }
        public int? Def { get; set; }
        public string Desc {get; set;}
        public int? Level { get; set; }
        public string Type { get; set; }
        public string Attribute { get; set; }
        [DisplayName("Image")]
        public IList<Image> Card_Images { get; set; }

        public IList<Deck> Deck { get; set; }
    }

EDIT: CrdResponse contains:

[{"id":"11714098","name":"30,000-Year White Turtle","type":"Normal Monster","desc":"A huge turtle that has existed for more than 30,000 years.","atk":"1250","def":"2100","level":"5","race":"Aqua","attribute":"WATER","card_images":[{"id":"11714098","image_url":"https://storage.googleapis.com/ygoprodeck.com/pics/11714098.jpg","image_url_small":"https://storage.googleapis.com/ygoprodeck.com/pics_small/11714098.jpg"}],"card_prices":{"cardmarket_price":"0.00","tcgplayer_price":"0.00","ebay_price":"10.0","amazon_price":"0.00"}}]

which is all the info i am hoping to pull through

dros
  • 1,217
  • 2
  • 15
  • 31
  • 1
    Also what is the error – DubDub Sep 12 '19 at 13:28
  • 2
    So, did you put a breakpoint there to see why `card` is empty? I cannot see you *using* the reply from the webservice anywhere, might that be the reason? – nvoigt Sep 12 '19 at 13:30
  • When i try to use Cards Info The error is Argument 1: cannot convert from 'System.Collections.Generic.List' to 'YGOBuilder.Models.Card' YGOBuilder – dros Sep 12 '19 at 13:31
  • Seems like you getting a single vlaue and you trying to deserialize into a list, the line `CardsInfo = JsonConvert.DeserializeObject>(CrdResponse);` is where your erro occurs, try making it as `CardsInfo = JsonConvert.DeserializeObject(CrdResponse);` – mahlatse Sep 12 '19 at 13:34
  • It pulls correctly when I call the same method to display all results, so i assume it is correct otherwise it would not work for the index method i use. – dros Sep 12 '19 at 13:46
  • So, you store the deserialized API call result into `CardsInfo`, but add `card` in your context. Your `CardsInfo` variable is not used anywhere and your `card` object is passed as the method parameter and not used at all until you add it to the context. – Marko Papic Sep 12 '19 at 13:53
  • Obligatory: https://aspnetmonsters.com/2016/08/2016-08-27-httpclientwrong/ and https://josefottosson.se/you-are-probably-still-using-httpclient-wrong-and-it-is-destabilizing-your-software/ and https://stackoverflow.com/a/27466042/3312 – Jesse C. Slicer Sep 12 '19 at 14:12

2 Answers2

1

You are adding the 'Card' you pass through in the method parameter:

public async Task <ActionResult> InsertCard(Card card)
...
_context.Cards.Add(card);

I think what you want to do is pass through the card you are deserialising from the string response:

CardsInfo = JsonConvert.DeserializeObject<List<Card>>(CrdResponse);

foreach(Card c in CardsInfo)
{
    _context.Cards.Add(c);
}
SBFrancies
  • 3,987
  • 2
  • 14
  • 37
  • This is actually quite close however for some reason the card ID does not accept the ID that comes through the JSON. but rather increments in the database. – dros Sep 12 '19 at 13:58
  • Question - does the `Card` already exist in the database - in that case you want to update it not add it, if not then your database design is wrong - you have an auto-incrementing key when you do not want one. – SBFrancies Sep 12 '19 at 14:01
  • no the card does not already exist, i am calling the api and adding a new object in the database based from the values in the api response – dros Sep 12 '19 at 14:03
  • Then you need to change the database ID column to allow inserts. This will vary depending on the type of database you are using. – SBFrancies Sep 12 '19 at 14:04
  • @AndyStav You need to configure your database not to generate ID automatically. Take a look at [generated values](https://learn.microsoft.com/en-us/ef/core/modeling/generated-properties). `[DatabaseGenerated(DatabaseGeneratedOption.None)]` attribute on your `Id` property of `Card` class could do the job (or using fluent API as shown in the article). – Marko Papic Sep 12 '19 at 14:09
  • amazing, thank you all so much this has been so helpful and i've learned loads! closing the question – dros Sep 12 '19 at 14:13
-2

You forgot to await the result of the ReadAsStringAsync method, like so:

var CrdResponse = await Res.Content.ReadAsStringAsync();

As it is an async method it might not have completed the operation when you call result, that depends on the size of the string you are trying to read.

Hope to have helped!

  • 1
    This guy's response shouldn't have the downvotes it has. `.Result` is a big no-no in general, and ESPECIALLY in a method which is already properly marked as `async` and `await`s other calls. This is a right change that needs to be made. – Jesse C. Slicer Sep 12 '19 at 14:14