Why URL with different port are allowed to use WEB API as default setting?

Viewed 87

I created a new ASP.NET Core Web API project and kept its default settings. It runs on this URL: https://localhost:7254/.

I also created an ASP.NET Core MVC web app as API user to test it and also kept its default settings. It runs on URL https://localhost:7120/

Both projects run on .NET 6.

Based on Microsoft documentation, those URLs have different ports so they are not the same origin.

I wonder why can I call my Web API method and use it, without any specific CORS setting?

Here is my Web API project Program.cs:

using Serilog;

Log.Logger = new LoggerConfiguration()
    .WriteTo.File(
     path: "..\\logs\\log-.txt",
     outputTemplate: "[{Timestamp:HH:mm:ss} {Level:u3}] {Message:lj}{NewLine}{Exception}",
     rollingInterval: RollingInterval.Day,
     restrictedToMinimumLevel: Serilog.Events.LogEventLevel.Information
    )
    .CreateLogger();

var builder = WebApplication.CreateBuilder(args);

builder.Host.UseSerilog();

builder.Services.AddControllers();
builder.Services.AddEndpointsApiExplorer();
builder.Services.AddSwaggerGen();

var app = builder.Build();

if (app.Environment.IsDevelopment())
{
    app.UseSwagger();
    app.UseSwaggerUI();
}

app.UseHttpsRedirection();

app.UseAuthorization();

app.MapControllers();

app.Run();

And here is a part of my ASP web app HomeController code, that calls Web API method:

public IActionResult Index()
{
    List<WeatherForecast> list = new List<WeatherForecast>();

    var client = new RestClient("https://localhost:7254");
    var request = new RestRequest("WeatherForecast", Method.Get);

    RestResponse response = client.Execute(request);

    if (response.IsSuccessful && response.Content != null)
    {
        var data = JsonConvert.DeserializeObject<List<WeatherForecast>>(response.Content);

        if (data != null) 
            list = data;
    }

    return View(list);
}
1 Answers

and use it, without any specific CORS setting?

If you decompile builder.Services.AddControllers(); you will see this one:

// Microsoft.AspNetCore.Mvc.dll (dotnet 6.0.8) 
public static IMvcBuilder AddControllers(this IServiceCollection services)
{
 IMvcCoreBuilder mvcCoreBuilder = services != null ? MvcServiceCollectionExtensions.AddControllersCore(services) : throw new ArgumentNullException(nameof (services));
 return (IMvcBuilder) new MvcBuilder(mvcCoreBuilder.Services, mvcCoreBuilder.PartManager);
}

MvcServiceCollectionExtensions.AddControllersCore(services) in turn is decompiled to this:

private static IMvcCoreBuilder AddControllersCore(IServiceCollection services)
{
  IMvcCoreBuilder mvcCoreBuilder = services.AddMvcCore().AddApiExplorer().AddAuthorization().AddCors().AddDataAnnotations().AddFormatterMappings();
  if (!MetadataUpdater.IsSupported)
    return mvcCoreBuilder;
  services.TryAddEnumerable(ServiceDescriptor.Singleton<IActionDescriptorChangeProvider, HotReloadService>());
  return mvcCoreBuilder;
}

So, you can see AddCors() call is already present there.

UPDATE
So, i created 2 webapi projects, both with default template (with WeatherForeacastController). And just made one of them making request to another - behavior you described is reproduced.
Then created third MVC project with a simple button on the page:

<div class="text-center">
    <button id="btn" style="width: 150px; height: 50px">Request to alien origin</button>
</div>
@section Scripts
{
    <script>
    $(function() {        
        
        $("#btn").click(function(){
            $.ajax("https://localhost:7139/weatherforecast").done(function(r) {
                            
                    }).fail(function(r){
                        
                    });
        })
        
    })
    </script>
}

And ajax request is blocked by browser: cors_error

On MDN documentation you can see many mentions of a browser word:

Cross-Origin Resource Sharing (CORS) is an HTTP-header based mechanism that allows a server to indicate any origins (domain, scheme, or port) other than its own from which a browser should permit loading resources.

CORS also relies on a mechanism by which browsers make a "preflight" request to the server hosting the cross-origin resource, in order to check that the server will permit the actual request. In that preflight, the browser sends headers that indicate the HTTP method and headers that will be used in the actual request.

HttpClient does not do any preflight requests, it just can't.
Also this one should be mentioned:

Functional overview
The Cross-Origin Resource Sharing standard works by adding new HTTP headers that let servers describe which origins are permitted to read that information from a web browser.

So, did not read the whole article, but strongly believe that CORS concept is only applied to a special type of http clients - browsers.

Related