Possible Duplicate:
CORS with WebAPI for XmlHttpRequest
I'm trying to implement cross-domain ajax post to my webApi project. I had few troubles with that:
1. I always was getting 204 error until changed my webapi action from
public void submit(Submission model)
to
public bool submit(Submission model)
don't know why, but now I'm getting 200 OK
status
2. Still my ajax firing error callback.
3. Long time ago I solved this kind of error of cross-domain posting by adding
HttpContext.Response.AddHeader("Access-Control-Allow-Origin", "*");
to my controller. But now in webApi i'm inherent from : ApiController
and this trick doesn't work. Shows me compiler Error an object reference is required for the non-static field, method, or property"System.Web.HttpContext.Response.get"
I have tryed to post via dataType: 'JSONP'
but I get null model.
Here goes Javascript request:
var model = { "type": $("#model-type").val(), "subject": $("#subject-text").val(), "body": $("#body-text").val() }; $.ajax({ type: "POST", dataType: 'JSONP', url: $("#submit-url").val(), data: model, success: function () { alert("Succesfully submitted"); }, error: function () { alert("Error..."); } });
What I'm doing wrong?
Thanks to everybody for helping me out. I found solution in one of the comment links. I used following approach, which I find pretty simple.
Source:
Implementing CORS support in ASP.NET Web APIs
What I made:
1. Created new Class in my project: CorsHandler.cs
and just copy-pasted following code:
public class CorsHandler : DelegatingHandler
{
const string Origin = "Origin";
const string AccessControlRequestMethod = "Access-Control-Request-Method";
const string AccessControlRequestHeaders = "Access-Control-Request-Headers";
const string AccessControlAllowOrigin = "Access-Control-Allow-Origin";
const string AccessControlAllowMethods = "Access-Control-Allow-Methods";
const string AccessControlAllowHeaders = "Access-Control-Allow-Headers";
protected override Task SendAsync(HttpRequestMessage request, CancellationToken cancellationToken)
{
bool isCorsRequest = request.Headers.Contains(Origin);
bool isPreflightRequest = request.Method == HttpMethod.Options;
if (isCorsRequest)
{
if (isPreflightRequest)
{
return Task.Factory.StartNew(() =>
{
HttpResponseMessage response = new HttpResponseMessage(HttpStatusCode.OK);
response.Headers.Add(AccessControlAllowOrigin, request.Headers.GetValues(Origin).First());
string accessControlRequestMethod = request.Headers.GetValues(AccessControlRequestMethod).FirstOrDefault();
if (accessControlRequestMethod != null)
{
response.Headers.Add(AccessControlAllowMethods, accessControlRequestMethod);
}
string requestedHeaders = string.Join(", ", request.Headers.GetValues(AccessControlRequestHeaders));
if (!string.IsNullOrEmpty(requestedHeaders))
{
response.Headers.Add(AccessControlAllowHeaders, requestedHeaders);
}
return response;
}, cancellationToken);
}
else
{
return base.SendAsync(request, cancellationToken).ContinueWith(t =>
{
HttpResponseMessage resp = t.Result;
resp.Headers.Add(AccessControlAllowOrigin, request.Headers.GetValues(Origin).First());
return resp;
});
}
}
else
{
return base.SendAsync(request, cancellationToken);
}
}
}
Global.asax
and modifyed Application_Start
:
protected void Application_Start()
{
AreaRegistration.RegisterAllAreas();
RegisterGlobalFilters(GlobalFilters.Filters);
RegisterRoutes(RouteTable.Routes);
GlobalConfiguration.Configuration.MessageHandlers.Add(new CorsHandler());
}
Pay attention to the last line in action.
This approach is compatible with MVC3 and .NET 4.0. Works great, now I can handle "success" and "error" callbacks in ajax.
Answers to your questions respectively:
10.2.5 204 No Content
The server has fulfilled the request but does not need to return an entity-body, and might want to return updated metainformation. The response MAY include new or updated metainformation in the form of entity-headers, which if present SHOULD be associated with the requested variant.
If the client is a user agent, it SHOULD NOT change its document view from that which caused the request to be sent. This response is primarily intended to allow input for actions to take place without causing a change to the user agent's active document view, although any new or updated metainformation SHOULD be applied to the document currently in the user agent's active view.
The 204 response MUST NOT include a message-body, and thus is always terminated by the first empty line after the header fields.
The first option is to define action return HttpResponse directly.
public HttpResponseMessage Get(int id)
{
var response = this.Request.CreateResponse();
response.StatusCode = HttpStatusCode.OK;
response.Headers.Add("Access-Control-Allow-Origin", "*");
return response;
}
The second option is to use ActionFilter:
// define action filter for cross domain
public class CrossDomainActionFilter : ActionFilterAttribute
{
public override void OnActionExecuted(HttpActionExecutedContext actionExecutedContext)
{
bool needCrossDomain = true;
if (needCrossDomain)
{
actionExecutedContext.Response.Headers.Add("Access-Control-Allow-Origin", "*");
}
base.OnActionExecuted(actionExecutedContext);
}
}
// At Controller
// GET api/values/5
[CrossDomainActionFilter]
public string Get(int id)
{
return "value";
}
The last option is to use MessageHandler:
public class CrossDomainMessageHandler : DelegatingHandler
{
protected async override Task<HttpResponseMessage> SendAsync(
HttpRequestMessage request,
CancellationToken cancellationToken)
{
var response = await base.SendAsync(request, cancellationToken);
response.Headers.Add("Access-Control-Allow-Origin", "*");
return response;
}
}
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With