Nachdem ich einen ganzen Abend gekämpft hatte, brachte ich das endlich zum Laufen. Nach einigem Debuggen stellte ich fest, dass mein Client eine sogenannte Preflight-Optionsanforderung sendete, um zu überprüfen, ob die Anwendung eine Postanforderung mit dem angegebenen Ursprung, den angegebenen Methoden und den angegebenen Headern senden durfte. Ich wollte weder Owin noch einen APIController verwenden, also begann ich zu graben und fand die folgende Lösung mit nur einem ActionFilterAttribute. Insbesondere der Teil "Access-Control-Allow-Headers" ist sehr wichtig, da die dort genannten Header mit den Headern übereinstimmen müssen, die Ihre Anfrage senden wird.
using System.Linq;
using System.Web;
using System.Web.Mvc;
namespace MyNamespace
{
public class AllowCrossSiteJsonAttribute : ActionFilterAttribute
{
public override void OnActionExecuting(ActionExecutingContext filterContext)
{
HttpRequest request = HttpContext.Current.Request;
HttpResponse response = HttpContext.Current.Response;
// check for preflight request
if (request.Headers.AllKeys.Contains("Origin") && request.HttpMethod == "OPTIONS")
{
response.AppendHeader("Access-Control-Allow-Origin", "*");
response.AppendHeader("Access-Control-Allow-Credentials", "true");
response.AppendHeader("Access-Control-Allow-Methods", "GET, PUT, POST, DELETE");
response.AppendHeader("Access-Control-Allow-Headers", "Origin, X-Requested-With, X-RequestDigest, Cache-Control, Content-Type, Accept, Access-Control-Allow-Origin, Session, odata-version");
response.End();
}
else
{
HttpContext.Current.Response.Cache.SetCacheability(HttpCacheability.NoCache);
HttpContext.Current.Response.Cache.SetNoStore();
response.AppendHeader("Access-Control-Allow-Origin", "*");
response.AppendHeader("Access-Control-Allow-Credentials", "true");
if (request.HttpMethod == "POST")
{
response.AppendHeader("Access-Control-Allow-Methods", "GET, PUT, POST, DELETE");
response.AppendHeader("Access-Control-Allow-Headers", "Origin, X-Requested-With, X-RequestDigest, Cache-Control, Content-Type, Accept, Access-Control-Allow-Origin, Session, odata-version");
}
base.OnActionExecuting(filterContext);
}
}
}
}
Schließlich sieht meine MVC-Aktionsmethode so aus. Wichtig ist hier auch, die Optionen HttpVerbs zu erwähnen, da sonst die Preflight-Anfrage fehlschlägt.
[AcceptVerbs(HttpVerbs.Post | HttpVerbs.Options)]
[AllowCrossSiteJson]
public async Task<ActionResult> Create(MyModel model)
{
return Json(await DoSomething(model));
}