1

I've been successfully using this method to GET REST data:

private JArray GetRESTData(string uri)
{
    try
    {
        var webRequest = (HttpWebRequest)WebRequest.Create(uri);
        var webResponse = (HttpWebResponse)webRequest.GetResponse();
        var reader = new StreamReader(webResponse.GetResponseStream());
        string s = reader.ReadToEnd();
        return JsonConvert.DeserializeObject<JArray>(s);
    }
    catch // This method crashes if only one json "record" is found - try this:
    {
        try
        {
            MessageBox.Show(GetScalarVal(uri));
        }
        catch (Exception ex)
        {
            MessageBox.Show(ex.Message);
        }
    }
    return null;
}

Between the webRequest and webResponse assignments, I added this:

if (uri.Contains("Post"))
{
    webRequest.Method = "POST";
}

...and called it with this URI:

http://localhost:28642/api/Departments/PostDepartment/42/76TrombonesLedTheZeppelin

Although I have a Post method that corresponds to it:

Controller

[Route("api/Departments/PostDepartment/{accountid}/{name}/{dbContext=03}")]
public void PostDepartment(string accountid, string name, string dbContext)
{
    _deptsRepository.PostDepartment(accountid, name, dbContext);
}

Repository

public Department PostDepartment(string accountid, string name, string dbContext)
{
    int maxId = departments.Max(d => d.Id);
    // Add to the in-memory generic list:
    var dept = new Department {Id = maxId + 1, AccountId = accountid, Name = name};
    departments.Add(dept);
    // Add to the "database":
    AddRecordToMSAccess(dept.AccountId, dept.Name, dbContext);
    return dept;
}

...it fails with, "The remote server returned an error: (405) Method Not Allowed."

Why is it not allowed?

UPDATE

Based on what I found here: http://blog.codelab.co.nz/2013/04/29/405-method-not-allowed-using-asp-net-web-api/, I added this to Web.Config:

  <validation validateIntegratedModeConfiguration="false" />
    <modules runAllManagedModulesForAllRequests="true">
      <remove name="WebDAVModule" />
    </modules>
    <handlers>
      <remove name="WebDAV" />
      <remove name="ExtensionlessUrlHandler-Integrated-4.0" />
      <add name="ExtensionlessUrlHandler-Integrated-4.0" path="*." verb="GET,HEAD,POST,DEBUG,PUT" 
type="System.Web.Handlers.TransferRequestHandler" resourceType="Unspecified" requireAccess="Script" 
preCondition="integratedMode,runtimeVersionv4.0" />
    </handlers>

...so that it went from this:

<system.webServer>
    <handlers>
      <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>
  </system.webServer></configuration>

...to this:

<system.webServer>
    <validation validateIntegratedModeConfiguration="false" />
    <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="GET,HEAD,POST,DEBUG,PUT" 
type="System.Web.Handlers.TransferRequestHandler" resourceType="Unspecified" requireAccess="Script" 
preCondition="integratedMode,runtimeVersionv4.0" />
    </handlers>
</system.webServer></configuration>

....but it made no diff.

UPDATE 2

It doesn't even make it to the call in the Controller:

        [HttpPost]
[System.Web.Http.Route("api/Departments/PostDepartment/{accountid}/{name}/{dbContext=03}")]
        public void PostDepartment(string accountid, string name, string dbContext)
        {
            _deptsRepository.PostDepartment(accountid, name, dbContext);
        }

I have a breakpoint inside it that's not reached...???

UPDATE 3

VirtualBlackFox's last comment was the one that did the trick. I just changed my "is it a post?" in my client code to the following:

if (uri.Contains("Post"))
{
    webRequest.Method = "POST";
    webRequest.ContentLength = 0; // <-- This line is all I added
}

...and now it works.

B. Clay Shannon-B. Crow Raven
  • 8,547
  • 144
  • 472
  • 862
  • You may need to allow it in your `web.config` or add an attribute to the api method allows `POST`. I've only experience with WCF though, so can't say for sure. – crush Feb 04 '14 at 23:05
  • @CodeCaster: That's why I added the logic to look for "Post" - because of this new type of method I want to use (up until now they have all been "GET"s. – B. Clay Shannon-B. Crow Raven Feb 04 '14 at 23:08
  • 1
    Do other POST methods work, or does it work when requested otherwise, for example trough jQuery? Did you try any of the many results for "web api 405"? – CodeCaster Feb 04 '14 at 23:09
  • @CodeCaster: I haven't gotten my jQuery test to work yet, because of CORS issues (http://stackoverflow.com/questions/21561121/how-do-i-modify-my-web-api-server-code-to-add-a-access-control-allow-origin-hea) – B. Clay Shannon-B. Crow Raven Feb 04 '14 at 23:11

