<?xml version="1.0" encoding="UTF-8"?>
<rss version="2.0" xmlns:atom="http://www.w3.org/2005/Atom" xmlns:dc="http://purl.org/dc/elements/1.1/">
  <channel>
    <title>DEV Community: Galina Melnik</title>
    <description>The latest articles on DEV Community by Galina Melnik (@galenam).</description>
    <link>https://dev.to/galenam</link>
    <image>
      <url>https://media2.dev.to/dynamic/image/width=90,height=90,fit=cover,gravity=auto,format=auto/https:%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Fuser%2Fprofile_image%2F586696%2Ffa5001e4-4a58-43f0-9b3e-6ea980896449.png</url>
      <title>DEV Community: Galina Melnik</title>
      <link>https://dev.to/galenam</link>
    </image>
    <atom:link rel="self" type="application/rss+xml" href="https://dev.to/feed/galenam"/>
    <language>en</language>
    <item>
      <title>Update Swashbuckle.AspNetCore Version from version"4.0.1" to "6.2.3"</title>
      <dc:creator>Galina Melnik</dc:creator>
      <pubDate>Fri, 13 May 2022 06:51:16 +0000</pubDate>
      <link>https://dev.to/galenam/update-swashbuckleaspnetcore-version-from-version401-to-623-4fcf</link>
      <guid>https://dev.to/galenam/update-swashbuckleaspnetcore-version-from-version401-to-623-4fcf</guid>
      <description>&lt;p&gt;Hi there. &lt;br&gt;
I had an interesting task: to update the Swashbuckle.AspNetCore version from "4.0.1" to "6.2.3". It looked very simple but it was not what it looked like.&lt;br&gt;
The main problem was breaking changes which happened when passing from version 4 to version &lt;a href="https://github.com/domaindrivendev/Swashbuckle.AspNetCore/releases/tag/v5.0.0"&gt;5&lt;/a&gt;. Swashbuckle.AspNetCore began to use Swagger/OpenAPI &lt;a href="https://swagger.io/specification/"&gt;version v3&lt;/a&gt; instead of OpenAPI v2. The project makes use of NSwag to generate httpClient for getting data from another microservice. Any attempt to regenerate auto generated code changed it after updating Swashbuckle.AspNetCore version. These caused a lot of build errors. I should have decreased differencies between the new code and old one.&lt;br&gt;
Main difference which cause incompatibility in the project were:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Autogenerated method names were changed. The previous format was, for example, "AddPersonalTaskV2Async" (it was a controller class method name). New auto generated names became "V2Async". There were a lot of such changes, it seemed impossible to change all method calls by hand. A better decision was to add CustomOperationIds to services.AddSwaggerGen. In my case:
&lt;/li&gt;
&lt;/ul&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;services.AddSwaggerGen(c =&amp;gt;
            {
                c.SwaggerDoc("v1", new OpenApiInfo {Title = "title", Version = "v1"});
                c.CustomOperationIds(apiDesc =&amp;gt;
                    apiDesc.TryGetMethodInfo(out MethodInfo methodInfo) ? methodInfo.Name : null);
            });
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;ul&gt;
&lt;li&gt;&lt;p&gt;There were no changes in names of parameters with attribute [FromUri]. But all parameters with attribute [FromBody] changed their names to body. As described in the &lt;a href="https://swagger.io/specification/"&gt;spec&lt;/a&gt; [FromUri] is aligned with Operation Object =&amp;gt; parameters, but [FromBody] is Operation Object =&amp;gt; requestBody. There is no field "name" in Request Body Object.&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;Parameter order was changed. Before the order was the same as in method declaration. By now [FromUri] goes earlier than [FromBody]. It doesn't matter what you have coded in method declaration.&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;If you use JObject as a request parameter, you will be in for an unpleasant surprise. NSWag changes JObject to System.Collections.Generic.Dictionary. If you are disagree, it will be better to code custom realization of ISchemaFilter like this:&lt;br&gt;
&lt;/p&gt;&lt;/li&gt;
&lt;/ul&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;public class JObjectSchemaFilter : ISchemaFilter
    {
        public void Apply(OpenApiSchema schema, SchemaFilterContext context)
        {
            if (context.Type != typeof(JObject)) return;
            schema.Type = "object";
            schema.AdditionalProperties = null;
        }
    }
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;ul&gt;
&lt;li&gt;Another change has affected Enums. Enum fields names don't be the same as in your code. They are changed to figures 1,2, ..., n. To fix this singularity it should be created another custom realization of ISchemaFilter:
&lt;/li&gt;
&lt;/ul&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;public class EnumSchemaFilter : ISchemaFilter
    {
        public void Apply(OpenApiSchema schema, SchemaFilterContext context)
        {
            if (!context.Type.IsEnum) return;

            var fields = context.Type.GetFields(BindingFlags.Static | BindingFlags.Public);

            schema.Enum = fields.Select(field =&amp;gt; new OpenApiString(field.Name)).Cast&amp;lt;IOpenApiAny&amp;gt;().ToList();
            schema.Type = "string";
            schema.Properties = null;
            schema.AllOf = null;
        }
    }
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;ul&gt;
&lt;li&gt;The last thing I should mention: some fields of custom request objects suddenly have an attribute [Required]. I'm not sure that I coded the best decision, but this worked:
&lt;/li&gt;
&lt;/ul&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;public class SettingsSchemaFilter : ISchemaFilter
    {
        public void Apply(OpenApiSchema schema, SchemaFilterContext context)
        {
            if (context.Type != typeof(Settings)) return;
            if (schema.Required == null || schema.Required.Count == 0)
            {
                schema.Nullable = true;
            }
        }
    }
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;It's all changes that I faced.&lt;/p&gt;

