Reputation: 1125
I have an Angular app running locally on my dev machine that's trying to make a request to a WCF web service running on IIS on another machine.
Using Postman I can make requests to the service OK, both with POST and OPTIONS verbs.
However, when my Angular app makes a request, I end up with a 400 error from the CORS preflight OPTIONS request that's made.
The request is made like this:
// passed-in url is https://myserver/myservice/Hello
public hello( url: string, name: string )
{
const headers = new HttpHeaders()
headers.append('Content-Type', 'application/json');
headers.append('Test', 'TestyTest');
return this.httpClient.post<string>( url,
{ name: name },
{ headers: headers }
);
}
In Chrome's debugging tools on the Network panel I see two entries for this one request:
Hello (failed) xhr zone.js:2935 0 B 188 ms
Hello 400 text/html Other 0 B 176 ms
If I examine the request headers for both of those entries, in neither do I see the Test
header that my code tried to add. This isn't a problem (I don't need that header), but it may be a clue.
The "Headers" panel for the first entry shows:
And for the second entry it shows:
Note that the Content-Type
header on this 2nd one is text/html
.
I'm not seeing any entries in my web service's log, or any errors in the IIS logs or in Event Viewer on the server.
What can be causing this problem, and how can I fix it, or get more info?
Upvotes: 0
Views: 2765
Reputation: 3974
This is caused by CORS. Do not use Global files to solve cross-domain problems. You can try to use IDispatchMessageInspector to solve cross-domain problems.
Add a SOAP.cs to your project:
using System;
using System.Collections.Generic;
using System.IO;
using System.Linq;
using System.Runtime.Serialization;
using System.ServiceModel;
using System.ServiceModel.Channels;
using System.ServiceModel.Configuration;
using System.ServiceModel.Description;
using System.ServiceModel.Dispatcher;
using System.ServiceModel.Web;
using System.Text;
using System.Threading.Tasks;
using System.Web;
using System.Xml;
namespace Demo_rest_ConsoleApp
{
public class ServerMessageLogger : IDispatchMessageInspector
{
public object AfterReceiveRequest(ref Message request, IClientChannel channel, InstanceContext instanceContext)
{
Console.WriteLine(request);
return null;
}
public void BeforeSendReply(ref Message reply, object correlationState)
{
WebOperationContext ctx = WebOperationContext.Current;
ctx.OutgoingResponse.Headers.Add("Access-Control-Allow-Origin", "*");
ctx.OutgoingResponse.StatusCode = System.Net.HttpStatusCode.OK;
if (ctx.IncomingRequest.Method == "OPTIONS")
{
ctx.OutgoingResponse.StatusCode = System.Net.HttpStatusCode.OK;
ctx.OutgoingResponse.Headers.Add("Access-Control-Allow-Methods", "GET,POST,PUT,PATCH,POST,DELETE,OPTIONS");
ctx.OutgoingResponse.Headers.Add("Access-Control-Allow-Headers", "Content-Type");
}
}
}
public class ClientMessageLogger : IClientMessageInspector
{
public void AfterReceiveReply(ref Message reply, object correlationState)
{
}
public object BeforeSendRequest(ref Message request, IClientChannel channel)
{
return null;
}
}
[AttributeUsage(AttributeTargets.Interface | AttributeTargets.Class, AllowMultiple = false)]
public class CustContractBehaviorAttribute : Attribute, IContractBehavior, IContractBehaviorAttribute
{
public Type TargetContract => throw new NotImplementedException();
public void AddBindingParameters(ContractDescription contractDescription, ServiceEndpoint endpoint, BindingParameterCollection bindingParameters)
{
return;
}
public void ApplyClientBehavior(ContractDescription contractDescription, ServiceEndpoint endpoint, ClientRuntime clientRuntime)
{
clientRuntime.ClientMessageInspectors.Add(new ClientMessageLogger());
}
public void ApplyDispatchBehavior(ContractDescription contractDescription, ServiceEndpoint endpoint, DispatchRuntime dispatchRuntime)
{
dispatchRuntime.MessageInspectors.Add(new ServerMessageLogger());
}
public void Validate(ContractDescription contractDescription, ServiceEndpoint endpoint)
{
return;
}
}
}
Finally, apply CustContractBehavior to the service:
Feel free to let me know if the problem persists.
Upvotes: 1
Reputation: 371
Try implementing a proxy config file
const HttpsProxyAgent = require('https-proxy-agent');
/*
* API proxy configuration.
* This allows you to proxy HTTP request like `http.get('/api/stuff')` to another server/port.
* This is especially useful during app development to avoid CORS issues while running a local server.
* For more details and options, see https://angular.io/guide/build#using-corporate-proxy
*/
const proxyConfig = [
{
context: '/api',
pathRewrite: { '^/api': '' },
target: 'https://api.chucknorris.io',
changeOrigin: true,
secure: false,
},
];
/*
* Configures a corporate proxy agent for the API proxy if needed.
*/
function setupForCorporateProxy(proxyConfig) {
if (!Array.isArray(proxyConfig)) {
proxyConfig = [proxyConfig];
}
const proxyServer = process.env.http_proxy || process.env.HTTP_PROXY;
let agent = null;
if (proxyServer) {
console.log(`Using corporate proxy server: ${proxyServer}`);
agent = new HttpsProxyAgent(proxyServer);
proxyConfig.forEach((entry) => {
entry.agent = agent;
});
}
return proxyConfig;
}
module.exports = setupForCorporateProxy(proxyConfig);
Next, open your angular.json
file and add a proxyConfig key under the serve->options
that points to the file you just created src/proxy.conf.json
file as follows:
"architect": {
"serve": {
"builder": "@angular-devkit/build-angular:dev-server",
"options": {
"browserTarget": "your-application-name:build",
"proxyConfig": "src/proxy.conf.json"
}
More information can be found here in the official angular documentation
Upvotes: 0