The Azure SDK guidelines aren't currently prescriptive regarding the use of ETag in APIs. In storage libraries, ETag is alternately handled in a separate blob properties class in Azure Blob Storage, and as an entity property in Azure Storage Tables. It would be helpful for the board to characterize when to take one approach versus the other and give further guidance about patterns for conditional operations.
There are several key questions to this issue:
- Should SDKs abstract the concept of ETag from the user?
- Should ETag live as a property on the logical entity it represents, or a separate object holding response headers?
- Should ETag be explicitly passed to a method, or read from the logical entity?
- Should ETag be settable on the logical entity so that the user can clear the value?
In the following discussion, we'll look specifically at the use of ETag in the AppConfiguration client library, several approaches that answer these questions in different ways, and make a recommendation for a solution that addresses most of our concerns.
ETag in AppConfiguration
The .NET APIs currently provide the following options for CRUD operations:

For Delete, ETag is explicitly passed as a parameter which has the benefit of alerting the caller to its use in the method. The concerns come with the Set operation, where If-Match is set on the Request if the ETag property on ConfigurationSetting has a value, which hides its use from callers. It also means we must make ETag a settable property on ConfigurationSettting to enable clearing it, which can cause confusion to users creating an instance of ConfigurationSetting, where they might believe they should set this value.
Possible Approaches
- ETag is not a property of ConfigurationSetting, and passed as a parameter to operations.
If ETag isn't a property of ConfigurationSetting, users must obtain ETag from the Response object and implement management of a group of ETags in order to pass them into Delete, Get and Set methods. It might not be obvious to the user that it should be obtained from the response, and it would require many customers to implement similar logic that our library should provide.
- ETag is a read-write property of ConfigurationSetting, and ConfigurationSetting is passed as a parameter to operations (not ETag)
If If-Match is set when the ConfigurationSetting's ETag property has a value, the user must learn this pattern to implement optimistic concurrency. There is no ETag parameter in method signatures for Delete, Get or Set, so it is not explicitly called out to the user that the value is used in the method. In order to use last writer wins semantics for these methods, ETag must be a settable property of ConfigurationSetting, which potentially leads to confusion when creating instances of ConfigurationSetting -- the implication is that the user should set it to something which is misleading, since in almost all cases this value should be obtained from the server. Another concern with this approach is that Set and Delete will throw infrequently, so users may not realize they need to handle the exception until they get to production.
- ETag is a read-only property of ConfigurationSetting, and both ConfigurationSetting and a separate ETag parameter is passed to override the ConfigurationSetting property.
Having two ETags passed to the method causes confusion about which one takes precedence.
- ETag is a read-only property of ConfigurationSetting, and both ConfigurationSetting and an onlyIfMatches parameter is passed to the method.
The onlyIfMatches parameter indicates whether or not the ETag value should be added to the Request in an If-Match header. This approach gives the user the option to make the operation conditional or not, without causing confusion with multiple ETag values available in the same method. There is a parameter indicating that ETag will be in use which will help alert callers both to its use and the need to handle exceptions the method could throw. ETag is not settable, so it avoids confusion when a ConfigurationSetting object is created.
Proposed API
The fourth approach addresses most of our concerns surrounding ETag. In this approach, the CRUD operations become:

In addition, in this approach, the answers to our key questions become:
- Should SDKs abstract the concept of ETag from the user?
-> No, ETag is still visible, but only its functionality is described at the method level, and the defaults use LWW semantics so user not handling optimistic concurrency won't fail sporadically.
- Should ETag live as a property on the logical entity it represents, or a separate object holding response headers?
-> Property of logical entity
- Should ETag be explicitly passed to a method, or read from the logical entity?
-> Read from the logical entity, applied based on parameter that defaults to last writer wins.
- Should ETag be settable on the logical entity so that the user can clear the value?
-> Not settable, but applied based on method parameter.
The Azure SDK guidelines aren't currently prescriptive regarding the use of ETag in APIs. In storage libraries, ETag is alternately handled in a separate blob properties class in Azure Blob Storage, and as an entity property in Azure Storage Tables. It would be helpful for the board to characterize when to take one approach versus the other and give further guidance about patterns for conditional operations.
There are several key questions to this issue:
In the following discussion, we'll look specifically at the use of ETag in the AppConfiguration client library, several approaches that answer these questions in different ways, and make a recommendation for a solution that addresses most of our concerns.
ETag in AppConfiguration
The .NET APIs currently provide the following options for CRUD operations:
For Delete, ETag is explicitly passed as a parameter which has the benefit of alerting the caller to its use in the method. The concerns come with the Set operation, where If-Match is set on the Request if the ETag property on ConfigurationSetting has a value, which hides its use from callers. It also means we must make ETag a settable property on ConfigurationSettting to enable clearing it, which can cause confusion to users creating an instance of ConfigurationSetting, where they might believe they should set this value.
Possible Approaches
If ETag isn't a property of ConfigurationSetting, users must obtain ETag from the Response object and implement management of a group of ETags in order to pass them into Delete, Get and Set methods. It might not be obvious to the user that it should be obtained from the response, and it would require many customers to implement similar logic that our library should provide.
If If-Match is set when the ConfigurationSetting's ETag property has a value, the user must learn this pattern to implement optimistic concurrency. There is no ETag parameter in method signatures for Delete, Get or Set, so it is not explicitly called out to the user that the value is used in the method. In order to use last writer wins semantics for these methods, ETag must be a settable property of ConfigurationSetting, which potentially leads to confusion when creating instances of ConfigurationSetting -- the implication is that the user should set it to something which is misleading, since in almost all cases this value should be obtained from the server. Another concern with this approach is that Set and Delete will throw infrequently, so users may not realize they need to handle the exception until they get to production.
Having two ETags passed to the method causes confusion about which one takes precedence.
The onlyIfMatches parameter indicates whether or not the ETag value should be added to the Request in an If-Match header. This approach gives the user the option to make the operation conditional or not, without causing confusion with multiple ETag values available in the same method. There is a parameter indicating that ETag will be in use which will help alert callers both to its use and the need to handle exceptions the method could throw. ETag is not settable, so it avoids confusion when a ConfigurationSetting object is created.
Proposed API
The fourth approach addresses most of our concerns surrounding ETag. In this approach, the CRUD operations become:
In addition, in this approach, the answers to our key questions become:
-> No, ETag is still visible, but only its functionality is described at the method level, and the defaults use LWW semantics so user not handling optimistic concurrency won't fail sporadically.
-> Property of logical entity
-> Read from the logical entity, applied based on parameter that defaults to last writer wins.
-> Not settable, but applied based on method parameter.