</description>
      <category>c</category>
      <category>swagger</category>
      <category>netcore</category>
      <category>netframework</category>
    </item>
    <item>
      <title>Migrate C# project to Istio</title>
      <dc:creator>Galina Melnik</dc:creator>
      <pubDate>Thu, 21 Apr 2022 11:02:39 +0000</pubDate>
      <link>https://dev.to/galenam/migrate-c-project-to-istio-2p93</link>
      <guid>https://dev.to/galenam/migrate-c-project-to-istio-2p93</guid>
      <description>&lt;p&gt;My team has a C# project. This project is deployed using k8s. There was a task to migrate to corpotive Istio using a certificate, a gateways and a virtual service but without a service mesh.&lt;br&gt;
If you have such type of a task there are my recomendations:&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;It's needed to create a file with a certificate:
&lt;/li&gt;
&lt;/ol&gt;
&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;apiVersion: cert-manager.io/v1alpha2
kind: Certificate
metadata:
  labels:
    istio-certificate: "true"            # if it would be used with gateway object, the value should be set to "true"
    app.kubernetes.io/managed-by: {{ .Release.Service }}
  name: {{ .Values.environment.servicename }}
spec:
  dnsNames:
  - {{ .Values.service.name }}.{{ .Release.Namespace }}.{{ .Values.environment.cluster }}
  issuerRef:
    kind: ClusterIssuer
    name: certificates-issuer
  secretName: {{ .Values.environment.servicename }} # the secretName should be equals to the certificate name
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;


&lt;p&gt;If you want to learn more about certificate resources, there is  pretty documentaions &lt;a href="https://cert-manager.io/docs/usage/certificate/"&gt;here&lt;/a&gt;&lt;br&gt;
The second thing is needed to do is to add a gateway description.&lt;br&gt;
The istio gateway provides a description of ports &amp;amp; protocols which will be used. More information &lt;a href="https://istio.io/latest/docs/reference/config/networking/gateway/"&gt;here&lt;/a&gt;&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;apiVersion: networking.istio.io/v1alpha3
kind: Gateway
metadata:
  name: {{ .Values.service.name }}
