Allowing the OPTIONS method in CORS when sending a REST request from AJAX to a WCF Service

After spending 7 hours scratching my head, I am still unable to figure this out. Despite my extensive search on the web, no luck has come my way. My Angular App is sending requests to a WCF command-line hosted service application. To bypass CORS, I utilized two classes:

public class CustomHeaderMessageInspector : IDispatchMessageInspector
{
    Dictionary<string, string> requiredHeaders;

    public CustomHeaderMessageInspector(Dictionary<string, string> headers)
    {
        requiredHeaders = headers ?? new Dictionary<string, string>();
    }

    public object AfterReceiveRequest(ref Message request, 
    System.ServiceModel.IClientChannel channel, 
    System.ServiceModel.InstanceContext instanceContext)
    {
        return null;
    }

    public void BeforeSendReply(ref Message reply, object correlationState)
    {
        var httpHeader = reply.Properties["httpResponse"] as HttpResponseMessageProperty;
        foreach (var item in requiredHeaders)
        {
            httpHeader.Headers.Add(item.Key, item.Value);
        }
    }
}

Additionally:

public class EnableCorsBehavior : BehaviorExtensionElement, IEndpointBehavior
{
    public void AddBindingParameters(ServiceEndpoint endpoint, System.ServiceModel.Channels.BindingParameterCollection bindingParameters)
    { }

    public void ApplyClientBehavior(ServiceEndpoint endpoint, System.ServiceModel.Dispatcher.ClientRuntime clientRuntime)
    { }

    public void ApplyDispatchBehavior(ServiceEndpoint endpoint, System.ServiceModel.Dispatcher.EndpointDispatcher endpointDispatcher)
    {
        var requiredHeaders = new Dictionary<string, string>();

        requiredHeaders.Add("Access-Control-Allow-Origin", "*");
        requiredHeaders.Add("Access-Control-Request-Method", "POST,GET,PUT,DELETE,OPTIONS");
        requiredHeaders.Add("Access-Control-Allow-Headers", "X-Requested-With,Content-Type");

        endpointDispatcher.DispatchRuntime.MessageInspectors.Add(new CustomHeaderMessageInspector(requiredHeaders));
    }

    public void Validate(ServiceEndpoint endpoint) { }

    public override Type BehaviorType
    {
        get { return typeof(EnableCorsBehavior); }
    }

    protected override object CreateBehavior()
    {
        return new EnableCorsBehavior();
    }
}

Implementing this custom extension within the app.config file addressed my CORS issue. However, a new challenge arises when making a POST request, resulting in the error message:

Request Method:OPTIONS
Status Code:405 Method Not Allowed

Being relatively new to C#, I am struggling to determine where to insert code to resolve this issue. I suspect it should be placed within the BeforeSendReply() method. Any assistance will be greatly appreciated!

Best Regards!

Answer №1

After investigating further, I was able to find a solution to the problem at hand. For those encountering the same issue, in the CustomHeaderMessageInspector class mentioned earlier, I made modifications to the code within the AfterReceiveRequest method:

// return null;
var httpRequest = (HttpRequestMessageProperty)request
    .Properties[HttpRequestMessageProperty.Name];
return new
{
    origin = httpRequest.Headers["Origin"],
    handlePreflight = httpRequest.Method.Equals("OPTIONS",
    StringComparison.InvariantCultureIgnoreCase)
};

The intention behind this change was to identify any requests using the OPTIONS method and mark them with a preflight status. Subsequently, I adjusted the code in the BeforeSendReply as follows:

var state = (dynamic)correlationState;
if (state.handlePreflight)
{
    reply = Message.CreateMessage(MessageVersion.None, "PreflightReturn");

    var httpResponse = new HttpResponseMessageProperty();
    reply.Properties.Add(HttpResponseMessageProperty.Name, httpResponse);

    httpResponse.SuppressEntityBody = true;
    httpResponse.StatusCode = HttpStatusCode.OK;
}

var httpHeader = reply.Properties["httpResponse"] as HttpResponseMessageProperty;
foreach (var item in requiredHeaders)
{
    httpHeader.Headers.Add(item.Key, item.Value);
}

Essentially, this implementation targets requests tagged with OPTIONS and handles them by issuing a 200 status code. This adjustment resolved the issue for me, and I hope it proves useful to others facing similar challenges!

Answer №2

Adding onto the answer from realnsleo:

I encountered difficulties using the (dynamic)correlationState due to the necessity of my project being in Framework 3.5

I also attempted to streamline certain sections:

private class CORSHeaderInjectingMessageInspector : IDispatchMessageInspector
{
    private static IDictionary<string, string> _headersToInject = new Dictionary<string, string>
    {
        { "Access-Control-Allow-Origin", "*" },
        { "Access-Control-Request-Method", "POST,GET,PUT,DELETE,OPTIONS" },
        { "Access-Control-Allow-Headers", "X-Requested-With,Content-Type,Origin,Accept" },
        { "Access-Control-Request-Headers", "POST" }
    };


    public object AfterReceiveRequest( ref Message request, IClientChannel channel, InstanceContext instanceContext)
    {
        var httpRequest = (HttpRequestMessageProperty)request.Properties[HttpRequestMessageProperty.Name];       
        return httpRequest.Method.Equals("OPTIONS", StringComparison.InvariantCulture);   
    }


