Search code examples
c#.netajaxcorsasp.net-core-webapi

ASP.NET Core 8 Web API + Ajax call to controller: Completely disable Cors


I created a website with API using .NET 8 and Razor, and I'm hosting my website using AWS Elastic Beanstalk.

My website allows to create and save tests, and it works just perfectly from my side, not only in dev mode, but the published prod version.

One person from India is trying to help me to load tests, but it is getting Cors related errors constantly. No matter what I try to disable Cors, it always receives an error when hitting "Save".

Whatever I try - from different SO threads - always leads to a different error, each longer and more confusing.

This is my jQuery Ajax call to save:

function saveTest() {
    var test = generateTestJson(true);

    if (test == Result.KO) 
        return false;

    toastMessage(Texts.processingData, InformationState.INFORMATION, true, Config.informationTimeout);

    var saveMode = SaveMode.Insert;

    if (selectedTestId != "") {   // Update
        saveMode = SaveMode.Update;
        testId = selectedTestId
    } else {   // Save
        //check for duplicates
        var testName = document.getElementById("Name").value;
        var testExists = ddlItemExists("ddlTests", testName);

        if (testExists) {
            toastMessage(Texts.testAlreadyExists.replace("%0", testName), InformationState.ERROR, false, Config.informationTimeout);
            return;
        }
    }

    var deletedElements = generateJsonDeletedElements();

    formData.delete('test');
    formData.delete('saveMode');
    formData.delete('deletedElements');
    //
    formData.append('test', test);
    formData.append('saveMode', saveMode);
    formData.append('deletedElements', deletedElements);

    $.ajax({
        url: '/Test/SaveTest',
        method: 'POST',
        contentType: false,
        processData: false,
        data: formData,
        success: function (data) {
            if (data.status == Result.OK) {
                selectedTestId = testId;
                formSubmitted = true;
                fillTestSelector();
            }
            showResultStatus(data.status, data.message);
        },
        error: function (xhr, status, error) {
            clearTimeout(informationTimer);
            showToast(xhr.responseText, InformationState.ERROR, false, true, "3");
        }
    })
}

Program.cs:

// ...
builder.Services.AddCors(options =>
{
   options.AddPolicy("MyPolicy",
       policy =>
       {
           policy
               .AllowAnyOrigin()
               .AllowAnyMethod()
               .AllowAnyHeader()
               .SetIsOriginAllowed(origin => true); // allow any origin
       }
   );
});

var app = builder.Build();
    
app.UseAuthentication();
app.UseAuthorization();

// Configure the HTTP request pipeline.
if (app.Environment.IsDevelopment())
{
    app.UseMigrationsEndPoint();
}
else
{
    app.UseExceptionHandler("/Home/Error");
    app.UseHsts();
}

app.UseWebOptimizer();

// app.UseHttpsRedirection();
app.UseStaticFiles();

app.UseRouting();

app.UseCors("TestMePolicy");

var locOptions = app.Services.GetService<IOptions<RequestLocalizationOptions>>();
app.UseRequestLocalization(locOptions.Value);

app.UseStaticFiles();

app.UseAuthentication();
app.UseAuthorization();

app.MapControllerRoute(
    name: "default",
    pattern: "{controller=Home}/{action=Index}/{id?}");
app.MapRazorPages();

app.Run();

Controller:

[HttpPost]
[EnableCors("MyPolicy")]
public async Task<JsonResult> SaveTest(string test, int saveMode, List<IFormFile> files, string deletedElements = "")

The most annoying thing is that it is working just fine from my location in Europe, but my friend is not able to work from India, whenever it hits "Save" a Cors related error is thrown, the controller method is obviously not called.

It is also incomprehensible the fact that from my side it works even without all that Program.cs code to disable Cors, but not from India.

I need to completely disable Cors, and I've checked many SO threads to no avail.


Solution

  • The policy name is different, please double check it.

    enter image description here

    Suggestions

    1. The middleware order is very important, you should change it like below.

    var app = builder.Build();
    //DELETE IT
    //app.UseAuthentication();
    //app.UseAuthorization();
    
    // Configure the HTTP request pipeline.
    if (app.Environment.IsDevelopment())
    {
        app.UseMigrationsEndPoint();
    }
    else
    {
        app.UseExceptionHandler("/Home/Error");
        app.UseHsts();
    }
    
    app.UseWebOptimizer();
    
    // app.UseHttpsRedirection();
    app.UseStaticFiles();
    
    app.UseRouting();
    
    app.UseCors("TestMePolicy");
    
    var locOptions = app.Services.GetService<IOptions<RequestLocalizationOptions>>();
    app.UseRequestLocalization(locOptions.Value);
    //DELETE IT
    //app.UseStaticFiles();
    
    app.UseAuthentication();
    app.UseAuthorization();
    
    app.MapControllerRoute(
        name: "default",
        pattern: "{controller=Home}/{action=Index}/{id?}");
    app.MapRazorPages();
    
    app.Run();
    

    2. If you want to allow all origin , you can set it like below.

        builder.Services.AddCors(options => options.AddPolicy("CorsPolicy", builder =>
        {
            builder.AllowAnyMethod()
                .SetIsOriginAllowed(_ => true)
                .AllowAnyHeader()
                .AllowCredentials();
        }));
        ...
        app.UseRouting();
    
        // add this line
        app.UseCors("CorsPolicy");