spec:
  selector:
    company/istio-ingressgateway: common
  servers:
    - port:
        number: 443                                       
        name: https
        protocol: HTTPS                                   
      tls:
        mode: SIMPLE                                      
        credentialName: {{ .Values.environment.servicename }} 
      hosts:
        - {{ .Values.service.name }}.{{ .Release.Namespace }}.{{ .Values.environment.cluster }}               # use a correct hostname for your namespace 
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Istio VirtualService describes routing. It's needed to specify hosts, ports and other things. All documentation available &lt;a href="https://istio.io/latest/docs/reference/config/networking/virtual-service/"&gt;here&lt;/a&gt;&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;apiVersion: networking.istio.io/v1alpha3
kind: VirtualService
metadata:
  name: {{ .Values.service.name }}
spec:
  hosts:
    - {{ .Values.service.name }}.{{ .Release.Namespace }}.{{ .Values.environment.cluster }}
  gateways:
    - {{ .Values.service.name }}                        # join the virtualService with the gateway
  http:
  - name: "default"
    route:
    - destination:
        port:
          number: {{ .Values.environment.serviceport }}       
        host: {{ .Values.environment.servicename }}-service
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



</description>
      <category>istio</category>
    </item>
    <item>
      <title>Add existing autotests to existing GitLab CI/CD</title>
      <dc:creator>Galina Melnik</dc:creator>
      <pubDate>Thu, 17 Mar 2022 06:22:21 +0000</pubDate>
      <link>https://dev.to/galenam/add-existing-autotests-to-existing-gitlab-cicd-1ml0</link>
      <guid>https://dev.to/galenam/add-existing-autotests-to-existing-gitlab-cicd-1ml0</guid>
      <description>&lt;p&gt;Hello. Our command has java-autotests in TeamCity for the C# project. It's our heritage, because our testers have java-background and they prefer to use java for their purposes. &lt;br&gt;
The company standart was changed some time ago. We begin to use GitLab CI/CD instead of TeamCity. I have a task to transfer java-tests from TeamCity to GitLab.&lt;br&gt;
The main idea of maven autotests was to deploy c# project into kubernetes and after that tried to call java-autotests using maven outside of deployed project.&lt;br&gt;
I've added stages after deploy to existed .gitlab-ci.yaml. I don't describe build and deploy stages.&lt;/p&gt;

&lt;p&gt;I should mention that "&amp;lt;&amp;lt;: *dp-auth-docker" is a common template that we use to auth in corporative instance of docker.&lt;/p&gt;

&lt;p&gt;My collegue found that k8s sometimes scaled down replicas to count equaled 0. That is why the first added stage is called scale-replicas:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;scale-replicas:
  &amp;lt;&amp;lt;: *dp-auth-docker
  stage: scale-replicas
  script:
    - theBranch=$(echo $CI_COMMIT_REF_NAME | tr '[:upper:]' '[:lower:]')
    - |
      echo 'Check replicas. Will be set value 1.'
      docker run --rm $CORPORATIVE_DOCKER_IMAGE_K8S kubectl scale --replicas=1 deployments/$theBranch
  only:
    - merge_requests
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;ul&gt;
&lt;li&gt;&lt;p&gt;$CI_COMMIT_REF_NAME is a predefined GitLab variable (&lt;a href="https://docs.gitlab.com/ee/ci/variables/predefined_variables.html"&gt;documentation&lt;/a&gt;)&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;theBranch is a local stage variable, which contains a name of a branch. We always use number of a task as the branch name. I should convert the branch name to lower case because k8s deployment names are case sensitive.&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;--rm flag define clean up container (&lt;a href="https://docs.docker.com/engine/reference/run/#clean-up---rm"&gt;documentation&lt;/a&gt;)&lt;/p&gt;&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Time to scale a replica could be significant. That is why it's needed to delay between scale the replica and tests.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;sleep:
  stage: sleep
  script:
    - sleep 120
  only:
    - merge_requests
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;ul&gt;
&lt;li&gt;GitLab measures time in seconds. 2 minutes delay is enough to scale a replica in the system.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Next step is running tests.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;run-tests:
  &amp;lt;&amp;lt;: *dp-auth-docker
  stage: run-tests
  script:
    - docker run --rm $CORPORATIVE_DOCKER_IMAGE_DIND dockerd &amp;amp; &amp;gt;/dev/null
    - |
      while [docker run --rm $CORPORATIVE_DOCKER_IMAGE_DIND ! -S /var/run/docker.sock ];
      do
          echo "waiting";
          sleep 1;
      done
    - pathKube="./.kube"
    - mkdir $pathKube
    - echo -e
    - |
      config=$(docker run \
        --rm -t \
        -p 7000:7000 \
        $CORPORATIVE_DOCKER_IMAGE_K8S \
        cat /root/.kube/config)
    - file="$pathKube/config"
    - echo "$config"&amp;gt;$file
    - echo -e
    - |
      if test -f "$file"; then
          echo "New config was saved to: $file"
      else
          echo"New config was not saved"
          exit -1
      fi
    - docker run --rm --volume $(pwd):/tests $CORPORATIVE_DOCKER_IMAGE_NEPTUNE mvn antrun:run -P !QA,featureBranch -f /tests/pom.xml -Dkubectl.config=/tests/.kube/config -Dfeature.branch.number=$CI_COMMIT_REF_NAME clean test -Dsuite=$SUITE_NAME
  cache:
    paths:
      - .m2/repository
  only:
    - merge_requests
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;ul&gt;
&lt;li&gt;&lt;p&gt;dockerd runs daemon in docker (&lt;a href="https://docs.docker.com/engine/reference/commandline/dockerd/"&gt;documentaion&lt;/a&gt;)&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;while an unix socket creates and openes, script waits.&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;copy /.kube/config from k8s image to local. I need it to run tests from k8s and to forward ports for MongoDB.&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;maven use cache in directory .m2/repository&lt;/p&gt;&lt;/li&gt;
&lt;/ul&gt;

