-
Notifications
You must be signed in to change notification settings - Fork 3
Expand file tree
/
Copy pathProgram.cs
More file actions
127 lines (105 loc) · 4.4 KB
/
Program.cs
File metadata and controls
127 lines (105 loc) · 4.4 KB
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
using Azure.Core;
using Azure.Identity;
using Generator;
using Generator.Services;
using Microsoft.Extensions.Caching.Memory;
using Microsoft.Extensions.Configuration;
using Microsoft.Extensions.DependencyInjection;
using Microsoft.Extensions.Logging;
using Microsoft.PowerPlatform.Dataverse.Client;
var configuration =
new ConfigurationBuilder()
.AddEnvironmentVariables()
.AddJsonFile("appsettings.local.json", optional: true)
.Build();
var verbose = configuration.GetValue("Verbosity", LogLevel.Warning);
// Set up dependency injection
var services = new ServiceCollection();
// Add logging
services.AddLogging(builder =>
{
builder
.SetMinimumLevel(verbose)
.AddConsole();
});
// Add configuration as a singleton
services.AddSingleton<IConfiguration>(configuration);
// Add ServiceClient as a singleton
services.AddSingleton(sp =>
{
var config = sp.GetRequiredService<IConfiguration>();
var loggerFactory = sp.GetRequiredService<ILoggerFactory>();
var logger = loggerFactory.CreateLogger("ServiceClient");
var cache = new MemoryCache(new MemoryCacheOptions());
var dataverseUrl = config["DataverseUrl"];
if (dataverseUrl == null)
{
throw new Exception("DataverseUrl is required");
}
return new ServiceClient(
instanceUrl: new Uri(dataverseUrl),
tokenProviderFunction: async url => await GetTokenAsync(url, cache, logger, config));
});
// Register services
services.AddSingleton<EntityMetadataService>();
services.AddSingleton<SolutionService>();
services.AddSingleton<SecurityRoleService>();
services.AddSingleton<EntityIconService>();
services.AddSingleton<AttributeMappingService>();
services.AddSingleton<RelationshipService>();
services.AddSingleton<RecordMappingService>();
services.AddSingleton<DataverseService>();
services.AddSingleton<WorkflowService>();
services.AddSingleton<SolutionComponentService>();
services.AddSingleton<SolutionComponentExtractor>();
// Build service provider
var serviceProvider = services.BuildServiceProvider();
// Resolve and use DataverseService
var dataverseService = serviceProvider.GetRequiredService<DataverseService>();
var (entities, warnings, solutionComponents, globalOptionSetUsages) = await dataverseService.GetFilteredMetadata();
var websiteBuilder = new WebsiteBuilder(configuration, entities, warnings, globalOptionSetUsages, solutionComponents);
websiteBuilder.AddData();
// Token provider function
static async Task<string> GetTokenAsync(string dataverseUrl, IMemoryCache cache, ILogger logger, IConfiguration configuration)
{
var cacheKey = $"AccessToken_{dataverseUrl}";
logger.LogTrace($"Attempting to retrieve access token for {dataverseUrl}");
return (await cache.GetOrCreateAsync(cacheKey, async cacheEntry =>
{
cacheEntry.AbsoluteExpirationRelativeToNow = TimeSpan.FromMinutes(50);
var credential = GetTokenCredential(logger, configuration);
var scope = BuildScopeString(dataverseUrl);
return await FetchAccessToken(credential, scope, logger);
}))!.Token;
}
static TokenCredential GetTokenCredential(ILogger logger, IConfiguration configuration)
{
if (configuration["DataverseClientId"] != null && configuration["DataverseClientSecret"] != null)
return new ClientSecretCredential(configuration["TenantId"], configuration["DataverseClientId"], configuration["DataverseClientSecret"]);
return new DefaultAzureCredential(); // in azure this will be managed identity, locally this depends... se midway of this post for the how local identity is chosen: https://dreamingincrm.com/2021/11/16/connecting-to-dataverse-from-function-app-using-managed-identity/
}
static string BuildScopeString(string dataverseUrl)
{
return $"{GetCoreUrl(dataverseUrl)}/.default";
}
static string GetCoreUrl(string url)
{
var uri = new Uri(url);
return $"{uri.Scheme}://{uri.Host}";
}
static async Task<AccessToken> FetchAccessToken(TokenCredential credential, string scope, ILogger logger)
{
var tokenRequestContext = new TokenRequestContext(new[] { scope });
try
{
logger.LogTrace("Requesting access token...");
var accessToken = await credential.GetTokenAsync(tokenRequestContext, CancellationToken.None);
logger.LogTrace("Access token successfully retrieved.");
return accessToken;
}
catch (Exception ex)
{
logger.LogError($"Failed to retrieve access token: {ex.Message}");
throw;
}
}