dotnet / dotnet/aspnetcore

# Feature Request: Add Fallback Policy Resolver to CORS Options

Open
#65,526 0 comments 0 reactions 0 assignees View on GitHub
area-middleware feature-cors
Dominant language
C#
Stars
38.4k
Forks
10.9k
Avg merge
2d 6h
Merged PRs (30d)
290

Description

### Is there an existing issue for this?

- [x] I have searched the existing issues

### Is your feature request related to a problem? Please describe the problem.

_No response_

### Describe the solution you'd like

# Feature Request: Add Fallback Policy Resolver to CORS Options

## Is your feature request related to a problem?

Currently, ASP.NET Core CORS middleware only supports predefined policies registered via `CorsOptions`. When a policy name is not found in the policy map, the middleware returns `null` and the request is not processed with CORS headers.

This limitation makes it difficult to implement:
- **Dynamic policy loading** from databases or external configuration sources
- **Multi-tenant applications** where each tenant has different CORS policies
- **Route-based policy resolution** where policies are determined by request path patterns
- **Fallback mechanisms** when named policies are not found

## Describe the solution you'd like

Add a `PolicyResolver` callback property to `CorsOptions` that allows custom policy resolution logic when a named policy is not found in the predefined policy map.

### Proposed API

```csharp
public class CorsOptions
{
private readonly IDictionary _policyMap = new Dictionary();

// Existing properties...
public string DefaultPolicyName { get; set; } = "__DefaultCorsPolicy";

///
/// Gets or sets a callback that resolves CORS policies when they are not found in the policy map.
/// This enables dynamic policy loading, multi-tenant scenarios, and custom fallback logic.
///
///
/// The callback receives the HttpContext and policy name, allowing context-aware policy resolution.
/// Return null if no policy should be applied.
///
public Func PolicyResolver { get; set; } = (_, _) => null;

// Existing methods...
}
```

### Implementation in CorsPolicyProvider

```csharp
public class CorsPolicyProvider : ICorsPolicyProvider
{
private readonly CorsOptions _options;

public CorsPolicyProvider(IOptions options)
{
_options = options.Value;
}

public Task GetPolicyAsync(HttpContext context, string? policyName)
{
var name = policyName ?? _options.DefaultPolicyName;

// Try to get from predefined policies first
if (_options.GetPolicy(name) is CorsPolicy policy)
{
return Task.FromResult(policy);
}

// Fallback to custom resolver
var resolvedPolicy = _options.PolicyResolver?.Invoke(context, policyName);
return Task.FromResult(resolvedPolicy);
}
}
```

## Use Cases

### 1. Multi-Tenant Application

```csharp
services.AddCors(options =>
{
options.PolicyResolver = (context, policyName) =>
{
var tenantId = context.Request.Headers["X-Tenant-ID"].FirstOrDefault();
if (string.IsNullOrEmpty(tenantId))
return null;

// Load tenant-specific policy from database
var tenantPolicy = _tenantPolicyService.GetPolicyForTenant(tenantId);
return tenantPolicy;
};
});
```

### 2. Dynamic Policy Loading from Database

```csharp
services.AddCors(options =>
{
options.PolicyResolver = (context, policyName) =>
{
if (string.IsNullOrEmpty(policyName))
return null;

// Load policy from database or cache
var policy = _policyRepository.GetByName(policyName);
return policy;
};
});
```

### 3. Route-Based Policy Resolution

```csharp
services.AddCors(options =>
{
options.PolicyResolver = (context, policyName) =>
{
var path = context.Request.Path.Value;

if (path?.StartsWith("/api/public") == true)
{
return new CorsPolicyBuilder()
.AllowAnyOrigin()
.AllowAnyMethod()
.AllowAnyHeader()
.Build();
}

if (path?.StartsWith("/api/internal") == true)
{
return new CorsPolicyBuilder()
.WithOrigins("https://internal.company.com")
.AllowAnyMethod()
.AllowAnyHeader()
.Build();
}

return null;
};
});
```

## Benefits

1. **Backward Compatible**: Existing code continues to work without changes
2. **Flexible**: Supports various dynamic policy resolution scenarios
3. **Performance**: Only invoked when predefined policies are not found
4. **Context-Aware**: Access to `HttpContext` enables request-based decisions
5. **Simple API**: Single callback property, easy to understand and use

## Alternatives Considered

### Alternative 1: Custom ICorsPolicyProvider
Users can already implement custom `ICorsPolicyProvider`, but this requires:
- More boilerplate code
- Replacing the entire provider implementation
- Losing the built-in policy map functionality

### Alternative 2: Middleware-Level Customization
Implementing custom middleware, but this:
- Duplicates CORS logic
- Harder to maintain
- Loses integration with `[EnableCors]` attribute

## Additional Context

This feature is inspired by similar extensibility patterns in ASP.NET Core:
- `AuthorizationOptions.FallbackPolicy`
- `RouteOptions.ConstraintMap` with custom constraint resolvers
- `JsonOptions` with custom converters

The proposed API follows the same design principles of providing extensibility points while maintaining backward compatibility.

---

**Would you be willing to contribute this feature?** Yes, I can submit a PR if this proposal is accepted.

### Additional context

_No response_

Contributor guide

Open the contributing guide

Assessment

This issue has not been assessed yet.

Get new issues in your inbox

A short digest of beginner-friendly GitHub issues.