Я рассмотрел почти все проблемы WCF Rest PUT / POST в SO и до сих пор не смог определить, почему я не могу PUT или POST для своего веб-сервиса, но могу вызвать тестовый метод GetTime через GET.
Эта конкретная служба обменивает пользовательскую учетную информацию (имя пользователя, пароль и некоторую другую информацию) для токена. Эта информация о токене зашифрована и добавлена в заголовок последующих запросов к другим веб-службам, так что имя пользователя / пароли не нужно передавать везде.
Все вызовы веб-службы по-прежнему обрабатываются как не имеющие состояния, но для доступа к защищенным операциям службы требуется эта информация заголовка аутентификации, а не имя пользователя / пароли.
Договор
[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();
}
Реализация услуг
public class UserService : IUserService
{
#region UserService Members
public AuthToken PutSession(string username, CustomCredential credential)
{
// ...
}
public DateTime GetTime()
{
return DateTime.Now;
}
}
Тестовый код
[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);
}
}
Вышеупомянутый GetTime работает (я добавил только тестовый метод).
[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);
}
}
Приведенный выше код возвращает MethodNotAllowed (405) .
Так же, как еще один тест, я добавил конечную точку Mex к службе, создал новое консольное приложение и добавил «ссылку на службу» к этой службе. Используя сгенерированный клиентский прокси-код, я смог что-то похожее на ....
IUserServiceClient client = new IUserServiceClient();
CustomCredential cred = ...
AuthToken token = client.PutSession("test_username", cred);
Что это говорит о том, что ...
- Веб-сервис правильно размещен в IIS
- Я могу использовать службу с использованием кода, сгенерированного прокси-сервером клиента SOAP
- Я могу получать запросы GET через более дружественный инструментарий HttpClient / rest
- Я протестировал это получить в браузере, и он работает
- По какой-то причине put и другие связанные методы (post, delete и т. Д.) Не работают через остальные инструменты
Понятия не имею, что является причиной этого.
EDIT
Я также заметил, что IIS должен был создать этот файл web.config в корне веб-сайта, на котором размещены сервисы, что, по-видимому, позволяет использовать основные HTTP-глаголы.
<?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>
Я также проверил в IIS 7 сопоставления обработчиков для * .svc и проверил, включены ли «все глаголы».