</description>
      <category>gitlab</category>
      <category>maven</category>
    </item>
    <item>
      <title>An easier method to deserialize json from NASA InSight: Mars Weather Service API</title>
      <dc:creator>Galina Melnik</dc:creator>
      <pubDate>Mon, 17 May 2021 10:17:33 +0000</pubDate>
      <link>https://dev.to/galenam/an-easier-method-to-deserialize-json-from-nasa-insight-mars-weather-service-api-1jol</link>
      <guid>https://dev.to/galenam/an-easier-method-to-deserialize-json-from-nasa-insight-mars-weather-service-api-1jol</guid>
      <description>&lt;p&gt;NASA has a free service with Mars wheather. I'm trying to use it and create a pet project with beautiful Mars's photos and wheathers descriptions.&lt;br&gt;
You can see demo data with this &lt;a href="https://api.nasa.gov/insight_weather/?api_key=DEMO_KEY&amp;amp;feedtype=json&amp;amp;ver=1.0"&gt;URL&lt;/a&gt; &lt;br&gt;
Just this time the service doesn't work but I hope It will work soon.&lt;br&gt;
I have saved json for unit tests and show it for clarity:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;{
    "781": {
        "First_UTC": "2021-02-05T16:28:36Z",
        "Last_UTC": "2021-02-06T17:08:11Z",
        "Month_ordinal": 12,
        "Northern_season": "late winter",
        "PRE": {
            "av": 717.422,
            "ct": 120387,
            "mn": 695.3022,
            "mx": 742.7693
        },
        "Season": "winter",
        "Southern_season": "late summer",
        "WD": {
            "most_common": null
        }
    },
// and so forth, and so on
    "sol_keys": [
        "781"
// and so forth, and so on
    ]
}
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Some monthes ago I've created a post with one of the methods to deserialize NASA data using custom JsonConverter.&lt;br&gt;
But now I think that there is an more easier method to do it.&lt;br&gt;
Let's begin.&lt;br&gt;
I have a class with description.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;public class MarsWheather
    {
        public int Sol { get; set; }
        [JsonPropertyName("First_UTC")]
        public DateTime FirstUTC { get; set; }
        [JsonPropertyName("Last_UTC")]
        public DateTime LastUTC { get; set; }
        [JsonPropertyName("Season")]
        [JsonConverter(typeof(JsonStringEnumConverter))]
        public Season MarsSeason { get; set; }
        [JsonPropertyName("PRE")]
        public DataDescription AtmosphericPressure { get; set; }

        [JsonIgnore]
        public HashSet&amp;lt;string&amp;gt; Photos { get; set; }
        [JsonIgnore]
        public List&amp;lt;RoverInfo&amp;gt; Rovers { get; set; }
    }

    public enum Season {
        winter,
        spring,
        summer,
        autumn
    }

    public class DataDescription{
        [JsonPropertyName("av")]
        public double Average { get; set; }
        [JsonPropertyName("ct")]
        public double TotalCount { get; set; }
        [JsonPropertyName("mn")]
        public double Minimum { get; set; }
        [JsonPropertyName("mx")]
        public double Maximum { get; set; }
    }
    public enum RoverName
    {
        Curiosity,
        Opportunity,
        Spirit
    }

    public class RoverInfo {
        public string Name { get; set; }
        public DateTime LandingDate { get; set; }
        public DateTime LaunchDate { get; set; }
        public string Status { get; set; }
    }
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;I've read a &lt;a href="https://api.nasa.gov/assets/insight/InSight%20Weather%20API%20Documentation.pdf"&gt;description of service&lt;/a&gt; not attentively, that was why I've missed this paragraph&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;Get a top-level Sol key from the top-level key sol_keys&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;Ha-ha, it was a big mistake! I should return to my server and change a method to get data.&lt;br&gt;
I've added a new class to process json (CustomDeserializer.cs)&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;public static class CustomDeserializer
    {
        static string fieldName = "sol_keys";
        public static async Task&amp;lt;IEnumerable&amp;lt;MarsWheather&amp;gt;&amp;gt; GetAsync(Stream stream)
        {
            var result = new List&amp;lt;MarsWheather&amp;gt;();
            using (var document = JsonDocument.Parse(stream))
            {
                var root = document.RootElement;
                var keys = root.GetProperty(fieldName);
                foreach (var key in keys.EnumerateArray())
                {
                    if (root.TryGetProperty(key.GetString(), out var element))
                    {
                            var wheather = await JsonSerializer.DeserializeAsync&amp;lt;MarsWheather&amp;gt;(new MemoryStream(Encoding.ASCII.GetBytes(element.GetRawText())));
                            int.TryParse(key.GetString(), out var sol);
                            wheather.Sol = sol;
                            result.Add(wheather);                        
                    }
                }
            }
            return result;
        }
    }
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;And this works! &lt;/p&gt;

