Scott Nimrod
Scott Nimrod

Reputation: 11570

Controller's Post method always has null property values on parameter (ASP.Net Core WebAPI & F#: )

My Controller's Post method always has null property values on parameter when triggered.

Environment:

I'm using ASP.Net Core WebAPI with F#.

Attempt:

I tried to apply a suggestion from this link to my Startup.fs file:

GlobalConfiguration.Configuration.Formatters.JsonFormatter.SerializerSettings.ContractResolver <-
        Newtonsoft.Json.Serialization.CamelCasePropertyNamesContractResolver()

However, GlobalConfiguration is an unrecognized type.

Here's a larger view of my attempt:

type Startup private () =
    new (configuration: IConfiguration) as this =
        Startup() then
        this.Configuration <- configuration

        // *** I INSERTED THIS BELOW *** //
        GlobalConfiguration.Configuration.Formatters.JsonFormatter.SerializerSettings.ContractResolver <-
            Newtonsoft.Json.Serialization.CamelCasePropertyNamesContractResolver()

Similar questions:

I did review this link. However, nothing worked.

HTTP Post:

This is the Post method where I keep observing null property values on my parameter:

[<HttpPost>]
member x.Post(request:DataTransfer.Request) = (* "request" parameter is always null *)

    request |> Query.carriers  
            |> function
               | Error _     -> x.StatusCode(500) :> IActionResult
               | Ok carriers -> x.Ok(carriers)    :> IActionResult

The actual type is defined here:

[<CLIMutable>]
type Request = { 
    RequestId : string 
    Customer  : Customer
    ItemQtys  : ItemQty seq
}

Client:

My client app makes the following call:

let client   = WebGateway.httpClient APIBaseAddress
let response = client.PostAsJsonAsync("carriers", request) |> toResult

Here's the request type on the client:

[<CLIMutable>]
type Request = { 
    RequestId : string 
    Customer  : Customer
    ItemQtys  : ItemQty seq
}

UPDATE:

I then attempted to apply a suggestion from this link and also using this reference. It didn't work though.

member this.ConfigureServices(services: IServiceCollection) =
    // Add framework services.
    services.AddMvc().SetCompatibilityVersion(CompatibilityVersion.Version_2_1)
            .AddJsonOptions(fun opt -> 

                               let resolver = Newtonsoft.Json.Serialization.DefaultContractResolver()
                               resolver.NamingStrategy <- null
                               opt.SerializerSettings.ContractResolver <- resolver

                           ) |> ignore

Postman:

enter image description here enter image description here

Screenshots:

enter image description here

Partial Success:

The following seems promising:

enter image description here

Hence, the code above results in actual values sent from the client. However, I haven't found a way to convert the object into the data transfer type that I need.

Upvotes: 2

Views: 330

Answers (1)

Aaron M. Eshbach
Aaron M. Eshbach

Reputation: 6510

You don't need to mess with Contract Resolvers in ASP.NET Core to use camel-case and F# record types, as you did with ASP.NET. I would take all of that out, or try creating a simple test project to get it working, then go back and make the appropriate changes to your real project. With no additional configuration, you should be able to get something working just by following these steps:

  1. Run dotnet new webapi -lang F#
  2. Add the following type to ValuesController.fs:
    [<CLIMutable>]
    type Request =
    {
        Name: string
        Value: string        
    }
  1. Change the Post method to be something like this:
    [<HttpPost>]
    member this.Post([<FromBody>] request:Request) =
        this.Created(sprintf "/%s" request.Name, request)
  1. Debug the service to validate that it works by sending the following request in PostMan:
    {
        "name": "test",
        "value": "abc"
    }

You should see the request object echoed back with a 201 response.

Upvotes: 1

Related Questions