Moving forward with my mobile app development learning process, I've found a new obstacle: Cross-origin Request Sharing or CORS.
I am using a combination of AngularJS + jQuery Mobile (Cordova phone client) and ASP.NET Web API (backend). My issue is that I have not been able to complete a POST request (or any other type of request) to an API controller.
My AngularJS controller uses the $http.post() service method to call the Web API controller. However, Chrome debugger says that the call failed in an OPTIONS request (possibly the CORS preflight request).
I have implemented the CORS action selector from the following post: Enabling CORS in Web API Project. Even tough I can call the api method from Fiddler, AngularJS keeps failing on the OPTIONS preflight request.
Is there anything I should be aware of about AngularJS and cross-domain calls? Any possible solution to my predicament?
Thanks.
You can skip the preflight option request by using content-type : application/x-www-form-urlencoded.
AngularJS:
var user = {
ID: 1,
Name: 'test'
};
$http({
url: "api.localhost/api/users/addUser",
method: "POST",
data: $.param(user),
headers: { 'Content-Type': 'application/x-www-form-urlencoded' },
withCredentials: true,
}).success(function (data, status, headers, config) {
console.log(data);
})
Web api:
[HttpPost]
public string AddUser(User user)
{
// Do something
return user.Name + " added";
}
Web.config
<system.webServer>
<validation validateIntegratedModeConfiguration="false" />
<handlers>
<remove name="ExtensionlessUrlHandler-ISAPI-4.0_32bit" />
<remove name="ExtensionlessUrlHandler-ISAPI-4.0_64bit" />
<remove name="ExtensionlessUrlHandler-Integrated-4.0" />
<remove name="OPTIONSVerbHandler" />
<remove name="TRACEVerbHandler" />
<add name="ExtensionlessUrlHandler-ISAPI-4.0_32bit" path="*." verb="GET,HEAD,POST,DEBUG,PUT,DELETE,PATCH,OPTIONS" modules="IsapiModule" scriptProcessor="%windir%\Microsoft.NET\Framework\v4.0.30319\aspnet_isapi.dll" preCondition="classicMode,runtimeVersionv4.0,bitness32" responseBufferLimit="0" />
<add name="ExtensionlessUrlHandler-ISAPI-4.0_64bit" path="*." verb="GET,HEAD,POST,DEBUG,PUT,DELETE,PATCH,OPTIONS" modules="IsapiModule" scriptProcessor="%windir%\Microsoft.NET\Framework64\v4.0.30319\aspnet_isapi.dll" preCondition="classicMode,runtimeVersionv4.0,bitness64" responseBufferLimit="0" />
<add name="ExtensionlessUrlHandler-Integrated-4.0" path="*." verb="*" type="System.Web.Handlers.TransferRequestHandler" preCondition="integratedMode,runtimeVersionv4.0" />
</handlers>
<httpProtocol>
<customHeaders>
<add name="Access-Control-Allow-Origin" value="http://localhost" />
<add name="Access-Control-Allow-Headers" value="Origin, X-Requested-With, Content-Type, Accept, Cache-Control" />
<add name="Access-Control-Allow-Credentials" value="true" />
<add name="Access-Control-Allow-Methods" value="GET, POST, PUT, DELETE, OPTIONS" />
</customHeaders>
</httpProtocol>
</system.webServer>
While stumbling onto this issue with AngularJS 1.3 with Microsoft Web API 2 I found a simple solution to the CORS configuration issue.
First from Nuget intall - Microsoft WebApi Cors
Install-Package Microsoft.AspNet.WebApi.Cors
Then in your WebApiConfig.cs file:
var cors = new System.Web.Http.Cors.EnableCorsAttribute("www.my-angular-web-site.com", "*", "*");
config.EnableCors(cors);
You can also enable CORS everywhere with a * instead of your web site but that defeats the purpose of CORS and opens up security holes - but you can do it for testing.
The WebApi.Cors assembly also lets you enable cors controller by controller or with other more granular details. Other details can be found here on the Web API site.
Check out Thinktecture Cors objects, with those (nugettable) you can get full CORS support in WebApi without any code of your own.
Even with a correct CORS implementation I've had a really strange issue with IIS 7 that was solved by enabling all verbs for WebDav (yes, WebDav - don't ask me why I just followed instructions on a blog post :-D).
Do this:
Open IIS manager, go to your application's Handler Mapping.
Double click the WebDav handler
Click "Request Restriction"
On the "Verbs" tab, select "All verbs".
Again, no idea why WebApi uses WebDav, but this solved problems with POST and DELETE that wouldn't work in spite of a correct CORS implementation.
Mostly the developers while running there UI and service on Localhost face this issue - There are many ways in which this can be resolved - alot of the developers tend to fix it at browser level " but thats a security breach.
Correct method is to fix this at your Web Service Layer- Following video will explain and solve this
Watch CORS- Implementing Cross Origin Resource Sharing ("EXPLAINED - Cross Origin Resource Sharing")!
Related
I have a .NET MVC application that uses Azure Active Directory for Auth.
I'm trying to add a custom JWTSecurityTokenHandler to authenticate a console app that performs some basic GET requests against the app. However every request just gets redirected to the Azure AD login page instead of being passed to the JWT handler (my breakpoints and logging statements in the handler are not being hit). Any ideas?
Web.config:
<system.identityModel>
<identityConfiguration>
<audienceUris>
<add value="https://localhost:44300/" />
</audienceUris>
<securityTokenHandlers>
<add type="QS.Admin.Infrastructure.MyJwtHandler, QS.Admin" />
<securityTokenHandlerConfiguration>
<certificateValidation certificateValidationMode="None" />
</securityTokenHandlerConfiguration>
</securityTokenHandlers>
<issuerNameRegistry type="System.IdentityModel.Tokens.ValidatingIssuerNameRegistry, System.IdentityModel.Tokens.ValidatingIssuerNameRegistry">
<authority name="https://[myaccessdomain].accesscontrol.windows.net/">
<keys>
<add thumbprint="[thumbprint]" />
</keys>
<validIssuers>
<add name="https://[myaccessdomain].accesscontrol.windows.net/" />
</validIssuers>
</authority>
</issuerNameRegistry>
<!--certificationValidationMode set to "None" by the the Identity and Access Tool for Visual Studio. For development purposes.-->
<certificateValidation certificateValidationMode="None" />
</identityConfiguration>
</system.identityModel>
<system.identityModel.services>
<federationConfiguration>
<cookieHandler requireSsl="false" />
<wsFederation passiveRedirectEnabled="true" issuer="https://[myaccessdomain].accesscontrol.windows.net/v2/wsfederation" realm="https://localhost:44300/" requireHttps="false" />
</federationConfiguration>
</system.identityModel.services>
in addition to the above advice,
the jwtsecuritytokenhandlers responsibility is to validate a jwt and serve claims upstream. I don't see session management anywhere in your config, if that is missing, each call to the host will require obtaining a new token from ACS.
The settings in web.config look right.
Couple of things to check :
Make sure ACS is configured to issue JWT tokens for your realm.
If you plug in the JwtSecurityTokenHandler from MS - is it getting hit? This will help in isolating the issue to your custom handler versus settings in ACS or web.config.
I've got 2 projects: Core and Web.
Core project has API controllers, models, etc. Web project has html pages only.
I'm loading data from API using jQuery. When I do this exactly from Core project (created a view), everything is ok. But when I do this from Web project, I've got error 404, but Fiddler shows everything is ok.
Why is it so? What's a problem?
I found the answer. That is because it's cross domain application. And it's necessary to implement CORS support. It can be done by two ways.
First. Add to section of web.config file next:
<httpProtocol>
<customHeaders>
<add name="Access-Control-Allow-Origin" value="*" />
<add name="Access-Control-Allow-Headers" value="Content-Type" />
<add name="Access-Control-Allow-Methods" value="GET, POST, PUT, DELETE, OPTIONS" />
</customHeaders>
</httpProtocol>
Second. Create custom MessageHandler. Like in this post
I would like to use ASP.Net Web API (http://asp.net/Webapi) in sitecore. I keep getting 404 when i try to browse the API's though i added the
<add name="ExtensionlessUrlHandler-ISAPI-4.0_32bit" path="*." verb="GET,HEAD,POST,DEBUG,PUT,DELETE,PATCH,OPTIONS" modules="IsapiModule" scriptProcessor="%windir%\Microsoft.NET\Framework\v4.0.30319\aspnet_isapi.dll" preCondition="classicMode,runtimeVersionv4.0,bitness32" responseBufferLimit="0" />
<add name="ExtensionlessUrlHandler-ISAPI-4.0_64bit" path="*." verb="GET,HEAD,POST,DEBUG,PUT,DELETE,PATCH,OPTIONS" modules="IsapiModule" scriptProcessor="%windir%\Microsoft.NET\Framework64\v4.0.30319\aspnet_isapi.dll" preCondition="classicMode,runtimeVersionv4.0,bitness64" responseBufferLimit="0" />
<add name="ExtensionlessUrlHandler-Integrated-4.0" path="*." verb="GET,HEAD,POST,DEBUG,PUT,DELETE,PATCH,OPTIONS" type="System.Web.Handlers.TransferRequestHandler" preCondition="integratedMode,runtimeVersionv4.0" />
</handlers>
in web.config. Referred the necessary assemblies. But, stil cant get through..
I am using web application project. I did few samples in web application project, they work fine. but, integrating with sitecore giving me hard time.
any inputs please..?
thanks
This could be Sitecore being a wise guy and interrupting your requests to try and find the URL in the content tree.
If you know the URLs you are going to be calling (or part of the paths to them) you can add them to the IgnoreUrlPrefixes setting in the config.
See nice little post here:
http://sitecoreblog.alexshyba.com/2011/05/teach-sitecore-to-ignore-directory.html
If you are creating webapi routes, you could also make a step in the RequestPipeline, that aborts the pipeline if it finds a route that matches the current URL
public override void Process(Sitecore.Pipelines.HttpRequest.HttpRequestArgs args)
{
RouteData routeData = RouteTable.Routes.GetRouteData(new HttpContextWrapper(args.Context));
if (routeData != null)
{
HttpContext.Current.RemapHandler(routeData.RouteHandler.GetHttpHandler(HttpContext.Current.Request.RequestContext));
args.AbortPipeline();
}
}
With that you could set it right after it resolves the database and the site, so you can use Sitecore.Context to handle database access and etc.
I am building an application that is ready for release however I have come up against the cross domain scripting problem within my ajax calls.
I am using IIS7.5 and I have the following applications setup
Marketing Application - 'www.mydomain.com' - Used as the marketing website and for registering for a new business.I have a rule that forces any non www. to be www
Business Application - 'https://newbusiness.mydomain.com' - Used to access their services they have subscribed to
API Application - 'https://newbusiness.mydomain.com/api/.......' - Used for business application to do crud operations
API application is an application running under the business application. Containing a number of secured methods and some anonymous ones.
With jquery I am having trouble from my marketing application trying to call the api application. Currently if I want to call the api from my marketing site I am doing something like 'https://api.mydomain.com/api/whatevermethod' because it is cross domain it fails.
Is there anyway that I can somehow map 'https://api.mydomain.com/api/whatevermethod' to be just 'https://mydomain.com/api/whatevermethod' as this would get me around the cross domain problem.
You need to allow cross domain calls in the IIS. You can do this by setting the Access-Control-Allow-Origin and Access-Control-Allow-Headers
ex:
in root web.config
<system.webserver>
<httpprotocol>
<customheaders>
<add name="access-control-allow-origin" value="*" />
<add name="access-control-allow-headers" value="content-type" />
</customheaders>
</httpprotocol>
</system.webserver>
taken from here
Just in case you also got an error 500 from Amila's answer, here's what the whole web.config file content should look like
<?xml version="1.0" encoding="UTF-8"?>
<configuration>
<system.webServer>
<httpProtocol>
<customHeaders>
<add name="access-control-allow-origin" value="*" />
<add name="access-control-allow-headers" value="content-type" />
</customHeaders>
</httpProtocol>
</system.webServer>
</configuration>
I have a HttpHandler for an asp.net mvc application. I've tested the handler for asp.net and asp.net mvc 3 applications and everything works as expected.
When I use the HttpHandler in an Azure based asp.net mvc 3 application the 'ProcessRequest' method is NOT being called - I can see the HttpHandler being created.
I have the following web.config and this works for a standard asp.net mvc 3 app:
<system.web>
<httpHandlers>
<add type="TestWebRole.Infrastructure.HttpHandlers.EPubHandler"
path="*.epub"
verb="*" />
</httpHandlers>
</system.web>
<system.webServer>
<validation validateIntegratedModeConfiguration="false" />
<modules runAllManagedModulesForAllRequests="true" />
<handlers>
<add name="EPubHandler"
type="TestWebRole.Infrastructure.HttpHandlers.EPubHandler"
path="*.epub"
verb="*"
resourceType="Unspecified"
allowPathInfo="false"
modules="IsapiModule"
scriptProcessor="%path%\aspnet_isapi.dll"/>
</handlers>
</system.webServer>
I also have the following statement in the global.asax.cs file to specify ignoring asp.net ,mvc routing for the extension type:
routes.IgnoreRoute("{resource}.epub/{*pathInfo}");
What do I have to configure to get this working when running in Azure - locally or deployed into the cloud?
Just to try, why don't you remove the httpHandlers section under system.web and leave only that in the system.webServer. And also strip all the unnecessary attributes from the one under system.webServer (scriptProcessor, modules, allowPathInfo).
And also you may check for any uncought exception, event log entry, anything showing some kind of error.