    public void BeforeSendReply(ref Message reply, object correlationState)
    {
        if ((bool) correlationState)
        {
            var httpResponse = (HttpResponseMessageProperty)reply.Properties[HttpResponseMessageProperty.Name];
            httpResponse.SuppressEntityBody = true;
            httpResponse.StatusCode = HttpStatusCode.OK;
        }

        var httpHeader = reply.Properties["httpResponse"] as HttpResponseMessageProperty;
        foreach (var item in _headersToInject)
        {
            httpHeader.Headers.Add(item.Key, item.Value);
        }
    }

Similar questions

If you have not found the answer to your question or you are interested in this topic, then look at other similar questions below or use the search

The pictures in a <div> tag are not showing up

Functionality: I have set up 2 different <div> elements with unique IDs. Each of these <div> elements will make an ajax call to fetch a specific set of images for display. To summarize, both <div> elements are invoking the same ajax met ...

What sets apart the browser/tab close event from the refresh event?

Can you help me understand the difference between a browser/tab close event and a refresh event? I've been researching this on Stack Overflow, but I'm still having trouble with it. My goal is to be able to log out a user through a server call whe ...

Stopping form submission on a jQuery form

I am in the process of implementing a password control feature on a login form using jQuery and ajax. This is the current script I have: $(document).ready(function() { $("#login-form").submit(function(e) { var csrftoken = getCookie('csr ...

Dynamic Mat-select-trigger that automatically adjusts its size to fit the content

Currently, I am experimenting with an Angular Mat-Select that allows multiple selections. To display the selected values in the value field, I have implemented a custom Mat-Select-Trigger. My goal is to enable automatic resizing of the value field (similar ...

Angular - Utilizing nested arrays for efficient file uploading

I am currently working on building a file uploader using Angular. My goal is to be able to upload different types of files, with each button capable of uploading multiple files at once. However, I am running into an issue where the uploaded files are not b ...

How to use AJAX to dynamically populate an HTML form with data retrieved from a PHP query结果

I'm having trouble populating a form with values after running a simple search. When I execute the script, I either receive an "undefined" response or nothing at all when I try alert(data);. search.php <?php include_once 'config/config.php&a ...

Filter error - Unable to retrieve property 'toLowerCase' from null value

When filtering the input against the cached query result, I convert both the user input value and database values to lowercase for comparison. result = this.cachedResults.filter(f => f.prj.toLowerCase().indexOf((this.sV).toLowerCase()) !== -1); This ...

Can Angular be used to dynamically filter a JSON object to display only the fields that match a specified filter text?

Sorry if this question has already been asked; I couldn't find the solution. Here is my issue: In my Angular app, I am retrieving a complex JSON object from a web service. I then present this JSON object to the user in tree format using ngx json vie ...

Tips for transmitting static information from route configuration to components

I am facing an issue with passing static data from a route to a component in Angular. Despite trying to pass the data in the route configuration, I keep receiving empty data when subscribing to it from the ActivatedRoute. Below is the code snippet that I h ...

Using Jquery's append() method to dynamically alter the HTML content

I am attempting to create a table with rows that are added dynamically. The challenge I am encountering is that each row consists of form elements, including multiple inputs. I have a PHP function that generates the correct row, and I have been able to sen ...

Steps for updating the clientId and authority values in MSAL configuration after they have already been read

Currently, I am utilizing Azure AD B2C for a multi-tenant application. The user starts by inputting their email, followed by selecting an option from a drop-down list populated based on the tenant they are associated with (tenant1, tenant2, tenant3). If th ...

Angular component is not identifiable within the Angular framework

Here's the content of my todos.component.ts file: import { Component, OnInit } from '@angular/core'; @Component({ selector: 'app-todos', standalone: true, imports: [], templateUrl: './todos.component.html', sty ...

Is there a way to verify if a username is available in the database?

Is there a way to check if the username entered in an input text field is available based on the database using JSF2? ...

What are the steps to perform an Ajax request to an online web service?

I would like to send an AJAX request to an external web service using jQuery. However, I am encountering an error and unable to receive a successful response from the server. var url = "http://www.example.com/api/convert"; var requestData = { temperat ...

When using Cordova on Android, the getResponseHeader("Set-Cookie") function will only return the last cookie and not the entire list of cookies

When working with an Android platform in a Cordova project, the function getResponseHeader("Set-Cookie") only retrieves the last cookie from the response, unlike in the iOS platform where it retrieves all cookies. $.ajax({ type: "POST", cache:false, url: ...

Ajax: The function assigned to the route does not get executed

Pressing a button triggers a confirmation box. If 'ok' is clicked, the div called 'EventData' should display the word 'reached'. The confirmation box appears when the button is clicked, but 'EventData' does not show ...

Using jQuery ajax in PHP, the ability to remove retrieved information from a different page is a

I'm currently working on a jQuery AJAX PHP application that allows for adding, deleting, and displaying records using switch case statements to streamline the code. Everything seems to be functioning correctly with inserting and displaying records, bu ...

Using Angular 2's ngModel directive to bind a value passed in from an

Using [(ngModel)] in my child component with a string passed from the parent via @Input() is causing some issues. Although the string is successfully passed from the parent to the child, any changes made to it within the child component do not reflect bac ...

What is the reason my synchronous jQuery AJAX callback is failing to function?

I am interested in learning about jQuery AJAX with callbacks, so I created this example: <?php sleep($_POST['sleep']); echo 'sleep for '.$_POST['sleep'] .'sec'; ?> $(function () { var timer = [5,2,3,1 ...

Here's a guide on executing both GET and POST requests using a single form

Currently, I am developing a web application which involves using a GET request to display checkboxes in a form. The selected data from the checkboxes needs to be sent back to the server using a POST request. However, I'm facing an issue with performi ...