1 Answers1

1

I don't do Asp.Net but i'll guess that you need to specify the HttpPost attribute as can be seen in Attribute Routing / HTTP Methods documentation :

[HttpPost]
[Route("api/Departments/PostDepartment/{accountid}/{name}/{dbContext=03}")]
public void PostDepartment(string accountid, string name, string dbContext)
{
    _deptsRepository.PostDepartment(accountid, name, dbContext);
}

Small sample that work on my PC :

TestController.cs:

using System.Web.Http;

namespace WebApplication2.Controllers
{
    public class TestController : ApiController
    {
        [HttpPost]
        [Route("api/Departments/PostDepartment/{accountid}/{name}/{dbContext=03}")]
        public string PostDepartment(string accountid, string name, string dbContext)
        {
            return accountid + name + dbContext;
        }
    }
}

Test.html :

<!DOCTYPE html>
<html xmlns="http://www.w3.org/1999/xhtml">
<head>
    <script src="http://ajax.aspnetcdn.com/ajax/jQuery/jquery-2.0.3.min.js"></script>
    <script>
        $(function () {
            $.ajax("api/Departments/PostDepartment/accountid/name/dbContext", {
                type: 'POST', success: function (data) {
                    $('#dest').text(data);
                }
            });
        });
    </script>
</head>
<body>
    <div id="dest"></div>
</body>
</html>

Sample program to call the service in C# :

namespace ConsoleApplication1
{
    using System;
    using System.IO;
    using System.Net;
    using Newtonsoft.Json;

    class Program
    {
        static void Main()
        {
            Console.WriteLine(GetRestData(@"http://localhost:52833//api/Departments/PostDepartment/42/76TrombonesLedTheZeppelin"));
            Console.ReadLine();
        }

        private static dynamic GetRestData(string uri)
        {

            var webRequest = (HttpWebRequest)WebRequest.Create(uri);
            webRequest.Method = "POST";
            webRequest.ContentLength = 0;
            var webResponse = (HttpWebResponse)webRequest.GetResponse();
            var reader = new StreamReader(webResponse.GetResponseStream());
            string s = reader.ReadToEnd();
            return JsonConvert.DeserializeObject<dynamic>(s);

        }
    }
}
Julien Roncaglia
  • 17,397
  • 4
  • 57
  • 75
  • I just tried that; although, when adding it, it forces you to choose between two different flavors of HttpPost. The first one didn't make any difference, and the second one won't compile. There's the "generic" one, and then there's a System.Web.MVC option, too. Now it won't let me use either (System.Web.Http being the other). – B. Clay Shannon-B. Crow Raven Feb 04 '14 at 23:49
  • Later: Removing the "system.web.mvc" using allowed me to use the first one (System.Web.Http). Still, though, it makes no difference (it IS supposed to decorate the method in the Controller, right?). – B. Clay Shannon-B. Crow Raven Feb 04 '14 at 23:55
  • Yes it goes on the controller. I created a small minimal sample creating a new Asp.Net project with only WebApi checked and adding a controller and a small html file (see code in answer). It works and display "accountidnamedbContext" as expected – Julien Roncaglia Feb 05 '14 at 00:07
  • Interesting; going the jQuery route won't work for me at present, though, as I'm having unresolved CORS problems with that (http://stackoverflow.com/questions/21561121/how-do-i-modify-my-web-api-server-code-to-add-a-access-control-allow-origin-hea) – B. Clay Shannon-B. Crow Raven Feb 05 '14 at 00:14
  • 1
    I added a small sample program that work for me (Same as the one in your question except that I added `webRequest.ContentLength = 0` to avoid https://stackoverflow.com/questions/5915131/can-i-send-an-empty-http-post-webrequest-object-from-c-sharp-to-iis – Julien Roncaglia Feb 05 '14 at 06:17
  • Excellent; that's all I needed. I'm marking your previous answer as such, for this comment (about adding ContentLength = 0). – B. Clay Shannon-B. Crow Raven Feb 05 '14 at 17:03