Skip to content

Commit 90fb5a7

Browse files
authored
Fix issue when using Unicode characters in CDP datasets (#2831)
When using Unicode characters, we were seeing HttpRequestException: Request headers must contain only ASCII characters.
1 parent 8956f56 commit 90fb5a7

File tree

5 files changed

+52
-12
lines changed

5 files changed

+52
-12
lines changed

src/libraries/Microsoft.PowerFx.Connectors/Tabular/CdpTableResolver.cs

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -52,7 +52,7 @@ public async Task<ConnectorType> ResolveTableAsync(string tableName, Cancellatio
5252
}
5353
}
5454

55-
string dataset = _doubleEncoding ? CdpServiceBase.DoubleEncode(_tabularTable.DatasetName) : _tabularTable.DatasetName;
55+
string dataset = _doubleEncoding ? CdpServiceBase.DoubleEncode(_tabularTable.DatasetName) : CdpServiceBase.SingleEncode(_tabularTable.DatasetName);
5656
string uri = (_uriPrefix ?? string.Empty) + (UseV2(_uriPrefix) ? "/v2" : string.Empty) + $"/$metadata.json/datasets/{dataset}/tables/{CdpServiceBase.DoubleEncode(tableName)}?api-version=2015-09-01";
5757

5858
string text = await CdpServiceBase.GetObject(_httpClient, $"Get table metadata", uri, null, cancellationToken, Logger).ConfigureAwait(false);

src/libraries/Microsoft.PowerFx.Connectors/Tabular/Services/CdpDataSource.cs

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -43,7 +43,7 @@ public virtual async Task<IEnumerable<CdpTable>> GetTablesAsync(HttpClient httpC
4343

4444
string uri = (_uriPrefix ?? string.Empty)
4545
+ (CdpTableResolver.UseV2(uriPrefix) ? "/v2" : string.Empty)
46-
+ $"/datasets/{(DatasetMetadata.IsDoubleEncoding ? DoubleEncode(DatasetName) : DatasetName)}"
46+
+ $"/datasets/{(DatasetMetadata.IsDoubleEncoding ? DoubleEncode(DatasetName) : SingleEncode(DatasetName))}"
4747
+ (uriPrefix.Contains("/sharepointonline/") ? "/alltables" : "/tables");
4848

4949
GetTables tables = await GetObject<GetTables>(httpClient, "Get tables", uri, null, cancellationToken, logger).ConfigureAwait(false);

src/libraries/Microsoft.PowerFx.Connectors/Tabular/Services/CdpServiceBase.cs

Lines changed: 6 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -69,7 +69,12 @@ protected internal static async Task<string> GetObject(HttpClient httpClient, st
6969

7070
internal static string DoubleEncode(string param)
7171
{
72-
return Uri.EscapeDataString(Uri.EscapeDataString(param));
72+
return SingleEncode(SingleEncode(param));
73+
}
74+
75+
internal static string SingleEncode(string param)
76+
{
77+
return Uri.EscapeDataString(param);
7378
}
7479
}
7580
}

src/libraries/Microsoft.PowerFx.Connectors/Tabular/Services/CdpTable.cs

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -113,7 +113,7 @@ protected override async Task<IReadOnlyCollection<DValue<RecordValue>>> GetItems
113113
Uri uri = new Uri(
114114
(_uriPrefix ?? string.Empty) +
115115
(CdpTableResolver.UseV2(_uriPrefix) ? "/v2" : string.Empty) +
116-
$"/datasets/{(DatasetMetadata.IsDoubleEncoding ? DoubleEncode(DatasetName) : DatasetName)}/tables/{Uri.EscapeDataString(TableName)}/items?api-version=2015-09-01" + queryParams, UriKind.Relative);
116+
$"/datasets/{(DatasetMetadata.IsDoubleEncoding ? DoubleEncode(DatasetName) : SingleEncode(DatasetName))}/tables/{Uri.EscapeDataString(TableName)}/items?api-version=2015-09-01" + queryParams, UriKind.Relative);
117117

118118
string text = await GetObject(_httpClient, $"List items ({nameof(GetItemsInternalAsync)})", uri.ToString(), null, cancellationToken, executionLogger).ConfigureAwait(false);
119119
return !string.IsNullOrWhiteSpace(text) ? GetResult(text) : Array.Empty<DValue<RecordValue>>();

src/tests/Microsoft.PowerFx.Connectors.Tests.Shared/PowerPlatformTabularTests.cs

Lines changed: 43 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -240,7 +240,7 @@ public async Task SQL_CdpTabular_GetTables2()
240240
// For SQL we don't have relationships
241241
bool b = sqlTable.RecordType.TryGetFieldExternalTableName("ProductModelID", out string externalTableName, out string foreignKey);
242242
Assert.False(b);
243-
243+
244244
testConnector.SetResponseFromFiles(@"Responses\SQL GetSchema ProductModel.json");
245245
b = sqlTable.RecordType.TryGetFieldType("ProductModelID", out FormulaType productModelID);
246246

@@ -251,6 +251,41 @@ public async Task SQL_CdpTabular_GetTables2()
251251
Assert.Equal("ProductID", string.Join("|", GetPrimaryKeyNames(sqlTable.RecordType)));
252252
}
253253

