dotnet / aspnetcore

ASP.NET Core is a cross-platform .NET framework for building modern cloud-based web applications on Windows, Mac, or Linux.
https://asp.net
MIT License
35.5k stars 10.04k forks source link

Make IDataProtectionKeyContext settable #52645

Closed amcasey closed 11 months ago

amcasey commented 11 months ago

Background and Motivation

I understand that it's required when persisting keys to EF, so we should reflect that in the interface. Note that it's included in our docs.

PR: https://github.com/dotnet/aspnetcore/pull/52644

Proposed API

namespace Microsoft.AspNetCore.DataProtection.EntityFrameworkCore;

public interface IDataProtectionKeyContext
{
-    DbSet<DataProtectionKey> DataProtectionKeys { get; }
+    DbSet<DataProtectionKey> DataProtectionKeys { get; set; }
}

Usage Examples

class MyContext : IDataProtectionKeyContext
{
    public DbSet<DataProtectionKey> DataProtectionKeys { get; set; } = null!;
}

Alternative Designs

It might be possible to use a default interface member that throws, but I wouldn't guess you could add a single accessor to an existing property.

Risks

Obviously, it's a breaking change. I understand it only breaks people who are already persisting keys incorrectly.

ghost commented 11 months ago

Thank you for submitting this for API review. This will be reviewed by @dotnet/aspnet-api-review at the next meeting of the ASP.NET Core API Review group. Please ensure you take a look at the API review process documentation and ensure that:

halter73 commented 11 months ago

API Review Notes:

@ajcvickers @csharpfritz Do you have any opinions?

As of now, we think that we should probably go with an analyzer if anything.

ajcvickers commented 11 months ago

From an EF perspective, the DbSet property does not need to be, and ideally should not be, settable.

csharpfritz commented 11 months ago

From an EF perspective, the DbSet property does not need to be, and ideally should not be, settable.

That's interesting... how do you work with the collection if the DbSet is not settable?

This syntax is invalid because DbSet is abstract:

public DbSet<DataProtectionKey> DataProtectionKeys { get; } = new DbSet<DataProtectionKey>();

We can initialize the property in the constructor with syntax like:

DataProtectionKeys = Set<DataProtectionKey>();

Either way... we can agree that the auto-generated syntax is invalid. I think I'd favor an analyzer that throws an error on this misconfiguration.

ajcvickers commented 11 months ago

@csharpfritz My personal favorite pattern is:

public DbSet<DataProtectionKey> DataProtectionKeys => Set<DataProtectionKey>();

You can provide a public or private setter, and then EF will initialize the properties for you. Or you can call Set in the constructor and initialize the properties explicitly there.

The main point here is that consumers will never call the setter, so my preference is to not include it, and certainly it should not be required by the interface.

amcasey commented 11 months ago

API rejected. Thanks, @ajcvickers!