5

There are so many questions in SO similar to this, but none have fixed my issue.

I've have an angularjs website hosted at http://localhost:49595 and I'm calling a Web Api 2.1 service hosted at http://localhost:63019. I've enabled CORS on the web api server in web.config. Requests for GET /buildings/1 and GET /buildings/?$top=10&$skip=1 work fine.

When it comes to PUT, I get the following error: { "Message":"No HTTP resource was found that matches the request URI 'http://localhost:63019/buildings/1105'.", "MessageDetail":"No action was found on the controller 'Building' that matches the request." }

Error in chrome

I can see the browser sends the OPTIONS request to the server, but the actual data to be updated is not in the request (checked in fiddler. Not sure if this is normal for an OPTIONS query.

enter image description here

I enabled tracing on the web api, and I see the following log. https://gist.github.com/rnarayana/8905229 The OPTIONS request (line 69) says it needs to do a PUT. Around line 77, it looks like it picked the correct action. And then the controller gets disposed. Moreover the controller is getting instantiated twice.

How can I find out what is happening?

Calling code in AngularJS: Tried:

$http.put('http://localhost:63019/buildings/' + building.BuildingId, building)
.then(onSuccess, onError);

also

$http({
    url: urlBase + '/' + building.BuildingId,
    dataType: 'json',
    method: 'PUT',
    data: building,
    headers: {"Content-Type": "application/json"}
}).then(onSuccess, onError);

These are in my controller:

[HttpGet]
[Route("buildings/")]
public IHttpActionResult GetAll(ODataQueryOptions<BuildingViewModel> queryOptions)
{
}

[HttpGet]
[Route("buildings/{id}")]
public IHttpActionResult Get(long id)
{
}

[Route("buildings/")]
[HttpPost]
public IHttpActionResult Post(BuildingEditViewModel buildingEditViewModel)
{
}

[HttpPut]
[Route("buildings/{id}")]
public IHttpActionResult Put(long id, [FromBody]BuildingEditViewModel buildingEditViewModel)
{
}

//Added this as per some blog. Not helping.
[HttpOptions]
[Route("buildings/{id}")]
public HttpResponseMessage Options(long id)
{
    var response = new HttpResponseMessage();
    response.StatusCode = HttpStatusCode.OK;
    return response;
}

My webapi web.config has:

<system.webServer>
        <modules runAllManagedModulesForAllRequests="true">
          <remove name="WebDAVModule" />
        </modules>
        <handlers>
          <remove name="WebDAV" />
          <remove name="ExtensionlessUrlHandler-Integrated-4.0" />
          <remove name="OPTIONSVerbHandler" />
          <remove name="TRACEVerbHandler" />
          <add name="ExtensionlessUrlHandler-Integrated-4.0" path="*." verb="*" type="System.Web.Handlers.TransferRequestHandler" preCondition="integratedMode,runtimeVersionv4.0" />
        </handlers>
        <httpProtocol>
          <customHeaders>
            <add name="Access-Control-Allow-Origin" value="http://localhost:49595" />
            <add name="Access-Control-Allow-Methods" value="GET, POST, OPTIONS, PUT, DELETE" />
            <add name="Access-Control-Allow-Headers" value="*" />
          </customHeaders>
        </httpProtocol>
    </system.webServer>

My WebApiConfig.Register() has:

public static void Register(HttpConfiguration config)
    {
    config.EnableSystemDiagnosticsTracing();
    config.Services.Replace(typeof(ITraceWriter), new WebApiTracer());

    //Enable CORS. The allowed origins and verbs are in the config file. Do not add in both places.
    config.EnableCors();

    // Attribute routing.
    config.MapHttpAttributeRoutes();

    config.Formatters.XmlFormatter.SupportedMediaTypes.Remove(
        config.Formatters.XmlFormatter.SupportedMediaTypes.FirstOrDefault((t => t.MediaType == "application/xml")));
}
Narayana
  • 2,654
  • 3
  • 32
  • 32
  • I found that removing the settings from the config and explicitly defining them in the Register method worked for me. Try starting with permissions for all (i.e. *) and work your way from there....Make sure you dont deploy that to production though :) – link64 Feb 10 '14 at 01:22

2 Answers2

6

I had issues getting it to work with the the values in the config so I removed them from there and I added the following to my WebApiConfig class:

        //Specify values as appropriate (origins,headers,methods)
        var cors = new EnableCorsAttribute("http://myurl","*","*");
        config.EnableCors(cors);

You can find the nuget package for Microsoft ASP.NET Web API 2.2 Cross-Origin from here

Reza
  • 18,865
  • 13
  • 88
  • 163
link64
  • 1,944
  • 1
  • 26
  • 41
  • I don't believe this! It worked when I moved it out of web.config. But why was GET alone working earlier? PUT and POST don't work because they are Preflight requests? – Narayana Feb 10 '14 at 03:53
  • I am not quite sure why. I had faced the exact same problem only a few days ago and stumbled across this solution myself – link64 Feb 10 '14 at 04:54
  • http://stackoverflow.com/questions/12458444/enabling-cross-origin-resource-sharing-on-iis7 gives the IIS configurations required to set this up. – Narayana Feb 25 '14 at 09:58
2

Besides the config option config.EnableCors(); in your Register method you need to enable CORS in your controller by using [EnableCors] attribute along with the declaration of the controller, here is an example how I do it:

 [EnableCors(origins: "http://localhost:49595", headers: "*", methods: "*")]
 public class ValuesController : ApiController
 {
 ...
Dalorzo
  • 19,834
  • 7
  • 55
  • 102
  • You are in a way correct, but I had put these values in the web.config file. GET works, but not PUT and POST. But what @link64 has given - moving it out of web.config- fixed my issue. – Narayana Feb 10 '14 at 03:54