Reputation: 1958
I have looked at nearly every single WCF Rest PUT/POST issues on SO here and have still been unable to determine why I am unable to PUT or POST to my web service but am able to call a test GetTime method via GET.
This particular service exchanges custom credential information (username, password and some other information) for a token. This token information is encrypted and added to the header of subsequent requests to other web services so that username/passwords don't have to be passed around everywhere.
All web service calls are still treated as stateless, but require this auth header information rather username/passwords to access secured service operations.
Contract
[ServiceContract(Namespace = "")]
public interface IUserService
{
[WebInvoke(Method = "PUT", UriTemplate = "users/{username}/session")]
[WebHelp(Comment = "Creates a new session for the specified username")]
[OperationContract]
AuthToken PutSession(string username, CustomCredential credential);
...
[WebInvoke(Method = "GET", UriTemplate = "time")]
[WebHelp(Comment = "Test method; returns the time")]
[RequireAuthToken]
[OperationContract]
DateTime GetTime();
}
Service Impelementation
public class UserService : IUserService
{
#region UserService Members
public AuthToken PutSession(string username, CustomCredential credential)
{
// ...
}
public DateTime GetTime()
{
return DateTime.Now;
}
}
Test Code
[Fact]
public void When_Authenticated_And_Getting_Time_Expect_200_Status()
{
// arrange
using (var client = Get_HttpClient_With_AuthHeaders()) {
// act
var result = client.Get("time");
// assert
Assert.Equal(HttpStatusCode.OK, result.StatusCode);
}
}
The aforementioned GetTime works (just a test method I added).
[Fact]
public void When_PuttingSession_Expect_AuthToken_Is_Returned()
{
// arrange
using (var client = Get_HttpClient_With_No_Auth_Headers()) {
var cred = new CustomCredential("test", "password", 1);
var content = HttpContentExtensions.CreateDataContract<CustomCredential>(cred);
// act
HttpResponseMessage response = client.Put("users/test/session", content);
// assert
response.EnsureStatusIsSuccessful();
Assert.Equal(HttpStatusCode.Created, response.StatusCode);
var authToken = response.Content.ReadAsDataContract<AuthToken>();
Assert.NotNull(authToken);
}
}
The above put returns a MethodNotAllowed (405).
Just as another test I added a Mex endpoint to the service, created a new console app and added a 'service reference' to this service. Using the generated client proxy code, I was able to something similar to....
IUserServiceClient client = new IUserServiceClient();
CustomCredential cred = ...
AuthToken token = client.PutSession("test_username", cred);
What this suggests is that...
Have no idea what is causing this one.
EDIT
I also noticed that IIS must have created this web.config in the root of the website where the services are hosted which would seem to be allowing the main HTTP verbs.
<?xml version="1.0" encoding="UTF-8"?>
<configuration>
<system.webServer>
<security>
<requestFiltering>
<verbs>
<add verb="PUT" allowed="true" />
<add verb="GET" allowed="true" />
<add verb="POST" allowed="true" />
<add verb="DELETE" allowed="true" />
</verbs>
<fileExtensions>
<add fileExtension=".svc" allowed="true" />
</fileExtensions>
</requestFiltering>
</security>
</system.webServer>
</configuration>
I have also checked in IIS 7 the handler mappings for *.svc and checked that 'all verbs' are enabled.
Upvotes: 2
Views: 3856
Reputation: 364279
Check that related handler for .svc in IIS is allowed to process HTTP POST, PUT, DELETE. In case of problems with only PUT and DELETE check that your virtual directory is not configured for WebDAV (I think it is some HTTP module).
Upvotes: 1