WebApi routing for asp.net WebForms returns 404

I think others were very close. Try this:

[RoutePrefix("api")]  // or maybe "api/", can't recall OTTOMH...
public class MyController : ApiController
{
    [Route("MyController")]
    [HttpPost]
    public HttpResponseMessage Post([FromBody]string value)

and then request /api/MyController

If this doesn't work, use RouteDebugger to analyze your routes, and why it rejects a match. Amend your question with what you see in RouteDebugger so I can trace down what is not matching.

Also, you may need to call MapHttpAttributeRoutes in your Register function - but not sure about that.


Edit

Now that I'm looking at it again, I think I see more issues with it.

First, let's start with the template:

Here is what you have (from your question):

config.Routes.MapHttpRoute(
                    name: "DefaultApi",
                    routeTemplate: "api/{controller}",
                    defaults: new { id = System.Web.Http.RouteParameter.Optional });

The odd part here is that your template does not have {id} segment, but is defined as optional. Sounds like it is missing from the template, and the route should be changed to:

config.Routes.MapHttpRoute(
    name: "DefaultApi",
    routeTemplate: "api/{controller}/{id}",
    defaults: new { id = System.Web.Http.RouteParameter.Optional });

Note that you also removed default action - I'm not sure if MVC automatically uses convention method of locating a method called Post, but I suppose it does.

Second problem is that your method signature is (again from your question):

public HttpResponseMessage Post([FromBody]string value)

It defines Post that takes in a parameter named value, whereas your route defines parameter named id. Hence there is another mismatch. You can rename the variable or decorate (see below). Also, {id} is marked optional, but I believe (and here I don't remember exactly OTTOMH) you need to give default value to to value for those cases where {id} is not supplied, and so combining together:

public HttpResponseMessage Post([FromBody(Name="id")]string value = null)

This should fix it, although there may be more issues... but let's start with these.