3

I need to build an ASP.NET Core 2.0 Web API app that will be able to have custom XML input and output formatting done.

I have been having success in setting up a custom output formatter but not a custom input formatter.

more precisely, this is the startup configuration:

public void ConfigureServices(IServiceCollection services)
{
    services
        .AddMvc(opt =>
        {
            opt.ReturnHttpNotAcceptable = true;

            opt.OutputFormatters.Clear();
            opt.InputFormatters.Clear();
            opt.InputFormatters.Add(new SoapInputFormatter());
            opt.OutputFormatters.Add(new SoapOutputFormatter());
        });
}

The idea is to have custom SOAP input and output formatting. No, the existing XmlDataContractSerializerInputFormatter will not do.

The SoapOutputFormatter class:

public class SoapOutputFormatter : IOutputFormatter
{
    public bool CanWriteResult(OutputFormatterCanWriteContext context)
    {
        return true;
    }

    public async Task WriteAsync(OutputFormatterWriteContext context)
    {
        var bytes = Encoding.UTF8.GetBytes(context.Object.ToString());
        await context.HttpContext.Response.Body.WriteAsync(bytes, 0, bytes.Length);
    }
}

and the SoapInputFormatter class:

public class SoapInputFormatter : InputFormatter
{
    public override Task<InputFormatterResult> ReadRequestBodyAsync(InputFormatterContext context)
    {
        throw new NotImplementedException();
    }

    protected override bool CanReadType(Type type)
    {
        return true;
    }
}

I've setup breakpoints just to get the code called so later I can actually implement useful code. But the SoapInputFormatter class does not get called at all. The controller:

[Route("api/[controller]")]
public class ValuesController : Controller
{
    // GET api/values
    [HttpGet]
    public IEnumerable<string> Get()
    {

        return new string[] { "value1", "value2" };
    }

    // GET api/values/5
    [HttpGet("{id}")]
    public string Get(int id)
    {
        return "value";
    }

    // POST api/values
    [HttpPost]
    public void Post([FromBody]string value)
    {
    }

    // PUT api/values/5
    [HttpPut("{id}")]
    public void Put(int id, [FromBody]string value)
    {
    }

    // DELETE api/values/5
    [HttpDelete("{id}")]
    public void Delete(int id)
    {
    }
}

(the classic new web api app controller)

I am doing POSTs with the Postman app. No POST will hit the SoapInputFormatter.

Any tips? Any ideas?

Ian Kemp
  • 28,293
  • 19
  • 112
  • 138
Andrei Rînea
  • 20,288
  • 17
  • 117
  • 166

2 Answers2

7

Had the same problem and then found this link:

http://www.dotnetcurry.com/aspnet-mvc/1368/aspnet-core-mvc-custom-model-binding

It basically comes down to these items in the article:

  • Not every binding source is checked by default. Some model binders require you to specifically enable a binding source. For example, when binding from the Body, you need to add [FromBody] to your model/action parameter, otherwise the BodyModelBinder won’t be used.
  • In particular, the Headers, Body and Files binding sources must be specifically enabled by the user and will use specific model binders

I added [FromBody] on the POST request and the my custom InputFormatter was then called.

-Rick

Rick
  • 119
  • 1
  • 7
0

Im a bit late, but you need to use [ApiController] in order to use an InputFormatter.

Edit as requested:

[ApiController]
[Route("api/[controller]")]
public class ValuesController : Controller
{
  // GET api/values
  [HttpGet]
  public IEnumerable<string> Get()
  {
      return new string[] { "value1", "value2" };
  }
}
....
Patrick Laramee
  • 171
  • 1
  • 11