</description>
    </item>
    <item>
      <title>JsonConverter&amp;lt;T&amp;gt;</title>
      <dc:creator>Galina Melnik</dc:creator>
      <pubDate>Sun, 28 Feb 2021 11:58:28 +0000</pubDate>
      <link>https://dev.to/galenam/jsonconverter-t-4424</link>
      <guid>https://dev.to/galenam/jsonconverter-t-4424</guid>
      <description>&lt;p&gt;I want to create home pet project with Mars wheather. Thanks God NASA have a public API with data.&lt;br&gt;
Test URL &lt;a href="https://api.nasa.gov/insight_weather/?api_key=DEMO_KEY&amp;amp;feedtype=json&amp;amp;ver=1.0"&gt;https://api.nasa.gov/insight_weather/?api_key=DEMO_KEY&amp;amp;feedtype=json&amp;amp;ver=1.0&lt;/a&gt; &lt;br&gt;
And there is their json for today :&lt;br&gt;
&lt;code&gt;{&lt;br&gt;
  "782": {&lt;br&gt;
    "First_UTC": "2021-02-06T17:08:11Z", &lt;br&gt;
    "Last_UTC": "2021-02-07T17:47:46Z", &lt;br&gt;
    "Month_ordinal": 12, &lt;br&gt;
    "Northern_season": "late winter", &lt;br&gt;
    "PRE": {&lt;br&gt;
      "av": 721.77, &lt;br&gt;
      "ct": 113450, &lt;br&gt;
      "mn": 698.8193, &lt;br&gt;
      "mx": 742.2686&lt;br&gt;
    }, &lt;br&gt;
    "Season": "winter", &lt;br&gt;
    "Southern_season": "late summer", &lt;br&gt;
    "WD": {&lt;br&gt;
      "most_common": null&lt;br&gt;
    }&lt;br&gt;
  }, &lt;br&gt;
  "783": {&lt;br&gt;
    "First_UTC": "2021-02-07T17:47:46Z", &lt;br&gt;
    "Last_UTC": "2021-02-08T18:27:22Z", &lt;br&gt;
    "Month_ordinal": 12, &lt;br&gt;
    "Northern_season": "late winter", &lt;br&gt;
    "PRE": {&lt;br&gt;
      "av": 722.186, &lt;br&gt;
      "ct": 107270, &lt;br&gt;
      "mn": 698.7664, &lt;br&gt;
      "mx": 743.1983&lt;br&gt;
    }, &lt;br&gt;
    "Season": "winter", &lt;br&gt;
    "Southern_season": "late summer", &lt;br&gt;
    "WD": {&lt;br&gt;
      "most_common": null&lt;br&gt;
    }&lt;br&gt;
  }, ... irrelevant&lt;br&gt;
"sol_keys": [... irrelevant],&lt;br&gt;
"validity_checks": { ...irrelevant }&lt;br&gt;
}&lt;/code&gt;&lt;/p&gt;

