Skip to content

Add nullability to remaining middleware #26098

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Merged
merged 5 commits into from
Oct 22, 2020
Merged

Conversation

pranavkm
Copy link
Contributor

Adds nullable annotations to the remaining middleware in the repo (except SpaServices)

@pranavkm pranavkm requested a review from JamesNK September 19, 2020 15:00
@pranavkm pranavkm added this to the 6.0.0-alpha1 milestone Sep 19, 2020
@@ -43,7 +44,7 @@ public interface ISession
/// <param name="key"></param>
/// <param name="value"></param>
/// <returns></returns>
bool TryGetValue(string key, out byte[] value);
bool TryGetValue(string key, [MaybeNullWhen(false)] out byte[] value);
Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I'll see if I can port this change to 5.0. It is more restrictive so we might as well try and get it right.

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Ideally we would have:

Suggested change
bool TryGetValue(string key, [MaybeNullWhen(false)] out byte[] value);
bool TryGetValue(string key, [NotNullWhen(true)] out byte[]? value);

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This might be more problematic with how distributed session works. I think it can return null while returning true.

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This might be more problematic with how distributed session works. I think it can return null while returning true.

I wouldn't expect that. Where do you see it happening?

@@ -29,7 +29,7 @@ internal static bool IsGetOrHeadMethod(string method)

internal static bool PathEndsInSlash(PathString path)
{
return path.Value.EndsWith("/", StringComparison.Ordinal);
return path.HasValue && path.Value!.EndsWith("/", StringComparison.Ordinal);
Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This seems like a bug. PathSting.HasValue is annotated with MemberNotNullWhen but it doesn't work here. @sharwell any idea why that might?

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Null

Now in gif!

@@ -11,6 +11,11 @@ public static class WebSocketsDependencyInjectionExtensions
{
public static IServiceCollection AddWebSockets(this IServiceCollection services, Action<WebSocketOptions> configure)
{
if (configure is null)
Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

services.Configure will throw if configure is null. Might as well throw it here and make it consistent with all of our other extension methods.

@@ -108,7 +108,7 @@ public async Task Invoke(HttpContext context)
}
finally
{
context.Features.Set<ISessionFeature>(null);
context.Features.Set<ISessionFeature?>(null);
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

❔ Can you link me to the definition of Set<T>?

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

public void Set<TFeature>(TFeature instance)
{
this[typeof(TFeature)] = instance;
}

@@ -8,6 +8,6 @@ namespace Microsoft.AspNetCore.Session
{
public class SessionFeature : ISessionFeature
{
public ISession Session { get; set; }
public ISession Session { get; set; } = default!;
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

💡 Consider using this instead:

Suggested change
public ISession Session { get; set; } = default!;
[DisallowNull]
public ISession? Session { get; set; }

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Ooh, what does this do?

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Hmm, I don't think this works for this case. In the ordinary case, features are instantiated by the framework and initialize these properties. If the feature exists, user code does not see a null value. Ideally we would have created initialized this in the ctor, but that ship has sailed.

@@ -105,7 +106,7 @@ private byte[] IdBytes
_sessionIdBytes = new byte[IdByteCount];
RandomNumberGenerator.Fill(_sessionIdBytes);
}
return _sessionIdBytes;
return _sessionIdBytes!;
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

:\ Not a huge fan of this suppression, but I'm not exactly sure what the alternative would be. You could put MemberNotNullWhen on the IsAvailable property and mark this property as nullable, but I'm not sure it's an improvement over what you have here. Here are all the potential options I see:

  • Applying MemberNotNullWhen to IsAvailable
  • Changing the property type to byte[]?
  • Returning _sessionIdBytes ?? Array.Empty<byte>()
  • Returning _sessionIdBytes ?? throw new InvalidOperationException(...)
  • Keeping the suppression

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

@Tratcher thoughts?

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This code could be restructured. Load always sets _sessionIdBytes or _sessionId so if IdBytes is called then it will return a non-null value. How about just removing the IsAvailable check here?

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Ok. I've removed the check here. I've added a new exception to Serialize which would have previously resulted in a null-ref.

@@ -43,7 +44,7 @@ public interface ISession
/// <param name="key"></param>
/// <param name="value"></param>
/// <returns></returns>
bool TryGetValue(string key, out byte[] value);
bool TryGetValue(string key, [MaybeNullWhen(false)] out byte[] value);
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This might be more problematic with how distributed session works. I think it can return null while returning true.

I wouldn't expect that. Where do you see it happening?

@pranavkm pranavkm force-pushed the prkrishn/nullable-middleware-2 branch from 81d7628 to b1b301c Compare October 17, 2020 00:19
Copy link
Contributor Author

@pranavkm pranavkm left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

🆙 📅

@@ -105,7 +106,7 @@ private byte[] IdBytes
_sessionIdBytes = new byte[IdByteCount];
RandomNumberGenerator.Fill(_sessionIdBytes);
}
return _sessionIdBytes;
return _sessionIdBytes!;
Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Ok. I've removed the check here. I've added a new exception to Serialize which would have previously resulted in a null-ref.

@@ -8,6 +8,6 @@ namespace Microsoft.AspNetCore.Session
{
public class SessionFeature : ISessionFeature
{
public ISession Session { get; set; }
public ISession Session { get; set; } = default!;
Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Hmm, I don't think this works for this case. In the ordinary case, features are instantiated by the framework and initialize these properties. If the feature exists, user code does not see a null value. Ideally we would have created initialized this in the ctor, but that ship has sailed.

@pranavkm pranavkm force-pushed the prkrishn/nullable-middleware-2 branch from e4923e8 to f99b482 Compare October 21, 2020 20:03
@runfoapp runfoapp bot mentioned this pull request Oct 22, 2020
@pranavkm pranavkm merged commit b0a6755 into master Oct 22, 2020
@pranavkm pranavkm deleted the prkrishn/nullable-middleware-2 branch October 22, 2020 23:41
@amcasey amcasey added the area-middleware Includes: URL rewrite, redirect, response cache/compression, session, and other general middlewares label Jun 2, 2023
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
area-middleware Includes: URL rewrite, redirect, response cache/compression, session, and other general middlewares
Projects
None yet
Development

Successfully merging this pull request may close these issues.

6 participants