4

I had a completely functioning program at version 2.2 when migrating to version 3.0 and replacing

public void ConfigureServices(IServiceCollection services)
{
    ...
    services.AddMvc();
}

With services.AddControllers();

And replacing app.UseMvc();

With:

app.UseRouting();
app.UseEndpoints(endpoints =>
{
    endpoints.MapControllers();
});

One of the controllers is broken. (Other controllers which also has Post Method and [FromBody] Works fine) The controller and the method broken is:

[Route("api/vm")]
public class MainController: Controller
{
    [HttpPost]
    [Route("Process")]
    public IActionResult GetProcess([FromBody]ProcessModel[] process)
    {
         ...
    }
}

The Model:

public class ProcessModel
{
    [JsonProperty("Name")]
    public string Name { get; set; }
    [JsonProperty("ExeName")]
    public string ExeName { get; set; }
    [JsonProperty("Path")]
    public string Path { get; set; }
    [JsonProperty("VersionPath")]
    public string VersionPath { get; set; }
    [JsonProperty("Id")]
    public string Id { get; set; }
    [JsonProperty("Status")]
    public string Status { get; set; }
    [JsonProperty("Ver")]
    public string Ver { get; set; }
    [JsonProperty("Args")]
    public string[] Args { get; set; }
    [JsonProperty("Instances")]
    public List<ProcessDetails> Instances { get; set; }
    [JsonProperty("Multiple")]
    public string Multiple { get; set; }
}  

The call I am making to /api/vm/Process:

[
    {
        "Name": "Test",
        "ExeName": "Test",
        "Multiple": false,
        "Path": "Test",
        "VersionPath": "Test",
        "Args": {
            "IsFile": false
        }
    },
    {
        "Name": "Test",
        "ExeName": "Test.exe",
        "Multiple": false,
        "Path": "Test",
        "VersionPath": "Test",
        "Args": {
            "IsFile": false
        }
    }
]

The app worked at production just fine for a few months. All I did was upgrade to .netcore 3, Now when I debug and get to the method at the controller I get null in a process variable

Note: I used this thread when the app was broken at first place Using 'UseMvc' to configure MVC is not supported while using Endpoint Routing

L_J
  • 2,351
  • 10
  • 23
  • 28
ATT
  • 921
  • 3
  • 13
  • 30
  • One possible thing is: Multiple is declared as a string in the model but in JSON you are passing as a bool. declare boolean value or assign false as a string "Multiple": "false", – Rafaqat Ali Dec 30 '19 at 14:42
  • This is the possible string for your model: [ { "Name": "Test", "ExeName": "Test", "Multiple": "false", "Path": "Test", "VersionPath": "Test", "Args": ["false"] }, { "Name": "Test", "ExeName": "Test.exe", "Multiple": "false", "Path": "Test", "VersionPath": "Test", "Args": ["false"] } ] – Rafaqat Ali Dec 30 '19 at 14:48
  • 2
    If your json bidding was working in .net 2 try with newtonsoft as described here https://learn.microsoft.com/en-us/aspnet/core/migration/22-to-30?view=aspnetcore-3.1&tabs=visual-studio#jsonnet-support – Jesus Santander Dec 30 '19 at 14:51
  • yea sounds like a system.text.json change. – Daniel A. White Dec 30 '19 at 14:54
  • 3
    Not an answer to your question, but you don't need to use `JsonProperty` if your property name is the same as JSON keys. – prinkpan Dec 30 '19 at 15:47
  • I know, it's in case I would change the name of The property so it wouldn't break – ATT Dec 30 '19 at 18:54

4 Answers4

2

Auto type converting is not available in new System.Text.Json, probably for performance reasons. You should use "Newtonsoft serializer" or use a custom converter. Some of your class properties are string but you are sending bool (Multiple property), int.

Using Newtonsoft: https://learn.microsoft.com/en-us/aspnet/core/migration/22-to-30?view=aspnetcore-3.1&tabs=visual-studio#jsonnet-support

System.Text.Json Converter sample:

https://github.com/dotnet/corefx/blob/master/src/System.Text.Json/tests/Serialization/CustomConverterTests.Int32.cs

Register your converter like this:

services.AddControllers().AddJsonOptions(options =>
{
    options.JsonSerializerOptions.Converters.Add(new MyInt32Converter());
});
pavinan
  • 1,275
  • 1
  • 12
  • 23
1

The reason is that your ProcessModel has string[] type for Args:

public string[] Args { get; set; }

While in your json, you pass it as an object which results in the model binding null

"Args": {
        "IsFile": false
    }

Either pass Args as string[] like

"Args": ["IsFile:false"]

Or if you do want to change the json, modify Args to a Dictionary type:

[JsonProperty("Args")]      
public Dictionary<string, string> Args { get; set; }

Remember to add reference to NewtonsoftJson like others have said

services.AddControllers().AddNewtonsoftJson();
Ryan
  • 19,118
  • 10
  • 37
  • 53
0

Problem here in Multiple and Args JSON properties.
In JSON they are bool and object, but in Process model they are both strings. I am not quite sure how it could work in Core 2.2.

Roman.Pavelko
  • 1,555
  • 2
  • 15
  • 18
0

Step 1: Download and install the "Microsoft.AspNetCore.Mvc.NewtonsoftJson" NuGet package in Visual Studio for Mac -I use Macbook Pro.

Step 2: I have read Migrate Startup.Configure to migrate my project to .Net Core 3. Basically all you need to do is to add the following to your existing setup on the ConfigureServices() method:

public void ConfigureServices(IServiceCollection services)
{
    // update Startup.ConfigureServices to call AddNewtonsoftJson
    services.AddControllers();
    ...
    ...
    services.AddMvc()
            .SetCompatibilityVersion(CompatibilityVersion.Version_3_0)
            .AddNewtonsoftJson(); 
}

And then on the Configure() method add the following:

public void Configure(IApplicationBuilder app, IWebHostEnvironment env)
{
    ...
    ...
    app.UseRouting();
    app.UseCors();

    app.UseAuthentication();
    app.UseAuthorization();

    app.UseEndpoints(endpoints => {
        endpoints.MapControllers();
    });
}

These screenshots are from Microsoft:

enter image description here

enter image description here

Step 3: Remove the FromBody from the method signature. It is not needed in .Net Core 3+ anymore. So your end point should like this:

[HttpPost("Login")]
public IActionResult Login(YourRequest request) {

}

Also, I didn't add the [JsonProperty] attribute to the model properties. My request class structure is:

using System;

namespace Models.Communication.Request
{
    public class LoginRequest
    {
        public String Email { get; set; }
        public String Password { get; set; }
    }
}
thus
  • 1,326
  • 1
  • 14
  • 23