0

I am new to web api in general and I am having problems with web api core when it comes to creating a new database entry using POST. The ajax call looks like;

addSelectedContract = function (contractId, url, callback) {
        // hard code url to get working
        url = "http://localhost:17972/api/selectedcontracts";
        var contract = JSON.stringify({ contractId: contractId });
        $.ajax({
            type: "Post",
            url: url,
            data: contract,
            contentType: "application/json"
        }).done(callback(status));
        };

My API method looks like;

namespace Properties.API.Controllers
{
    [Route("api/selectedcontracts")]
    public class SelectedContractController : BaseController
    {
        private readonly ISirUoW SirUoW;
        private readonly SirDb Db;

        public SelectedContractController(SirDb db, ISirUoW repo, Services.IMailService mailService)
            : base(mailService)
        {
            this.Db = db;
            this.SirUoW = repo;
        }

        [HttpPost()]
        public IActionResult Post([FromBody] SelectedContract contract)
        {
            try
            {
                this.SirUoW.SelectContract.Add(contract);
                return Ok(new OperationStatus
                {
                    Status = true,
                    OperationID = contract.SelectedContractId
                });
            }
            catch (Exception e)
            {
                Console.WriteLine(e);
                var status = Mapper.Map<OperationStatus>(e);
                return Ok(status);
            }
        } 

My test from powershell gives this result;

Invoke-RestMethod http://localhost:xxxx/api/selectedcontracts -Method POST -Body (@{contractId="7"} | ConvertTo-Json) -ContentType "application/json"
[ERROR] Invoke-RestMethod : The remote server returned an error: (500) Internal Server Error.
[ERROR] At line:1 char:1
[ERROR] + Invoke-RestMethod http://localhost:xxxx/api/selectedcontracts -Method POST -Bod ...
[ERROR] + ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
[ERROR]     + CategoryInfo          : InvalidOperation: (System.Net.HttpWebRequest:HttpWebRequest) [Invoke- 
[ERROR]    RestMethod], WebException
[ERROR]     + FullyQualifiedErrorId : WebCmdletWebResponseException,Microsoft.PowerShell.Commands.InvokeRes 
[ERROR]    tMethodCommand
[ERROR]  

The SelectedContract class is defined as; namespace SIR.Domain.Poco { using Interfaces; using System; using System.ComponentModel.DataAnnotations;

public class SelectedContract : IAuditCreated
{
    [Key]
    public int SelectedContractId { get; set; }

    public int ContractId { get; set; }

    public DateTime Created { get; set; }

    [MaxLength(50)]
    public string CreatedBy { get; set; }
}

} I have searched around for example code and I cannot see what I am doing wrong.

EDIT: I have made a change although I get the same result. The SelectedContract class is defined as;

    namespace SIR.Domain.Poco
    {
        using Interfaces;
        using System;
        using System.ComponentModel.DataAnnotations;

        public class SelectedContract : IAuditCreated
        {
            [Key]
            public int SelectedContractId { get; set; }

            public int ContractId { get; set; }

            public DateTime Created { get; set; }

            [MaxLength(50)]
            public string CreatedBy { get; set; }
        }
    }

However I am only sending one the fields, the ContractId. I do not want to send the primary key or the audit fields. So I have created a DTO class;

    namespace Properties.API.Models
    {
        public class SelectedContractDto
        {
            public int ContractId { get; set; }
        }
    }

And changed the signature of my Post method in the API;

        [HttpPost()]
        public IActionResult Post([FromBody] SelectedContractDto contract)
        {
            var selectedContract = new SelectedContract { ContractId = Convert.ToInt32(contract.ContractId) };
            try
            {
                this.SirUoW.SelectContract.Add(selectedContract);
                return Ok(new OperationStatus
                {
                    Status = true,
                    OperationID = selectedContract.SelectedContractId
                });
            }
            catch (Exception e)
            {
                Console.WriteLine(e);
                var status = Mapper.Map<OperationStatus>(e);
                return Ok(status);
            }
        }

Still get the 500 Internal Server Error. I had a look in Fiddler and found this error as well

An unhandled exception occurred while processing the request.
InvalidOperationException: 'Microsoft.AspNetCore.Mvc.MvcOptions.InputFormatter c2 s' must not be empty. At least one 'Microsoft.AspNetCore.Mvc.Formatters.IInputFormatter' is required to bind from the body.
Microsoft.As fdc pNetCore.Mvc.ModelBinding.Binders.BodyModelBinderProvider.GetBinder(ModelBinderProviderContext context)

I cant find anything about this error online.

arame3333
  • 9,887
  • 26
  • 122
  • 205

1 Answers1

0

I assume that you call is hitting method but after that there is error which is not shown in try-catch block? Check "Common Language Runtime Exceptions" in Debug -> Windows -> Exception Settings and try again.

Post result.

lolek
  • 59
  • 3
  • 12
  • please add a structure of SelectedContract class and update your question. also read [this](http://stackoverflow.com/questions/24625303/why-do-we-have-to-specify-frombody-and-fromuri-in-asp-net-web-api) and make sure that you are using [FromBody] properly. – lolek May 11 '17 at 08:56
  • read [this](http://stackoverflow.com/questions/41559050/string-value-is-empty-when-using-frombody-in-asp-net-web-api) and try to manipulate a little your ajax request and use your contract object without JSON.stringify() method – lolek May 11 '17 at 09:49
  • I am not making any headway, although I notice that the question you link to is for web api rather than web api core. Are they the same for POST methods on an API? – arame3333 May 11 '17 at 10:04