2

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.

17
  • Try using the DefaultContractResolver? See stackoverflow.com/questions/22789504/… Commented Jul 23, 2019 at 13:26
  • 2
    And what are you sending? Post the JSON and the request details in general, along with what you're using to make that request HttpClient/Postman/etc. If you're making the request in code, post that code. Commented Jul 23, 2019 at 13:27
  • 1
    @ScottNimrod This also looks like a mixing of versions. GlobalConfiguration is not part of asp.net-core. That was from previous version. Commented Jul 23, 2019 at 13:45
  • 3
    member x.Post([<FromBody>]request:DataTransfer.Request) Commented Jul 23, 2019 at 13:48
  • 1
    An "easy" way to check if it is the record type is to try with a class? Commented Jul 23, 2019 at 16:35

1 Answer 1

1

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.

Sign up to request clarification or add additional context in comments.

7 Comments

Thanks but I'm still observing null property values on my record parameter even when I reference the example you provided.
@ScottNimrod Can you update your question with a snap from PostMan or Fiddler of the request body you're sending?
I'm not an expert with Postman. However, I provided some screenshots.
@ScottNimrod Ah, ok, I see the problem (at least with the example). You need to use the "raw" option under body type, then use application/json as the content type, and paste in the JSON above. In your real service, are you trying to process JSON data, or a form? If JSON, are you sending the application/json content-type header?
I attempted to apply your feedback. However, I'm still not able to get Postman to work with HTTP Post. I did update the screenshots though.
|

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.