Steve Gaines
Steve Gaines

Reputation: 601

Why Does My Web API Fail On Put Only?

I have written a Web API in ASP.NET and I have written a test method in a desktop application that calls the Web API. The test method inserts a new record, updates the record, then deletes the record. The insert is successful and I can see the new record in the database table. The delete method also works and the record is removed from the table. The update method fails with this error message:

Response status code does not indicate success: 405 (Method Not Allowed).

I created the Web API using Visual Studio's normal process and I did not modify the framework code that it built. I have created a utility function called WebSave (shown below) to handle both the insert and update functions. I can't see why the update is any different in substance. Hopefully someone here can tell me.

    private void SaveData_Test()
    {
        string sRequestURI = "http://localhost:49625/api/tipshare_def";
        int iStoreNo = 40004;
        tipshare_def oTipShareDef = new tipshare_def() { storeno = iStoreNo, tipshare_type = 1, total_bar_share = (decimal)1.0, food_bar_share = (decimal)0.6, alc_bar_share = (decimal)0.4, job_exclude1 = 1, job_exclude2 = 1, job_exclude3 = 0 };
        Utilities.WebSave(sRequestURI, oTipShareDef, typeof(tipshare_def), true);
        oTipShareDef.food_bar_share = (decimal)0.7;
        oTipShareDef.alc_bar_share = (decimal)0.3;
        Utilities.WebSave(sRequestURI, oTipShareDef, typeof(tipshare_def), false);
        string sRequestURI2 = "http://localhost:49625/api/tipshare_def/" + iStoreNo.ToString("0");
        Utilities.WebDelete(sRequestURI2);
    }

        public static async Task WebSave(string sRequestURI, object oRecord, Type tRecordType, bool bNewRecord)
    {
        try
        {
            HttpClient oHttpClient = new HttpClient();
            if (bNewRecord == true)
            {
                HttpResponseMessage oResponse = await oHttpClient.PostAsJsonAsync(sRequestURI, oRecord);
                oResponse.EnsureSuccessStatusCode();
                HttpStatusCode oStatus = oResponse.StatusCode;
                string sStatus = oStatus.ToString();
            }
            else
            {
                HttpResponseMessage oResponse = await oHttpClient.PutAsJsonAsync(sRequestURI, oRecord);
                oResponse.EnsureSuccessStatusCode();
                HttpStatusCode oStatus = oResponse.StatusCode;
                string sStatus = oStatus.ToString();
            }
        }
        catch (Exception oException)
        {
            HandleError("WebSave", oException);
        }
    }

// Here is the related Web API code:

    // PUT: api/tipshare_def/5
    [ResponseType(typeof(void))]
    public async Task<IHttpActionResult> Puttipshare_def(int id, tipshare_def tipshare_def)
    {
        if (!ModelState.IsValid)
        {
            return BadRequest(ModelState);
        }

        if (id != tipshare_def.storeno)
        {
            return BadRequest();
        }

        db.Entry(tipshare_def).State = EntityState.Modified;

        try
        {
            await db.SaveChangesAsync();
        }
        catch (DbUpdateConcurrencyException)
        {
            if (!tipshare_defExists(id))
            {
                return NotFound();
            }
            else
            {
                throw;
            }
        }

        return StatusCode(HttpStatusCode.NoContent);
    }

    // POST: api/tipshare_def
    [ResponseType(typeof(tipshare_def))]
    public async Task<IHttpActionResult> Posttipshare_def(tipshare_def tipshare_def)
    {
        if (!ModelState.IsValid)
        {
            return BadRequest(ModelState);
        }

        db.tipshare_def.Add(tipshare_def);

        try
        {
            await db.SaveChangesAsync();
        }
        catch (DbUpdateException)
        {
            if (tipshare_defExists(tipshare_def.storeno))
            {
                return Conflict();
            }
            else
            {
                throw;
            }
        }

        return CreatedAtRoute("DefaultApi", new { id = tipshare_def.storeno }, tipshare_def);
    }

Upvotes: 2

Views: 1729

Answers (2)

David L
David L

Reputation: 33823

In this case, your parameters do not match. You have an Id in your PUT request but not in your POST.


As a general rule, if you receive a 405 response on only a few verbs (usually PUT and DELETE), you need to update your web.config with one of the following changes:

<system.webServer>
    <handlers>
        <add name="ExtensionlessUrlHandler-Integrated-4.0" path="*." 
            verb="GET,HEAD,POST,DEBUG,PUT,DELETE" 
            type="System.Web.Handlers.TransferRequestHandler"              
            preCondition="integratedMode,runtimeVersionv4.0" />
    </handlers>
</system.webServer>

It is also possible that WEBDAV will interfere with your requests. The following will remove it.

<modules runAllManagedModulesForAllRequests="true">
    <remove name="WebDAVModule"/>
</modules>

Upvotes: 4

maniak1982
maniak1982

Reputation: 717

I've gotten this error from one of two different reasons:

  1. The HTTP Verb is not allowed.

The fix for this is posted above by David L.

  1. Cross-origin resource sharing is not enabled for the service.

The solution to this can be a bit more complex, as it depends on which version of the Web API that you are using and which version of ASP.NET you are using. Microsoft has provided an article on enabling Cross-Origin Requests in ASP.NET Web API 2, which is a good place to start:

http://www.asp.net/web-api/overview/security/enabling-cross-origin-requests-in-web-api

Upvotes: 0

Related Questions