dotnet / dotnet/aspnetcore

MediaType.IsSubsetOf returns true for application/hal+json and application/json

Open
#39,959 2 comments 0 reactions 1 assignee Claimed by @rafikiassumani-msft View on GitHub
area-mvc investigate
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

### Describe the bug

MediaType.IsSubsetOf(MediaType set) would return true for application/hal+json and application/json respectfully.
In aspnetcore 2.1 it was returning false. I see that the change was introduced with aspnetcore 2.2.3, I just don't understand why (I am sorry if it is not a bug) But if it is not a bug, then maybe the logic in the OutputFormatter could be changed so that CanWriteResult of a formatter for application/hal+json returns false for application/json.

This is an issue if you have 2 different formatters for application/hal+json and application/json because CanWriteResult of the formatter for application/json now returns true for application/hal+json and it uses this formatter instead of the other one.

I think that there would be other people who would expect it to return false (as it was). See this issue -
https://github.com/dotnet/aspnetcore/issues/8469 - the problem there was that they made their own implementation which was wrong because it was only looking at the content type of the request, but still they were expecting that CanWriteResult of the output formatter would return false (in aspnetcore 2.2.3+ it will return true even if they fixed their issue with the content type)

With this change in MediaType we would have to override CanWriteResult and explicitly check for application/hal+json so that we can keep both formatters.

This is the relevant code in aspnetcore 2.1 (we fall in the last "else")(https://github.com/aspnet/Mvc/blob/2.1.0/src/Microsoft.AspNetCore.Mvc.Core/Formatters/MediaType.cs):
```
private bool MatchesSubtype(MediaType set)
{
if (set.MatchesAllSubTypes)
{
return true;
}

if (set.SubTypeSuffix.HasValue)
{
if (SubTypeSuffix.HasValue)
{
// Both the set and the media type being checked have suffixes, so both parts must match.
return MatchesSubtypeWithoutSuffix(set) && MatchesSubtypeSuffix(set);
}
else
{
// The set has a suffix, but the media type being checked doesn't. We never consider this to match.
return false;
}
}
else
{
// The set has no suffix, so we're just looking for an exact match (which means that if 'this'
// has a suffix, it won't match).
return set.SubType.Equals(SubType, StringComparison.OrdinalIgnoreCase);
}
}
```

This is in aspnetcore 6 (https://github.com/dotnet/aspnetcore/blob/main/src/Mvc/Mvc.Core/src/Formatters/MediaType.cs):
```
private bool MatchesSubtype(ReadOnlyMediaTypeHeaderValue set)
{
if (set.MatchesAllSubTypes)
{
return true;
}

if (set.SubTypeSuffix.HasValue)
{
if (SubTypeSuffix.HasValue)
{
// Both the set and the media type being checked have suffixes, so both parts must match.
return MatchesSubtypeWithoutSuffix(set) && MatchesSubtypeSuffix(set);
}
else
{
// The set has a suffix, but the media type being checked doesn't. We never consider this to match.
return false;
}
}
else
{
// If this subtype or suffix matches the subtype of the set,
// it is considered a subtype.
// Ex: application/json > application/val+json
return MatchesEitherSubtypeOrSuffix(set);
}
}

private bool MatchesEitherSubtypeOrSuffix(ReadOnlyMediaTypeHeaderValue set)
{
return set.SubType.Equals(SubType, StringComparison.OrdinalIgnoreCase) ||
set.SubType.Equals(SubTypeSuffix, StringComparison.OrdinalIgnoreCase);
}
```

### Expected Behavior

MediaType.IsSubsetOf returns false for application/hal+json and application/json as it was in aspnetcore 2.1.

Maybe it would be better to change the logic in OutputFormatter so that CanWriteResult returns false.

### Steps To Reproduce

1. In MvcOptions add an output formatter for application/hal+json and then another for application/json.
2. make a request with accept:application/json.
3. the result will be formatted by the first ( application/hal+json) formatter instead of the second one (application/json).

### Exceptions (if any)

_No response_

### .NET Version

.NET 6

### Anything else?

_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.