-
Notifications
You must be signed in to change notification settings - Fork 201
Add support for assembly attribute containing user secret id #525
Conversation
/// <summary> | ||
/// The user secrets id. | ||
/// </summary> | ||
public string UserSecretsId { get; private set; } |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
nit: i believe you can just omit the private set; without any change in behavior
@@ -14,6 +14,18 @@ public class PathHelper | |||
internal const string Secrets_File_Name = "secrets.json"; | |||
internal const string Config_File_Name = "project.json"; | |||
|
|||
/// <summary> | |||
/// <para> | |||
/// This method is obsolete and will be removed in a future version. The recommended alternative is Microsoft.Extensions.Configuration.UserSecrets.PathHelper.GetSecretsPath(string, string). |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Can the "alternative" method be an actual doc link?
{ | ||
if (string.IsNullOrEmpty(userSecretId)) | ||
{ | ||
throw new ArgumentNullException(nameof(userSecretId)); |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
ArgNull is only for null args.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
So ArgumentException? ...we should probably clean up a few other places in our code where we do this. 😳
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
ArgException works, yes. Can you file a bug for other places where we throw the wrong exception?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Fixed it in aspnet/BasicMiddleware@dafe4cd 😄
}, | ||
"dependencies": { | ||
"Microsoft.Extensions.Configuration.Json": "1.0.0" | ||
}, | ||
"frameworks": { | ||
"net451": {}, | ||
"netstandard1.3": {} | ||
"netstandard1.5": {} |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I forget. Is this ok? Or is this a breaking change?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
It's not a breaking change. All currently supported netstandard platforms will continue to work.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Got it!
@@ -14,5 +14,8 @@ | |||
<PropertyGroup> | |||
<SchemaVersion>2.0</SchemaVersion> | |||
</PropertyGroup> | |||
<ItemGroup> | |||
<Service Include="{82a7f48d-3b50-4b1e-b82e-3ada8210c358}" /> |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Is this something important?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
VS will keep adding this...
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
It's VS fluff that's required for Test Explorer. Other projects have it already..
public void AddUserSecrets_FindsAssemblyAttribute() | ||
{ | ||
var configKey = nameof(AddUserSecrets_FindsAssemblyAttribute); | ||
SetSecret("Microsoft.Extensions.Configuration.UserSecrets.Test", configKey, "true"); |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Not sure I understand this test. What is "true" and "false" here? Is that the "user secrets id"? I.e. the "application name id" that I would use? If so, can we put a clearer dummy value here, e.g. "MyUserSecretsIdValue" or something?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
The secret id and values aren't important to the test. I can make them dummy values if it makes the purpose of the test clearer.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Yeah I had to re-read this several times. The problem I had is that "true" and "false" have actual meanings. Changing these to be more meaningless, but perhaps also to be clearer about their semantic meaning, could certainly make this easier to understand.
|
||
Assert.Equal("true", config[configKey]); | ||
|
||
SetSecret("Microsoft.Extensions.Configuration.UserSecrets.Test", configKey, "false"); |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Why is this setting the value again? Is it trying to "undo" the change? Because if so, this isn't safe - the file could be left dirty if this test fails.
var ex = Assert.Throws<InvalidOperationException>(() => builder.AddUserSecrets()); | ||
Assert.Equal(Resources.FormatError_Missing_UserSecretsIdAttribute(Assembly.GetEntryAssembly().FullName), ex.Message); | ||
|
||
UserSecretHelper.DeleteTempSecretProject(projectPath); |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Is this also cleanup code? This isn't reliable - the test might not get here.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
...yeah, I know. I've already fixed up the 1.1 branch.
@@ -0,0 +1,44 @@ | |||
<!-- |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
This file is beautiful. I just wanted to say that 😄
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
XML is as much an art as it is a language. 🎨
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Which begs the question: Why are .resx
files so ugly? 😈
🆙 📅 |
throw new ArgumentNullException(nameof(assembly)); | ||
} | ||
|
||
var attribute = assembly.GetCustomAttribute<UserSecretsIdAttribute>(); |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Did you consider extracting common code between this method and the one above?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Sure, could be done, but as I was implementing it didn't seem like it would make it any cleaner.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Yeah I had a similar thought at first, but I couldn't come up with any meaningful way to refactor. The methods are similar, but there's not much actual common code.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I found one simplification: created a private method for constructing the exception message. I couldn't find other useful reductions.
@@ -19,7 +19,7 @@ public UserSecretsIdAttribute(string userSecretId) | |||
{ | |||
if (string.IsNullOrEmpty(userSecretId)) | |||
{ | |||
throw new ArgumentNullException(nameof(userSecretId)); | |||
throw new ArgumentException(nameof(userSecretId)); |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
This now needs a proper message. We often have a Common_StringNullOrEmpty message that we use everywhere. Otherwise this exception has little meaning because it doesn't say what was invalid.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Updated to include error message.
{ | ||
while (_disposables.Count > 0) | ||
{ | ||
_disposables.Pop()?.Invoke(); |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Pop() never returns null here, right?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
In theory it could return null. In current implementation, it doesn't.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
In theory lots of things can happen 😄 Why would it ever be null in any implementation? Presumably we'd only push stuff if there's an actual action to push? It's of course safe to leave it the way it is, though.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Fair enough. Updated :)
cc @abpiskunov |
a6fc338
to
30572db
Compare
6fd21d9
to
ff2b07c
Compare
30572db
to
d617138
Compare
ff2b07c
to
9ce21a6
Compare
d617138
to
32e552d
Compare
9ce21a6
to
25d9ec8
Compare
After vacillating between approaches, I think we've found a solution that will preserve functionality for project.json users and help us move to an MSBuild world.
This adds API for configuring user secret ID from an assembly attribute,
UserSecretsIdAttribute
.When using
.AddUserSecrets()
, this method will first checkAssembly.GetEntryAssembly()
for the attribute. If no attribute is present, it will fallback to current behavior of reading project.json.This also adds a code gen build task. Users can set the
<UserSecretsId>xxxx-xxxx</UserSecretsId>
property in MSBuild and it will generateUserSecretsIdAttribute
on build.NB: the target of this is a rel/1.0.1 release since we need MSBuild support in LTS.
Part of aspnet/DotNetTools#169
cc @Eilon @glennc @muratg