Reputation: 1589
I have three applications in my architecture.
They are on the same server but having different port numbers.
A - Token Application (port 4444) - Asp.net WebApi
B - API Application (port 3333) - Asp.net WebApi
C - UI Application (port 2222) - AngularJS App.
The application flow is like below
1- The UI project gets the token from Token Application (It requires Windows Auth.)
Ex : awxrsdsaWeffs12da
2- UI application puts this token to a custom header which is named as "accessToken"
Ex : accessToken : awxrsdsaWeffs12da
3- UI application sends a request to API Application
Ex: http:myaddress:3333/api/TheRestServiceHere
UI application gets 401 Error. Which sends OPTIONS method. (I guess preflight issue)
In my web api project I enabled Cors like this below.
public static void Register(HttpConfiguration config)
{
....
//CORS
var cors = new EnableCorsAttribute("*", "*", "*");
config.EnableCors(cors);
....
}
Config
public static class WebApiConfig
{
public static void Register(HttpConfiguration config)
{
//CORS
var cors = new EnableCorsAttribute("*", "*", "*");
config.EnableCors();
// Web API routes
config.MapHttpAttributeRoutes();
config.Routes.MapHttpRoute(
name: "DefaultApi",
routeTemplate: "api/{controller}/{id}",
defaults: new { id = RouteParameter.Optional }
);
var json = config.Formatters.JsonFormatter;
json.SerializerSettings.PreserveReferencesHandling = PreserveReferencesHandling.None;
json.SerializerSettings.ReferenceLoopHandling = ReferenceLoopHandling.Ignore;
json.SerializerSettings.Formatting = Formatting.None;
json.SerializerSettings.ContractResolver = new CamelCasePropertyNamesContractResolver();
config.Formatters.Remove(config.Formatters.XmlFormatter);
}
}
So I am looking for a solution to call API application (B) controllers and get 200 :)
Regards
Upvotes: 5
Views: 14025
Reputation: 109
This problem happened for Cordova v11, platform for Android. I used the solution provided by Jereme (the top rated answer) with one exception: In OptionsModule, I had to omit the statement
app.Response.AddHeader("Access-Control-Allow-Origin", APISettings.ApplicationOrigin);
Instead in the web.config file I added in the <system.webServer> section the following:
<httpProtocol>
<customHeaders>
<add name="Access-Control-Allow-Origin" value="*" />
<!-- Note: "localhost" for Cordova is not valid, only * worked. -->
</customHeaders>
</httpProtocol>
A word about Cordova in case one is unfamiliar. Cordova packages a native app for the Android platform with a “javascript page” included in the app, using a web view in the app to display the page. Using the Chrome debugger to view the javascript page, the page origin appears as localhost. However, localhost is not an acceptable value for the Access-Control-Allow-Origin header; therefore I had to use “*” in the Web.config file. When I had the response header in the OptionsModule, the preflight response was ok (status 200), but not the response for the XMLHttpRequest (the api) that initiated the preflight request. Putting the custom header only in the Web.config file allowed both responses to be ok (status 200).
Upvotes: 0
Reputation: 1485
I fixed this in an application I am working on by creating a module that responds to requests that are using the OPTIONS verb. You should probably modify it a bit to include the verbs and content type that the application is requesting. In my case, I decided to post everything as JSON (which requires the pre-flight check). The module is as follows:
public class OptionsModule : IHttpModule
{
public void Init(HttpApplication context)
{
context.BeginRequest += (sender, args) =>
{
var app = (HttpApplication) sender;
if (app.Request.HttpMethod == "OPTIONS")
{
app.Response.StatusCode = 200;
app.Response.AddHeader("Access-Control-Allow-Headers", "content-type");
app.Response.AddHeader("Access-Control-Allow-Origin", APISettings.ApplicationOrigin);
app.Response.AddHeader("Access-Control-Allow-Credentials", "true");
app.Response.AddHeader("Access-Control-Allow-Methods", "POST,GET,OPTIONS");
app.Response.AddHeader("Content-Type", "application/json");
app.Response.End();
}
};
}
public void Dispose()
{
}
}
Then you need to register it in your web.config:
<system.webServer>
<modules>
<add name="HandleOptions" type="namespace.OptionsModule" />
</modules>
</system.webServer>
Another thing you may want to do is specify the allowed origin explicitly. Chrome doesn't like having a wildcard there.
Upvotes: 16
Reputation: 1589
One of my friend solved the issue by using OPTIONSVerbHandler.
When UI application wants to use GET method, browser sends OPTION method first to the server (Preflight). Then if Preflight request is OK it sends GET request.
For CORS test purpose we used the following code to send GET method.
<html>
<head>
<script src="https://code.jquery.com/jquery-1.9.1.min.js"></script>
<script>
$( document ).ready(function() {
var adress = "http://10.10.27.36:3434/backend/api/role";
$.ajaxSetup({
headers: {
'Content-Type': 'application/json',
'accessToken': 'some value',
'Origin' : ''
}
});
$.ajax({
type: "GET",
url: adress,
dataType: "json"
});
});
</script></head><body></body></html>
To handle OPTION method which sends by browser before GET you should have the following settings.
1- Webconfig
<system.webServer>
<handlers>
<add name="OPTIONSVerbHandler" path="*" verb="OPTIONS" modules="ProtocolSupportModule" resourceType="Unspecified" requireAccess="None" />
</handlers>
</system.webServer>
2- Adding OPTIONSVerbHandler with following settings
Click on request restrictions
3- Our Header Settings we have accessToken which is custom as you can see
Upvotes: 3