254+
[Fact]
255+
public async Task SQL_CdpTabular_GetTables3()
256+
{
257+
using var testConnector = new LoggingTestServer(null /* no swagger */, _output);
258+
var config = new PowerFxConfig(Features.PowerFxV1);
259+
var engine = new RecalcEngine(config);
260+
261+
ConsoleLogger logger = new ConsoleLogger(_output);
262+
using var httpClient = new HttpClient(testConnector);
263+
string connectionId = "29941b77eb0a40fe925cd7a03cb85b40";
264+
string jwt = "eyJ0eX...";
265+
using var client = new PowerPlatformConnectorClient("49970107-0806-e5a7-be5e-7c60e2750f01.12.common.firstrelease.azure-apihub.net", "49970107-0806-e5a7-be5e-7c60e2750f01", connectionId, () => jwt, httpClient) { SessionId = "8e67ebdc-d402-455a-b33a-304820832383" };
266+
267+
testConnector.SetResponseFromFile(@"Responses\SQL GetDatasetsMetadata.json");
268+
DatasetMetadata dm = await CdpDataSource.GetDatasetsMetadataAsync(client, $"/apim/sql/{connectionId}", CancellationToken.None, logger);
269+
270+
Assert.NotNull(dm);
271+
Assert.Null(dm.Blob);
272+
273+
// Use of Unicode characters in DataSource
274+
CdpDataSource cds = new CdpDataSource("pfxdev-sql.database.windows.net,Aßþ");
275+
276+
testConnector.SetResponseFromFiles(@"Responses\SQL GetDatasetsMetadata.json", @"Responses\SQL GetTables SampleDB.json");
277+
IEnumerable<CdpTable> tables = await cds.GetTablesAsync(client, $"/apim/sql/{connectionId}", CancellationToken.None, logger);
278+
279+
Assert.NotNull(tables);
280+
281+
CdpTable connectorTable = tables.First(t => t.DisplayName == "Customer");
282+
Assert.False(connectorTable.IsInitialized);
283+
284+
testConnector.SetResponseFromFile(@"Responses\SQL Server Load Customers DB.json");
285+
await connectorTable.InitAsync(client, $"/apim/sql/{connectionId}", CancellationToken.None, logger);
286+
Assert.True(connectorTable.IsInitialized);
287+
}
288+
254289
[Fact]
255290
public async Task SQL_CdpTabular_JoinCapabilityTest()
256291
{
@@ -264,23 +299,23 @@ public async Task SQL_CdpTabular_JoinCapabilityTest()
264299
string jwt = "eyJ0eXAiOiJKSuA...";
265300
using var client = new PowerPlatformConnectorClient("dac64a92-df6a-ee6e-a6a2-be41a923e371.15.common.tip1002.azure-apihub.net", "dac64a92-df6a-ee6e-a6a2-be41a923e371", connectionId, () => jwt, httpClient) { SessionId = "8e67ebdc-d402-455a-b33a-304820832383" };
266301

267-
string realTableName = "Product";
268-
302+
string realTableName = "Product";
303+
269304
CdpDataSource cds = new CdpDataSource("default,default");
270305

271306
testConnector.SetResponseFromFiles(@"Responses\SQL GetDatasetsMetadata.json", @"Responses\SQL GetTables SampleDB.json");
272307
IEnumerable<CdpTable> tables = await cds.GetTablesAsync(client, $"/apim/sql/{connectionId}", CancellationToken.None, logger);
273-
308+
274309
CdpTable table = tables.First(t => t.DisplayName == realTableName);
275-
310+
276311
testConnector.SetResponseFromFiles(@"Responses\SQL GetSchema Products v2.json");
277312
await table.InitAsync(client, $"/apim/sql/{connectionId}", CancellationToken.None, logger);
278313
Assert.True(table.IsInitialized);
279314

280315
CdpTableValue sqlTable = table.GetTableValue();
281316
Assert.True(sqlTable._tabularService.IsInitialized);
282317
Assert.True(sqlTable.IsDelegable);
283-
318+
284319
HashSet<IExternalTabularDataSource> ads = sqlTable.Type._type.AssociatedDataSources;
285320
Assert.NotNull(ads);
286321
Assert.Single(ads);
@@ -645,7 +680,7 @@ private static IEnumerable<string> GetPrimaryKeyNames(RecordType rt)
645680

646681
[Fact]
647682
public async Task SF_CdpTabular_GetTables()
648-
{
683+
{
649684
using var testConnector = new LoggingTestServer(null /* no swagger */, _output);
650685
var config = new PowerFxConfig(Features.PowerFxV1);
651686
var engine = new RecalcEngine(config);
@@ -942,7 +977,7 @@ public async Task ZD_CdpTabular_GetTables()
942977
Assert.True(zdTable._tabularService.IsInitialized);
943978
Assert.True(zdTable.IsDelegable);
944979

945-
Assert.Equal(
980+
Assert.Equal(
946981
"r![active:b, alias:s, created_at:d, custom_role_id:w, details:s, email:s, external_id:s, id:w, last_login_at:d, locale:s, locale_id:w, moderator:b, name:s, notes:s, only_private_comments:b, organization_id:w, " +
947982
"phone:s, photo:s, restricted_agent:b, role:s, shared:b, shared_agent:b, signature:s, suspended:b, tags:s, ticket_restriction:s, time_zone:s, updated_at:d, url:s, user_fields:s, verified:b]", ((CdpRecordType)zdTable.RecordType).ToStringWithDisplayNames());
948983

0 commit comments

Comments
 (0)