-
Notifications
You must be signed in to change notification settings - Fork 6
GWP Minimal API and Razor Pages hosting samples #172
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Open
alafleur-genetec
wants to merge
6
commits into
main
Choose a base branch
from
feat/gwp-web-samples
base: main
Could not load branches
Branch not found: {{ refName }}
Loading
Could not load tags
Nothing to show
Loading
Are you sure you want to change the base?
Some commits from the old base branch may be removed from the timeline,
and old review comments may become outdated.
Open
Changes from all commits
Commits
Show all changes
6 commits
Select commit
Hold shift + click to select a range
a831c49
feat: add GWP Minimal API and Razor Pages hosting samples
alafleur-genetec 6bc2fe3
docs: clarify authentication scope in web sample READMEs
alafleur-genetec ac4c5f6
docs: remove filler 'Why this shape' section from web sample READMEs
alafleur-genetec f174024
Update Samples/Genetec Web Player/GwpRazorPagesSample/README.md
alafleur-genetec 0f4d714
Update Samples/Genetec Web Player/GwpMinimalApiSample/README.md
alafleur-genetec f5edfbe
Update Samples/Genetec Web Player/GwpRazorPagesSample/README.md
alafleur-genetec File filter
Filter by extension
Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
There are no files selected for viewing
14 changes: 14 additions & 0 deletions
14
Samples/Genetec Web Player/GwpMinimalApiSample/GwpMinimalApiSample.csproj
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,14 @@ | ||
| <Project Sdk="Microsoft.NET.Sdk.Web"> | ||
|
|
||
| <PropertyGroup> | ||
| <TargetFramework>net8.0</TargetFramework> | ||
| <Nullable>enable</Nullable> | ||
| <ImplicitUsings>enable</ImplicitUsings> | ||
| <AssemblyName>GwpMinimalApiSample</AssemblyName> | ||
| <RootNamespace>Genetec.Dap.CodeSamples</RootNamespace> | ||
| <Description>Sample project</Description> | ||
| <Company>Genetec Inc.</Company> | ||
| <Copyright>Copyright © Genetec Inc. 2025</Copyright> | ||
| </PropertyGroup> | ||
|
|
||
| </Project> |
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,62 @@ | ||
| // Copyright 2025 Genetec Inc. | ||
| // Licensed under the Apache License, Version 2.0 | ||
|
|
||
| using System.Net.Http.Headers; | ||
| using System.Text; | ||
|
|
||
| var builder = WebApplication.CreateBuilder(args); | ||
|
|
||
| var mediaGateway = builder.Configuration.GetSection("MediaGateway"); | ||
| var endpoint = mediaGateway["Endpoint"]?.TrimEnd('/') ?? throw new InvalidOperationException("MediaGateway:Endpoint is required."); | ||
| var username = mediaGateway["Username"] ?? throw new InvalidOperationException("MediaGateway:Username is required."); | ||
| var password = mediaGateway["Password"] ?? string.Empty; | ||
| var sdkCertificate = mediaGateway["SdkCertificate"] ?? throw new InvalidOperationException("MediaGateway:SdkCertificate is required."); | ||
| var serverVersion = mediaGateway["ServerVersion"]; | ||
|
|
||
| var authorizationParameter = Convert.ToBase64String(Encoding.UTF8.GetBytes($"{username};{sdkCertificate}:{password}")); | ||
|
|
||
| builder.Services.AddHttpClient("MediaGateway", client => | ||
| { | ||
| client.DefaultRequestHeaders.Authorization = new AuthenticationHeaderValue("Basic", authorizationParameter); | ||
| }).ConfigurePrimaryHttpMessageHandler(() => | ||
| { | ||
| var handler = new HttpClientHandler(); | ||
| if (builder.Environment.IsDevelopment()) | ||
| { | ||
| handler.ServerCertificateCustomValidationCallback = HttpClientHandler.DangerousAcceptAnyServerCertificateValidator; | ||
| } | ||
| return handler; | ||
| }); | ||
|
|
||
| var app = builder.Build(); | ||
|
|
||
| app.UseStaticFiles(); | ||
|
|
||
| app.MapGet("/api/config", () => Results.Ok(new | ||
| { | ||
| mediaGatewayEndpoint = endpoint, | ||
| serverVersion = string.IsNullOrWhiteSpace(serverVersion) ? null : serverVersion.Trim(), | ||
| })); | ||
|
|
||
| app.MapGet("/api/token/{cameraId}", async (string cameraId, IHttpClientFactory httpClientFactory) => | ||
| { | ||
| if (string.IsNullOrWhiteSpace(cameraId)) | ||
| { | ||
| return Results.BadRequest("A camera GUID is required."); | ||
| } | ||
|
|
||
| var client = httpClientFactory.CreateClient("MediaGateway"); | ||
| var response = await client.GetAsync($"{endpoint}/v2/token/{Uri.EscapeDataString(cameraId.Trim())}"); | ||
|
|
||
| if (!response.IsSuccessStatusCode) | ||
| { | ||
| return Results.StatusCode((int)response.StatusCode); | ||
| } | ||
|
|
||
| var token = await response.Content.ReadAsStringAsync(); | ||
| return Results.Text(token); | ||
| }); | ||
|
|
||
| app.MapFallbackToFile("index.html"); | ||
|
|
||
| app.Run(); |
12 changes: 12 additions & 0 deletions
12
Samples/Genetec Web Player/GwpMinimalApiSample/Properties/launchSettings.json
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,12 @@ | ||
| { | ||
| "profiles": { | ||
| "GwpMinimalApiSample": { | ||
| "commandName": "Project", | ||
| "launchBrowser": true, | ||
| "environmentVariables": { | ||
| "ASPNETCORE_ENVIRONMENT": "Development" | ||
| }, | ||
| "applicationUrl": "https://localhost:59205;http://localhost:59206" | ||
| } | ||
| } | ||
| } |
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,77 @@ | ||
| # GWP Minimal API Sample | ||
|
|
||
| This sample demonstrates hosting the Genetec Web Player inside an ASP.NET Core Minimal API application: | ||
|
|
||
| - ASP.NET Core serves a static HTML page that loads and runs GWP. | ||
| - A server-side `/api/token/{cameraId}` endpoint proxies token requests to the Media Gateway using credentials from `appsettings.json`. Media Gateway credentials never reach the browser. | ||
| - A `/api/config` endpoint provides the Media Gateway endpoint and server version to the page without exposing authentication details. | ||
| - The page loads `gwp.js` directly from the target Media Gateway and uses the browser environment GWP expects. | ||
|
|
||
| ## Run | ||
|
|
||
| ```powershell | ||
| dotnet run | ||
| ``` | ||
|
|
||
| Then open the URL shown in the console output (for example, `https://localhost:5001`). | ||
|
|
||
| ### Configuration | ||
|
|
||
| Media Gateway settings are configured in `appsettings.json`: | ||
|
|
||
| ```json | ||
| { | ||
| "MediaGateway": { | ||
| "Endpoint": "https://localhost/media", | ||
| "Username": "admin", | ||
| "Password": "", | ||
| "SdkCertificate": "KxsD11z743Hf5Gq9mv3+5ekxzemlCiUXkTFY5ba1NOGcLCmGstt2n0zYE9NsNimv", | ||
| "ServerVersion": "" | ||
| } | ||
| } | ||
| ``` | ||
|
|
||
| You can also use environment variables or user secrets. If you haven't already initialized user secrets for this project, run: | ||
|
|
||
| ```powershell | ||
| dotnet user-secrets init | ||
| dotnet user-secrets set "MediaGateway:Password" "your-password" | ||
| ``` | ||
|
|
||
| ## Required environment setup | ||
|
|
||
| ### 1. Trust the Media Gateway certificate | ||
|
|
||
| If the Media Gateway certificate is self-signed or otherwise untrusted, the browser will fail to load `gwp.js` or connect to the gateway. | ||
|
|
||
| For development, the sample automatically allows certificate warnings when connecting to the Media Gateway from the server-side token endpoint. The browser must still trust the certificate for the `gwp.js` script load and WebSocket connections. Add the certificate to the browser's trust store or use a trusted certificate. | ||
|
|
||
| ### 2. Allow the page origin in Media Gateway CORS | ||
|
|
||
| If strict CORS is enabled, add the ASP.NET application origin to `MediaGateway.gconfig`: | ||
|
|
||
| ```xml | ||
| <?xml version="1.0" encoding="UTF-8"?> | ||
| <Configuration> | ||
| <MediaGateway EnforceStrictCrossOrigin="true"> | ||
| <AllowedOrigin Origin="https://localhost:5001" /> | ||
| </MediaGateway> | ||
| </Configuration> | ||
| ``` | ||
|
|
||
| Restart the Media Gateway role after the change. | ||
|
|
||
| ### 3. Use a matching GWP build | ||
|
|
||
| The sample loads `gwp.js` from `${mediaGatewayEndpoint}/v2/files/gwp.js` so the player version matches the Security Center version. | ||
|
|
||
| ## Scope and limitations | ||
|
|
||
| - This sample demonstrates a feasible hosting pattern. It is not a production-ready security design. | ||
| - This sample has no user authentication. Anyone who can reach the application can view camera streams. A real application must add its own authentication layer to control who can access the application. | ||
| - Media Gateway credentials are stored in `appsettings.json`. For production, use a secure configuration provider such as user secrets, Azure Key Vault, or environment variables. | ||
| - The default SDK certificate is the Genetec development certificate intended for SDK development only. | ||
| - A Content Security Policy meta tag restricts script sources, connections, and media to `self`, `https:`, `wss:`, and `blob:`. The policy allows `'unsafe-inline'` for scripts and styles because the page uses inline markup. The Razor Pages sample demonstrates how to use CSP nonces instead. | ||
| - Player startup is cancellable. Clicking Stop during script load or session establishment cancels the in-flight start and cleans up any partially created player. | ||
| - Browser autoplay rules apply to audio. | ||
| - Video rendering and overlays remain in the HTML layer, not the ASP.NET server. | ||
9 changes: 9 additions & 0 deletions
9
Samples/Genetec Web Player/GwpMinimalApiSample/appsettings.json
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,9 @@ | ||
| { | ||
| "MediaGateway": { | ||
| "Endpoint": "https://localhost/media", | ||
| "Username": "admin", | ||
| "Password": "", | ||
| "SdkCertificate": "KxsD11z743Hf5Gq9mv3+5ekxzemlCiUXkTFY5ba1NOGcLCmGstt2n0zYE9NsNimv", | ||
| "ServerVersion": "" | ||
| } | ||
| } |
Oops, something went wrong.
Add this suggestion to a batch that can be applied as a single commit.
This suggestion is invalid because no changes were made to the code.
Suggestions cannot be applied while the pull request is closed.
Suggestions cannot be applied while viewing a subset of changes.
Only one suggestion per line can be applied in a batch.
Add this suggestion to a batch that can be applied as a single commit.
Applying suggestions on deleted lines is not supported.
You must change the existing code in this line in order to create a valid suggestion.
Outdated suggestions cannot be applied.
This suggestion has been applied or marked resolved.
Suggestions cannot be applied from pending reviews.
Suggestions cannot be applied on multi-line comments.
Suggestions cannot be applied while the pull request is queued to merge.
Suggestion cannot be applied right now. Please check back later.
Uh oh!
There was an error while loading. Please reload this page.