&lt;p&gt;I've created a project using netcoreapp3.0 and wanted to use System.Text.Json library. My first wrong way to do it was :&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;var dict = await JsonSerializer.DeserializeAsync&amp;lt;Dictionary&amp;lt;string, MarsWheather&amp;gt;&amp;gt;(stream);
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;But I caught an exception &lt;br&gt;
&lt;code&gt;&lt;br&gt;
System.Text.Json.JsonException: The JSON value could not be converted to MarsWheather. Path: $.sol_keys | LineNumber: 120 | BytePositionInLine: 15.&lt;/code&gt;&lt;br&gt;
BOOM!&lt;br&gt;
That's why I've created custom JsonConverter. I hope this code will helpful for community.&lt;br&gt;
UPDATE 03/03/2021 : There was a bug with my code. This is a new version without it.&lt;br&gt;
Data classes is :&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;[JsonConverter(typeof(MarsWheatherRootObjectConverter))]
    public class MarsWheatherRootObject
    {
        public List&amp;lt;MarsWheather&amp;gt; MarsWheather { get; set}
    }
    public class MarsWheather {
        public int Sol { get; set; }
        [JsonPropertyName("First_UTC")]
        public DateTime FirstUTC { get; set; }
        [JsonPropertyName("Last_UTC")]
        public DateTime LastUTC { get; set; }
        [JsonPropertyName("Season")]
        [JsonConverter(typeof(JsonStringEnumConverter))]
        public Season MarsSeason { get; set; }
        [JsonPropertyName("PRE")]
        public DataDescription AtmosphericPressure { get; set; }
    }
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;I've created an class wrapper (MarsWheatherRootObject) to use class attribute.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;internal class MarsWheatherRootObjectConverter : JsonConverter&amp;lt;MarsWheatherRootObject&amp;gt;
    {
        public override MarsWheatherRootObject Read(ref Utf8JsonReader reader, Type typeToConvert, JsonSerializerOptions options)
        {
            var root = new MarsWheatherRootObject();
            var list = new List&amp;lt;MarsWheather&amp;gt;();
            while (reader.Read())
            {
                switch (reader.TokenType)
                {
                    case JsonTokenType.PropertyName:
                    case JsonTokenType.String:
                        var keyStr = reader.GetString();
                        int key;
                        if (!int.TryParse(keyStr, out key))
                        {
                            reader.Skip();
                        }
                        else
                        {
                            var value = JsonSerializer.Deserialize&amp;lt;MarsWheather&amp;gt;(ref reader, options);
                            value.Sol = key;
                            list.Add(value);
                        }
                        break;
                    default: break;
                }
            }
            root.MarsWheather = list;
            return root;
        }

        public override void Write(Utf8JsonWriter writer, MarsWheatherRootObject value, JsonSerializerOptions options)
        {
            throw new NotImplementedException();
        }
    }
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;I don't need to serialize the object. That's why I don't write code for Write method by now.&lt;/p&gt;

</description>
      <category>csharp</category>
      <category>dotnet</category>
    </item>
  </channel>
</rss>
