Search code examples
angularwcfcorshttp-status-code-400

Angular CORS preflight request causes 400 Bad Request, but Postman request works OK


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: enter image description here

And for the second entry it shows: enter image description here

Note that the Content-Type header on this 2nd one is text/html.

In the console I see this: enter image description here

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?


Solution

  • 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:

    enter image description here

    Feel free to let me know if the problem persists.