azure-sdk-for-net
azure-sdk-for-net copied to clipboard
resourceGroup.GetAppCertificates() error "Value cannot be an empty string. (Parameter 'resourceId')"
Library name and version
Azure.ResourceManager.AppService 1.0.0
Describe the bug
I try to get the managed certificate of an app service using resourceGroup.GetAppCertificates
but the result set had this error Value cannot be an empty string. (Parameter 'resourceId')
. Any operations on the resulting AppCertificateCollection
fail with this error. I tried getting the managed certificates from an app service where I had created the certificate using the SDK and then also from a manually created (using the portal) resource group/app service/managed certificate but I get the same results.
If I use the method resourceGroup.GetAppCertificates()
on a resource group that only contains "bring your own" certificates then it works fine. The certificate data for these looks exactly the same as for my managed certificates (except the issuer/issue date).
One other strange thing I noticed is that upon creating the managed certificates using certificates.CreateOrUpdate()
or the REST APIS it requires a "serverFarmId" but when I view the certificates in resources.azure.com
the serverFarmId shows as null?
I also have the issue that the certificates.CreateOrUpdate()
returns 202
which causes an exception as mentioned here. I can handle that but I would really like to be able to get the newly created managed certificate using the new azure resource SDK so I can use the thumbprint for a next step. For the time being I will resort to using the REST APIS but please let me know if there is any advice or a work around for this. Is it a bug or am I doing something wrong?
Expected behavior
AppCertificateCollection
is returned containing managed certificates I can use.
Actual behavior
Value cannot be an empty string. (Parameter 'resourceId')
error is thrown when I try to use the AppCertificateCollection
for anything.
Stack Trace
at Azure.Core.Argument.AssertNotNullOrEmpty(String value, String name)
at Azure.Core.ResourceIdentifier..ctor(String resourceId)
at Azure.ResourceManager.AppService.AppCertificateData.DeserializeAppCertificateData(JsonElement element)
at Azure.ResourceManager.AppService.Models.CertificateCollection.DeserializeCertificateCollection(JsonElement element)
at Azure.ResourceManager.AppService.CertificatesRestOperations.ListByResourceGroup(String subscriptionId, String resourceGroupName, CancellationToken cancellationToken)
at Azure.ResourceManager.AppService.AppCertificateCollection.<>c__DisplayClass10_0.<GetAll>g__FirstPageFunc|0(Nullable1 pageSizeHint) at Azure.Core.PageableHelpers.FuncPageable
1.<AsPages>d__4.MoveNext()
at Azure.Pageable1.<GetEnumerator>d__8.MoveNext() at System.Collections.Generic.LargeArrayBuilder
1.AddRange(IEnumerable1 items) at System.Collections.Generic.EnumerableHelpers.ToArray[T](IEnumerable
1 source)
at System.Linq.Enumerable.ToArray[TSource](IEnumerable1 source) at System.Linq.SystemCore_EnumerableDebugView
1.get_Items()
Reproduction Steps
-
Create a managed certificate on an app service using either the azure portal or the
Azure.ResourceManager.AppService 1.0.0
package. -
Retrieve the
AppCertificateCollection
usingresourceGroup.GetCertificates()
-
Inspecting the returned value results will show the above mentioned error. Also calling ExistsAsync, GetAsyc etc will invoke the error.
Environment
Microsoft Visual Studio Enterprise 2022 (64-bit) - Current Version 17.4.3
.NET SDK: Version: 7.0.101 Commit: bb24aafa11
Runtime Environment: OS Name: Windows OS Version: 10.0.22621 OS Platform: Windows RID: win10-x64 Base Path: C:\Program Files\dotnet\sdk\7.0.101\
Host: Version: 7.0.1 Architecture: x64 Commit: 97203d38ba
.NET SDKs installed: 6.0.404 [C:\Program Files\dotnet\sdk] 7.0.101 [C:\Program Files\dotnet\sdk]
.NET runtimes installed: Microsoft.AspNetCore.App 6.0.12 [C:\Program Files\dotnet\shared\Microsoft.AspNetCore.App] Microsoft.AspNetCore.App 7.0.1 [C:\Program Files\dotnet\shared\Microsoft.AspNetCore.App] Microsoft.NETCore.App 6.0.12 [C:\Program Files\dotnet\shared\Microsoft.NETCore.App] Microsoft.NETCore.App 7.0.1 [C:\Program Files\dotnet\shared\Microsoft.NETCore.App] Microsoft.WindowsDesktop.App 6.0.12 [C:\Program Files\dotnet\shared\Microsoft.WindowsDesktop.App] Microsoft.WindowsDesktop.App 7.0.1 [C:\Program Files\dotnet\shared\Microsoft.WindowsDesktop.App]
Other architectures found: x86 [C:\Program Files (x86)\dotnet] registered at [HKLM\SOFTWARE\dotnet\Setup\InstalledVersions\x86\InstallLocation]
Environment variables: Not set
global.json file: Not found
I was able to achieve what I wanted using Generic Resources
as follows but I'd still like to know why it doesn't work with the Typed Resources
:
// Get/create managed certificate
GenericResource managedCertificateResource;
var appCertificateName = $"{siteHostName}-{website.Data.Name}";
var subscriptionId = "mysubid";
var certificateResourceId = AppCertificateResource.CreateResourceIdentifier(subscriptionId, resourceGroupName, appCertificateName);
var genericResources = client.GetGenericResources();
if (!await genericResources.ExistsAsync(certificateResourceId))
{
var appCertificateData = new
{
CanonicalName = siteHostName,
HostNames = new List<string> { siteHostName },
ServerFarmId = appServicePlan.Id.ToString()
};
var createCertificateData = new GenericResourceData(AzureLocation.WestEurope)
{
Properties = BinaryData.FromObjectAsJson(appCertificateData, new JsonSerializerOptions()),
};
var createAppCertificateOperationResult = await genericResources.CreateOrUpdateAsync(WaitUntil.Completed, certificateResourceId, createCertificateData, CancellationToken.None);
managedCertificateResource = createAppCertificateOperationResult.Value;
}
else
{
managedCertificateResource = await client.GetGenericResource(certificateResourceId).GetAsync();
}
var appCertificateProperties = managedCertificateResource.Data.Properties.ToObject<AppCertificateProperties>(new JsonObjectSerializer());
// Bind the Custom Domain with Certificate (SNI/SLL)
if (siteHostNameBindingResource.Data.Thumbprint == null)
{
var bindingData = siteHostNameBindingResource.Data;
bindingData.HostNameType = AppServiceHostNameType.Verified;
bindingData.SslState = HostNameBindingSslState.SniEnabled;
bindingData.CustomHostNameDnsRecordType = CustomHostNameDnsRecordType.CName;
bindingData.Thumbprint = BinaryData.FromString("\"" + appCertificateProperties.thumbprint + "\"");
var updateSiteHostNameBindingOperationResult = await siteHostNameBindings.CreateOrUpdateAsync(WaitUntil.Completed, siteHostName, bindingData, CancellationToken.None);
siteHostNameBindingResource = updateSiteHostNameBindingOperationResult.Value;
}
Thank you for your feedback. Tagging and routing to the team member best able to assist. Please expect delayed responses due to the US holidays.
Hi @absolutebandit, for your questions here:
- I will try to reproduce the exception about
resourceGroup.GetCertificates()
, it might take some time. - What do you mean by saying it requires a
serverFarmId
? Will the service request fail if you don't set this property? From te perspective of SDK, ServerFarmId is not required. In our sdk, if the property is required, we will put it into the ctor. And AppCertificateData only requires location when we try to construct it. - The exception will be thrown when the service return 202 is because the service didn't define 202 in the API service, so we don't have a good work around for this. I will try to see if we can fix it from API spec side.
Hi Yao,
Yes if you don't set the server farm id the request will fail with a validation error. I just noted that it's strange that it's requried when the property is still showing as null in the resource json once the certificate is created. However this is not the main issue and it's not a problem for me, I can just set the server farm id.
As mentioned my code is currently using the gerneric resource approach as shown above and is shipped like this for now but if you can fix the issue with the typed resources we would prefer to use that approach and patch our code later.
Thanks for looking into this.
Thanks for you feedback, we have created this feature request for this kind of issue. Will discuss to finalize the solution.