У меня есть проект WebAPI, и я включил CORS, выполнив следующие шаги:
Install-Package Microsoft.AspNet.WebApi.Cors
.config.EnableCors();
к WebApiConfig.cs.[EnableCors(origins: "*", headers: "*", methods: "*")]
к моему контроллеру.У меня есть контроллеры, которые находятся в папке корневых контроллеров и внутри области.
/Controllers/ValuesController
/Areas/TestArea/Controllers/OtherStuffController
Оба контроллера имеют [EnableCors(...)]
.
Моя проблема в том, что работает только ValuesController
.
Используя Fiddler для проверки запросов для OtherStuffController
я вижу, что клиент отправляет запрос предварительной OtherStuffController
OPTIONS, но ответы сервера с 404 не найдены вместо 200 OK, но ValuesController
отлично работает.
Что я делаю не так? Почему контроллер в области TestArea не работает с запросами CORS, но контроллер Values делает это?
Нет ничего особенного в двух контроллерах, кроме имени, и что это в области.
ДОПОЛНИТЕЛЬНАЯ ИНФОРМАЦИЯ
Маршруты:
// In WebApiConfig.cs
config.Routes.MapHttpRoute("DefaultApi", "{controller}/{id}",
new {id = RouteParameter.Optional} );
// In Areas/TestArea/TestAreaAreaRegistration.cs
context.MapRoute("TestArea_default","TestArea/{controller}/{id}",
new {id = UrlParameter.Optional});
URL-адреса, которые я использую для доступа к методам действий:
http://localhxst:57578/values
http://localhxst:57578/testarea/otherstuff
Запрос значений (рабочий):
(REQUEST)
OPTIONS http://localhost:57578/values HTTP/1.1
Host: localhost:57578
User-Agent: Mozilla/5.0 (Windows NT 6.3; WOW64; rv:31.0) Gecko/20100101 Firefox/31.0
Accept: text/html,application/xhtml+xml,application/xml;q=0.9,*/*;q=0.8
Accept-Language: en-gb,en;q=0.5
Accept-Encoding: gzip, deflate
Origin: http://localhxst:12345
Access-Control-Request-Method: GET
Access-Control-Request-Headers: authorization
Connection: keep-alive
(RESPONSE)
HTTP/1.1 200 OK
Cache-Control: no-cache
Pragma: no-cache
Expires: -1
Server: Microsoft-IIS/8.0
Access-Control-Allow-Origin: *
Access-Control-Allow-Headers: authorization
X-AspNet-Version: 4.0.30319
X-SourceFiles: =?UTF-8?B?QzpcVXNlcnNcYmVuLmdvbGRlblxEb2N1bWVudHNcV29ya1xWb2ljZVNpbXBsaWZpZWRcQVBJXFZvaWNlU2ltcGxpZmllZC5QdWJsaWNBUElcdmFsdWVz?=
X-Powered-By: ASP.NET
Date: Thu, 24 Jul 2014 20:12:56 GMT
Content-Length: 0
С последующим:
(REQUEST)
GET http://localhxst:57578/values HTTP/1.1
Host: localhost:57578
User-Agent: Mozilla/5.0 (Windows NT 6.3; WOW64; rv:31.0) Gecko/20100101 Firefox/31.0
Accept: application/json
Accept-Language: en-gb,en;q=0.5
Accept-Encoding: gzip, deflate
Authorization: Bearer HQkpyzeQ5NM1Va1Ow__6N6JzuRdMweDIJDneDQer1tL1uMhkrG4gsRYkXLQ1F4782L5vDTMOkoqvOEtO753n6TJ2BU-KNaxdXRAtf336c-r8MXMi_nWliw1vT1Xa7Wmt3eV5b9HmJR4Bnmt4gTavtoC0qwQVsoX_miV_VanJ98j_aaoNdNNZcnN5FsJ2eoLx7UebBDxXBMFmXEtOUTtWCsRp-g26mwKjbK3HeDoiUU2Ivh-VleUVImdh9ASwInbZ
Referer: http://localhxst:12345/
Origin: http://localhxst:12345
Connection: keep-alive
(RESPONSE)
HTTP/1.1 200 OK
Cache-Control: no-cache
Pragma: no-cache
Content-Type: application/json; charset=utf-8
Expires: -1
Server: Microsoft-IIS/8.0
Access-Control-Allow-Origin: *
X-AspNet-Version: 4.0.30319
X-SourceFiles: =?UTF-8?B?QzpcVXNlcnNcYmVuLmdvbGRlblxEb2N1bWVudHNcV29ya1xWb2ljZVNpbXBsaWZpZWRcQVBJXFZvaWNlU2ltcGxpZmllZC5QdWJsaWNBUElcdmFsdWVz?=
X-Powered-By: ASP.NET
Date: Thu, 24 Jul 2014 20:12:56 GMT
Content-Length: 13
["ABC","DEF"]
Запрос OtherStuff (прожектор не прошел):
(REQUEST)
OPTIONS http://localhxst:57578/testarea/otherstuff HTTP/1.1
Host: localhost:57578
User-Agent: Mozilla/5.0 (Windows NT 6.3; WOW64; rv:31.0) Gecko/20100101 Firefox/31.0
Accept: text/html,application/xhtml+xml,application/xml;q=0.9,*/*;q=0.8
Accept-Language: en-gb,en;q=0.5
Accept-Encoding: gzip, deflate
Origin: http://localhost:12345
Access-Control-Request-Method: GET
Access-Control-Request-Headers: authorization
Connection: keep-alive
(RESPONSE)
HTTP/1.1 404 Not Found
Cache-Control: private
Content-Type: text/html; charset=utf-8
Server: Microsoft-IIS/8.0
X-AspNet-Version: 4.0.30319
X-SourceFiles: =?UTF-8?B?QzpcVXNlcnNcYmVuLmdvbGRlblxEb2N1bWVudHNcV29ya1xWb2ljZVNpbXBsaWZpZWRcQVBJXFZvaWNlU2ltcGxpZmllZC5QdWJsaWNBUElcdGVzdGFyZWFcb3RoZXJzdHVmZg==?=
X-Powered-By: ASP.NET
Date: Thu, 24 Jul 2014 20:35:08 GMT
Content-Length: 3194
<!DOCTYPE html>
<html>
<head>
<title>The resource cannot be found.</title>
<meta name="viewport" content="width=device-width" />
<style>
body {font-family:"Verdana";font-weight:normal;font-size: .7em;color:black;}
p {font-family:"Verdana";font-weight:normal;color:black;margin-top: -5px}
b {font-family:"Verdana";font-weight:bold;color:black;margin-top: -5px}
H1 { font-family:"Verdana";font-weight:normal;font-size:18pt;color:red }
H2 { font-family:"Verdana";font-weight:normal;font-size:14pt;color:maroon }
pre {font-family:"Consolas","Lucida Console",Monospace;font-size:11pt;margin:0;padding:0.5em;line-height:14pt}
.marker {font-weight: bold; color: black;text-decoration: none;}
.version {color: gray;}
.error {margin-bottom: 10px;}
.expandable { text-decoration:underline; font-weight:bold; color:navy; cursor:hand; }
@media screen and (max-width: 639px) {
pre { width: 440px; overflow: auto; white-space: pre-wrap; word-wrap: break-word; }
}
@media screen and (max-width: 479px) {
pre { width: 280px; }
}
</style>
</head>
<body bgcolor="white">
<span><H1>Server Error in '/' Application.<hr width=100% size=1 color=silver></H1>
<h2> <i>The resource cannot be found.</i> </h2></span>
<font face="Arial, Helvetica, Geneva, SunSans-Regular, sans-serif ">
<b> Description: </b>HTTP 404. The resource you are looking for (or one of its dependencies) could have been removed, had its name changed, or is temporarily unavailable. Please review the following URL and make sure that it is spelled correctly.
<br><br>
<b> Requested URL: </b>/testarea/otherstuff<br><br>
<hr width=100% size=1 color=silver>
<b>Version Information:</b> Microsoft .NET Framework Version:4.0.30319; ASP.NET Version:4.0.30319.34009
</font>
</body>
</html>
<!--
[HttpException]: The controller for path '/testarea/otherstuff' was not found or does not implement IController.
at System.Web.Mvc.DefaultControllerFactory.GetControllerInstance(RequestContext requestContext, Type controllerType)
at System.Web.Mvc.DefaultControllerFactory.CreateController(RequestContext requestContext, String controllerName)
at System.Web.Mvc.MvcHandler.ProcessRequestInit(HttpContextBase httpContext, IController& controller, IControllerFactory& factory)
at System.Web.Mvc.MvcHandler.BeginProcessRequest(HttpContextBase httpContext, AsyncCallback callback, Object state)
at System.Web.Mvc.MvcHandler.BeginProcessRequest(HttpContext httpContext, AsyncCallback callback, Object state)
at System.Web.Mvc.MvcHandler.System.Web.IHttpAsyncHandler.BeginProcessRequest(HttpContext context, AsyncCallback cb, Object extraData)
at System.Web.HttpApplication.CallHandlerExecutionStep.System.Web.HttpApplication.IExecutionStep.Execute()
at System.Web.HttpApplication.ExecuteStep(IExecutionStep step, Boolean& completedSynchronously)
-->
ValuesController.cs
namespace MyAPIApp.PublicAPI.Controllers
{
[EnableCors(origins: "*", headers: "*", methods: "*")]
[Authorize]
public class ValuesController : ApiController
{
private static readonly List<string> values = new List<string> { "ABC", "DEF" };
public IEnumerable<string> Get() { return values; }
}
}
OtherStuffController.cs
namespace MyAPIApp.PublicAPI.Areas.TestArea.Controllers
{
[EnableCors(origins: "*", headers: "*", methods: "*")]
[Authorize]
public class OtherStuffController : ApiController
{
private static readonly List<string> values = new List<string> { "ABC", "DEF" };
public IEnumerable<string> Get() { return values; }
}
}
Я нашел проблему.
Когда вы создаете область в проекте через контекстное меню "Добавить"> "Область", Visual Studio создает область с шаблоном AreaRegistration, используя следующий код:
public override void RegisterArea(AreaRegistrationContext context) {
context.MapRoute(
"TestArea_default",
"TestArea/{controller}/{id}",
new {id = UrlParameter.Optional}
);
}
Однако этот код не подходит для ApiControllers. Правильный код регистрации маршрута:
public override void RegisterArea(AreaRegistrationContext context) {
context.Routes.MapHttpRoute(
"TestArea_default",
"TestArea/{controller}/{id}",
new { id = RouteParameter.Optional });
}
Оказывается, это не имеет ничего общего с CORS.