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?
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.