Files
microsoft-365-service/examples/csharp/ListUsersTop10/Program.cs
T
JiriUhlirandClaude Fable 5.1 d80193da8b Hlavicky X-MS365-* jako obycejne hodnoty, GET /users/{user_id}/calendar
- credentials: sifrovani AES-GCM/HKDF odstraneno, tri hlavicky se berou
  tak, jak jsou; bez hlavicek se pouziji hodnoty z prostredi
- zrusena promenna MS365_CREDENTIAL_ENCODING_SECRET a zavislost cryptography
- novy endpoint GET /users/{user_id}/calendar (objekt kalendare schranky,
  id a name) pro read-only overeni pristupu pres e-mail schranky
- C# ukazka posila hodnoty primo, CredentialEncoder smazan
- README: sekce o hlavickach vcetne PowerShell ukazky, zaznam zmen
- .gitignore: bin/ a obj/, zaverzovane obj/ soubory ukazky odstraneny z gitu

Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com>
2026-09-22 12:49:25 +02:00

75 lines
2.8 KiB
C#

// Ukazka volani microsoft-365-service: vypis prvnich 10 uzivatelu z GET /users.
//
// Sluzba: https://services.csbot.cz/apps/microsoft-365-service
// Dokumentace (Swagger): https://services.csbot.cz/apps/microsoft-365-service/docs
//
// Credentials se posilaji v hlavickach X-MS365-* jako obycejne hodnoty.
//
// Spusteni:
// set MS365_SERVICE_BASE_URL=https://services.csbot.cz/apps/microsoft-365-service
// set MS365_TENANT_ID=<tenant id klienta>
// set MS365_CLIENT_ID=<client id aplikace CSBOT>
// set MS365_CLIENT_SECRET=<client secret VALUE, ne secret id>
// dotnet run
using System.Net.Http.Headers;
using System.Text.Json;
var baseUrl = Env("MS365_SERVICE_BASE_URL", "https://services.csbot.cz/apps/microsoft-365-service");
var tenantId = Env("MS365_TENANT_ID");
var clientId = Env("MS365_CLIENT_ID");
var clientSecret = Env("MS365_CLIENT_SECRET");
const int top = 10;
using var http = new HttpClient { BaseAddress = new Uri(baseUrl.TrimEnd('/') + "/") };
http.DefaultRequestHeaders.Accept.Add(new MediaTypeWithQualityHeaderValue("application/json"));
using var request = new HttpRequestMessage(HttpMethod.Get, $"users?top={top}");
request.Headers.Add("X-MS365-Tenant-Id", tenantId);
request.Headers.Add("X-MS365-Client-Id", clientId);
request.Headers.Add("X-MS365-Client-Secret", clientSecret);
using var response = await http.SendAsync(request);
var body = await response.Content.ReadAsStringAsync();
if (!response.IsSuccessStatusCode)
{
// 400 = neuplne hlavicky, 502 = chyba z Microsoft Graph (detail je v tele),
// 403 text/plain = request neprosel pres reverzni proxy (IP allowlist pro GET).
Console.Error.WriteLine($"HTTP {(int)response.StatusCode} {response.ReasonPhrase}");
Console.Error.WriteLine(body);
return 1;
}
// Sluzba vraci odpoved Microsoft Graph beze zmeny: { "value": [ { ...user... } ], "@odata.nextLink": "..." }
using var json = JsonDocument.Parse(body);
var users = json.RootElement.GetProperty("value");
Console.WriteLine($"Nacteno uzivatelu: {users.GetArrayLength()}");
foreach (var user in users.EnumerateArray())
{
var displayName = user.TryGetProperty("displayName", out var dn) ? dn.GetString() : null;
var upn = user.TryGetProperty("userPrincipalName", out var up) ? up.GetString() : null;
var mail = user.TryGetProperty("mail", out var m) && m.ValueKind == JsonValueKind.String ? m.GetString() : null;
var id = user.GetProperty("id").GetString();
Console.WriteLine($"{displayName} | {upn} | {mail ?? "-"} | {id}");
}
return 0;
static string Env(string name, string? fallback = null)
{
var value = Environment.GetEnvironmentVariable(name);
if (!string.IsNullOrWhiteSpace(value))
{
return value;
}
if (fallback is not null)
{
return fallback;
}
throw new InvalidOperationException($"Chybi environment promenna {name}.");
}