Ошибка WCF: 405 Метод не разрешен
Идти орехи с этой проблемой. У меня есть решение с двумя проектами, один из них - простой старый html с jquery ajax-вызовом, а другой - служба WCF. На странице html вызывается вызов ajax для службы WCF, чтобы получить строку json и использовать ее для показа.
Теперь проблема возникает, когда я запускаю в режиме отладки, и html-страница, и WCF будут запущены с другим портом. И это создало проблему с перекрестным происхождением для меня, когда я выполняю тестирование (т.е. Получение ошибки 405 "Метод не разрешенной" с вызывающим типом = ОПЦИИ в Firefox). Я бы тройным образом проверял метод вызова на моем ajax script, а служба WCF была одинаковой (GET).
Я бы поискал google, но обнаружил, что либо мне нужно установить расширение, либо выполнить некоторую конфигурацию в IIS, что я нашел громоздким, так как то, что я делаю, является чем-то простым. Следуя одному примеру, я добавлю следующую конфигурацию в свой web.config, но это не сработало:
<system.serviceModel>
<bindings>
<webHttpBinding>
<binding name="crossDomain" crossDomainScriptAccessEnabled="true" />
</webHttpBinding>
</bindings>
<behaviors>
<endpointBehaviors>
<behavior name="MobileService.webHttpBehavior">
<webHttp />
</behavior>
</endpointBehaviors>
<serviceBehaviors>
<behavior name="MyServiceBehavior">
<serviceMetadata httpGetEnabled="true" />
<serviceDebug includeExceptionDetailInFaults="true"/>
</behavior>
</serviceBehaviors>
</behaviors>
<serviceHostingEnvironment aspNetCompatibilityEnabled="true" multipleSiteBindingsEnabled="true" />
<services>
<service name="MobileService.SimpleMemberInfo" behaviorConfiguration="MyServiceBehavior">
<endpoint address="" binding="webHttpBinding" contract="MobileService.IMemberInfo" bindingConfiguration="crossDomain" behaviorConfiguration="MobileService.webHttpBehavior">
</endpoint>
</service>
</services>
</system.serviceModel>
<system.webServer>
<httpProtocol>
<customHeaders>
<add name="Access-Control-Allow-Origin" value="*" />
<add name="Access-Control-Allow-Methods" value="GET" />
<add name="Access-Control-Allow-Headers" value="Content-Type, Accept" />
</customHeaders>
</httpProtocol>
<modules runAllManagedModulesForAllRequests="true"/>
<directoryBrowse enabled="true"/>
</system.webServer>
У кого-нибудь есть идея избавиться от этой досадной проблемы?
РЕДАКТИРОВАТЬ: Чтобы добавить, я запускаю отладку с помощью IIS Express, который поставляется вместе с VS Studio 2012
Добавить в код WCF и обновить web.config
[ServiceContract]
public interface IMemberInfo
{
[WebInvoke(Method = "GET",
BodyStyle = WebMessageBodyStyle.Wrapped,
ResponseFormat = WebMessageFormat.Json
)]
[OperationContract]
string GetMemberInfoById();
// TODO: Add your service operations here
}
Мой Script:
$(document).ready(function () {
$.ajax("http://localhost:32972/SimpleMemberInfo.svc/GetMemberInfoById", {
cache: false,
beforeSend: function (xhr) {
$.mobile.showPageLoadingMsg();
},
complete: function () {
$.mobile.hidePageLoadingMsg();
},
contentType: 'application/json',
dataType: 'json',
type: 'GET',
error: function () {
alert('Something awful happened');
},
success: function (data) {
var s = "";
s += "<li>" + data + "</li>";
$("#myList").html(s);
}
});
});
Ответы
Ответ 1
Вам нужно использовать JSONP для междоменного вызова, чтобы обойти ограничения браузера и обновить ваш web.config с помощью crossDomainScriptAccessEnabled
, установленного в true, чтобы обойти серверные. Вот хороший пример в ответе: как избежать перекрестной политики домена в jQuery ajax для использования службы wcf?
У вас также может возникнуть проблема с запросами GET. Попробуйте исправления, изложенные здесь:
Создание веб-службы WCF с помощью запросов GET
В целом вы хотите, чтобы web.config выглядел примерно так:
<bindings>
<webHttpBinding>
<binding name="crossDomain" crossDomainScriptAccessEnabled="true" />
</webHttpBinding>
</bindings>
<behaviors>
<endpointBehavior>
<behavior name="restBehavior">
<webHttp />
</behavior>
</endpointBehavior>
<serviceBehavior>
<behavior name="MyServiceBehavior">
<serviceMetadata httpGetEnabled="true" />
<serviceDebug includeExceptionDetailInFaults="true"/>
</behavior>
</serviceBehavior>
</behaviors>
<services>
<service name="..." behaviorConfiguration="MyServiceBehavior">
<endpoint address="" binding="webHttpBinding" bindingConfiguration="crossDomain"
contract="..." behaviorConfigurations="restBehavior" />
</service>
</services>
(Обратите внимание, что и служба, и конечная точка привязаны к поведению, разрешая вызовы webHttp и вызовы httpGet соответственно, и что привязка имеет доступ к CrossDomain явно).
... метод службы, украшенный следующим образом:
[ServiceContract]
public interface IMyService
{
[WebGet] // Required Attribute to allow GET
[OperationContract]
string MyMethod(string MyParam);
}
... и клиентский вызов с использованием JSONP:
<script type="text/javascript">
$(document).ready(function() {
var url = "...";
$.getJSON(url + "?callback=?", null, function(result) { // Note crucial ?callback=?
// Process result
});
});
</script>
Ответ 2
Однако его старый поток, но я хотел бы добавить свой комментарий о проблемах, с которыми я столкнулся, и о решении, которое я получил для работы CORS.
Я разрабатываю веб-сервис в следующей среде:
- Веб-сервис WCF.
- Структура .NET 3.5.
- Добавлен веб-сервис wcf на существующий веб-сайт asp.net.
- Visual Studio 2008
Большинство людей упомянули о добавлении атрибута crossDomainScriptAccessEnabled
в тег под <webHttpBinding>
в web.config. Я не уверен, что это работает или нет, но его нет в версии 3.5, поэтому у меня не было выбора. Я также обнаружил, что добавление следующих тегов в web.config будет работать...
<httpProtocol>
<customHeaders>
<add name="Access-Control-Allow-Origin" value="*" />
<add name="Access-Control-Allow-Methods" value="GET" />
<add name="Access-Control-Allow-Headers" value="Content-Type, Accept" />
</customHeaders>
</httpProtocol>
но не повезло... продолжал получать ошибки 405 не допускал ошибок
После многого с этими опциями я нашел другое решение для добавления этих заголовков в файл global.asax динамически в соответствии с приведенным ниже...
protected void Application_BeginRequest(object sender, EventArgs e)
{
HttpContext.Current.Response.AddHeader("Access-Control-Allow-Origin", "*");
if (HttpContext.Current.Request.HttpMethod == "OPTIONS")
{
HttpContext.Current.Response.AddHeader("Cache-Control", "no-cache");
HttpContext.Current.Response.AddHeader("Access-Control-Allow-Methods", "GET, POST");
HttpContext.Current.Response.AddHeader("Access-Control-Allow-Headers", "Content-Type, Accept, Authorization");
HttpContext.Current.Response.AddHeader("Access-Control-Max-Age", "1728000");
HttpContext.Current.Response.End();
}
}
И удалите файл web.config. Публикуйте веб-сайт и продолжайте работу с jQuery/ajax на стороне клиента... и вы получите данные из вызовов api. Удачи!
Ответ 3
Просто хотел добавить некоторые проблемы с обработкой CORS внизу. Проблема заключается в том, что если ваш вход не поддерживает метод GET и POST, запрос OPTIONS фактически не возвращает правильные разрешенные заголовки. На самом деле, он не смотрит, какие методы фактически разрешены на конечной точке WCF - его просто искусственное выражение "GET, POST" разрешено для каждой отдельной конечной точки в приложении, когда клиент выполняет запрос OPTIONS (который действительно является клиентом, спрашивающим, поддерживается).
Это, вероятно, хорошо, если вы действительно не полагаетесь на информацию в методе OPTIONS, чтобы вернуть вам правильный список методов (как в случае с некоторыми запросами CORS), но если вы находитесь, вам нужно будет сделайте что-нибудь вроде решения по этому вопросу:
Как обрабатывать запрос AJAX JACKERY POST с самообслуживанием WCF
В принципе, каждая конечная точка должна реализовывать:
Webinvoke(Method="OPTIONS", UriTemplate="")
и вызовите соответствующий метод, который загружает соответствующие заголовки в ответ (включая правильный список "Access-Control-Allow-Method" для этой конечной точки) вызывающему. Это отвратительно, что размещенные конечные точки WCF не делают этого для нас автоматически, но это временное решение, которое позволяет более точно контролировать конечную точку.
В этом решении правильные заголовки ответов загружаются в реализацию конечной точки:
public void GetOptions()
{
// The data loaded in these headers should match whatever it is you support on the endpoint
// for your application.
// For Origin: The "*" should really be a list of valid cross site domains for better security
// For Methods: The list should be the list of support methods for the endpoint
// For Allowed Headers: The list should be the supported header for your application
WebOperationContext.Current.OutgoingResponse.Headers.Add("Access-Control-Allow-Origin", "*");
WebOperationContext.Current.OutgoingResponse.Headers.Add("Access-Control-Allow-Methods", "POST, GET, OPTIONS");
WebOperationContext.Current.OutgoingResponse.Headers.Add("Access-Control-Allow-Headers", "Content-Type, Accept, Authorization");
}
Ответ 4
попробуйте использовать.
WebInvoke(Method = "POST")
вместо WebInvoke(Method = "GET")