First push
ASP.NET AJAX / build_web_app (push) Waiting to run
Angular / build_angular (push) Waiting to run
ASP.NET Core (with Reporting) / build_windows (push) Waiting to run
Blazor (with Reporting) / build_windows (push) Waiting to run
Blazor (with Reporting) / build_linux (push) Waiting to run
Console (.NET) / build_console (arm64, linux) (push) Waiting to run
Console (.NET) / build_console (arm64, win) (push) Waiting to run
Console (.NET) / build_console (x64, linux) (push) Waiting to run
Console (.NET) / build_console (x64, win) (push) Waiting to run
MAUI / Windows Smoketest (push) Waiting to run
MAUI / Android Smoketest (push) Waiting to run
MAUI / iOS Smoketest (push) Waiting to run
MAUI / MacCatalyst Smoketest (push) Waiting to run
WinForms (.NET Framework) / build_desktop (Release, x64) (push) Waiting to run
WinForms (.NET Framework) / build_desktop (Release, x86) (push) Waiting to run
WinUI3 / build-windows (push) Waiting to run
WPF (.NET Framework) / build_desktop (Release, x64) (push) Waiting to run
WPF (.NET Framework) / build_desktop (Release, x86) (push) Waiting to run
ASP.NET Core (with Reporting) - Docker / Microsoft Base - Publish to Docker Hub (push) Waiting to run
ASP.NET Core (with Reporting) - Docker / CentOS Base - Publish to Docker Hub (push) Waiting to run
Blazor (with Reporting) - Docker / Dockerfile Build and Publish (push) Waiting to run
@@ -0,0 +1,19 @@
|
||||
# Project Overview
|
||||
|
||||
This project contains many different applications, whose purpose is to demonstrate how to build Telerik and Kendo applications on CI/CD platforms like GitHub Actions, Azure DevOps, and others. The repo has a variety of project types, from WPF to .NET MAUI that has an accompanying build example in the respective CI YAML file.
|
||||
|
||||
## Folder Structure
|
||||
|
||||
- `/src`: Contains the project folders, each project folder contains one example of a Telerik product being used in that platform. The folder names are describing which framework/platform that the demo is for. For example, the 'WPF' folder contains a WPF project that uses Telerik UI for WPF... and the 'Blazor' folder contains a project for ASP.NET Blazor that is using Telerik UI for Blazor. That same pattern is followed for all the subfolders of the 'src' folder
|
||||
|
||||
## Libraries and Frameworks
|
||||
|
||||
- .NET and C# for the WPF, WinForms, ASP.NET, Blazor, MAUI, WinUI and AJAX demos
|
||||
- Angular and Node.js for the Angular project
|
||||
- GitHub Actions flavor YAML for the workflows in '/.github/workflows'
|
||||
- Azure DevOps flavored YAML for the 'azure-pipelines.yaml' file
|
||||
|
||||
## CI Examples
|
||||
|
||||
- `/.github/workflows`: Contains all the GitHub Actions examples
|
||||
- `azure-pipelines.yaml`: Contains all the Azure DevOps examples
|
||||
@@ -0,0 +1,16 @@
|
||||
# Combines all dependency updates into a single PR
|
||||
# https://docs.github.com/en/code-security/dependabot/dependabot-version-updates/configuration-options-for-the-dependabot.yml-file
|
||||
version: 2
|
||||
updates:
|
||||
- package-ecosystem: "npm"
|
||||
directory: "/src/Kendo/angular_demo"
|
||||
schedule:
|
||||
interval: "monthly"
|
||||
ignore:
|
||||
- dependency-name: "*"
|
||||
update-types: ["version-update:semver-patch"]
|
||||
groups:
|
||||
dependencies:
|
||||
applies-to: version-updates
|
||||
patterns:
|
||||
- "*"
|
||||
@@ -0,0 +1,112 @@
|
||||
---
|
||||
name: configure-telerik-nuget
|
||||
version: 1.1.0
|
||||
description: Helps setup, configure and manage Telerik NuGet feeds in your repo's nuget.config file.
|
||||
required_binaries:
|
||||
- pwsh
|
||||
- dotnet
|
||||
author: Lance McCarthy
|
||||
homepage: https://github.com/DevOpsExamples/.github
|
||||
source: https://github.com/DevOpsExamples/.github/tree/main/skills/configure-telerik-nuget
|
||||
---
|
||||
|
||||
Use these helper functions to manage Telerik NuGet source configuration.
|
||||
|
||||
Get a new api key at https://www.telerik.com/account/downloads/api-keys
|
||||
|
||||
## Function: configure
|
||||
|
||||
Sets a global user environment variable for the Telerik API key and updates/creates `nuget.config` so credentials use the environment variable instead of a hardcoded secret.
|
||||
|
||||
```powershell
|
||||
function Configure-TelerikNuGetSource {
|
||||
param(
|
||||
[Parameter(Mandatory = $true)]
|
||||
[string]$ApiKey,
|
||||
|
||||
[string]$ApiKeyEnvVarName = "TELERIK_NUGET_API_KEY",
|
||||
[string]$SourceName = "Telerik_NuGet_Server",
|
||||
[string]$SourceUrl = "https://nuget.telerik.com/v3/index.json",
|
||||
[string]$NuGetConfigPath = "./nuget.config"
|
||||
)
|
||||
|
||||
# Store API key as a user-level environment variable so it is available globally
|
||||
[Environment]::SetEnvironmentVariable($ApiKeyEnvVarName, $ApiKey, "User")
|
||||
$env:$ApiKeyEnvVarName = $ApiKey
|
||||
|
||||
if (-not (Test-Path $NuGetConfigPath)) {
|
||||
@"
|
||||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<configuration>
|
||||
<packageSources />
|
||||
<packageSourceCredentials />
|
||||
</configuration>
|
||||
"@ | Set-Content -Path $NuGetConfigPath -Encoding UTF8
|
||||
}
|
||||
|
||||
[xml]$nugetConfig = Get-Content -Path $NuGetConfigPath
|
||||
|
||||
if (-not $nugetConfig.configuration.packageSources) {
|
||||
$packageSourcesNode = $nugetConfig.CreateElement("packageSources")
|
||||
$nugetConfig.configuration.AppendChild($packageSourcesNode) | Out-Null
|
||||
}
|
||||
|
||||
if (-not $nugetConfig.configuration.packageSourceCredentials) {
|
||||
$credentialsNode = $nugetConfig.CreateElement("packageSourceCredentials")
|
||||
$nugetConfig.configuration.AppendChild($credentialsNode) | Out-Null
|
||||
}
|
||||
|
||||
$existingSource = $nugetConfig.configuration.packageSources.add | Where-Object {
|
||||
$_.key -eq $SourceName
|
||||
}
|
||||
|
||||
if ($existingSource) {
|
||||
$existingSource.value = $SourceUrl
|
||||
} else {
|
||||
$sourceNode = $nugetConfig.CreateElement("add")
|
||||
$sourceNode.SetAttribute("key", $SourceName)
|
||||
$sourceNode.SetAttribute("value", $SourceUrl)
|
||||
$nugetConfig.configuration.packageSources.AppendChild($sourceNode) | Out-Null
|
||||
}
|
||||
|
||||
$existingCredentialNode = $nugetConfig.configuration.packageSourceCredentials.$SourceName
|
||||
|
||||
if (-not $existingCredentialNode) {
|
||||
$existingCredentialNode = $nugetConfig.CreateElement($SourceName)
|
||||
$nugetConfig.configuration.packageSourceCredentials.AppendChild($existingCredentialNode) | Out-Null
|
||||
}
|
||||
|
||||
$existingCredentialNode.RemoveAll()
|
||||
|
||||
$usernameNode = $nugetConfig.CreateElement("add")
|
||||
$usernameNode.SetAttribute("key", "Username")
|
||||
$usernameNode.SetAttribute("value", "api-key")
|
||||
$existingCredentialNode.AppendChild($usernameNode) | Out-Null
|
||||
|
||||
$passwordNode = $nugetConfig.CreateElement("add")
|
||||
$passwordNode.SetAttribute("key", "ClearTextPassword")
|
||||
$passwordNode.SetAttribute("value", "%$ApiKeyEnvVarName%")
|
||||
$existingCredentialNode.AppendChild($passwordNode) | Out-Null
|
||||
|
||||
$nugetConfig.Save((Resolve-Path $NuGetConfigPath))
|
||||
|
||||
Write-Host "Configured Telerik feed '$SourceName' in '$NuGetConfigPath'."
|
||||
Write-Host "Saved API key in user environment variable '$ApiKeyEnvVarName'."
|
||||
Write-Host "Restart your terminal/IDE so new processes can read the updated environment variable."
|
||||
}
|
||||
```
|
||||
|
||||
Example usage:
|
||||
|
||||
```powershell
|
||||
Configure-TelerikNuGetSource -ApiKey "<telerik-api-key>"
|
||||
```
|
||||
|
||||
## Changelog
|
||||
|
||||
### 1.1.0 - 2026-03-20
|
||||
|
||||
- Added skill package metadata: `required_binaries`, `author`, `homepage`, and `source`.
|
||||
- Updated configure function to save API key as a user-level environment variable.
|
||||
- Updated `nuget.config` credential handling to use environment variable expansion instead of hardcoded API key values.
|
||||
- Added `version` field to frontmatter.
|
||||
@@ -0,0 +1,17 @@
|
||||
---
|
||||
name: github-actions-failure-debugging
|
||||
description: Guide for debugging failing GitHub Actions workflows. Use this when asked to debug failing GitHub Actions workflows.
|
||||
version: 1.0.0
|
||||
author: Lance McCarthy
|
||||
homepage: https://github.com/DevOpsExamples/.github
|
||||
source: https://github.com/DevOpsExamples/.github/tree/main/skills/github-actions-failure-debugging
|
||||
---
|
||||
|
||||
To debug failing GitHub Actions workflows in a pull request, follow this process, using tools provided from the GitHub MCP Server:
|
||||
|
||||
1. Use the `list_workflow_runs` tool to look up recent workflow runs for the pull request and their status
|
||||
2. Use the `summarize_job_log_failures` tool to get an AI summary of the logs for failed jobs, to understand what went wrong without filling your context windows with thousands of lines of logs
|
||||
3. If you still need more information, use the `get_job_logs` or `get_workflow_run_logs` tool to get the full, detailed failure logs
|
||||
4. Try to reproduce the failure yourself in your own environment.
|
||||
5. Fix the failing build. If you were able to reproduce the failure yourself, make sure it is fixed before committing your changes.ng to use environment variable expansion instead of hardcoded API key values.
|
||||
- Added `version` field to frontmatter.
|
||||
@@ -0,0 +1,45 @@
|
||||
# This example shows you how you can use the named environment variables in the nuget.config file to set the credentials, for more information see https://github.com/LanceMcCarthy/DevOpsExamples#github-actions-using-secrets-to-set-environment-variables
|
||||
name: ASP.NET AJAX
|
||||
|
||||
on:
|
||||
workflow_dispatch:
|
||||
push:
|
||||
branches:
|
||||
- main
|
||||
- "ajax/*"
|
||||
paths:
|
||||
- 'src/Ajax/**/*'
|
||||
- '.github/workflows/main_build-ajax.yml'
|
||||
|
||||
env:
|
||||
CSPROJ_PATH: "src/Ajax/MySite.sln"
|
||||
NUGETCONFIG_PATH: "src/NuGet.Config"
|
||||
|
||||
jobs:
|
||||
build_web_app:
|
||||
runs-on: windows-latest
|
||||
steps:
|
||||
- name: Checkout
|
||||
uses: actions/checkout@v4
|
||||
with:
|
||||
fetch-depth: 0
|
||||
|
||||
- name: Setup Nuget.exe
|
||||
uses: nuget/setup-nuget@v2
|
||||
with:
|
||||
nuget-version: '5.x'
|
||||
|
||||
- name: Setup MSBuild.exe
|
||||
uses: microsoft/setup-msbuild@v2
|
||||
|
||||
# Important: We are using nuget CLI (not dotnet CLI) See https://docs.microsoft.com/en-us/nuget/reference/nuget-exe-cli-reference
|
||||
- name: NuGet.exe Restore
|
||||
run: nuget restore ${{env.CSPROJ_PATH}} -ConfigFile ${{env.NUGETCONFIG_PATH}}
|
||||
env:
|
||||
TELERIK_USERNAME: "api-key" # Variable name used in the nuget.config file
|
||||
TELERIK_PASSWORD: ${{secrets.TELERIK_NUGET_KEY}} # Variable name used in the nuget.config file
|
||||
|
||||
- name: Build the AJAX application
|
||||
run: msbuild ${{env.CSPROJ_PATH}} /t:Restore /p:Configuration=Release /p:RuntimeIdentifier=any
|
||||
env:
|
||||
TELERIK_LICENSE: ${{secrets.TELERIK_LICENSE_KEY}}
|
||||
@@ -0,0 +1,37 @@
|
||||
name: Angular
|
||||
|
||||
on:
|
||||
workflow_dispatch:
|
||||
push:
|
||||
branches:
|
||||
- main
|
||||
- "angular/*"
|
||||
paths:
|
||||
- 'src/Kendo/angular_demo/**/*'
|
||||
- '.github/workflows/main_build-angular.yml'
|
||||
|
||||
jobs:
|
||||
build_angular:
|
||||
runs-on: ubuntu-latest
|
||||
|
||||
steps:
|
||||
- name: Checkout
|
||||
uses: actions/checkout@v4
|
||||
|
||||
- name: Build App
|
||||
working-directory: src/Kendo/angular_demo
|
||||
run: |
|
||||
# 1. Clean the angular cache, to avoid using any expired keys
|
||||
rm -rf .angular/cache
|
||||
|
||||
# 2. Install your project dependencies
|
||||
npm install
|
||||
# npm install --save @progress/kendo-licensing; # if missing from package.json
|
||||
|
||||
#3. Activate
|
||||
npx kendo-ui-license activate
|
||||
|
||||
#4. Build the project
|
||||
npm run build --prod
|
||||
env:
|
||||
TELERIK_LICENSE: ${{secrets.TELERIK_LICENSE_KEY}}
|
||||
@@ -0,0 +1,56 @@
|
||||
name: ASP.NET Core (with Reporting)
|
||||
|
||||
on:
|
||||
workflow_dispatch:
|
||||
push:
|
||||
branches:
|
||||
- main
|
||||
- "aspnetcore/*"
|
||||
paths:
|
||||
- 'src/AspNetCore/**/*'
|
||||
- '.github/workflows/main_build-aspnetcore.yml'
|
||||
|
||||
permissions:
|
||||
id-token: write # JWT for Akeyless and Azure auth
|
||||
|
||||
env:
|
||||
DOTNET_VERSION: "10.0.x"
|
||||
PROJECT_PATH: src/AspNetCore/MyAspNetCoreApp/MyAspNetCoreApp.csproj
|
||||
NUGETCONFIG_PATH: src/NuGet.Config
|
||||
|
||||
jobs:
|
||||
build_windows:
|
||||
runs-on: windows-latest
|
||||
steps:
|
||||
- name: Checkout
|
||||
uses: actions/checkout@v6
|
||||
|
||||
# Using AKeyless for secrets in this demo, but you can use github Secrets instead
|
||||
- name: Fetch secrets from AKeyless
|
||||
id: akeyless
|
||||
uses: LanceMcCarthy/akeyless-action@v5
|
||||
with:
|
||||
access-id: 'p-4blpeo5zdfeaom'
|
||||
static-secrets: |
|
||||
{
|
||||
"/progress/TELERIK_NUGET_KEY":"TELERIK_NUGET_KEY",
|
||||
"/progress/TELERIK_LICENSE":"TELERIK_LICENSE_KEY"
|
||||
}
|
||||
export-secrets-to-outputs: true
|
||||
export-secrets-to-environment: false
|
||||
|
||||
- name: Setup .NET Core SDK
|
||||
uses: actions/setup-dotnet@v5
|
||||
with:
|
||||
dotnet-version: ${{env.DOTNET_VERSION}}
|
||||
|
||||
- name: Restore NuGet Packages
|
||||
run: dotnet restore ${{env.PROJECT_PATH}} --configfile ${{env.NUGETCONFIG_PATH}}
|
||||
env:
|
||||
TELERIK_USERNAME: "api-key"
|
||||
TELERIK_PASSWORD: ${{steps.akeyless.outputs.TELERIK_NUGET_KEY}}
|
||||
|
||||
- name: Build ASP.NET Core Project
|
||||
run: dotnet build ${{env.PROJECT_PATH}} -c Debug --no-restore
|
||||
env:
|
||||
TELERIK_LICENSE: ${{steps.akeyless.outputs.TELERIK_LICENSE_KEY}}
|
||||
@@ -0,0 +1,65 @@
|
||||
name: ASP.NET Core (with Reporting) - Azure
|
||||
|
||||
on:
|
||||
workflow_dispatch:
|
||||
|
||||
env:
|
||||
DOTNET_VERSION: "10.0.x"
|
||||
PROJECT_PATH: src/AspNetCore/MyAspNetCoreApp/MyAspNetCoreApp.csproj
|
||||
NUGETCONFIG_PATH: src/NuGet.Config
|
||||
AZURE_WEBAPP_NAME: DevOpsExamplesCore
|
||||
ARTIFACTS_DIRECTORY: "src/AspNetCore/MyAspNetCoreApp/artifacts"
|
||||
TELERIK_USERNAME: "api-key"
|
||||
TELERIK_PASSWORD: ${{secrets.TELERIK_NUGET_KEY}}
|
||||
TELERIK_LICENSE: ${{secrets.TELERIK_LICENSE_KEY}}
|
||||
|
||||
jobs:
|
||||
build_windows:
|
||||
runs-on: windows-latest
|
||||
steps:
|
||||
- name: Checkout
|
||||
uses: actions/checkout@v6
|
||||
|
||||
# ----------------------------------------------------------------------- #
|
||||
# BUILD
|
||||
# ----------------------------------------------------------------------- #
|
||||
|
||||
- name: Setup .NET Core SDK
|
||||
uses: actions/setup-dotnet@v5
|
||||
with:
|
||||
dotnet-version: ${{env.DOTNET_VERSION}}
|
||||
|
||||
- name: Restore NuGet Packages
|
||||
run: dotnet restore ${{env.PROJECT_PATH}} --configfile ${{env.NUGETCONFIG_PATH}}
|
||||
|
||||
- name: Build ASP.NET Core Project
|
||||
run: dotnet publish ${{env.PROJECT_PATH}} -o ${{env.ARTIFACTS_DIRECTORY}} --no-restore
|
||||
|
||||
|
||||
# ----------------------------------------------------------------------- #
|
||||
# DEPLOY to https://devopsexamplescore.azurewebsites.net/
|
||||
# ----------------------------------------------------------------------- #
|
||||
|
||||
# Option 1
|
||||
# Deploy using the publish profile saved as a Github Actions secret
|
||||
- name: Deploy to Azure WebApp
|
||||
uses: azure/webapps-deploy@v3
|
||||
with:
|
||||
app-name: ${{env.AZURE_WEBAPP_NAME}}
|
||||
publish-profile: ${{secrets.DEVOPSEXAMPLESCORE_PUBLISHSETTINGS}}
|
||||
package: ${{env.ARTIFACTS_DIRECTORY}}
|
||||
|
||||
# Option 2
|
||||
# Use a service principal to log into Azure, no reliance on GitHub secrets
|
||||
# - name: Azure Login
|
||||
# uses: azure/login@v2
|
||||
# with:
|
||||
# client-id: ${{secrets.AZUREAPPSERVICE_CLIENTID}}
|
||||
# tenant-id: ${{secrets.AZUREAPPSERVICE_TENANTID}}
|
||||
# subscription-id: ${{secrets.AZUREAPPSERVICE_SUBSCRIPTIONID}}
|
||||
|
||||
# - name: Deploy to Azure WebApp
|
||||
# uses: azure/webapps-deploy@v3
|
||||
# with:
|
||||
# app-name: ${{env.AZURE_WEBAPP_NAME}}
|
||||
# package: ${{env.ARTIFACTS_DIRECTORY}}
|
||||
@@ -0,0 +1,108 @@
|
||||
# This workflow has three examples (one for IIS, two using containers)
|
||||
# [Option A] Typical IIS build & publish
|
||||
# [Option B] DOCKER FILE BUILD - publishes the image to ghcr.io (GitHub container registry)
|
||||
# [Option C] .NET SDK CONTAINER BUILD - publishes the image to Docker Hub
|
||||
name: Blazor (with Reporting)
|
||||
|
||||
on:
|
||||
workflow_dispatch:
|
||||
push:
|
||||
branches:
|
||||
- main
|
||||
- "blazor/*"
|
||||
paths:
|
||||
- 'src/Blazor/**/*'
|
||||
- '.github/workflows/main_build-blazor.yml'
|
||||
|
||||
permissions:
|
||||
contents: read
|
||||
packages: write # to publish to GitHub container registry
|
||||
id-token: write # # JWT for Akeyless auth
|
||||
|
||||
env:
|
||||
CONFIGURATION: Release
|
||||
BLAZOR_PROJ_PATH: src/Blazor/MyBlazorApp/MyBlazorApp.csproj
|
||||
TEST_PROJ_PATH: src/Blazor/MyBlazorApp.Tests/MyBlazorApp.Tests.csproj
|
||||
NUGET_CONFIG_PATH: src/NuGet.Config
|
||||
DOTNET_VERSION: "10.0.x"
|
||||
|
||||
jobs:
|
||||
build_windows:
|
||||
runs-on: windows-latest
|
||||
steps:
|
||||
- name: Checkout
|
||||
uses: actions/checkout@v4
|
||||
with:
|
||||
fetch-depth: 0
|
||||
|
||||
# Using AKeyless for secrets in this demo
|
||||
- name: Fetch secrets from AKeyless
|
||||
id: akeyless
|
||||
uses: LanceMcCarthy/akeyless-action@v5
|
||||
with:
|
||||
access-id: 'p-4blpeo5zdfeaom'
|
||||
static-secrets: |
|
||||
{
|
||||
"/progress/TELERIK_NUGET_KEY":"TELERIK_NUGET_KEY",
|
||||
"/progress/TELERIK_LICENSE":"TELERIK_LICENSE_KEY"
|
||||
}
|
||||
export-secrets-to-outputs: true
|
||||
export-secrets-to-environment: false
|
||||
|
||||
- name: Setup .NET Core SDK
|
||||
uses: actions/setup-dotnet@v4
|
||||
with:
|
||||
dotnet-version: ${{env.DOTNET_VERSION}}
|
||||
|
||||
- name: Restore NuGet Packages
|
||||
run: |
|
||||
dotnet restore ${{env.BLAZOR_PROJ_PATH}} --configfile ${{env.NUGET_CONFIG_PATH}}
|
||||
dotnet restore ${{env.TEST_PROJ_PATH}} --configfile ${{env.NUGET_CONFIG_PATH}}
|
||||
env:
|
||||
TELERIK_USERNAME: "api-key"
|
||||
TELERIK_PASSWORD: ${{steps.akeyless.outputs.TELERIK_NUGET_KEY}}
|
||||
|
||||
- name: Build Test Project
|
||||
run: dotnet build ${{env.TEST_PROJ_PATH}} -c ${{env.CONFIGURATION}} --no-restore
|
||||
env:
|
||||
TELERIK_LICENSE: ${{steps.akeyless.outputs.TELERIK_LICENSE_KEY}}
|
||||
|
||||
build_linux:
|
||||
runs-on: ubuntu-latest
|
||||
steps:
|
||||
- name: Checkout
|
||||
uses: actions/checkout@v4
|
||||
with:
|
||||
fetch-depth: 0
|
||||
|
||||
# Using AKeyless for secrets in this demo
|
||||
- name: Fetch secrets from AKeyless
|
||||
id: akeyless
|
||||
uses: LanceMcCarthy/akeyless-action@v5
|
||||
with:
|
||||
access-id: 'p-4blpeo5zdfeaom'
|
||||
static-secrets: |
|
||||
{
|
||||
"/progress/TELERIK_NUGET_KEY":"TELERIK_NUGET_KEY",
|
||||
"/progress/TELERIK_LICENSE":"TELERIK_LICENSE_KEY"
|
||||
}
|
||||
export-secrets-to-outputs: true
|
||||
export-secrets-to-environment: false
|
||||
|
||||
- name: Setup .NET Core SDK
|
||||
uses: actions/setup-dotnet@v4
|
||||
with:
|
||||
dotnet-version: ${{env.DOTNET_VERSION}}
|
||||
|
||||
- name: Restore NuGet Packages
|
||||
run: |
|
||||
dotnet restore ${{env.BLAZOR_PROJ_PATH}} --configfile ${{env.NUGET_CONFIG_PATH}}
|
||||
dotnet restore ${{env.TEST_PROJ_PATH}} --configfile ${{env.NUGET_CONFIG_PATH}}
|
||||
env:
|
||||
TELERIK_USERNAME: "api-key"
|
||||
TELERIK_PASSWORD: ${{steps.akeyless.outputs.TELERIK_NUGET_KEY}}
|
||||
|
||||
- name: Build Test Project
|
||||
run: dotnet build ${{env.TEST_PROJ_PATH}} -c ${{env.CONFIGURATION}} --no-restore
|
||||
env:
|
||||
TELERIK_LICENSE: ${{steps.akeyless.outputs.TELERIK_LICENSE_KEY}}
|
||||
@@ -0,0 +1,50 @@
|
||||
# This example shows you how ot use Akeyless to fetch the required secrets instead of GitHub Actions secrets
|
||||
name: Console (.NET)
|
||||
|
||||
on:
|
||||
workflow_dispatch:
|
||||
push:
|
||||
branches:
|
||||
- main
|
||||
- "console/*"
|
||||
paths:
|
||||
- 'src/Console/**/*'
|
||||
- '.github/workflows/main_build-console.yml'
|
||||
|
||||
defaults:
|
||||
run:
|
||||
shell: pwsh
|
||||
|
||||
env:
|
||||
CSPROJ_PATH: src/Console/MyDocProcApp/MyDocProcApp.csproj
|
||||
NUGETCONFIG_PATH: src/NuGet.Config
|
||||
BUILD_CONFIGURATION: Release
|
||||
|
||||
jobs:
|
||||
build_console:
|
||||
runs-on: ubuntu-22.04
|
||||
strategy:
|
||||
matrix:
|
||||
os: [linux, win]
|
||||
config: [x64, arm64]
|
||||
steps:
|
||||
- name: Checkout
|
||||
uses: actions/checkout@v4
|
||||
with:
|
||||
fetch-depth: 0
|
||||
|
||||
- name: Setup .NET SDK
|
||||
uses: actions/setup-dotnet@v4
|
||||
with:
|
||||
dotnet-version: '10.0.x'
|
||||
|
||||
- name: Update NuGet Package Sources
|
||||
run: dotnet nuget update source 'Telerik_v3_Feed' -s 'https://nuget.telerik.com/v3/index.json' -u "api-key" -p ${{secrets.TELERIK_NUGET_KEY}} --configfile ${{env.NUGETCONFIG_PATH}} --store-password-in-clear-text
|
||||
|
||||
- name: Restore NuGet packages
|
||||
run: dotnet restore ${{env.CSPROJ_PATH}} --configfile ${{env.NUGETCONFIG_PATH}} --runtime ${{matrix.os}}-${{matrix.config}}
|
||||
|
||||
- name: Build project
|
||||
run: dotnet build ${{env.CSPROJ_PATH}} --configuration ${{env.BUILD_CONFIGURATION}} --runtime ${{matrix.os}}-${{matrix.config}} --no-self-contained --no-restore
|
||||
env:
|
||||
TELERIK_LICENSE: ${{secrets.TELERIK_LICENSE_KEY}}
|
||||
@@ -0,0 +1,119 @@
|
||||
name: Console (.NET) - Trusted Signing
|
||||
|
||||
on:
|
||||
workflow_dispatch:
|
||||
|
||||
defaults:
|
||||
run:
|
||||
shell: pwsh
|
||||
|
||||
permissions:
|
||||
id-token: write # For OIDC auth
|
||||
|
||||
env:
|
||||
CSPROJ_PATH: src/Console/MyDocProcApp/MyDocProcApp.csproj
|
||||
NUGETCONFIG_PATH: src/NuGet.Config
|
||||
BUILD_CONFIGURATION: Release
|
||||
|
||||
jobs:
|
||||
build_console:
|
||||
runs-on: ubuntu-22.04
|
||||
strategy:
|
||||
matrix:
|
||||
os: [linux, win]
|
||||
config: [x64, arm64]
|
||||
env:
|
||||
OUTPUT_DIR: ${{github.workspace}}/output/${{matrix.os}}-${{matrix.config}}/
|
||||
steps:
|
||||
- name: Checkout
|
||||
uses: actions/checkout@v4
|
||||
with:
|
||||
fetch-depth: 0
|
||||
|
||||
- name: Setup .NET SDK
|
||||
uses: actions/setup-dotnet@v4
|
||||
with:
|
||||
dotnet-version: '10.0.x'
|
||||
|
||||
- name: Update NuGet Package Sources
|
||||
run: dotnet nuget update source 'Telerik_v3_Feed' -s 'https://nuget.telerik.com/v3/index.json' -u "api-key" -p ${{secrets.TELERIK_NUGET_KEY}} --configfile ${{env.NUGETCONFIG_PATH}} --store-password-in-clear-text
|
||||
|
||||
- name: Restore NuGet packages
|
||||
run: dotnet restore ${{env.CSPROJ_PATH}} --configfile ${{env.NUGETCONFIG_PATH}} --runtime ${{matrix.os}}-${{matrix.config}}
|
||||
|
||||
- name: Build project
|
||||
run: dotnet publish ${{env.CSPROJ_PATH}} --configuration ${{env.BUILD_CONFIGURATION}} --runtime ${{matrix.os}}-${{matrix.config}} --no-self-contained --no-restore --output ${{env.OUTPUT_DIR}}
|
||||
env:
|
||||
TELERIK_LICENSE: ${{secrets.TELERIK_LICENSE_KEY}}
|
||||
|
||||
- name: Attach artifacts
|
||||
id: upload-artifact
|
||||
uses: actions/upload-artifact@v4
|
||||
with:
|
||||
name: "Console_${{matrix.os}}-${{matrix.config}}"
|
||||
path: ${{env.OUTPUT_DIR}}
|
||||
if-no-files-found: error
|
||||
retention-days: 30
|
||||
|
||||
codesign_release:
|
||||
name: Codesign Release
|
||||
if: ${{ success() }}
|
||||
runs-on: windows-latest
|
||||
needs: [build_console]
|
||||
steps:
|
||||
- name: Download artifacts
|
||||
uses: actions/download-artifact@v4
|
||||
with:
|
||||
path: ${{github.workspace}}/artifacts/
|
||||
|
||||
# No secrets needed, uses the GitHub OIDC token to authenticate.
|
||||
- name: Azure login using OIDC via GitHub
|
||||
uses: azure/login@v2
|
||||
id: azlogin
|
||||
with:
|
||||
client-id: "32daa13b-f4bb-4809-8ef6-58cb39051acd"
|
||||
tenant-id: "bd47e796-3473-4b8a-9101-1f4c0c7af31a"
|
||||
subscription-id: "48ab4839-62af-4ab3-afe6-043ea4d7c137"
|
||||
|
||||
# Codesign files with Azure Trusted Signing
|
||||
- name: Sign files with Trusted Signing
|
||||
uses: azure/trusted-signing-action@v0.4.0
|
||||
with:
|
||||
endpoint: https://eus.codesigning.azure.net/
|
||||
trusted-signing-account-name: PrimaryCodeSign
|
||||
certificate-profile-name: lancemccarthylivepublic
|
||||
timestamp-rfc3161: http://timestamp.acs.microsoft.com
|
||||
timestamp-digest: SHA256
|
||||
file-digest: SHA256
|
||||
files-folder: ${{github.workspace}}/artifacts/
|
||||
files-folder-filter: exe
|
||||
files-folder-depth: 3
|
||||
exclude-azure-cli-credential: false
|
||||
exclude-environment-credential: true
|
||||
exclude-workload-identity-credential: true
|
||||
exclude-managed-identity-credential: true
|
||||
exclude-shared-token-cache-credential: true
|
||||
exclude-visual-studio-credential: true
|
||||
exclude-visual-studio-code-credential: true
|
||||
exclude-azure-powershell-credential: true
|
||||
exclude-azure-developer-cli-credential: true
|
||||
exclude-interactive-browser-credential: true
|
||||
|
||||
- name: Attach signed artifact
|
||||
id: upload-artifact
|
||||
uses: actions/upload-artifact@v4
|
||||
with:
|
||||
name: "Console_Codesigned"
|
||||
path: ${{github.workspace}}/artifacts/
|
||||
if-no-files-found: error
|
||||
retention-days: 30
|
||||
|
||||
- name: Delete unsigned artifacts from run
|
||||
uses: geekyeggo/delete-artifact@v5
|
||||
with:
|
||||
name: |
|
||||
Console_linux-x64
|
||||
Console_linux-arm64
|
||||
Console_win-x64
|
||||
Console_win-arm64
|
||||
failOnError: false
|
||||
@@ -0,0 +1,50 @@
|
||||
name: Console (.NET) - Artifactory Only
|
||||
|
||||
on:
|
||||
workflow_dispatch:
|
||||
|
||||
defaults:
|
||||
run:
|
||||
shell: pwsh
|
||||
|
||||
jobs:
|
||||
build_console:
|
||||
runs-on: ubuntu-latest
|
||||
steps:
|
||||
- uses: actions/checkout@v4
|
||||
with:
|
||||
fetch-depth: 0
|
||||
|
||||
- uses: actions/setup-dotnet@v4
|
||||
with:
|
||||
dotnet-version: '10.0.x'
|
||||
|
||||
- name: Build Console App w/only Artifactory Source
|
||||
run: |
|
||||
# 1. Remove all existing package sources
|
||||
$sourceList = dotnet nuget list source
|
||||
$sourceNames = @()
|
||||
foreach ($line in $sourceList) {
|
||||
if ($line -match '^\s*\d+\.\s+(.*)\s+\[Enabled\]') {
|
||||
$sourceNames += $matches[1].Trim()
|
||||
}
|
||||
}
|
||||
foreach ($name in $sourceNames) {
|
||||
dotnet nuget remove source "$name"
|
||||
Write-Host "Removed $name ..."
|
||||
}
|
||||
|
||||
# 2. Add Artifactory source with credentials from GitHub Secrets
|
||||
dotnet nuget add source "https://bed-artifactory.bedford.progress.com/artifactory/api/nuget/v3/dt-nuget-virtual-tierpoint/index.json" `
|
||||
--name "artifactory_virtual" `
|
||||
--username ${{secrets.ARTIFACTORY_NUGET_USERNAME}} `
|
||||
--password ${{secrets.ARTIFACTORY_NUGET_PASSWORD}} `
|
||||
--store-password-in-clear-text
|
||||
|
||||
# 3. List sources to verify
|
||||
dotnet nuget list source
|
||||
|
||||
# 4. Build the project
|
||||
dotnet build "src/Console/MyDocProcApp/MyDocProcApp.csproj"
|
||||
env:
|
||||
TELERIK_LICENSE: ${{secrets.TELERIK_LICENSE_KEY}}
|
||||
@@ -0,0 +1,137 @@
|
||||
name: MAUI
|
||||
|
||||
on:
|
||||
workflow_dispatch:
|
||||
push:
|
||||
branches:
|
||||
- main
|
||||
paths:
|
||||
- 'src/MAUI/**/*'
|
||||
- '.github/workflows/main_build-maui.yml'
|
||||
|
||||
env:
|
||||
TELERIK_LICENSE: ${{secrets.TELERIK_LICENSE_KEY}}
|
||||
PROJECT_PATH: "src/MAUI/MauiDemo.csproj"
|
||||
NUGETCONFIG_PATH: "src/NuGet.Config"
|
||||
DOTNET_VERSION: "10.0.x"
|
||||
MAC_DOTNET_VERSION: "10.0.203" # Used to avoid Xcode and MAUI workload problems
|
||||
TFM_VERSION: "net10.0"
|
||||
XCODE_VERSION: '26.4'
|
||||
BUILD_CONFIG: "Debug"
|
||||
|
||||
jobs:
|
||||
maui-windows:
|
||||
name: Windows Smoketest
|
||||
runs-on: windows-latest
|
||||
steps:
|
||||
- name: Checkout
|
||||
uses: actions/checkout@v6
|
||||
|
||||
- name: Setup .NET SDK
|
||||
uses: actions/setup-dotnet@v5
|
||||
with:
|
||||
dotnet-version: ${{env.DOTNET_VERSION}}
|
||||
|
||||
# Only needed for WinUI builds
|
||||
- name: Add msbuild to PATH
|
||||
uses: microsoft/setup-msbuild@v3
|
||||
|
||||
- name: Install MAUI workloads
|
||||
run: dotnet workload install maui --source https://api.nuget.org/v3/index.json
|
||||
|
||||
- name: Set Telerik NuGet Credentials
|
||||
run: dotnet nuget update source 'Telerik_v3_Feed' -s 'https://nuget.telerik.com/v3/index.json' -u 'api-key' -p "${{secrets.TELERIK_NUGET_KEY}}" --configfile ${{env.NUGETCONFIG_PATH}} --store-password-in-clear-text
|
||||
|
||||
- name: Restore NuGet packages
|
||||
run: dotnet restore ${{env.PROJECT_PATH}} --configfile ${{env.NUGETCONFIG_PATH}}
|
||||
|
||||
- name: Build Maui WinUI project
|
||||
run: dotnet build ${{env.PROJECT_PATH}} -c ${{env.BUILD_CONFIG}} -f "${{env.TFM_VERSION}}-windows10.0.22621.0" --no-restore
|
||||
|
||||
|
||||
maui-android:
|
||||
name: Android Smoketest
|
||||
runs-on: windows-latest
|
||||
steps:
|
||||
- name: Checkout
|
||||
uses: actions/checkout@v6
|
||||
|
||||
- name: Setup .NET SDK
|
||||
uses: actions/setup-dotnet@v5
|
||||
with:
|
||||
dotnet-version: ${{env.DOTNET_VERSION}}
|
||||
|
||||
- uses: actions/setup-java@v4
|
||||
with:
|
||||
distribution: 'microsoft'
|
||||
java-version: '11'
|
||||
|
||||
- name: Install MAUI workloads
|
||||
run: dotnet workload install maui --source https://api.nuget.org/v3/index.json
|
||||
|
||||
- name: Set Telerik NuGet Credentials
|
||||
run: dotnet nuget update source 'Telerik_v3_Feed' -s 'https://nuget.telerik.com/v3/index.json' -u 'api-key' -p "${{secrets.TELERIK_NUGET_KEY}}" --configfile ${{env.NUGETCONFIG_PATH}} --store-password-in-clear-text
|
||||
|
||||
- name: Restore NuGet packages
|
||||
run: dotnet restore ${{env.PROJECT_PATH}} --configfile ${{env.NUGETCONFIG_PATH}}
|
||||
|
||||
- name: Build Maui Android project
|
||||
run: dotnet build ${{env.PROJECT_PATH}} -c ${{env.BUILD_CONFIG}} -f "${{env.TFM_VERSION}}-android" --no-restore
|
||||
|
||||
|
||||
maui-ios:
|
||||
name: iOS Smoketest
|
||||
runs-on: macos-26
|
||||
steps:
|
||||
- name: Checkout
|
||||
uses: actions/checkout@v6
|
||||
|
||||
- uses: maxim-lobanov/setup-xcode@v1
|
||||
with:
|
||||
xcode-version: ${{env.XCODE_VERSION}}
|
||||
|
||||
- name: Setup .NET SDK
|
||||
uses: actions/setup-dotnet@v5
|
||||
with:
|
||||
dotnet-version: ${{env.MAC_DOTNET_VERSION}}
|
||||
|
||||
- name: Install MAUI workloads
|
||||
run: dotnet workload install maui --source https://api.nuget.org/v3/index.json
|
||||
|
||||
- name: Set Telerik NuGet Credentials
|
||||
run: dotnet nuget update source 'Telerik_v3_Feed' -s 'https://nuget.telerik.com/v3/index.json' -u 'api-key' -p "${{secrets.TELERIK_NUGET_KEY}}" --configfile ${{env.NUGETCONFIG_PATH}} --store-password-in-clear-text
|
||||
|
||||
- name: Restore NuGet packages
|
||||
run: dotnet restore ${{env.PROJECT_PATH}} --configfile ${{env.NUGETCONFIG_PATH}}
|
||||
|
||||
- name: Build MAUI iOS project
|
||||
run: dotnet build ${{env.PROJECT_PATH}} -c ${{env.BUILD_CONFIG}} -f "${{env.TFM_VERSION}}-ios" --no-restore -p:PublishTrimmed=True -p:MtouchLink=SdkOnly
|
||||
|
||||
|
||||
maui-macos:
|
||||
name: MacCatalyst Smoketest
|
||||
runs-on: macos-26
|
||||
steps:
|
||||
- name: Checkout
|
||||
uses: actions/checkout@v6
|
||||
|
||||
- uses: maxim-lobanov/setup-xcode@v1
|
||||
with:
|
||||
xcode-version: ${{env.XCODE_VERSION}}
|
||||
|
||||
- name: Setup .NET SDK
|
||||
uses: actions/setup-dotnet@v5
|
||||
with:
|
||||
dotnet-version: ${{env.MAC_DOTNET_VERSION}}
|
||||
|
||||
- name: Install MAUI workloads
|
||||
run: dotnet workload install maui --source https://api.nuget.org/v3/index.json
|
||||
|
||||
- name: Set Telerik NuGet Credentials
|
||||
run: dotnet nuget update source 'Telerik_v3_Feed' -s 'https://nuget.telerik.com/v3/index.json' -u 'api-key' -p "${{secrets.TELERIK_NUGET_KEY}}" --configfile ${{env.NUGETCONFIG_PATH}} --store-password-in-clear-text
|
||||
|
||||
- name: Restore NuGet packages
|
||||
run: dotnet restore ${{env.PROJECT_PATH}} --configfile ${{env.NUGETCONFIG_PATH}}
|
||||
|
||||
- name: Build MAUI MacCatalyst project
|
||||
run: dotnet build ${{env.PROJECT_PATH}} -c ${{env.BUILD_CONFIG}} -f "${{env.TFM_VERSION}}-maccatalyst" --no-restore -p:PublishTrimmed=True -p:MtouchLink=SdkOnly
|
||||
@@ -0,0 +1,771 @@
|
||||
name: MAUI (Distribution)
|
||||
|
||||
on:
|
||||
workflow_dispatch:
|
||||
|
||||
defaults:
|
||||
run:
|
||||
shell: pwsh
|
||||
|
||||
permissions:
|
||||
actions: write # Needed to delete artifacts after bundle upload
|
||||
contents: write # Needed to create GitHub Releases
|
||||
id-token: write # Needed for Azure auth (OIDC)
|
||||
|
||||
env:
|
||||
# ____Global____________________________________________
|
||||
APP_NAME: "MauiDemo"
|
||||
PROJECT_PATH: "src/MAUI/MauiDemo.csproj"
|
||||
PROJECT_DIRECTORY: "src/MAUI"
|
||||
SDK_VERSION: '10.0.x'
|
||||
NET_TFM: 'net10.0'
|
||||
XCODE_VERSION: '26.4'
|
||||
MAC_DOTNET_VERSION: '10.0.203'
|
||||
NUGET_CONFIG_PATH: 'src/nuget.config'
|
||||
TELERIK_NUGET_KEY: ${{secrets.TELERIK_NUGET_KEY}}
|
||||
TELERIK_LICENSE: ${{secrets.TELERIK_LICENSE_KEY}}
|
||||
# ____Android___________________________________________
|
||||
ANDROID_ARTIFACTS_PATH: "artifacts_android"
|
||||
ANDROID_KEYSTORE_PATH: "${{github.workspace}}/android-upload.keystore"
|
||||
JAVA_VERSION: '17'
|
||||
JAVA_DISTRIBUTION: 'microsoft'
|
||||
# ____MacCatalyst_______________________________________
|
||||
APPLE_DEV_ID_APP_CERT_NAME: "Developer ID Application: Lancelot Software, LLC (L65255N3F7)"
|
||||
APPLE_DEV_ID_INSTALLER_CERT_NAME: "Developer ID Installer: Lancelot Software, LLC (L65255N3F7)"
|
||||
APPLE_NOTARY_TEAM_ID: "L65255N3F7"
|
||||
MAC_PACKAGE_NAME: "MauiDemo-MacCatalyst"
|
||||
MAC_APP_BUNDLE_PATH: "src/Maui/bin/Release/net10.0-maccatalyst/MauiDemo.app"
|
||||
MAC_ARTIFACTS_PATH: "artifacts/maccatalyst"
|
||||
# ____iOS______________________________________________ (also check matrix vars)
|
||||
APPLE_APP_ID: "com.lancelotsoftware.MauiDemoApp"
|
||||
IOS_RID: ios-arm64
|
||||
# ____Windows__________________________________________ (also check matrix vars)
|
||||
WINDOWS_ARTIFACTS_PATH: "artifacts_windows"
|
||||
SERVICE_PRINCIPAL_CLIENT_ID: "32daa13b-f4bb-4809-8ef6-58cb39051acd"
|
||||
SERVICE_PRINCIPAL_TENANT_ID: "bd47e796-3473-4b8a-9101-1f4c0c7af31a"
|
||||
SERVICE_PRINCIPAL_SUBSCRIPTION_ID: "48ab4839-62af-4ab3-afe6-043ea4d7c137"
|
||||
SIGNING_ACCT_NAME: "PrimaryCodeSign"
|
||||
SIGNING_ACCT_CERT_PROFILE: "lancemccarthylivepublic"
|
||||
SIGNING_ACCT_ENDPOINT_URL: "https://eus.codesigning.azure.net/"
|
||||
|
||||
# ------------------ REQUIRED SECRETS ---------------- #
|
||||
# ____Global____________________________________________
|
||||
# TELERIK_NUGET_KEY
|
||||
# TELERIK_LICENSE_KEY
|
||||
# ____Android___________________________________________
|
||||
# ANDROID_SIGNING_KEYSTORE_BASE64
|
||||
# ANDROID_SIGNING_KEYSTORE_PASS
|
||||
# ANDROID_SIGNING_KEY_ALIAS
|
||||
# ANDROID_SIGNING_KEY_PASS
|
||||
# ____MacCatalyst_______________________________________
|
||||
# APPLE_DEVELOPER_ID_INSTALLER_CERT_BASE64
|
||||
# APPLE_DEVELOPER_ID_INSTALLER_CERT_PASSWORD
|
||||
# APPLE_DEVELOPER_ID_APPLICATION_CERT_BASE64
|
||||
# APPLE_NOTARY_APPLE_ID
|
||||
# APPLE_NOTARY_APP_PASSWORD
|
||||
# ____iOS______________________________________________
|
||||
# APPLE_DISTRIBUTION_CERT_BASE64
|
||||
# APPLE_DISTRIBUTION_CERT_PASSWORD
|
||||
# APPSTORE_API_ISSUER_ID
|
||||
# APPSTORE_API_KEY_ID
|
||||
# APPSTORE_API_PRIVATE_KEY
|
||||
# ____Windows__________________________________________
|
||||
# No additional secrets needed, uses Azure Trusted Signing.
|
||||
|
||||
|
||||
jobs:
|
||||
# ********************************************************************************** #
|
||||
# Shared Resources #
|
||||
# ********************************************************************************** #
|
||||
shared-resources:
|
||||
name: Create Shared Resources
|
||||
runs-on: windows-latest
|
||||
outputs:
|
||||
app_version: ${{steps.version-creator.outputs.app_version}}
|
||||
steps:
|
||||
# Generates a version number using year.monthday.run_number (e.g., 2024.824.1)
|
||||
- name: Generate version number using date and run number
|
||||
id: version-creator
|
||||
shell: pwsh
|
||||
run: |
|
||||
$buildDay = Get-Date -Format "yyyy.Mdd"
|
||||
$runNumber = "$env:GITHUB_RUN_NUMBER"
|
||||
$ver = $buildDay + "." + $runNumber
|
||||
echo "app_version=$ver" >> $env:GITHUB_OUTPUT
|
||||
|
||||
|
||||
# ********************************************************************************** #
|
||||
# Android #
|
||||
# ********************************************************************************** #
|
||||
android:
|
||||
name: Build Android (Store Upload)
|
||||
runs-on: windows-latest
|
||||
needs: shared-resources
|
||||
if: ${{ success() && needs.shared-resources.outputs.app_version != '' }}
|
||||
steps:
|
||||
- uses: actions/checkout@v6
|
||||
|
||||
- name: Decode the Keystore
|
||||
shell: pwsh
|
||||
run: |
|
||||
$file_bytes = [System.Convert]::FromBase64String("${{secrets.ANDROID_SIGNING_KEYSTORE_BASE64}}")
|
||||
[IO.File]::WriteAllBytes("${{env.ANDROID_KEYSTORE_PATH}}", $file_bytes)
|
||||
|
||||
- name: Setup .NET SDK
|
||||
uses: actions/setup-dotnet@v5
|
||||
with:
|
||||
dotnet-version: ${{env.SDK_VERSION}}
|
||||
|
||||
- uses: actions/setup-java@v5
|
||||
with:
|
||||
distribution: ${{env.JAVA_DISTRIBUTION}}
|
||||
java-version: ${{env.JAVA_VERSION}}
|
||||
|
||||
- name: Install MAUI Workloads
|
||||
run: dotnet workload install maui --source https://api.nuget.org/v3/index.json
|
||||
|
||||
- name: Set Telerik NuGet Credentials
|
||||
run: dotnet nuget update source 'Telerik_v3_Feed' -s 'https://nuget.telerik.com/v3/index.json' -u 'api-key' -p "${{secrets.TELERIK_NUGET_KEY}}" --configfile '${{env.NUGET_CONFIG_PATH}}' --store-password-in-clear-text
|
||||
|
||||
- name: Restore NuGet packages
|
||||
run: dotnet restore ${{env.PROJECT_PATH}} --configfile ${{env.NUGET_CONFIG_PATH}}
|
||||
|
||||
- name: Publish MAUI Android
|
||||
run: |
|
||||
dotnet publish ${{env.PROJECT_PATH}} -c Release -f ${{env.NET_TFM}}-android /p:AndroidKeyStore=true /p:AndroidSigningKeyStore=${{env.ANDROID_KEYSTORE_PATH}} /p:AndroidSigningStorePass=${{secrets.ANDROID_SIGNING_KEYSTORE_PASS}} /p:AndroidSigningKeyAlias=${{secrets.ANDROID_SIGNING_KEY_ALIAS}} /p:AndroidSigningKeyPass=${{secrets.ANDROID_SIGNING_KEY_PASS}}
|
||||
|
||||
- name: Create artifacts folder
|
||||
run: |
|
||||
New-Item -ItemType Directory -Force -Path ${{env.ANDROID_ARTIFACTS_PATH}} | Out-Null
|
||||
|
||||
- name: Copy signed APKs & AABs
|
||||
run: |
|
||||
$publishRoot = "src/Maui/bin/Release/${{env.NET_TFM}}-android"
|
||||
$apkFiles = Get-ChildItem -Path $publishRoot -Filter *-Signed.apk -File -Recurse -ErrorAction SilentlyContinue
|
||||
$aabFiles = Get-ChildItem -Path $publishRoot -Filter *-Signed.aab -File -Recurse -ErrorAction SilentlyContinue
|
||||
|
||||
if ($apkFiles.Count -eq 0 -and $aabFiles.Count -eq 0) {
|
||||
throw "No signed Android APK/AAB files found under $publishRoot"
|
||||
}
|
||||
|
||||
$apkFiles | ForEach-Object { Copy-Item -Path $_.FullName -Destination ${{env.ANDROID_ARTIFACTS_PATH}} -Force }
|
||||
$aabFiles | ForEach-Object { Copy-Item -Path $_.FullName -Destination ${{env.ANDROID_ARTIFACTS_PATH}} -Force }
|
||||
|
||||
- name: Publish Android build artifacts
|
||||
uses: actions/upload-artifact@v7
|
||||
with:
|
||||
name: "${{env.APP_NAME}}_v${{needs.shared-resources.outputs.app_version}}_signed-android"
|
||||
path: "${{env.ANDROID_ARTIFACTS_PATH}}/*"
|
||||
if-no-files-found: error
|
||||
retention-days: 60
|
||||
|
||||
|
||||
# ********************************************************************************** #
|
||||
# Windows (Sideload - msixbundle) #
|
||||
# ********************************************************************************** #
|
||||
windows-sideload-packages:
|
||||
name: Build Windows (Sideload)
|
||||
needs: shared-resources
|
||||
runs-on: windows-latest
|
||||
if: ${{ needs.shared-resources.outputs.app_version != ''}}
|
||||
strategy:
|
||||
fail-fast: false
|
||||
matrix:
|
||||
include:
|
||||
- arch: x64
|
||||
runtime_id: win-x64
|
||||
platform: x64
|
||||
- arch: arm64
|
||||
runtime_id: win-arm64
|
||||
platform: ARM64
|
||||
steps:
|
||||
- name: Checkout
|
||||
uses: actions/checkout@v6
|
||||
with:
|
||||
fetch-depth: 0
|
||||
|
||||
- name: Setup .NET Core SDK
|
||||
uses: actions/setup-dotnet@v5
|
||||
with:
|
||||
dotnet-version: ${{env.SDK_VERSION}}
|
||||
|
||||
# Needed only for WinUI builds
|
||||
- name: Add msbuild to PATH
|
||||
uses: microsoft/setup-msbuild@v3
|
||||
|
||||
- name: Install MAUI workloads
|
||||
run: dotnet workload install maui --source https://api.nuget.org/v3/index.json
|
||||
|
||||
- name: Set Telerik NuGet Credentials
|
||||
run: dotnet nuget update source 'Telerik_v3_Feed' -s 'https://nuget.telerik.com/v3/index.json' -u 'api-key' -p "${{secrets.TELERIK_NUGET_KEY}}" --configfile '${{env.NUGET_CONFIG_PATH}}' --store-password-in-clear-text
|
||||
|
||||
- name: Restore NuGet packages
|
||||
run: dotnet restore ${{env.PROJECT_PATH}} --configfile ${{env.NUGET_CONFIG_PATH}}
|
||||
|
||||
- name: Update manifest for sideload build
|
||||
run: |
|
||||
[xml]$manifest = Get-Content '${{env.PROJECT_DIRECTORY}}\Platforms\Windows\Package.appxmanifest'
|
||||
$manifest.Package.Identity.Version = "${{needs.shared-resources.outputs.app_version}}.0"
|
||||
$manifest.Save('${{env.PROJECT_DIRECTORY}}\Platforms\Windows\Package.appxmanifest')
|
||||
|
||||
- name: Publish ${{matrix.arch}} Windows package
|
||||
id: publish-package
|
||||
run: |
|
||||
$appVersion = "${{needs.shared-resources.outputs.app_version}}.0"
|
||||
$artifactDir = "${{github.workspace}}\${{env.WINDOWS_ARTIFACTS_PATH}}\${{matrix.arch}}"
|
||||
New-Item -ItemType Directory -Force -Path $artifactDir | Out-Null
|
||||
Write-Host "Publishing Windows ${{matrix.arch}}..."
|
||||
$publishArgs = @(
|
||||
'publish'
|
||||
'${{env.PROJECT_PATH}}'
|
||||
'-c', 'Release'
|
||||
'-f', '${{env.NET_TFM}}-windows10.0.19041.0'
|
||||
'-p:Platform=${{matrix.platform}}'
|
||||
'-p:AppxPackageBuildPlatform=${{matrix.platform}}'
|
||||
'-p:RuntimeIdentifierOverride=${{matrix.runtime_id}}'
|
||||
'-p:GenerateAppxPackageOnBuild=true'
|
||||
'-p:AppxPackageSigningEnabled=false'
|
||||
'-p:UapAppxPackageBuildMode=SideloadOnly'
|
||||
'-p:AppxBundle=Never'
|
||||
'-p:WindowsPackageType=MSIX'
|
||||
)
|
||||
& dotnet @publishArgs
|
||||
if ($LASTEXITCODE -ne 0) { throw "dotnet publish failed for ${{matrix.arch}} with exit code $LASTEXITCODE" }
|
||||
# MAUI writes MSIX to src\${{env.APP_NAME}}\AppPackages\<name>_<ver>_<arch>_Test\*.msix
|
||||
$appPackagesRoot = "src\${{env.APP_NAME}}\AppPackages"
|
||||
$candidates = Get-ChildItem -Path $appPackagesRoot -Filter *.msix -Recurse -ErrorAction SilentlyContinue |
|
||||
Where-Object { $_.FullName -notmatch '\\Dependencies\\' -and $_.Name -match "_${{matrix.arch}}\.msix$" }
|
||||
Write-Host "Found $($candidates.Count) candidate MSIX file(s) for ${{matrix.arch}}:"
|
||||
$candidates | ForEach-Object { Write-Host " $($_.FullName)" }
|
||||
$msix = $candidates | Sort-Object LastWriteTime -Descending | Select-Object -ExpandProperty FullName -First 1
|
||||
if (-not $msix) { throw "No .msix found after publish for ${{matrix.arch}}" }
|
||||
Write-Host "Found ${{matrix.arch}} package: $msix"
|
||||
Copy-Item -Path $msix -Destination "$artifactDir\${{env.APP_NAME}}.${{matrix.arch}}.msix" -Force
|
||||
echo "PACKAGE_PATH=$artifactDir\${{env.APP_NAME}}.${{matrix.arch}}.msix" >> $env:GITHUB_OUTPUT
|
||||
|
||||
- name: Upload ${{matrix.arch}} artifact
|
||||
uses: actions/upload-artifact@v7
|
||||
with:
|
||||
name: "${{env.APP_NAME}}_v${{needs.shared-resources.outputs.app_version}}_${{matrix.runtime_id}}"
|
||||
path: ${{steps.publish-package.outputs.PACKAGE_PATH}}
|
||||
if-no-files-found: error
|
||||
retention-days: 30
|
||||
|
||||
windows-generate-msixbundle:
|
||||
name: Bundle MSIX packages
|
||||
needs: [shared-resources, windows-sideload-packages]
|
||||
runs-on: windows-latest
|
||||
steps:
|
||||
- name: Clean bundle workspace
|
||||
run: |
|
||||
Remove-Item -Recurse -Force "${{github.workspace}}\bundle-input" -ErrorAction SilentlyContinue
|
||||
Remove-Item -Recurse -Force "${{github.workspace}}\bundle-output" -ErrorAction SilentlyContinue
|
||||
|
||||
- name: Download x64 artifact
|
||||
uses: actions/download-artifact@v8
|
||||
with:
|
||||
name: "${{env.APP_NAME}}_v${{needs.shared-resources.outputs.app_version}}_win-x64"
|
||||
path: ${{github.workspace}}\bundle-input
|
||||
|
||||
- name: Download arm64 artifact
|
||||
uses: actions/download-artifact@v8
|
||||
with:
|
||||
name: "${{env.APP_NAME}}_v${{needs.shared-resources.outputs.app_version}}_win-arm64"
|
||||
path: ${{github.workspace}}\bundle-input
|
||||
|
||||
- name: Create MSIX bundle
|
||||
id: bundle
|
||||
run: |
|
||||
$appVersion = "${{needs.shared-resources.outputs.app_version}}.0"
|
||||
$inputDir = "${{github.workspace}}\bundle-input"
|
||||
$outputDir = "${{github.workspace}}\bundle-output"
|
||||
New-Item -ItemType Directory -Force -Path $outputDir | Out-Null
|
||||
# Locate makeappx.exe from the latest installed Windows 10 SDK
|
||||
$sdkRoot = "C:\Program Files (x86)\Windows Kits\10\bin"
|
||||
$makeAppx = Get-ChildItem -Path $sdkRoot -Recurse -Filter makeappx.exe -ErrorAction SilentlyContinue |
|
||||
Where-Object { $_.FullName -match '\\x64\\makeappx\.exe$' } |
|
||||
Sort-Object FullName -Descending | Select-Object -First 1
|
||||
if (-not $makeAppx) { throw "makeappx.exe not found under $sdkRoot" }
|
||||
Write-Host "Using makeappx: $($makeAppx.FullName)"
|
||||
Get-ChildItem $inputDir -Filter *.msix | ForEach-Object { Write-Host "Input: $($_.FullName)" }
|
||||
$bundlePath = "$outputDir\${{env.APP_NAME}}_v${{needs.shared-resources.outputs.app_version}}.msixbundle"
|
||||
& $makeAppx.FullName bundle /d $inputDir /p $bundlePath /bv $appVersion /o
|
||||
if ($LASTEXITCODE -ne 0) { throw "makeappx bundle failed with exit code $LASTEXITCODE" }
|
||||
|
||||
echo "BUNDLE_PATH=$bundlePath" >> $env:GITHUB_OUTPUT
|
||||
|
||||
# Entra ID App Registration (Akeyless OIDC Provider) > Certificates and Secrets > Federated Credentials
|
||||
- name: Azure login using OIDC via GitHub
|
||||
uses: azure/login@v3
|
||||
id: azlogin
|
||||
with:
|
||||
client-id: ${{env.SERVICE_PRINCIPAL_CLIENT_ID}}
|
||||
tenant-id: ${{env.SERVICE_PRINCIPAL_TENANT_ID}}
|
||||
subscription-id: ${{env.SERVICE_PRINCIPAL_SUBSCRIPTION_ID}}
|
||||
|
||||
- name: Sign MSIX bundle
|
||||
uses: azure/trusted-signing-action@v1.2.0
|
||||
with:
|
||||
endpoint: ${{env.SIGNING_ACCT_ENDPOINT_URL}}
|
||||
signing-account-name: ${{env.SIGNING_ACCT_NAME}}
|
||||
certificate-profile-name: ${{env.SIGNING_ACCT_CERT_PROFILE}}
|
||||
timestamp-rfc3161: http://timestamp.acs.microsoft.com
|
||||
timestamp-digest: SHA256
|
||||
file-digest: SHA256
|
||||
files: ${{steps.bundle.outputs.BUNDLE_PATH}}
|
||||
exclude-azure-cli-credential: false
|
||||
exclude-environment-credential: true
|
||||
exclude-workload-identity-credential: true
|
||||
exclude-managed-identity-credential: true
|
||||
exclude-shared-token-cache-credential: true
|
||||
exclude-visual-studio-credential: true
|
||||
exclude-visual-studio-code-credential: true
|
||||
exclude-azure-powershell-credential: true
|
||||
exclude-azure-developer-cli-credential: true
|
||||
exclude-interactive-browser-credential: true
|
||||
|
||||
- name: Upload MSIX bundle artifact
|
||||
uses: actions/upload-artifact@v7
|
||||
with:
|
||||
name: "${{env.APP_NAME}}_v${{needs.shared-resources.outputs.app_version}}_signed-windows.msixbundle"
|
||||
path: ${{steps.bundle.outputs.BUNDLE_PATH}}
|
||||
if-no-files-found: error
|
||||
retention-days: 30
|
||||
|
||||
|
||||
# ********************************************************************************** #
|
||||
# Windows (Store - msixupload) #
|
||||
# ********************************************************************************** #
|
||||
windows-store:
|
||||
name: Build Windows (Store Upload)
|
||||
runs-on: windows-latest
|
||||
needs: shared-resources
|
||||
if: ${{ success() && needs.shared-resources.outputs.app_version != '' }}
|
||||
steps:
|
||||
- uses: actions/checkout@v6
|
||||
|
||||
- name: Setup .NET SDK
|
||||
uses: actions/setup-dotnet@v5
|
||||
with:
|
||||
dotnet-version: ${{env.SDK_VERSION}}
|
||||
|
||||
- name: Add msbuild to PATH
|
||||
uses: microsoft/setup-msbuild@v3
|
||||
|
||||
- name: Install MAUI Workloads
|
||||
run: dotnet workload install maui --source https://api.nuget.org/v3/index.json
|
||||
|
||||
- name: Set Telerik NuGet Credentials
|
||||
run: dotnet nuget update source 'Telerik_v3_Feed' -s 'https://nuget.telerik.com/v3/index.json' -u 'api-key' -p "${{secrets.TELERIK_NUGET_KEY}}" --configfile '${{env.NUGET_CONFIG_PATH}}' --store-password-in-clear-text
|
||||
|
||||
- name: Restore NuGet packages
|
||||
run: dotnet restore ${{env.PROJECT_PATH}} --configfile ${{env.NUGET_CONFIG_PATH}}
|
||||
|
||||
- name: Update manifest for store build
|
||||
run: |
|
||||
[xml]$manifest = Get-Content '${{env.PROJECT_DIRECTORY}}\Platforms\Windows\Package.appxmanifest'
|
||||
$manifest.Package.Identity.Version = "${{needs.shared-resources.outputs.app_version}}.0"
|
||||
$manifest.Save('${{env.PROJECT_DIRECTORY}}\Platforms\Windows\Package.appxmanifest')
|
||||
|
||||
- name: Build Maui WinUI project
|
||||
run: dotnet publish ${{env.PROJECT_PATH}} -c Release -f ${{env.NET_TFM}}-windows10.0.19041.0 -p:AppxPackageSigningEnabled=false -p:AppxSymbolPackageEnabled=false -p:UapAppxPackageBuildMode=StoreUpload -p:AppxBundle=Always "-p:AppxBundlePlatforms=x64|arm64" -p:PlatformTarget=AnyCPU
|
||||
|
||||
- name: Publish build artifacts
|
||||
uses: actions/upload-artifact@v7
|
||||
with:
|
||||
name: "${{env.APP_NAME}}_v${{needs.shared-resources.outputs.app_version}}_storeupload-windows"
|
||||
path: "**/*.msixupload"
|
||||
if-no-files-found: error
|
||||
retention-days: 60
|
||||
|
||||
|
||||
# ********************************************************************************** #
|
||||
# MacCatalyst #
|
||||
# ********************************************************************************** #
|
||||
maccatalyst:
|
||||
name: Build MacCatalyst (Signed & Notiarized)
|
||||
runs-on: macos-26 # https://github.com/actions/runner-images#available-images
|
||||
needs: shared-resources
|
||||
if: ${{ success() && needs.shared-resources.outputs.app_version != '' }}
|
||||
steps:
|
||||
- uses: actions/checkout@v6
|
||||
|
||||
- uses: maxim-lobanov/setup-xcode@v1
|
||||
with:
|
||||
xcode-version: ${{env.XCODE_VERSION}}
|
||||
|
||||
- name: Setup .NET SDK
|
||||
uses: actions/setup-dotnet@v5
|
||||
with:
|
||||
dotnet-version: ${{env.SDK_VERSION}}
|
||||
|
||||
- name: Install MAUI Workloads
|
||||
run: dotnet workload install maui --source https://api.nuget.org/v3/index.json
|
||||
|
||||
- name: Set Telerik NuGet Credentials
|
||||
run: dotnet nuget update source 'Telerik_v3_Feed' -s 'https://nuget.telerik.com/v3/index.json' -u 'api-key' -p "${{secrets.TELERIK_NUGET_KEY}}" --configfile '${{env.NUGET_CONFIG_PATH}}' --store-password-in-clear-text
|
||||
|
||||
- name: Restore NuGet packages
|
||||
run: dotnet restore ${{env.PROJECT_PATH}} --configfile ${{env.NUGET_CONFIG_PATH}}
|
||||
|
||||
- name: Import Developer ID Installer Certificates
|
||||
uses: Apple-Actions/import-codesign-certs@v7
|
||||
with:
|
||||
p12-file-base64: "${{secrets.APPLE_DEVELOPER_ID_INSTALLER_CERT_BASE64}}"
|
||||
p12-password: "${{secrets.APPLE_DEVELOPER_ID_INSTALLER_CERT_PASSWORD}}"
|
||||
keychain: installer_signing_temp
|
||||
|
||||
- name: Import Developer ID Application Certificates
|
||||
uses: Apple-Actions/import-codesign-certs@v7
|
||||
with:
|
||||
p12-file-base64: "${{secrets.APPLE_DEVELOPER_ID_APPLICATION_CERT_BASE64}}"
|
||||
p12-password: "${{secrets.APPLE_DEVELOPER_ID_APPLICATION_CERT_PASSWORD}}"
|
||||
keychain: application_signing_temp
|
||||
|
||||
# Each import-codesign-certs call rewrites the keychain search list. The second import step (Application cert) drops the first (Installer) keychain, so product build cannot find the "Developer ID Installer" identity. This step re-adds both keychains explicitly before any signing occurs.
|
||||
- name: Ensure both signing keychains are in the search list
|
||||
shell: bash
|
||||
run: |
|
||||
set -euo pipefail
|
||||
security list-keychains -d user -s "$HOME/Library/Keychains/installer_signing_temp.keychain-db" "$HOME/Library/Keychains/application_signing_temp.keychain-db" "$HOME/Library/Keychains/login.keychain-db"
|
||||
echo "Keychain search list:"
|
||||
security list-keychains -d user
|
||||
|
||||
# Finally make sure both certs are available before we build
|
||||
- name: Verify Developer ID identities are available
|
||||
shell: bash
|
||||
run: |
|
||||
set -euo pipefail
|
||||
APPLE_DEV_ID_APP_CERT_NAME="${{env.APPLE_DEV_ID_APP_CERT_NAME}}"
|
||||
APPLE_DEV_ID_INSTALLER_CERT_NAME="${{env.APPLE_DEV_ID_INSTALLER_CERT_NAME}}"
|
||||
|
||||
security find-identity -v -p codesigning
|
||||
security find-certificate -a -c "$APPLE_DEV_ID_INSTALLER_CERT_NAME" || true
|
||||
|
||||
if ! security find-identity -v -p codesigning | grep -F "$APPLE_DEV_ID_APP_CERT_NAME" >/dev/null; then
|
||||
echo "Missing Developer ID Application identity: $APPLE_DEV_ID_APP_CERT_NAME"
|
||||
exit 1
|
||||
fi
|
||||
|
||||
if ! security find-certificate -a -c "$APPLE_DEV_ID_INSTALLER_CERT_NAME" >/dev/null; then
|
||||
echo "Missing Developer ID Installer certificate: $APPLE_DEV_ID_INSTALLER_CERT_NAME"
|
||||
exit 1
|
||||
fi
|
||||
|
||||
- name: Build and sign MacCatalyst artifacts
|
||||
shell: bash
|
||||
run: |
|
||||
set -euo pipefail
|
||||
cd "$GITHUB_WORKSPACE"
|
||||
|
||||
if [[ ! -f "$PROJECT_PATH" ]]; then
|
||||
echo "Project file not found: $PROJECT_PATH"
|
||||
echo "Current directory: $(pwd)"
|
||||
exit 1
|
||||
fi
|
||||
|
||||
mkdir -p "$ARTIFACTS_DIR"
|
||||
|
||||
echo "Cleaning project..."
|
||||
dotnet clean "$PROJECT_PATH" -c "$CONFIGURATION" -f "$TFM"
|
||||
|
||||
publish_args=(
|
||||
"$PROJECT_PATH"
|
||||
-c "$CONFIGURATION"
|
||||
-f "$TFM"
|
||||
"-p:CodesignKey=\"$CODESIGN_KEY\""
|
||||
"-p:ApplicationVersion=$APP_VERSION"
|
||||
"-p:ApplicationDisplayVersion=$APP_VERSION"
|
||||
-p:UseHardenedRuntime=true
|
||||
)
|
||||
|
||||
echo "Publishing project..."
|
||||
dotnet publish "${publish_args[@]}"
|
||||
|
||||
if [[ ! -d "$APP_BUNDLE_PATH" ]]; then
|
||||
echo "Expected app bundle not found at $APP_BUNDLE_PATH"
|
||||
exit 1
|
||||
fi
|
||||
|
||||
echo "Verifying app signature..."
|
||||
codesign -dv --verbose=2 "$APP_BUNDLE_PATH" >/dev/null 2>&1
|
||||
|
||||
echo "Creating signed app zip and installer pkg..."
|
||||
rm -f "$SIGNED_ZIP_PATH" "$SIGNED_PKG_PATH"
|
||||
ditto -c -k --sequesterRsrc --keepParent "$APP_BUNDLE_PATH" "$SIGNED_ZIP_PATH"
|
||||
productbuild --component "$APP_BUNDLE_PATH" /Applications --sign "$INSTALLER_SIGN_ID" "$SIGNED_PKG_PATH"
|
||||
|
||||
echo "Done. Signed artifacts:"
|
||||
echo "- $SIGNED_PKG_PATH"
|
||||
echo "- $SIGNED_ZIP_PATH"
|
||||
env:
|
||||
PROJECT_PATH: "${{env.PROJECT_PATH}}"
|
||||
TFM: "${{env.NET_TFM}}-maccatalyst"
|
||||
CONFIGURATION: "Release"
|
||||
APP_VERSION: "${{needs.shared-resources.outputs.app_version}}"
|
||||
ARTIFACTS_DIR: "${{env.MAC_ARTIFACTS_PATH}}"
|
||||
APP_BUNDLE_PATH: "${{env.MAC_APP_BUNDLE_PATH}}"
|
||||
CODESIGN_KEY: "${{env.APPLE_DEV_ID_APP_CERT_NAME}}"
|
||||
INSTALLER_SIGN_ID: "${{ env.APPLE_DEV_ID_INSTALLER_CERT_NAME}}"
|
||||
SIGNED_ZIP_PATH: "$ARTIFACTS_DIR/${{env.MAC_PACKAGE_NAME}}-Release-signed.zip"
|
||||
SIGNED_PKG_PATH: "$ARTIFACTS_DIR/${{env.MAC_PACKAGE_NAME}}-Release-signed.pkg"
|
||||
|
||||
- name: Notarize and staple MacCatalyst artifacts
|
||||
shell: bash
|
||||
run: |
|
||||
set -euo pipefail
|
||||
cd "$GITHUB_WORKSPACE"
|
||||
|
||||
if [[ -z "$APPLE_NOTARY_APPLE_ID" || -z "$APPLE_NOTARY_APP_PASSWORD" || -z "$APPLE_NOTARY_TEAM_ID" ]]; then
|
||||
echo "Missing notarization credentials."
|
||||
echo "Set APPLE_NOTARY_APPLE_ID, APPLE_NOTARY_APP_PASSWORD, and APPLE_NOTARY_TEAM_ID."
|
||||
exit 1
|
||||
fi
|
||||
|
||||
if [[ ! -d "$APP_BUNDLE_PATH" ]]; then
|
||||
echo "Expected app bundle not found at $APP_BUNDLE_PATH"
|
||||
exit 1
|
||||
fi
|
||||
|
||||
if [[ ! -f "$SIGNED_PKG_PATH" || ! -f "$SIGNED_ZIP_PATH" ]]; then
|
||||
echo "Expected signed artifacts not found in $ARTIFACTS_DIR"
|
||||
exit 1
|
||||
fi
|
||||
|
||||
echo "Submitting pkg for notarization..."
|
||||
pkg_submit_json="$(xcrun notarytool submit "$SIGNED_PKG_PATH" --apple-id "$APPLE_NOTARY_APPLE_ID" --team-id "$APPLE_NOTARY_TEAM_ID" --password "$APPLE_NOTARY_APP_PASSWORD" --wait --output-format json)"
|
||||
echo "$pkg_submit_json"
|
||||
if ! grep -Eq '"status"[[:space:]]*:[[:space:]]*"Accepted"' <<< "$pkg_submit_json"; then
|
||||
echo "Notarization failed for pkg."
|
||||
exit 1
|
||||
fi
|
||||
|
||||
echo "Stapling and validating pkg..."
|
||||
xcrun stapler staple "$SIGNED_PKG_PATH"
|
||||
xcrun stapler validate "$SIGNED_PKG_PATH"
|
||||
|
||||
echo "Submitting signed app zip for notarization..."
|
||||
zip_submit_json="$(xcrun notarytool submit "$SIGNED_ZIP_PATH" --apple-id "$APPLE_NOTARY_APPLE_ID" --team-id "$APPLE_NOTARY_TEAM_ID" --password "$APPLE_NOTARY_APP_PASSWORD" --wait --output-format json)"
|
||||
echo "$zip_submit_json"
|
||||
if ! grep -Eq '"status"[[:space:]]*:[[:space:]]*"Accepted"' <<< "$zip_submit_json"; then
|
||||
echo "Notarization failed for app zip."
|
||||
exit 1
|
||||
fi
|
||||
|
||||
echo "Stapling and validating app..."
|
||||
xcrun stapler staple "$APP_BUNDLE_PATH"
|
||||
xcrun stapler validate "$APP_BUNDLE_PATH"
|
||||
|
||||
# Recreate the final distributable zip from the stapled app.
|
||||
ditto -c -k --sequesterRsrc --keepParent "$APP_BUNDLE_PATH" "$NOTARIZED_ZIP_PATH"
|
||||
|
||||
echo "Gatekeeper checks..."
|
||||
spctl -a -t exec -vv "$APP_BUNDLE_PATH"
|
||||
spctl -a -t install -vv "$SIGNED_PKG_PATH"
|
||||
|
||||
echo "Done. Artifacts:"
|
||||
echo "- $SIGNED_PKG_PATH"
|
||||
echo "- $NOTARIZED_ZIP_PATH"
|
||||
env:
|
||||
ARTIFACTS_DIR: "${{env.MAC_ARTIFACTS_PATH}}"
|
||||
APP_BUNDLE_PATH: "${{env.MAC_APP_BUNDLE_PATH}}"
|
||||
APPLE_NOTARY_APPLE_ID: "${{secrets.APPLE_NOTARY_APPLE_ID}}"
|
||||
APPLE_NOTARY_APP_PASSWORD: "${{secrets.APPLE_NOTARY_APP_PASSWORD}}"
|
||||
APPLE_NOTARY_TEAM_ID: "${{env.APPLE_NOTARY_TEAM_ID}}"
|
||||
SIGNED_ZIP_PATH: "${{env.MAC_ARTIFACTS_PATH}}/${{env.MAC_PACKAGE_NAME}}-Release-signed.zip"
|
||||
NOTARIZED_ZIP_PATH: "${{env.MAC_ARTIFACTS_PATH}}/${{env.MAC_PACKAGE_NAME}}-Release-notarized.zip"
|
||||
SIGNED_PKG_PATH: "${{env.MAC_ARTIFACTS_PATH}}/${{env.MAC_PACKAGE_NAME}}-Release-signed.pkg"
|
||||
|
||||
- name: Publish MacCatalyst build artifacts
|
||||
uses: actions/upload-artifact@v7
|
||||
with:
|
||||
name: "${{env.APP_NAME}}_v${{needs.shared-resources.outputs.app_version}}_signed-maccatalyst"
|
||||
path: ${{env.MAC_ARTIFACTS_PATH}}/${{env.MAC_PACKAGE_NAME}}-Release-signed.pkg
|
||||
if-no-files-found: error
|
||||
retention-days: 30
|
||||
|
||||
|
||||
# ********************************************************************************** #
|
||||
# iOS #
|
||||
# ********************************************************************************** #
|
||||
ios:
|
||||
name: Build iOS (${{matrix.distribution_name}})
|
||||
runs-on: macos-26 # https://github.com/actions/runner-images#available-images
|
||||
needs: shared-resources
|
||||
if: ${{ success() && needs.shared-resources.outputs.app_version != '' }}
|
||||
strategy:
|
||||
fail-fast: false
|
||||
matrix:
|
||||
include:
|
||||
- distribution_name: Store Upload IPA
|
||||
artifact_suffix: storeupload-ios
|
||||
provisioning_profile: MauiDemo_AppStore_Distribution
|
||||
provisioning_profile_type: IOS_APP_STORE
|
||||
rid: ios-arm64
|
||||
- distribution_name: Ad Hoc Sideload IPA
|
||||
artifact_suffix: sideload-ios
|
||||
provisioning_profile: MauiDemo_AdHoc_Distribution
|
||||
provisioning_profile_type: IOS_APP_ADHOC
|
||||
rid: ios-arm64
|
||||
env:
|
||||
APPLE_PROV_PROFILE: ${{matrix.provisioning_profile}}
|
||||
APPLE_PROV_PROFILE_TYPE: ${{matrix.provisioning_profile_type}}
|
||||
steps:
|
||||
- uses: actions/checkout@v6
|
||||
|
||||
- uses: maxim-lobanov/setup-xcode@v1
|
||||
with:
|
||||
xcode-version: ${{env.XCODE_VERSION}}
|
||||
|
||||
- name: Setup .NET SDK
|
||||
uses: actions/setup-dotnet@v5
|
||||
with:
|
||||
dotnet-version: ${{env.SDK_VERSION}}
|
||||
|
||||
- name: Install MAUI Workloads
|
||||
run: dotnet workload install maui --source https://api.nuget.org/v3/index.json
|
||||
|
||||
- name: Set Telerik NuGet Credentials
|
||||
run: dotnet nuget update source 'Telerik_v3_Feed' -s 'https://nuget.telerik.com/v3/index.json' -u 'api-key' -p "${{secrets.TELERIK_NUGET_KEY}}" --configfile '${{env.NUGET_CONFIG_PATH}}' --store-password-in-clear-text
|
||||
|
||||
- name: Restore NuGet packages
|
||||
run: dotnet restore ${{env.PROJECT_PATH}} --configfile ${{env.NUGET_CONFIG_PATH}}
|
||||
|
||||
# Docs https://github.com/Apple-Actions/import-codesign-certs
|
||||
- name: Import Code-Signing Certificates
|
||||
uses: Apple-Actions/import-codesign-certs@v7
|
||||
with:
|
||||
p12-file-base64: "${{secrets.APPLE_DISTRIBUTION_CERT_BASE64}}"
|
||||
p12-password: "${{secrets.APPLE_DISTRIBUTION_CERT_PASSWORD}}"
|
||||
|
||||
# Docs https://github.com/Apple-Actions/download-provisioning-profiles
|
||||
- id: provisioning-profiles
|
||||
uses: Apple-Actions/download-provisioning-profiles@v6
|
||||
with:
|
||||
profile-type: "${{env.APPLE_PROV_PROFILE_TYPE}}"
|
||||
bundle-id: "${{env.APPLE_APP_ID}}"
|
||||
issuer-id: "${{secrets.APPSTORE_API_ISSUER_ID}}"
|
||||
api-key-id: "${{secrets.APPSTORE_API_KEY_ID}}"
|
||||
api-private-key: "${{secrets.APPSTORE_API_PRIVATE_KEY}}"
|
||||
|
||||
- name: Verify provisioning profile
|
||||
run: |
|
||||
$profiles = '${{steps.provisioning-profiles.outputs.profiles}}' | ConvertFrom-Json
|
||||
$profile = $profiles | Where-Object { $_.name -eq $env:APPLE_PROV_PROFILE -and $_.type -eq $env:APPLE_PROV_PROFILE_TYPE } | Select-Object -First 1
|
||||
|
||||
if ($null -eq $profile) {
|
||||
$profiles | Format-Table -AutoSize | Out-String | Write-Host
|
||||
throw "Provisioning profile '$env:APPLE_PROV_PROFILE' with type '$env:APPLE_PROV_PROFILE_TYPE' was not downloaded."
|
||||
}
|
||||
|
||||
- name: Verify iOS signing identity is available
|
||||
shell: bash
|
||||
run: |
|
||||
set -euo pipefail
|
||||
security find-identity -v -p codesigning
|
||||
if ! security find-identity -v -p codesigning | grep -F "Apple Distribution" >/dev/null; then
|
||||
echo "Missing Apple Distribution identity"
|
||||
exit 1
|
||||
fi
|
||||
|
||||
# Docs https://learn.microsoft.com/en-us/dotnet/maui/ios/deployment/publish-cli?view=net-maui-9.0
|
||||
- name: Publish MAUI iOS IPA
|
||||
run: |
|
||||
# Query the actual signing identity to avoid comma parsing issues
|
||||
$identityOutput = security find-identity -v -p codesigning | Select-String "Apple Distribution"
|
||||
if (-not $identityOutput) { throw "No Apple Distribution identity found in keychain" }
|
||||
$codesignKey = [regex]::Match($identityOutput.Line, '"(?<name>Apple Distribution:[^"]+)"').Groups['name'].Value
|
||||
if (-not $codesignKey) { throw "Could not parse Apple Distribution identity from keychain output" }
|
||||
Write-Host "Using codesign key: $codesignKey"
|
||||
$quotedCodesignKey = '"' + $codesignKey + '"'
|
||||
|
||||
$publishArgs = @(
|
||||
'publish'
|
||||
'${{env.PROJECT_PATH}}'
|
||||
'-f', '${{env.NET_TFM}}-ios'
|
||||
'-c', 'Release'
|
||||
'-p:ArchiveOnBuild=true'
|
||||
'-p:RuntimeIdentifier=${{matrix.rid}}'
|
||||
'-p:MtouchLink=SdkOnly'
|
||||
'-p:ApplicationId=${{env.APPLE_APP_ID}}'
|
||||
'-p:ApplicationVersion=${{needs.shared-resources.outputs.app_version}}'
|
||||
'-p:CodesignProvision=${{env.APPLE_PROV_PROFILE}}'
|
||||
"-p:CodesignKey=$quotedCodesignKey"
|
||||
)
|
||||
& dotnet @publishArgs
|
||||
if ($LASTEXITCODE -ne 0) { throw "dotnet publish failed with exit code $LASTEXITCODE" }
|
||||
|
||||
- name: Publish iOS build artifacts
|
||||
uses: actions/upload-artifact@v7
|
||||
with:
|
||||
name: "${{env.APP_NAME}}_v${{needs.shared-resources.outputs.app_version}}_${{matrix.artifact_suffix}}"
|
||||
path: "${{env.PROJECT_DIRECTORY}}/bin/Release/${{env.NET_TFM}}-ios/${{matrix.rid}}/publish/*.ipa"
|
||||
if-no-files-found: error
|
||||
retention-days: 60
|
||||
|
||||
|
||||
# ********************************************************************************** #
|
||||
# GitHub Release #
|
||||
# ********************************************************************************** #
|
||||
# create-release:
|
||||
# name: Create GitHub Release
|
||||
# runs-on: ubuntu-latest
|
||||
# needs: [shared-resources, android, windows-sideload-packages, windows-generate-msixbundle, windows-store, maccatalyst, ios]
|
||||
# steps:
|
||||
# - name: Download all artifacts
|
||||
# uses: actions/download-artifact@v8
|
||||
# with:
|
||||
# path: release-artifacts
|
||||
|
||||
# - name: List downloaded artifacts
|
||||
# shell: bash
|
||||
# run: find release-artifacts -type f | sort
|
||||
|
||||
# - name: Prepare release files
|
||||
# shell: bash
|
||||
# run: |
|
||||
# set -euo pipefail
|
||||
# VER="${{needs.shared-resources.outputs.app_version}}"
|
||||
# PREFIX="${{env.APP_NAME}}_v${VER}"
|
||||
# mkdir -p release-upload
|
||||
# copy_one() {
|
||||
# local artifact_dir="$1"
|
||||
# local pattern="$2"
|
||||
# local destination="$3"
|
||||
# local -a matches=()
|
||||
# if [[ ! -d "$artifact_dir" ]]; then
|
||||
# echo "Expected artifact directory not found: $artifact_dir" >&2
|
||||
# exit 1
|
||||
# fi
|
||||
# mapfile -d '' matches < <(find "$artifact_dir" -type f -name "$pattern" -print0 | sort -z)
|
||||
# if [[ ${#matches[@]} -ne 1 ]]; then
|
||||
# echo "Expected exactly one match for '$pattern' under '$artifact_dir', found ${#matches[@]}." >&2
|
||||
# find "$artifact_dir" -type f | sort >&2
|
||||
# exit 1
|
||||
# fi
|
||||
# cp -- "${matches[0]}" "$destination"
|
||||
# }
|
||||
# # Android
|
||||
# copy_one "release-artifacts/${PREFIX}_signed-android" "*-Signed.apk" "release-upload/${PREFIX}_android-signed.apk"
|
||||
# copy_one "release-artifacts/${PREFIX}_signed-android" "*-Signed.aab" "release-upload/${PREFIX}_android-signed.aab"
|
||||
# # Windows msixbundle (signed)
|
||||
# copy_one "release-artifacts/${PREFIX}_signed-windows.msixbundle" "*.msixbundle" "release-upload/${PREFIX}_windows.msixbundle"
|
||||
# # Windows Store
|
||||
# copy_one "release-artifacts/${PREFIX}_storeupload-windows" "*.msixupload" "release-upload/${PREFIX}_msstore.msixupload"
|
||||
# # MacCatalyst
|
||||
# copy_one "release-artifacts/${PREFIX}_signed-maccatalyst" "*.pkg" "release-upload/${PREFIX}_mac.pkg"
|
||||
# # iOS
|
||||
# copy_one "release-artifacts/${PREFIX}_ios-adhoc" "*.ipa" "release-upload/${PREFIX}_ios-adhoc.ipa"
|
||||
# copy_one "release-artifacts/${PREFIX}_ios-store" "*.ipa" "release-upload/${PREFIX}_ios-store.ipa"
|
||||
# echo "Files prepared for release:"
|
||||
# ls -lh release-upload/
|
||||
|
||||
# - name: Create GitHub Release
|
||||
# uses: softprops/action-gh-release@v3.0.0
|
||||
# with:
|
||||
# tag_name: "v${{needs.shared-resources.outputs.app_version}}"
|
||||
# name: "${{env.APP_NAME}} v${{needs.shared-resources.outputs.app_version}}"
|
||||
# draft: false
|
||||
# prerelease: false
|
||||
# generate_release_notes: true
|
||||
# files: release-upload/*
|
||||
@@ -0,0 +1,49 @@
|
||||
# This example shows you how you can use the named environment variables in the nuget.config file to set the credentials, for more information see https://github.com/LanceMcCarthy/DevOpsExamples#github-actions-using-secrets-to-set-environment-variables
|
||||
name: WinForms (.NET Framework)
|
||||
|
||||
on:
|
||||
workflow_dispatch:
|
||||
push:
|
||||
branches:
|
||||
- main
|
||||
- "winforms/*"
|
||||
paths:
|
||||
- 'src/WinForms/**/*'
|
||||
- '.github/workflows/main_build-winforms.yml'
|
||||
|
||||
env:
|
||||
TELERIK_USERNAME: "api-key" # Variable name used in the nuget.config file
|
||||
TELERIK_PASSWORD: ${{secrets.TELERIK_NUGET_KEY}} # Variable name used in the nuget.config file
|
||||
TELERIK_LICENSE: ${{secrets.TELERIK_LICENSE_KEY}} # Used when compiling the project
|
||||
CSPROJ_PATH: "src/WinForms/MyWinFormsApp/MyWinFormsApp.csproj"
|
||||
NUGETCONFIG_PATH: "src/NuGet.Config"
|
||||
|
||||
jobs:
|
||||
# A job that builds a .NET Framework WPF application using Telerik UI for WinForms
|
||||
build_desktop:
|
||||
runs-on: windows-latest # WinForms apps must be built on Windows runners
|
||||
strategy:
|
||||
matrix:
|
||||
configuration: [Release]
|
||||
platform: [x86, x64]
|
||||
steps:
|
||||
- name: Checkout
|
||||
uses: actions/checkout@v4
|
||||
with:
|
||||
fetch-depth: 0
|
||||
|
||||
- name: Setup .NET SDK
|
||||
uses: actions/setup-dotnet@v4
|
||||
with:
|
||||
dotnet-version: '10.0.x'
|
||||
|
||||
- name: Setup MSBuild.exe
|
||||
uses: microsoft/setup-msbuild@v2
|
||||
|
||||
# We use the dotnet CLI (instead of nuget CLI) to restore the nuget packages before using msbuild
|
||||
- name: NuGet Restore
|
||||
run: dotnet restore ${{env.CSPROJ_PATH}} --configfile ${{env.NUGETCONFIG_PATH}} --runtime win-${{matrix.platform}}
|
||||
|
||||
# Use msbuild to compile the .NET Framework WinForms project
|
||||
- name: Build the WinForms application
|
||||
run: msbuild ${{env.CSPROJ_PATH}} /t:Restore /p:Configuration=${{matrix.configuration}} /p:RuntimeIdentifier=win-${{matrix.platform}}
|
||||
@@ -0,0 +1,57 @@
|
||||
name: WinUI3
|
||||
|
||||
on:
|
||||
workflow_dispatch:
|
||||
push:
|
||||
branches:
|
||||
- main
|
||||
- "winui/*"
|
||||
paths:
|
||||
- 'src/WinUI/**/*'
|
||||
- '.github/workflows/main_build-winui.yml'
|
||||
|
||||
env:
|
||||
TELERIK_USERNAME: "api-key" # Used by the nuget.config file
|
||||
TELERIK_PASSWORD: ${{secrets.TELERIK_NUGET_KEY}} # Used by the nuget.config file
|
||||
SOLUTION_NAME: "src/WinUI/MyDemo.sln"
|
||||
NUGETCONFIG_PATH: "src/NuGet.Config"
|
||||
|
||||
jobs:
|
||||
build-windows:
|
||||
runs-on: windows-2022
|
||||
steps:
|
||||
- name: Checkout
|
||||
uses: actions/checkout@v4
|
||||
with:
|
||||
fetch-depth: 0
|
||||
|
||||
- name: Setup .NET
|
||||
uses: actions/setup-dotnet@v4
|
||||
with:
|
||||
dotnet-version: '10.0.x'
|
||||
|
||||
- name: Add msbuild to PATH
|
||||
uses: microsoft/setup-msbuild@v2
|
||||
|
||||
- name: Restore NuGet packages
|
||||
shell: pwsh
|
||||
run: dotnet restore ${{env.SOLUTION_NAME}} --configfile ${{env.NUGETCONFIG_PATH}}
|
||||
|
||||
# Restore the application to populate the obj folder with RuntimeIdentifiers
|
||||
- name: Restore RIDs
|
||||
run: msbuild ${{env.SOLUTION_NAME}} /t:Restore /p:Configuration=Release
|
||||
|
||||
- name: Build and Create MSIX
|
||||
run: |
|
||||
msbuild ${{env.SOLUTION_NAME}} `
|
||||
/p:Configuration=Release `
|
||||
/p:Platform=x64 `
|
||||
/p:AppxBundlePlatforms="x64|arm64" `
|
||||
/p:UapAppxPackageBuildMode=CI `
|
||||
/p:AppxBundle=Never `
|
||||
/p:AppxPackageDir="${{github.workspace}}/AppPackages" `
|
||||
/p:GenerateAppxPackageOnBuild=true `
|
||||
/p:AppxPackageSigningEnabled=false `
|
||||
/p:SelfContained=true
|
||||
env:
|
||||
TELERIK_LICENSE: ${{secrets.TELERIK_LICENSE_KEY}}
|
||||
@@ -0,0 +1,48 @@
|
||||
# This example shows you how you can use the named environment variables in the nuget.config file to set the credentials
|
||||
name: WPF (.NET Framework)
|
||||
|
||||
on:
|
||||
workflow_dispatch:
|
||||
push:
|
||||
branches:
|
||||
- main
|
||||
- "wpf/*"
|
||||
paths:
|
||||
- 'src/Wpf/**/*'
|
||||
- '.github/workflows/main_build-wpf.yml'
|
||||
|
||||
env:
|
||||
TELERIK_USERNAME: "api-key" # Variable name used in the nuget.config file
|
||||
TELERIK_PASSWORD: ${{secrets.TELERIK_NUGET_KEY}} # Variable name used in the nuget.config file
|
||||
TELERIK_LICENSE: ${{secrets.TELERIK_LICENSE_KEY}} # Used when compiling the project
|
||||
CSPROJ_PATH: "src/Wpf/MyWpfApp/MyWpfApp.csproj"
|
||||
NUGETCONFIG_PATH: "src/NuGet.Config"
|
||||
|
||||
jobs:
|
||||
build_desktop:
|
||||
runs-on: windows-latest
|
||||
strategy:
|
||||
matrix:
|
||||
configuration: [Release]
|
||||
platform: [x86, x64]
|
||||
steps:
|
||||
- name: Checkout
|
||||
uses: actions/checkout@v4
|
||||
with:
|
||||
fetch-depth: 0
|
||||
|
||||
- name: Install .NET SDK
|
||||
uses: actions/setup-dotnet@v4
|
||||
with:
|
||||
dotnet-version: '10.0.x'
|
||||
|
||||
- name: Setup MSBuild.exe
|
||||
uses: microsoft/setup-msbuild@v2
|
||||
|
||||
# We use the dotnet CLI (instead of nuget.exe) to restore the nuget packages before using msbuild
|
||||
- name: NuGet Restore
|
||||
run: dotnet restore ${{env.CSPROJ_PATH}} --configfile ${{env.NUGETCONFIG_PATH}} --runtime win-${{matrix.platform}}
|
||||
|
||||
# Use msbuild to compile the .NET Framework WPF project
|
||||
- name: Build the WPF application
|
||||
run: msbuild ${{env.CSPROJ_PATH}} /t:Restore /p:Configuration=${{matrix.configuration}} /p:RuntimeIdentifier=${{matrix.platform}}
|
||||
@@ -0,0 +1,173 @@
|
||||
name: ASP.NET Core (with Reporting) - Docker
|
||||
|
||||
on:
|
||||
workflow_dispatch:
|
||||
push:
|
||||
branches:
|
||||
- main
|
||||
paths:
|
||||
- 'src/AspNetCore/**/*'
|
||||
|
||||
env:
|
||||
WORKING_DIRECTORY: "src/AspNetCore/MyAspNetCoreApp"
|
||||
TARGET_PLATFORMS: "linux/amd64,linux/arm64"
|
||||
|
||||
jobs:
|
||||
#################### Example 1 ##########################
|
||||
# Dockerfile build and publish to Docker Hub
|
||||
# - Uses mcr.microsoft.com/dotnet/aspnet base image
|
||||
# - Webook to automatically redeploy stack in Portainer
|
||||
#########################################################
|
||||
dockerhub_msftbase_build:
|
||||
name: Microsoft Base - Publish to Docker Hub
|
||||
runs-on: ubuntu-latest
|
||||
env:
|
||||
CONTAINER_REPOSITORY: "lancemccarthy/aspnetcore-reporting-from-msftbase"
|
||||
DOCKERFILE_PATH: "src/AspNetCore/MyAspNetCoreApp/Dockerfile_MSRuntimeBase"
|
||||
CONTAINER_REGISTRY: "docker.io"
|
||||
steps:
|
||||
- name: Checkout
|
||||
uses: actions/checkout@v6
|
||||
|
||||
- name: Set up QEMU for multi-arch support
|
||||
uses: docker/setup-qemu-action@v3
|
||||
|
||||
- name: Set up Docker Buildx
|
||||
uses: docker/setup-buildx-action@v3
|
||||
|
||||
- name: Get package metadata from Docker Hub
|
||||
id: meta
|
||||
uses: docker/metadata-action@v5
|
||||
with:
|
||||
images: ${{env.CONTAINER_REGISTRY}}/${{env.CONTAINER_REPOSITORY}}
|
||||
|
||||
- name: Login to DockerHub
|
||||
uses: docker/login-action@v3
|
||||
with:
|
||||
username: ${{secrets.DOCKER_HUB_USERNAME}}
|
||||
password: ${{secrets.DOCKER_HUB_PAT}}
|
||||
|
||||
- name: Build and push to Docker Hub
|
||||
uses: docker/build-push-action@v5
|
||||
with:
|
||||
file: ${{env.DOCKERFILE_PATH}}
|
||||
context: ${{env.WORKING_DIRECTORY}}
|
||||
platforms: ${{env.TARGET_PLATFORMS}}
|
||||
push: true
|
||||
secrets: |
|
||||
telerik-nuget-key=${{secrets.TELERIK_NUGET_KEY}}
|
||||
telerik-license-key=${{secrets.TELERIK_LICENSE_KEY}}
|
||||
tags: ${{steps.meta.outputs.tags}}
|
||||
|
||||
- name: Trigger Portainer to pull images and redeploy the stack
|
||||
run: curl -X POST ${{secrets.PORTAINER_WEBHOOK_ASPNETCORE}}
|
||||
|
||||
|
||||
#################### Example 2 ##########################
|
||||
# Dockerfile build and publish to Docker Hub
|
||||
# - Uses a CentOS Base Image
|
||||
# - Webook to automatically redeploy stack in Portainer
|
||||
#########################################################
|
||||
dockerhub_centosbase_build:
|
||||
name: CentOS Base - Publish to Docker Hub
|
||||
runs-on: ubuntu-latest
|
||||
env:
|
||||
CONTAINER_REPOSITORY: "lancemccarthy/aspnetcore-reporting-from-centosbase"
|
||||
DOCKERFILE_PATH: "src/AspNetCore/MyAspNetCoreApp/Dockerfile_CentOS"
|
||||
CONTAINER_REGISTRY: "docker.io"
|
||||
steps:
|
||||
- name: Checkout
|
||||
uses: actions/checkout@v4
|
||||
with:
|
||||
fetch-depth: 0
|
||||
|
||||
- name: Set up QEMU for multi-arch support
|
||||
uses: docker/setup-qemu-action@v3
|
||||
|
||||
- name: Set up Docker Buildx
|
||||
uses: docker/setup-buildx-action@v3
|
||||
|
||||
- name: Get package metadata from Docker Hub
|
||||
id: meta
|
||||
uses: docker/metadata-action@v5
|
||||
with:
|
||||
images: ${{env.CONTAINER_REGISTRY}}/${{env.CONTAINER_REPOSITORY}}
|
||||
|
||||
- name: Login to DockerHub
|
||||
uses: docker/login-action@v3
|
||||
with:
|
||||
username: ${{secrets.DOCKER_HUB_USERNAME}}
|
||||
password: ${{secrets.DOCKER_HUB_PAT}}
|
||||
|
||||
- name: Build and push to Docker Hub
|
||||
uses: docker/build-push-action@v5
|
||||
with:
|
||||
file: ${{env.DOCKERFILE_PATH}}
|
||||
context: ${{env.WORKING_DIRECTORY}}
|
||||
platforms: ${{env.TARGET_PLATFORMS}}
|
||||
push: true
|
||||
secrets: |
|
||||
telerik-nuget-key=${{secrets.TELERIK_NUGET_KEY}}
|
||||
telerik-license-key=${{secrets.TELERIK_LICENSE_KEY}}
|
||||
tags: ${{steps.meta.outputs.tags}}
|
||||
|
||||
# ############################################################################
|
||||
# ghcr.io option
|
||||
# ############################################################################
|
||||
|
||||
# Set worklow permissions for publishing to GitHub Container Registry
|
||||
# permissions:
|
||||
# contents: read
|
||||
# packages: write # to publish to GitHub container registry
|
||||
|
||||
# ghcr_msftbase_build:
|
||||
# name: Microsoft Base - Publish to GitHub Container Registry
|
||||
# runs-on: ubuntu-latest
|
||||
# env:
|
||||
# CONTAINER_REGISTRY: "ghcr.io"
|
||||
# CONTAINER_REPOSITORY: "lancemccarthy/reporting-msft-base"
|
||||
# DOCKERFILE_PATH: "src/AspNetCore/MyAspNetCoreApp/Dockerfile_MSRuntimeBase"
|
||||
# steps:
|
||||
# - name: Checkout
|
||||
# uses: actions/checkout@v6
|
||||
# with:
|
||||
# fetch-depth: 0
|
||||
|
||||
# - name: Set up QEMU
|
||||
# uses: docker/setup-qemu-action@v3
|
||||
|
||||
# - name: Set up Docker Buildx
|
||||
# uses: docker/setup-buildx-action@v3
|
||||
|
||||
# - name: Get package metadata from Docker Hub
|
||||
# id: meta
|
||||
# uses: docker/metadata-action@v5
|
||||
# with:
|
||||
# images: ${{env.CONTAINER_REGISTRY}}/${{env.CONTAINER_REPOSITORY}}
|
||||
|
||||
# - name: Login to DockerHub
|
||||
# uses: docker/login-action@v3
|
||||
# with:
|
||||
# registry: ${{env.CONTAINER_REGISTRY}}
|
||||
# username: ${{secrets.DOCKER_HUB_USERNAME}}
|
||||
# password: ${{secrets.DOCKER_HUB_PAT}}
|
||||
|
||||
# - name: Build and push to Docker Hub
|
||||
# uses: docker/build-push-action@v5
|
||||
# with:
|
||||
# file: ${{env.DOCKERFILE_PATH}}
|
||||
# context: ${{env.WORKING_DIRECTORY}}
|
||||
# platforms: ${{env.TARGET_PLATFORMS}}
|
||||
# push: true
|
||||
# secrets: |
|
||||
# telerik-nuget-key=${{secrets.TELERIK_NUGET_KEY}}
|
||||
# telerik-license-key=${{secrets.TELERIK_LICENSE_KEY}}
|
||||
# tags: ${{steps.meta.outputs.tags}}
|
||||
|
||||
# - name: Delete old Docker images
|
||||
# uses: actions/delete-package-versions@v5
|
||||
# with:
|
||||
# package-name: "myaspnetcoreapp"
|
||||
# package-type: container
|
||||
# min-versions-to-keep: 3
|
||||
# token: ${{secrets.GITHUB_TOKEN}}
|
||||
@@ -0,0 +1,213 @@
|
||||
name: Blazor (with Reporting) - Docker
|
||||
|
||||
on:
|
||||
workflow_dispatch:
|
||||
push:
|
||||
branches:
|
||||
- main
|
||||
paths:
|
||||
- 'src/Blazor/**/*'
|
||||
|
||||
env:
|
||||
DOTNET_VERSION: "10.0.x"
|
||||
BLAZOR_PROJ_PATH: src/Blazor/MyBlazorApp/MyBlazorApp.csproj
|
||||
NUGET_CONFIG_PATH: src/NuGet.Config
|
||||
CONTAINER_REPOSITORY: "lancemccarthy/myblazorapp"
|
||||
|
||||
# For ghcr.io access
|
||||
permissions:
|
||||
contents: read
|
||||
packages: write
|
||||
|
||||
jobs:
|
||||
#################### Example 1 ##########################
|
||||
# Dockerfile build and publish to Docker Hub
|
||||
# - Webook to automatically redeploy stack in Portainer
|
||||
#########################################################
|
||||
dockerfile_to_dockerhub:
|
||||
name: "Dockerfile Build and Publish"
|
||||
runs-on: ubuntu-latest
|
||||
env:
|
||||
CONTAINER_REGISTRY: "docker.io"
|
||||
steps:
|
||||
- name: Checkout
|
||||
uses: actions/checkout@v6
|
||||
|
||||
- name: Generate tag version
|
||||
id: tag-creator
|
||||
run: |
|
||||
buildDay=`date +%Y.%m.%d`
|
||||
tags="$buildDay.$GITHUB_RUN_NUMBER"
|
||||
echo "VERSION_TAG=$tags" >> $GITHUB_OUTPUT
|
||||
|
||||
- name: Set up QEMU
|
||||
uses: docker/setup-qemu-action@v3
|
||||
|
||||
- name: Set up Docker Buildx
|
||||
uses: docker/setup-buildx-action@v3
|
||||
|
||||
- name: Get package metadata from Docker Hub
|
||||
id: meta
|
||||
uses: docker/metadata-action@v5
|
||||
with:
|
||||
images: ${{env.CONTAINER_REGISTRY}}/${{env.CONTAINER_REPOSITORY}}
|
||||
|
||||
- name: Login to DockerHub
|
||||
uses: docker/login-action@v3
|
||||
with:
|
||||
username: ${{secrets.DOCKER_HUB_USERNAME}}
|
||||
password: ${{secrets.DOCKER_HUB_PAT}}
|
||||
|
||||
- name: Build and Publish arm64, amd64 Container Images
|
||||
uses: docker/build-push-action@v5
|
||||
with:
|
||||
context: src/Blazor/MyBlazorApp
|
||||
platforms: linux/arm64,linux/amd64
|
||||
push: true
|
||||
secrets: |
|
||||
telerik-nuget-key=${{secrets.TELERIK_NUGET_KEY}}
|
||||
telerik-license-key=${{secrets.TELERIK_LICENSE_KEY}}
|
||||
tags: ${{steps.meta.outputs.tags}}
|
||||
|
||||
# Required because actions/delete-package-versions@v5 does not work with Docker Hub
|
||||
- name: Delete old (untagged) images
|
||||
run: |
|
||||
IMAGE_TAGS=$(curl -s "https://hub.docker.com/v2/repositories/${{env.CONTAINER_REPOSITORY}}/tags/?page_size=100" | jq -r '.results|.[]|.name')
|
||||
for TAGG in $IMAGE_TAGS; do
|
||||
if [[ "$TAGG" == "null" ]]; then
|
||||
docker rmi "${{env.CONTAINER_REPOSITORY}}:$TAGG"
|
||||
curl -s -X DELETE "https://hub.docker.com/v2/repositories/${{env.CONTAINER_REPOSITORY}}/tags/$TAGG/"
|
||||
fi
|
||||
done
|
||||
|
||||
- name: Trigger Portainer to pull images and redeploy the stack
|
||||
run: curl -X POST ${{secrets.PORTAINER_WEBHOOK_BLAZOR}}
|
||||
|
||||
|
||||
#################### Example 2 ##########################
|
||||
# .NET SDK build and publish to ghcr.io
|
||||
############################################################
|
||||
|
||||
# # 2.1 - Build the lancemccarthy/myblazorapp:latest-x64 image
|
||||
# build_x64:
|
||||
# runs-on: ubuntu-latest
|
||||
# name: "[NET SDK] Create x64 image"
|
||||
# outputs:
|
||||
# build_tag: ${{steps.build.outputs.build_tag}}
|
||||
# env:
|
||||
# target_arch: "x64"
|
||||
# CONTAINER_REGISTRY: "ghcr.io"
|
||||
# CONTAINER_BASE_IMAGE: "docker.io/lancemccarthy/skia-aspnet:10.0"
|
||||
# steps:
|
||||
# - name: Checkout
|
||||
# uses: actions/checkout@v6
|
||||
# with:
|
||||
# fetch-depth: 0
|
||||
|
||||
# - name: Setup .NET Core SDK
|
||||
# uses: actions/setup-dotnet@v4
|
||||
# with:
|
||||
# dotnet-version: ${{env.DOTNET_VERSION}}
|
||||
|
||||
# # Needed because dotnet publish -t:PublishContainer uses the CLI (not docker/login-action@v3)
|
||||
# - name: Login to ghcr.io
|
||||
# run: docker login ${{env.CONTAINER_REGISTRY}} -u ${{github.actor}} -p ${{secrets.GITHUB_TOKEN}}
|
||||
|
||||
# - name: Restore NuGet Packages
|
||||
# run: dotnet restore ${{env.BLAZOR_PROJ_PATH}} -r "linux-${{env.target_arch}}"
|
||||
# env:
|
||||
# TELERIK_USERNAME: "api-key"
|
||||
# TELERIK_PASSWORD: ${{secrets.TELERIK_NUGET_KEY}}
|
||||
|
||||
# - name: build the x64 image
|
||||
# id: build
|
||||
# run: |
|
||||
# TAG="latest-${{env.target_arch}}"
|
||||
# dotnet publish ${{env.BLAZOR_PROJ_PATH}} \
|
||||
# -t:PublishContainer \
|
||||
# -p PublishProfile=DefaultContainer \
|
||||
# -p ContainerBaseImage=${{env.CONTAINER_BASE_IMAGE}} \
|
||||
# -p ContainerRegistry="${{env.CONTAINER_REGISTRY}}" \
|
||||
# -p ContainerRepository="${{env.CONTAINER_REPOSITORY}}" \
|
||||
# -p ContainerImageTag="$TAG" \
|
||||
# --arch ${{env.target_arch}} \
|
||||
# --no-restore
|
||||
# echo "build_tag=$TAG" >> $GITHUB_OUTPUT
|
||||
# env:
|
||||
# TELERIK_LICENSE: ${{secrets.TELERIK_LICENSE_KEY}}
|
||||
|
||||
# # Builds the lancemccarthy/myblazorapp:latest-arm64 image
|
||||
# build_arm64:
|
||||
# name: "[NET SDK] Create arm64 image"
|
||||
# runs-on: ubuntu-latest
|
||||
# outputs:
|
||||
# build_tag: ${{steps.build.outputs.build_tag}}
|
||||
# env:
|
||||
# target_arch: "arm64"
|
||||
# CONTAINER_REGISTRY: "ghcr.io"
|
||||
# CONTAINER_BASE_IMAGE: "docker.io/lancemccarthy/skia-aspnet:10.0"
|
||||
# steps:
|
||||
# - name: Checkout
|
||||
# uses: actions/checkout@v4
|
||||
# with:
|
||||
# fetch-depth: 0
|
||||
|
||||
# - name: Setup .NET Core SDK
|
||||
# uses: actions/setup-dotnet@v4
|
||||
# with:
|
||||
# dotnet-version: ${{env.DOTNET_VERSION}}
|
||||
|
||||
# # Needed because dotnet publish -t:PublishContainer uses the CLI (not docker/login-action@v3)
|
||||
# - name: Login to ghcr.io
|
||||
# run: docker login ${{env.CONTAINER_REGISTRY}} -u ${{github.actor}} -p ${{secrets.GITHUB_TOKEN}}
|
||||
|
||||
# - name: Restore NuGet Packages
|
||||
# run: dotnet restore ${{env.BLAZOR_PROJ_PATH}} -r "linux-${{env.target_arch}}"
|
||||
# env:
|
||||
# TELERIK_USERNAME: "api-key"
|
||||
# TELERIK_PASSWORD: ${{secrets.TELERIK_NUGET_KEY}}
|
||||
|
||||
# - name: build the arm64 image
|
||||
# id: build
|
||||
# run: |
|
||||
# TAG="latest-${{env.target_arch}}"
|
||||
# dotnet publish ${{env.BLAZOR_PROJ_PATH}} \
|
||||
# -t:PublishContainer \
|
||||
# -p PublishProfile=DefaultContainer \
|
||||
# -p ContainerBaseImage=${{env.CONTAINER_BASE_IMAGE}} \
|
||||
# -p ContainerRegistry="${{env.CONTAINER_REGISTRY}}" \
|
||||
# -p ContainerRepository="${{env.CONTAINER_REPOSITORY}}" \
|
||||
# -p ContainerImageTag="$TAG" \
|
||||
# --arch ${{env.target_arch}} \
|
||||
# --no-restore
|
||||
# echo "build_tag=$TAG" >> $GITHUB_OUTPUT
|
||||
# env:
|
||||
# TELERIK_LICENSE: ${{secrets.TELERIK_LICENSE_KEY}}
|
||||
|
||||
# # Create a manifest to combine both images into a single "lancemccarthy/myblazorapp:latest" tag
|
||||
# publish_combined_manifest:
|
||||
# runs-on: ubuntu-latest
|
||||
# name: "[NET SDK] Publish multi-arch manifest"
|
||||
# needs: [build_x64, build_arm64]
|
||||
# env:
|
||||
# CONTAINER_REGISTRY: "ghcr.io"
|
||||
# steps:
|
||||
# - name: Checkout
|
||||
# uses: actions/checkout@v4
|
||||
|
||||
# - name: Login to ghcr.io
|
||||
# run: docker login ${{env.CONTAINER_REGISTRY}} -u ${{github.actor}} -p ${{secrets.GITHUB_TOKEN}}
|
||||
|
||||
# - name: Create multi-arch manifest
|
||||
# run: docker manifest create "${{env.CONTAINER_REPOSITORY}}:latest" "${{env.CONTAINER_REPOSITORY}}:${{needs.build_x64.outputs.build_tag}}" "${{env.CONTAINER_REPOSITORY}}:${{needs.build_arm64.outputs.build_tag}}"
|
||||
|
||||
# - name: Push multi-arch manifest
|
||||
# run: docker manifest push "${{env.CONTAINER_REPOSITORY}}:latest"
|
||||
|
||||
# - name: Delete old images
|
||||
# uses: actions/delete-package-versions@v5
|
||||
# with:
|
||||
# package-name: "myblazorapp"
|
||||
# package-type: container
|
||||
# min-versions-to-keep: 2
|
||||
# token: ${{secrets.GITHUB_TOKEN}}
|
||||
@@ -1,402 +1,359 @@
|
||||
# ---> VisualStudio
|
||||
## Ignore Visual Studio temporary files, build results, and
|
||||
## files generated by popular Visual Studio add-ons.
|
||||
##
|
||||
## Get latest from https://github.com/github/gitignore/blob/main/VisualStudio.gitignore
|
||||
|
||||
# User-specific files
|
||||
*.rsuser
|
||||
*.suo
|
||||
*.user
|
||||
*.userosscache
|
||||
*.sln.docstates
|
||||
|
||||
# User-specific files (MonoDevelop/Xamarin Studio)
|
||||
*.userprefs
|
||||
|
||||
# Mono auto generated files
|
||||
mono_crash.*
|
||||
|
||||
# Build results
|
||||
[Dd]ebug/
|
||||
[Dd]ebugPublic/
|
||||
[Rr]elease/
|
||||
[Rr]eleases/
|
||||
x64/
|
||||
x86/
|
||||
[Ww][Ii][Nn]32/
|
||||
[Aa][Rr][Mm]/
|
||||
[Aa][Rr][Mm]64/
|
||||
bld/
|
||||
[Bb]in/
|
||||
[Oo]bj/
|
||||
[Ll]og/
|
||||
[Ll]ogs/
|
||||
|
||||
# Visual Studio 2015/2017 cache/options directory
|
||||
.vs/
|
||||
# Uncomment if you have tasks that create the project's static files in wwwroot
|
||||
#wwwroot/
|
||||
|
||||
# Visual Studio 2017 auto generated files
|
||||
Generated\ Files/
|
||||
|
||||
# MSTest test Results
|
||||
[Tt]est[Rr]esult*/
|
||||
[Bb]uild[Ll]og.*
|
||||
|
||||
# NUnit
|
||||
*.VisualState.xml
|
||||
TestResult.xml
|
||||
nunit-*.xml
|
||||
|
||||
# Build Results of an ATL Project
|
||||
[Dd]ebugPS/
|
||||
[Rr]eleasePS/
|
||||
dlldata.c
|
||||
|
||||
# Benchmark Results
|
||||
BenchmarkDotNet.Artifacts/
|
||||
|
||||
# .NET Core
|
||||
project.lock.json
|
||||
project.fragment.lock.json
|
||||
artifacts/
|
||||
|
||||
# ASP.NET Scaffolding
|
||||
ScaffoldingReadMe.txt
|
||||
|
||||
# StyleCop
|
||||
StyleCopReport.xml
|
||||
|
||||
# Files built by Visual Studio
|
||||
*_i.c
|
||||
*_p.c
|
||||
*_h.h
|
||||
*.ilk
|
||||
*.meta
|
||||
*.obj
|
||||
*.iobj
|
||||
*.pch
|
||||
*.pdb
|
||||
*.ipdb
|
||||
*.pgc
|
||||
*.pgd
|
||||
*.rsp
|
||||
# but not Directory.Build.rsp, as it configures directory-level build defaults
|
||||
!Directory.Build.rsp
|
||||
*.sbr
|
||||
*.tlb
|
||||
*.tli
|
||||
*.tlh
|
||||
*.tmp
|
||||
*.tmp_proj
|
||||
*_wpftmp.csproj
|
||||
*.log
|
||||
*.tlog
|
||||
*.vspscc
|
||||
*.vssscc
|
||||
.builds
|
||||
*.pidb
|
||||
*.svclog
|
||||
*.scc
|
||||
|
||||
# Chutzpah Test files
|
||||
_Chutzpah*
|
||||
|
||||
# Visual C++ cache files
|
||||
ipch/
|
||||
*.aps
|
||||
*.ncb
|
||||
*.opendb
|
||||
*.opensdf
|
||||
*.sdf
|
||||
*.cachefile
|
||||
*.VC.db
|
||||
*.VC.VC.opendb
|
||||
|
||||
# Visual Studio profiler
|
||||
*.psess
|
||||
*.vsp
|
||||
*.vspx
|
||||
*.sap
|
||||
|
||||
# Visual Studio Trace Files
|
||||
*.e2e
|
||||
|
||||
# TFS 2012 Local Workspace
|
||||
$tf/
|
||||
|
||||
# Guidance Automation Toolkit
|
||||
*.gpState
|
||||
|
||||
# ReSharper is a .NET coding add-in
|
||||
_ReSharper*/
|
||||
*.[Rr]e[Ss]harper
|
||||
*.DotSettings.user
|
||||
|
||||
# TeamCity is a build add-in
|
||||
_TeamCity*
|
||||
|
||||
# DotCover is a Code Coverage Tool
|
||||
*.dotCover
|
||||
|
||||
# AxoCover is a Code Coverage Tool
|
||||
.axoCover/*
|
||||
!.axoCover/settings.json
|
||||
|
||||
# Coverlet is a free, cross platform Code Coverage Tool
|
||||
coverage*.json
|
||||
coverage*.xml
|
||||
coverage*.info
|
||||
|
||||
# Visual Studio code coverage results
|
||||
*.coverage
|
||||
*.coveragexml
|
||||
|
||||
# NCrunch
|
||||
_NCrunch_*
|
||||
.*crunch*.local.xml
|
||||
nCrunchTemp_*
|
||||
|
||||
# MightyMoose
|
||||
*.mm.*
|
||||
AutoTest.Net/
|
||||
|
||||
# Web workbench (sass)
|
||||
.sass-cache/
|
||||
|
||||
# Installshield output folder
|
||||
[Ee]xpress/
|
||||
|
||||
# DocProject is a documentation generator add-in
|
||||
DocProject/buildhelp/
|
||||
DocProject/Help/*.HxT
|
||||
DocProject/Help/*.HxC
|
||||
DocProject/Help/*.hhc
|
||||
DocProject/Help/*.hhk
|
||||
DocProject/Help/*.hhp
|
||||
DocProject/Help/Html2
|
||||
DocProject/Help/html
|
||||
|
||||
# Click-Once directory
|
||||
publish/
|
||||
|
||||
# Publish Web Output
|
||||
*.[Pp]ublish.xml
|
||||
*.azurePubxml
|
||||
# Note: Comment the next line if you want to checkin your web deploy settings,
|
||||
# but database connection strings (with potential passwords) will be unencrypted
|
||||
*.pubxml
|
||||
*.publishproj
|
||||
|
||||
# Microsoft Azure Web App publish settings. Comment the next line if you want to
|
||||
# checkin your Azure Web App publish settings, but sensitive information contained
|
||||
# in these scripts will be unencrypted
|
||||
PublishScripts/
|
||||
|
||||
# NuGet Packages
|
||||
*.nupkg
|
||||
# NuGet Symbol Packages
|
||||
*.snupkg
|
||||
# The packages folder can be ignored because of Package Restore
|
||||
**/[Pp]ackages/*
|
||||
# except build/, which is used as an MSBuild target.
|
||||
!**/[Pp]ackages/build/
|
||||
# Uncomment if necessary however generally it will be regenerated when needed
|
||||
#!**/[Pp]ackages/repositories.config
|
||||
# NuGet v3's project.json files produces more ignorable files
|
||||
*.nuget.props
|
||||
*.nuget.targets
|
||||
|
||||
# Microsoft Azure Build Output
|
||||
csx/
|
||||
*.build.csdef
|
||||
|
||||
# Microsoft Azure Emulator
|
||||
ecf/
|
||||
rcf/
|
||||
|
||||
# Windows Store app package directories and files
|
||||
AppPackages/
|
||||
BundleArtifacts/
|
||||
Package.StoreAssociation.xml
|
||||
_pkginfo.txt
|
||||
*.appx
|
||||
*.appxbundle
|
||||
*.appxupload
|
||||
|
||||
# Visual Studio cache files
|
||||
# files ending in .cache can be ignored
|
||||
*.[Cc]ache
|
||||
# but keep track of directories ending in .cache
|
||||
!?*.[Cc]ache/
|
||||
|
||||
# Others
|
||||
ClientBin/
|
||||
~$*
|
||||
*~
|
||||
*.dbmdl
|
||||
*.dbproj.schemaview
|
||||
*.jfm
|
||||
*.pfx
|
||||
*.publishsettings
|
||||
orleans.codegen.cs
|
||||
|
||||
# Including strong name files can present a security risk
|
||||
# (https://github.com/github/gitignore/pull/2483#issue-259490424)
|
||||
#*.snk
|
||||
|
||||
# Since there are multiple workflows, uncomment next line to ignore bower_components
|
||||
# (https://github.com/github/gitignore/pull/1529#issuecomment-104372622)
|
||||
#bower_components/
|
||||
|
||||
# RIA/Silverlight projects
|
||||
Generated_Code/
|
||||
|
||||
# Backup & report files from converting an old project file
|
||||
# to a newer Visual Studio version. Backup files are not needed,
|
||||
# because we have git ;-)
|
||||
_UpgradeReport_Files/
|
||||
Backup*/
|
||||
UpgradeLog*.XML
|
||||
UpgradeLog*.htm
|
||||
ServiceFabricBackup/
|
||||
*.rptproj.bak
|
||||
|
||||
# SQL Server files
|
||||
*.mdf
|
||||
*.ldf
|
||||
*.ndf
|
||||
|
||||
# Business Intelligence projects
|
||||
*.rdl.data
|
||||
*.bim.layout
|
||||
*.bim_*.settings
|
||||
*.rptproj.rsuser
|
||||
*- [Bb]ackup.rdl
|
||||
*- [Bb]ackup ([0-9]).rdl
|
||||
*- [Bb]ackup ([0-9][0-9]).rdl
|
||||
|
||||
# Microsoft Fakes
|
||||
FakesAssemblies/
|
||||
|
||||
# GhostDoc plugin setting file
|
||||
*.GhostDoc.xml
|
||||
|
||||
# Node.js Tools for Visual Studio
|
||||
.ntvs_analysis.dat
|
||||
node_modules/
|
||||
|
||||
# Visual Studio 6 build log
|
||||
*.plg
|
||||
|
||||
# Visual Studio 6 workspace options file
|
||||
*.opt
|
||||
|
||||
# Visual Studio 6 auto-generated workspace file (contains which files were open etc.)
|
||||
*.vbw
|
||||
|
||||
# Visual Studio 6 auto-generated project file (contains which files were open etc.)
|
||||
*.vbp
|
||||
|
||||
# Visual Studio 6 workspace and project file (working project files containing files to include in project)
|
||||
*.dsw
|
||||
*.dsp
|
||||
|
||||
# Visual Studio 6 technical files
|
||||
*.ncb
|
||||
*.aps
|
||||
|
||||
# Visual Studio LightSwitch build output
|
||||
**/*.HTMLClient/GeneratedArtifacts
|
||||
**/*.DesktopClient/GeneratedArtifacts
|
||||
**/*.DesktopClient/ModelManifest.xml
|
||||
**/*.Server/GeneratedArtifacts
|
||||
**/*.Server/ModelManifest.xml
|
||||
_Pvt_Extensions
|
||||
|
||||
# Paket dependency manager
|
||||
.paket/paket.exe
|
||||
paket-files/
|
||||
|
||||
# FAKE - F# Make
|
||||
.fake/
|
||||
|
||||
# CodeRush personal settings
|
||||
.cr/personal
|
||||
|
||||
# Python Tools for Visual Studio (PTVS)
|
||||
__pycache__/
|
||||
*.pyc
|
||||
|
||||
# Cake - Uncomment if you are using it
|
||||
# tools/**
|
||||
# !tools/packages.config
|
||||
|
||||
# Tabs Studio
|
||||
*.tss
|
||||
|
||||
# Telerik's JustMock configuration file
|
||||
*.jmconfig
|
||||
|
||||
# BizTalk build output
|
||||
*.btp.cs
|
||||
*.btm.cs
|
||||
*.odx.cs
|
||||
*.xsd.cs
|
||||
|
||||
# OpenCover UI analysis results
|
||||
OpenCover/
|
||||
|
||||
# Azure Stream Analytics local run output
|
||||
ASALocalRun/
|
||||
|
||||
# MSBuild Binary and Structured Log
|
||||
*.binlog
|
||||
|
||||
# NVidia Nsight GPU debugger configuration file
|
||||
*.nvuser
|
||||
|
||||
# MFractors (Xamarin productivity tool) working folder
|
||||
.mfractor/
|
||||
|
||||
# Local History for Visual Studio
|
||||
.localhistory/
|
||||
|
||||
# Visual Studio History (VSHistory) files
|
||||
.vshistory/
|
||||
|
||||
# BeatPulse healthcheck temp database
|
||||
healthchecksdb
|
||||
|
||||
# Backup folder for Package Reference Convert tool in Visual Studio 2017
|
||||
MigrationBackup/
|
||||
|
||||
# Ionide (cross platform F# VS Code tools) working folder
|
||||
.ionide/
|
||||
|
||||
# Fody - auto-generated XML schema
|
||||
FodyWeavers.xsd
|
||||
|
||||
# VS Code files for those working on multiple tools
|
||||
.vscode/*
|
||||
!.vscode/settings.json
|
||||
!.vscode/tasks.json
|
||||
!.vscode/launch.json
|
||||
!.vscode/extensions.json
|
||||
*.code-workspace
|
||||
|
||||
# Local History for Visual Studio Code
|
||||
.history/
|
||||
|
||||
# Windows Installer files from build outputs
|
||||
*.cab
|
||||
*.msi
|
||||
*.msix
|
||||
*.msm
|
||||
*.msp
|
||||
|
||||
# JetBrains Rider
|
||||
*.sln.iml
|
||||
|
||||
## Ignore Visual Studio temporary files, build results, and
|
||||
## files generated by popular Visual Studio add-ons.
|
||||
##
|
||||
## Get latest from https://github.com/github/gitignore/blob/master/VisualStudio.gitignore
|
||||
|
||||
# User-specific files
|
||||
*.rsuser
|
||||
*.suo
|
||||
*.user
|
||||
*.userosscache
|
||||
*.sln.docstates
|
||||
|
||||
# User-specific files (MonoDevelop/Xamarin Studio)
|
||||
*.userprefs
|
||||
|
||||
# Angular cache
|
||||
.angular/
|
||||
|
||||
# Mono auto generated files
|
||||
mono_crash.*
|
||||
|
||||
# Build results
|
||||
[Dd]ebug/
|
||||
[Dd]ebugPublic/
|
||||
[Rr]elease/
|
||||
[Rr]eleases/
|
||||
x64/
|
||||
x86/
|
||||
[Aa][Rr][Mm]/
|
||||
[Aa][Rr][Mm]64/
|
||||
bld/
|
||||
[Bb]in/
|
||||
[Oo]bj/
|
||||
[Ll]og/
|
||||
[Ll]ogs/
|
||||
|
||||
# Visual Studio 2015/2017 cache/options directory
|
||||
.vs/
|
||||
# Uncomment if you have tasks that create the project's static files in wwwroot
|
||||
#wwwroot/
|
||||
|
||||
# Visual Studio 2017 auto generated files
|
||||
Generated\ Files/
|
||||
|
||||
# MSTest test Results
|
||||
[Tt]est[Rr]esult*/
|
||||
[Bb]uild[Ll]og.*
|
||||
|
||||
# NUnit
|
||||
*.VisualState.xml
|
||||
TestResult.xml
|
||||
nunit-*.xml
|
||||
|
||||
# Build Results of an ATL Project
|
||||
[Dd]ebugPS/
|
||||
[Rr]eleasePS/
|
||||
dlldata.c
|
||||
|
||||
# Benchmark Results
|
||||
BenchmarkDotNet.Artifacts/
|
||||
|
||||
# .NET Core
|
||||
project.lock.json
|
||||
project.fragment.lock.json
|
||||
artifacts/
|
||||
|
||||
# StyleCop
|
||||
StyleCopReport.xml
|
||||
|
||||
# Files built by Visual Studio
|
||||
*_i.c
|
||||
*_p.c
|
||||
*_h.h
|
||||
*.ilk
|
||||
*.meta
|
||||
*.obj
|
||||
*.iobj
|
||||
*.pch
|
||||
*.pdb
|
||||
*.ipdb
|
||||
*.pgc
|
||||
*.pgd
|
||||
*.rsp
|
||||
*.sbr
|
||||
*.tlb
|
||||
*.tli
|
||||
*.tlh
|
||||
*.tmp
|
||||
*.tmp_proj
|
||||
*_wpftmp.csproj
|
||||
*.log
|
||||
*.vspscc
|
||||
*.vssscc
|
||||
.builds
|
||||
*.pidb
|
||||
*.svclog
|
||||
*.scc
|
||||
|
||||
# Chutzpah Test files
|
||||
_Chutzpah*
|
||||
|
||||
# Visual C++ cache files
|
||||
ipch/
|
||||
*.aps
|
||||
*.ncb
|
||||
*.opendb
|
||||
*.opensdf
|
||||
*.sdf
|
||||
*.cachefile
|
||||
*.VC.db
|
||||
*.VC.VC.opendb
|
||||
|
||||
# Visual Studio profiler
|
||||
*.psess
|
||||
*.vsp
|
||||
*.vspx
|
||||
*.sap
|
||||
|
||||
# Visual Studio Trace Files
|
||||
*.e2e
|
||||
|
||||
# TFS 2012 Local Workspace
|
||||
$tf/
|
||||
|
||||
# Guidance Automation Toolkit
|
||||
*.gpState
|
||||
|
||||
# ReSharper is a .NET coding add-in
|
||||
_ReSharper*/
|
||||
*.[Rr]e[Ss]harper
|
||||
*.DotSettings.user
|
||||
|
||||
# TeamCity is a build add-in
|
||||
_TeamCity*
|
||||
|
||||
# DotCover is a Code Coverage Tool
|
||||
*.dotCover
|
||||
|
||||
# AxoCover is a Code Coverage Tool
|
||||
.axoCover/*
|
||||
!.axoCover/settings.json
|
||||
|
||||
# Visual Studio code coverage results
|
||||
*.coverage
|
||||
*.coveragexml
|
||||
|
||||
# NCrunch
|
||||
_NCrunch_*
|
||||
.*crunch*.local.xml
|
||||
nCrunchTemp_*
|
||||
|
||||
# MightyMoose
|
||||
*.mm.*
|
||||
AutoTest.Net/
|
||||
|
||||
# Web workbench (sass)
|
||||
.sass-cache/
|
||||
|
||||
# Installshield output folder
|
||||
[Ee]xpress/
|
||||
|
||||
# DocProject is a documentation generator add-in
|
||||
DocProject/buildhelp/
|
||||
DocProject/Help/*.HxT
|
||||
DocProject/Help/*.HxC
|
||||
DocProject/Help/*.hhc
|
||||
DocProject/Help/*.hhk
|
||||
DocProject/Help/*.hhp
|
||||
DocProject/Help/Html2
|
||||
DocProject/Help/html
|
||||
|
||||
# Click-Once directory
|
||||
publish/
|
||||
|
||||
# Publish Web Output
|
||||
*.[Pp]ublish.xml
|
||||
*.azurePubxml
|
||||
# Note: Comment the next line if you want to checkin your web deploy settings,
|
||||
# but database connection strings (with potential passwords) will be unencrypted
|
||||
*.pubxml
|
||||
*.publishproj
|
||||
|
||||
# Microsoft Azure Web App publish settings. Comment the next line if you want to
|
||||
# checkin your Azure Web App publish settings, but sensitive information contained
|
||||
# in these scripts will be unencrypted
|
||||
PublishScripts/
|
||||
|
||||
# NuGet Packages
|
||||
*.nupkg
|
||||
# NuGet Symbol Packages
|
||||
*.snupkg
|
||||
# The packages folder can be ignored because of Package Restore
|
||||
**/[Pp]ackages/*
|
||||
# except build/, which is used as an MSBuild target.
|
||||
!**/[Pp]ackages/build/
|
||||
# Uncomment if necessary however generally it will be regenerated when needed
|
||||
#!**/[Pp]ackages/repositories.config
|
||||
# NuGet v3's project.json files produces more ignorable files
|
||||
*.nuget.props
|
||||
*.nuget.targets
|
||||
|
||||
# Microsoft Azure Build Output
|
||||
csx/
|
||||
*.build.csdef
|
||||
|
||||
# Microsoft Azure Emulator
|
||||
ecf/
|
||||
rcf/
|
||||
|
||||
# Windows Store app package directories and files
|
||||
AppPackages/
|
||||
BundleArtifacts/
|
||||
Package.StoreAssociation.xml
|
||||
_pkginfo.txt
|
||||
*.appx
|
||||
*.appxbundle
|
||||
*.appxupload
|
||||
|
||||
# Visual Studio cache files
|
||||
# files ending in .cache can be ignored
|
||||
*.[Cc]ache
|
||||
# but keep track of directories ending in .cache
|
||||
!?*.[Cc]ache/
|
||||
|
||||
# Others
|
||||
ClientBin/
|
||||
~$*
|
||||
*~
|
||||
*.dbmdl
|
||||
*.dbproj.schemaview
|
||||
*.jfm
|
||||
*.pfx
|
||||
*.publishsettings
|
||||
orleans.codegen.cs
|
||||
|
||||
# Including strong name files can present a security risk
|
||||
# (https://github.com/github/gitignore/pull/2483#issue-259490424)
|
||||
#*.snk
|
||||
|
||||
# Since there are multiple workflows, uncomment next line to ignore bower_components
|
||||
# (https://github.com/github/gitignore/pull/1529#issuecomment-104372622)
|
||||
#bower_components/
|
||||
|
||||
# RIA/Silverlight projects
|
||||
Generated_Code/
|
||||
|
||||
# Backup & report files from converting an old project file
|
||||
# to a newer Visual Studio version. Backup files are not needed,
|
||||
# because we have git ;-)
|
||||
_UpgradeReport_Files/
|
||||
Backup*/
|
||||
UpgradeLog*.XML
|
||||
UpgradeLog*.htm
|
||||
ServiceFabricBackup/
|
||||
*.rptproj.bak
|
||||
|
||||
# SQL Server files
|
||||
*.mdf
|
||||
*.ldf
|
||||
*.ndf
|
||||
|
||||
# Business Intelligence projects
|
||||
*.rdl.data
|
||||
*.bim.layout
|
||||
*.bim_*.settings
|
||||
*.rptproj.rsuser
|
||||
*- [Bb]ackup.rdl
|
||||
*- [Bb]ackup ([0-9]).rdl
|
||||
*- [Bb]ackup ([0-9][0-9]).rdl
|
||||
|
||||
# Microsoft Fakes
|
||||
FakesAssemblies/
|
||||
|
||||
# GhostDoc plugin setting file
|
||||
*.GhostDoc.xml
|
||||
|
||||
# Node.js Tools for Visual Studio
|
||||
.ntvs_analysis.dat
|
||||
node_modules/
|
||||
|
||||
# Visual Studio 6 build log
|
||||
*.plg
|
||||
|
||||
# Visual Studio 6 workspace options file
|
||||
*.opt
|
||||
|
||||
# Visual Studio 6 auto-generated workspace file (contains which files were open etc.)
|
||||
*.vbw
|
||||
|
||||
# Visual Studio LightSwitch build output
|
||||
**/*.HTMLClient/GeneratedArtifacts
|
||||
**/*.DesktopClient/GeneratedArtifacts
|
||||
**/*.DesktopClient/ModelManifest.xml
|
||||
**/*.Server/GeneratedArtifacts
|
||||
**/*.Server/ModelManifest.xml
|
||||
_Pvt_Extensions
|
||||
|
||||
# Paket dependency manager
|
||||
.paket/paket.exe
|
||||
paket-files/
|
||||
|
||||
# FAKE - F# Make
|
||||
.fake/
|
||||
|
||||
# CodeRush personal settings
|
||||
.cr/personal
|
||||
|
||||
# Python Tools for Visual Studio (PTVS)
|
||||
__pycache__/
|
||||
*.pyc
|
||||
|
||||
# Cake - Uncomment if you are using it
|
||||
# tools/**
|
||||
# !tools/packages.config
|
||||
|
||||
# Tabs Studio
|
||||
*.tss
|
||||
|
||||
# Telerik's JustMock configuration file
|
||||
*.jmconfig
|
||||
|
||||
# BizTalk build output
|
||||
*.btp.cs
|
||||
*.btm.cs
|
||||
*.odx.cs
|
||||
*.xsd.cs
|
||||
|
||||
# OpenCover UI analysis results
|
||||
OpenCover/
|
||||
|
||||
# Azure Stream Analytics local run output
|
||||
ASALocalRun/
|
||||
|
||||
# MSBuild Binary and Structured Log
|
||||
*.binlog
|
||||
|
||||
# NVidia Nsight GPU debugger configuration file
|
||||
*.nvuser
|
||||
|
||||
# Local History for Visual Studio
|
||||
.localhistory/
|
||||
|
||||
# BeatPulse healthcheck temp database
|
||||
healthchecksdb
|
||||
|
||||
# Backup folder for Package Reference Convert tool in Visual Studio 2017
|
||||
MigrationBackup/
|
||||
|
||||
# Ionide (cross platform F# VS Code tools) working folder
|
||||
.ionide/
|
||||
|
||||
# macoOS
|
||||
.DS_Store
|
||||
|
||||
# Any generated license data
|
||||
src/AspNetCore/MyAspNetCoreApp/wwwroot/js/kendo-ui-license.js
|
||||
|
||||
# Jetbrains Rider
|
||||
.idea
|
||||
|
||||
@@ -0,0 +1,33 @@
|
||||
{
|
||||
// Use IntelliSense to learn about possible attributes.
|
||||
// Hover to view descriptions of existing attributes.
|
||||
// For more information, visit: https://go.microsoft.com/fwlink/?linkid=830387
|
||||
"version": "0.2.0",
|
||||
"configurations": [
|
||||
{
|
||||
"name": ".NET Core Launch (web)",
|
||||
"type": "coreclr",
|
||||
"request": "launch",
|
||||
"preLaunchTask": "build",
|
||||
"program": "${workspaceFolder}/src/Blazor/MyBlazorApp/bin/Debug/net7.0/MyBlazorApp.dll",
|
||||
"args": [],
|
||||
"cwd": "${workspaceFolder}/src/Blazor/MyBlazorApp",
|
||||
"stopAtEntry": false,
|
||||
"serverReadyAction": {
|
||||
"action": "openExternally",
|
||||
"pattern": "\\bNow listening on:\\s+(https?://\\S+)"
|
||||
},
|
||||
"env": {
|
||||
"ASPNETCORE_ENVIRONMENT": "Development"
|
||||
},
|
||||
"sourceFileMap": {
|
||||
"/Views": "${workspaceFolder}/Views"
|
||||
}
|
||||
},
|
||||
{
|
||||
"name": ".NET Core Attach",
|
||||
"type": "coreclr",
|
||||
"request": "attach"
|
||||
}
|
||||
]
|
||||
}
|
||||
@@ -0,0 +1,41 @@
|
||||
{
|
||||
"version": "2.0.0",
|
||||
"tasks": [
|
||||
{
|
||||
"label": "build blazor",
|
||||
"command": "dotnet",
|
||||
"type": "process",
|
||||
"args": [
|
||||
"build",
|
||||
"${workspaceFolder}/src/Blazor/MyBlazorApp.sln",
|
||||
"/property:GenerateFullPaths=true",
|
||||
"/consoleloggerparameters:NoSummary"
|
||||
],
|
||||
"problemMatcher": "$msCompile"
|
||||
},
|
||||
{
|
||||
"label": "publish blazor",
|
||||
"command": "dotnet",
|
||||
"type": "process",
|
||||
"args": [
|
||||
"publish",
|
||||
"${workspaceFolder}/src/Blazor/MyBlazorApp.sln",
|
||||
"/property:GenerateFullPaths=true",
|
||||
"/consoleloggerparameters:NoSummary"
|
||||
],
|
||||
"problemMatcher": "$msCompile"
|
||||
},
|
||||
{
|
||||
"label": "watch blazor",
|
||||
"command": "dotnet",
|
||||
"type": "process",
|
||||
"args": [
|
||||
"watch",
|
||||
"run",
|
||||
"--project",
|
||||
"${workspaceFolder}/src/Blazor/MyBlazorApp.sln"
|
||||
],
|
||||
"problemMatcher": "$msCompile"
|
||||
}
|
||||
]
|
||||
}
|
||||
@@ -0,0 +1,21 @@
|
||||
MIT License
|
||||
|
||||
Copyright (c) 2020 Lance McCarthy
|
||||
|
||||
Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||
of this software and associated documentation files (the "Software"), to deal
|
||||
in the Software without restriction, including without limitation the rights
|
||||
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
||||
copies of the Software, and to permit persons to whom the Software is
|
||||
furnished to do so, subject to the following conditions:
|
||||
|
||||
The above copyright notice and this permission notice shall be included in all
|
||||
copies or substantial portions of the Software.
|
||||
|
||||
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
||||
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
||||
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
||||
SOFTWARE.
|
||||
@@ -1,330 +1,330 @@
|
||||
# DevOps - Pipeline and Workflow Examples
|
||||
|
||||
This repository contains a rich set of CI-CD demos where I show you how to:
|
||||
|
||||
- Connect to private nuget feeds; Azure, GitHub packages, and custom (eg Telerik).
|
||||
- Build .NET apps and publish to a container registry; Docker, Azure, GitHub, etc.
|
||||
|
||||
Although I use Telerik's NuGet server because I have a license, these demos are good for any private feed type; just use your source URL and credentials instead!
|
||||
|
||||
## Table of Contents
|
||||
- [CI Systems](https://github.com/LanceMcCarthy/DevOpsExamples#ci-systems)
|
||||
- [Build Badges](https://github.com/LanceMcCarthy/DevOpsExamples#badges)
|
||||
- [Docker Examples](https://github.com/LanceMcCarthy/DevOpsExamples#docker-examples)
|
||||
- [Video: Authenticating in Azure DevOps](https://github.com/LanceMcCarthy/DevOpsExamples#videos)
|
||||
- [Tips and Troubleshooting](https://github.com/LanceMcCarthy/DevOpsExamples#tips-and-troubleshooting)
|
||||
- [Walkthrough: Use GitHub Secrets](https://github.com/LanceMcCarthy/DevOpsExamples#github-actions-using-secrets-to-set-environment-variables)
|
||||
- [Example: Update package source dynamically](https://github.com/LanceMcCarthy/DevOpsExamples#powershell-update-package-source-dynamically)
|
||||
- [Example: Using Telerik NuGet Keys](https://github.com/LanceMcCarthy/DevOpsExamples#using-telerik-nuget-keys)
|
||||
- [Dockerfile: Using Secrets](https://github.com/LanceMcCarthy/DevOpsExamples#dockerfile-using-secrets)
|
||||
- [Telerik License Approaches](https://github.com/LanceMcCarthy/DevOpsExamples#telerik-license-approaches)
|
||||
- Related Blog Posts
|
||||
- [Blog: DevOps and Telerik NuGet Packages](https://www.telerik.com/blogs/azure-devops-and-telerik-nuget-packages)
|
||||
- [Blog: Announcing Telerik NuGet Keys](https://www.telerik.com/blogs/announcing-nuget-keys)
|
||||
|
||||
## CI Systems
|
||||
|
||||
| System | CI/CD file(s) |
|
||||
|---------------|------------------|
|
||||
| GitHub Actions | [.github/workflows](/.github/workflows) |
|
||||
| Azure DevOps (YAML) | [azure-pipelines.yml](https://github.com/LanceMcCarthy/DevOpsExamples/blob/main/azure-pipelines.yml) |
|
||||
| Azure DevOps (classic) | click build badge |
|
||||
| GitLab CI/CD | [.gitlab-ci.yml](https://gitlab.com/LanceMcCarthy/DevOpsExamples/-/blob/main/.gitlab-ci.yml) ↗|
|
||||
|
||||
## Badges
|
||||
|
||||
| Project | GitHub Actions | Azure DevOps | GitLab CI |
|
||||
|---------|--------------|----------------|-----------|
|
||||
| **.NET MAUI** | [](https://github.com/LanceMcCarthy/DevOpsExamples/actions/workflows/main_build-maui.yml) | [](https://dev.azure.com/lance/DevOps%20Examples/_build/latest?definitionId=72) | [](https://gitlab.com/LanceMcCarthy/DevOpsExamples) |
|
||||
| **ASP.NET Core** | [](https://github.com/LanceMcCarthy/DevOpsExamples/actions/workflows/main_build-aspnetcore.yml) | [](https://dev.azure.com/lance/DevOps%20Examples/_build/latest?definitionId=45&branchName=main) | [](https://gitlab.com/LanceMcCarthy/DevOpsExamples) |
|
||||
| **ASP.NET Blazor** | [](https://github.com/LanceMcCarthy/DevOpsExamples/actions/workflows/main_build-blazor.yml) | [](https://dev.azure.com/lance/DevOps%20Examples/_build/latest?definitionId=45&branchName=main) | [](https://gitlab.com/LanceMcCarthy/DevOpsExamples) |
|
||||
| **WPF** (`net48`) | [](https://github.com/LanceMcCarthy/DevOpsExamples/actions/workflows/main_build-wpf.yml) | [](https://dev.azure.com/lance/DevOps%20Examples/_build/latest?definitionId=46) | [](https://gitlab.com/LanceMcCarthy/DevOpsExamples) |
|
||||
| **WinForms** (`net48`) | [](https://github.com/LanceMcCarthy/DevOpsExamples/actions/workflows/main_build-winforms.yml) | [](https://dev.azure.com/lance/DevOps%20Examples/_build/latest?definitionId=79&branchName=main) | [](https://gitlab.com/LanceMcCarthy/DevOpsExamples) |
|
||||
| **Console** | [](https://github.com/LanceMcCarthy/DevOpsExamples/actions/workflows/main_build-console.yml) | [](https://dev.azure.com/lance/DevOps%20Examples/_build/latest?definitionId=45&branchName=main) | [](https://gitlab.com/LanceMcCarthy/DevOpsExamples) |
|
||||
| **WinUI 3** | [](https://github.com/LanceMcCarthy/DevOpsExamples/actions/workflows/main_build-winui.yml) | [](https://dev.azure.com/lance/DevOps%20Examples/_build/latest?definitionId=45&branchName=main) | [](https://gitlab.com/LanceMcCarthy/DevOpsExamples) |
|
||||
| **Kendo Angular** | [](https://github.com/LanceMcCarthy/DevOpsExamples/actions/workflows/main_build-angular.yml) | [](https://dev.azure.com/lance/DevOps%20Examples/_build/latest?definitionId=45&branchName=main) | [](https://gitlab.com/LanceMcCarthy/DevOpsExamples) |
|
||||
| **ASP.NET AJAX** (`net48`) | [](https://github.com/LanceMcCarthy/DevOpsExamples/actions/workflows/main_build-ajax.yml) | [](https://dev.azure.com/lance/DevOps%20Examples/_build/latest?definitionId=45&branchName=main) | [](https://gitlab.com/LanceMcCarthy/DevOpsExamples) |
|
||||
|
||||
> All Azure DevOps status badges are for classic pipelines, except the `Console` project, which uses Azure DevOps YAML pipelines.
|
||||
|
||||
## Docker Examples
|
||||
|
||||
This repo also contains examples on how to build and publish a Telerik powered .NET project as a container image. The image names below are published to the `lancemccarthy` Docker Hub user, but the approach also works for any container registry.
|
||||
|
||||
| Image | GitHub Action | Dockerfile |
|
||||
|--------------|---------------|------------|
|
||||
| `aspnetcore-reporting-from-centosbase` | [](https://github.com/LanceMcCarthy/DevOpsExamples/actions/workflows/main_docker-aspnetcore.yml) | [link](https://github.com/LanceMcCarthy/DevOpsExamples/blob/main/src/AspNetCore/MyAspNetCoreApp/Dockerfile_CentOS "MyAspNetCoreApp/Dockerfile_CentOS") |
|
||||
| `aspnetcore-reporting-from-msftbase` | [](https://github.com/LanceMcCarthy/DevOpsExamples/actions/workflows/main_docker-aspnetcore.yml) | [link](https://github.com/LanceMcCarthy/DevOpsExamples/blob/main/src/AspNetCore/MyAspNetCoreApp/Dockerfile_MSRuntimeBase "MyAspNetCoreApp/Dockerfile_MSRuntimeBase") |
|
||||
| `myblazorapp` | [](https://github.com/LanceMcCarthy/DevOpsExamples/actions/workflows/main_docker-blazor.yml) | [link](https://github.com/LanceMcCarthy/DevOpsExamples/blob/main/src/Blazor/MyBlazorApp/Dockerfile "MyBlazorApp/Dockerfile") |
|
||||
|
||||
> [!NOTE]
|
||||
> When creating a container, forward port 8080 to the host. For example:
|
||||
> 1. Run `docker run -d -p 9999:8080 lancemccarthy/myblazorapp:latest`
|
||||
> 2. Visit site on http://localhost:9999
|
||||
|
||||
## Videos
|
||||
|
||||
### Azure DevOps with Telerik NuGet Server
|
||||
|
||||
The following **4 minute** video takes you though all the steps on adding a private NuGet feed as a Service Connection and consuming that service in three different pipeline setups.
|
||||
|
||||
[](https://www.youtube.com/watch?v=rUWU2n6FwgA)
|
||||
|
||||
- [0:09](https://youtu.be/rUWU2n6FwgA?t=9) Add a Service connection to the Telerik server
|
||||
- [1:14](https://youtu.be/rUWU2n6FwgA?t=74) Classic pipeline for .NET Core
|
||||
- [1:47](https://youtu.be/rUWU2n6FwgA?t=107) Classic .NET Framework pipeline
|
||||
- [2:25](https://youtu.be/rUWU2n6FwgA?t=145) YAML pipeline setup for .NET Core
|
||||
|
||||
> [!IMPORTANT]
|
||||
> The recording has some outdated information, take the following updates into consideration when watching:
|
||||
> - Use the v3 server address `https://nuget.telerik.com/v3/index.json`
|
||||
> - Use an API key credential if your telerik.com account is SSO (see [Announcing NuGet Keys](https://www.telerik.com/blogs/announcing-nuget-keys)).
|
||||
|
||||
## Tips and Troubleshooting
|
||||
|
||||
### GitHub Actions: Using Secrets to Set Environment Variables
|
||||
|
||||
If you have environment variable placeholders in your nuget.config file, you can easily set them using GitHub Secrets. For example, let's say in your packageSourceCredentials, you have the following the environment variable placeholders `%TELERIK_USERNAME%` and `%TELERIK_PASSWORD%`
|
||||
|
||||
```xaml
|
||||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<configuration>
|
||||
...
|
||||
<packageSourceCredentials>
|
||||
<Telerik_v3_Feed>
|
||||
<add key="Username" value="%TELERIK_USERNAME%" />
|
||||
<add key="ClearTextPassword" value="%TELERIK_PASSWORD%" />
|
||||
</Telerik_v3_Feed>
|
||||
</packageSourceCredentials>
|
||||
...
|
||||
</configuration>
|
||||
```
|
||||
|
||||
You can directly set those vars on the same step which you invoke the `dotnet restore/build/publish` command. For example, here I use an API key from my GitHub Actions Secrets for credentials
|
||||
|
||||
```yaml
|
||||
- name: Restore NuGet Packages
|
||||
run: dotnet restore src/MyProject.csproj --configfile src/nuget.config
|
||||
env:
|
||||
TELERIK_USERNAME: "api-key"
|
||||
TELERIK_PASSWORD: ${{secrets.TELERIK_API_KEY}}
|
||||
```
|
||||
|
||||
> [!TIP]
|
||||
> This is also very useful for Dependabot runs. You can set a Dependabot secret (in the repo settings) and it will be able to restore packages during checks that were triggered by Dependabot.
|
||||
|
||||
### Powershell: Adding or Updating Package Source Dynamically
|
||||
|
||||
#### Option 1 - Update existing package source
|
||||
|
||||
You could also dynamically update the credentials of a Package Source defined in your nuget.config file This is a good option when you do not want to use a `packageSourceCredentials` section that uses environment variables.
|
||||
|
||||
```powershell
|
||||
# Setting credentials for the 'Telerik_v3_Feed' defined in the nuget.config file.
|
||||
dotnet nuget update source "Telerik_v3_Feed" -s "https://nuget.telerik.com/v3/index.json" -u '${{secrets.MyTelerikEmail}}' -p '${{secrets.MyTelerikPassword}}' --configfile "src/nuget.config" --store-password-in-clear-text
|
||||
```
|
||||
That command will look through the nuget.config for a package source with the key `Telerik_v3_Feed` and then add/update the credentials for that source.
|
||||
|
||||
#### Option 2 - Add a new package source
|
||||
|
||||
The other approach is a bit simpler because you dont need a custom nuget.config file. Just use the dotnet nuget add source command
|
||||
|
||||
```powershell
|
||||
dotnet nuget add source 'https://nuget.telerik.com/v3/index.json' -n "AddedTelerikServer" -u ${{secrets.MyTelerikEmail}} -p ${{secrets.MyTelerikPassword}} --store-password-in-clear-text
|
||||
```
|
||||
|
||||
> The `--store-password-in-clear-text` switch is important. It does *not* mean the password is visible, rather it means that you're using the password text and not a custom encrypted variant. For more information, please visit https://docs.microsoft.com/en-us/nuget/reference/nuget-config-file#packagesourcecredentials
|
||||
|
||||
### Using Telerik NuGet Keys
|
||||
|
||||
You can use the same approach in the previous section. Everything is exactly the same, except you use `api-key` for the username and the NuGet key for the password.
|
||||
|
||||
Please visit the [Announcing NuGet Keys](https://www.telerik.com/blogs/announcing-nuget-keys) blog post for more details how ot create the key and how to use it.
|
||||
|
||||
```powershell
|
||||
dotnet nuget update source "Telerik_v3_Feed" -s "https://nuget.telerik.com/v3/index.json" -u 'api-key' -p '${{secrets.MyNuGetKey}}' --configfile "src/nuget.config" --store-password-in-clear-text
|
||||
```
|
||||
|
||||
> [!CAUTION]
|
||||
> Protect your key by storing it in a GitHub Secret, then use the secret's ID in the command.
|
||||
|
||||
### Dockerfile: Using Secrets
|
||||
|
||||
When using a Dockerfile to build a .NET project that uses the Telerik NuGet server, you'll need a safe and secure way to handle your NuGet crednetials and your Telerik License Key. This can be done my mounting a Docker secret.
|
||||
|
||||
In your GitHub Actions workflow, you can define and set docker secrets in the docker build step. In the following example, notice how we are setting two docker secrets (`nuget-sec` and `license-sec`) using the values from GitHub secrets.
|
||||
|
||||
```yaml
|
||||
- uses: docker/build-push-action@v3
|
||||
with:
|
||||
secrets: |
|
||||
nuget-sec=${{secrets.MY_NUGET_KEY}}
|
||||
license-sec=${{secrets.MY_TELERIK_LICENSE_KEY}}
|
||||
```
|
||||
|
||||
Now, inside the Dockerfile, you can mount and use those secrets. See Stage 2 in the following example:
|
||||
|
||||
```Dockerfile
|
||||
### STAGE 1 ###
|
||||
FROM --platform=$BUILDPLATFORM mcr.microsoft.com/dotnet/aspnet:10.0 AS base
|
||||
WORKDIR /app
|
||||
|
||||
### STAGE 2 ###
|
||||
FROM mcr.microsoft.com/dotnet/sdk:10.0 AS build
|
||||
WORKDIR /src
|
||||
COPY . .
|
||||
# STEP 1. Mount the 'nuget-sec' secret, then:
|
||||
# a. add the Telerik package source
|
||||
# b. restore packages
|
||||
RUN --mount=type=secret,id=nuget-sec,required \
|
||||
dotnet nuget add source 'https://nuget.telerik.com/v3/index.json' -n "Telerik_v3_Feed" -u "api-key" -p "$(cat /run/secrets/nuget-sec)" --store-password-in-clear-text \
|
||||
&& \
|
||||
dotnet restore "MyBlazorApp.csproj"
|
||||
# STEP 2. Mount the "license-sec" secret, then:
|
||||
# a. create the license file
|
||||
# b. build the project
|
||||
# c. delete the file so you don't distribute it in your image (important!)
|
||||
RUN --mount=type=secret,id=license-key,required \
|
||||
mkdir -p ~/.telerik && echo "$(cat /run/secrets/license-sec)" > ~/.telerik/telerik-license.txt \
|
||||
&& \
|
||||
dotnet publish "Researcher.Web/Researcher.Web.csproj" -o /app/publish /p:UseAppHost=false --no-restore --self-contained false \
|
||||
&& \
|
||||
rm -rf ~/.telerik
|
||||
|
||||
### STAGE 3 ###
|
||||
# Build final from base, but copy ONLY THE PUBLISH ARTIFACTS from stage 2
|
||||
FROM base AS final
|
||||
WORKDIR /app
|
||||
COPY --from=build /app/publish .
|
||||
ENTRYPOINT ["dotnet", "MyBlazorApp.dll"]
|
||||
```
|
||||
|
||||
> [!CAUTION]
|
||||
> Pay attention to whether or not you are including any secrets in your final image. You can run your container to explore the files (and env vars in Exec) to make sure.
|
||||
|
||||
### Telerik License Approaches
|
||||
|
||||
Depending on how you're building our code, there are several ways to introduce the Telerik License Key at the right time for the build. Let me show you two; variable and file.
|
||||
|
||||
- [Approach 1 - Using an Environment Variable](https://github.com/LanceMcCarthy/DevOpsExamples?tab=readme-ov-file#approach-1---using-a-variable)
|
||||
- [Approach 2 - Using a License File](https://github.com/LanceMcCarthy/DevOpsExamples?tab=readme-ov-file#approach-2---using-a-file)
|
||||
- [In a YAML Pipeline](https://github.com/LanceMcCarthy/DevOpsExamples?tab=readme-ov-file#yaml-pipeline)
|
||||
- [In a Classic Pipeline](https://github.com/LanceMcCarthy/DevOpsExamples?tab=readme-ov-file#classic-pipeline)
|
||||
- [Approach 1 - Using a Variable](https://github.com/LanceMcCarthy/DevOpsExamples#approach-1---using-a-variable)
|
||||
- [Approach 2 - Using a File](https://github.com/LanceMcCarthy/DevOpsExamples#approach-2---using-a-file)
|
||||
- [Secure File - YAML Pipeline](https://github.com/LanceMcCarthy/DevOpsExamples#secure-file---yaml-pipeline)
|
||||
- [Secure File - Classic Pipeline](https://github.com/LanceMcCarthy/DevOpsExamples#secure-file---classic-pipeline)
|
||||
- [Scenario 1 - Task With Env Vars Inputs](https://github.com/LanceMcCarthy/DevOpsExamples#scenario-1---task-with-env-var-inputs)
|
||||
- [Scenario 2 - Task Without Env Var Inputs](https://github.com/LanceMcCarthy/DevOpsExamples#scenario-2---task-without-env-var-inputs)
|
||||
- [Scenario 3 - Move Secure File](https://github.com/LanceMcCarthy/DevOpsExamples#scenario-3---move-secure-file)
|
||||
|
||||
#### Approach 1 - Using a Variable
|
||||
|
||||
This is by far the easiest and safest way. You can use a secret (GitHub Action secret or AzDO Variable secret) and set the `TELERIK_LICENSE` environment variable before the project is compiled.
|
||||
|
||||
In a YAML workflow/pipeline, you can set the environment variable at the beginning of the job or on a step that needs it.
|
||||
|
||||
GH Actions
|
||||
```yaml
|
||||
- run: dotnet publish MyApp.csproj -o /app/publish /p:UseAppHost=false --no-restore
|
||||
env:
|
||||
TELERIK_LICENSE: ${{secrets.TELERIK_LICENSE_KEY}}
|
||||
```
|
||||
|
||||
Azure Pipelines YAML
|
||||
|
||||
```yaml
|
||||
- powershell: dotnet publish MyApp.csproj -o /app/publish /p:UseAppHost=false --no-restore
|
||||
displayName: 'Build and publish the project'
|
||||
env:
|
||||
TELERIK_LICENSE: $(MY_TELERIK_LICENSE_KEY) # AzDO pipeline secret variable
|
||||
```
|
||||
|
||||
If you're using classic pipelines, you can use a pipeline variable:
|
||||
|
||||

|
||||
|
||||
> [!IMPORTANT]
|
||||
> License key length - If you are using a Library **Variable Group**, there is a character limit for the variable values. The only way to have a long value in the Variable Group is to link it from Azure KeyVault. If you cannot use Azure KeyVault, then use a normal pipeline variable instead (seen above) or use the Secure File approach instead (see below).
|
||||
|
||||
|
||||
#### Approach 2 - Using a File
|
||||
|
||||
You have two options for a file-base option. Set the TELERIK_LICENSE_PATH variable or add a file named **telerik-license.txt** to the project directory. The licensing runtime will do a recursive check from the project directory to root, and then finally %appdata%/telerik/.
|
||||
|
||||
On Azure DevOps, there is a powerful feature called Secure Files. It lets you upload a file and then use it in a pipeline. Go to your Library tab, then select Secure File. After you've uploaded the Secure File to your Azure DevOps project, you can use it in a pipeline.
|
||||
|
||||
Here are several ways to use that Secure File.
|
||||
|
||||
> [!CAUTION]
|
||||
> Never include the **telerik-license.txt** file inside your application/docker image!
|
||||
|
||||
##### YAML Pipeline
|
||||
|
||||
With a YAML pipeline, you can use the **DownloadSecureFile@1** task, then use `$(name.secureFilePath)` to reference it. For example:
|
||||
|
||||
```yaml
|
||||
- task: DownloadSecureFile@1
|
||||
name: DownloadTelerikLicenseFile # defining the 'name' is important
|
||||
displayName: 'Download Telerik License Key File'
|
||||
inputs:
|
||||
secureFile: 'telerik-license.txt'
|
||||
|
||||
- task: MSBuild@1
|
||||
displayName: 'Build Project'
|
||||
inputs:
|
||||
solution: 'myapp.csproj'
|
||||
platform: Any CPU
|
||||
configuration: Release
|
||||
msbuildArguments: '/p:RestorePackages=false'
|
||||
env:
|
||||
# use the name.secureFilePath value to set the special TELERIK_LICENSE_PATH
|
||||
TELERIK_LICENSE_PATH: $(DownloadTelerikLicenseFile.secureFilePath)
|
||||
```
|
||||
|
||||
##### Classic Pipeline
|
||||
|
||||
With a classic pipeline, you can use the same `DownloadSecureFile` Task
|
||||
|
||||

|
||||
|
||||
> [!IMPORTANT]
|
||||
> Make sure you set the **reference name** which gets prefixed to the `.secureFilePath` output variable.
|
||||
|
||||
###### Scenario 1 - Task With Env Var Inputs
|
||||
|
||||
With the secure file downloaded to the runner, you can now set the **TELERIK_LICENSE_PATH** variable using `$(telerik.secureFilePath)`.
|
||||
|
||||
<img width="700" alt="image" src="https://github.com/user-attachments/assets/e6bb5425-a721-4307-9837-0ef2e6f8cefa" />
|
||||
|
||||
###### Scenario 2 - Task Without Env Var Inputs
|
||||
|
||||
Not all AzDO tasks have the "Environment variables" section (e.g. MsBuild task doesn't have it). To solve this, you can set a pipeline variable before that task. Using the secure file
|
||||
|
||||
1. Add a new Powershell or Bash task (_after_ the Download Secure File task)
|
||||
2. Set the **TELERIK_LICENSE_PATH** using `task.setvariable` command with `issecret=true`and the secure file task's output variable
|
||||
```powershell
|
||||
# If using Powershell
|
||||
Write-Host "##vso[task.setvariable variable=TELERIK_LICENSE_PATH;issecret=true]$(telerik.secureFilePath)"
|
||||
|
||||
# If using Bash
|
||||
echo "##vso[task.setvariable variable=TELERIK_LICENSE_PATH;issecret=true]$(telerik.secureFilePath)"
|
||||
```
|
||||
|
||||
<img width="700" alt="image" src="https://github.com/user-attachments/assets/9f1bcecd-a2d2-45f2-95b6-76bdfbda6516" />
|
||||
|
||||
###### Scenario 3 - Move Secure File
|
||||
|
||||
If you have nay trouble with the TELERIK_LICENSE_PATH variable, you can just simply move the file to the root build directory.
|
||||
|
||||
1. Add a new Powershell or Bash task (_after_ the Download Secure File task)
|
||||
```powershell
|
||||
Move-Item -Path "$(telerik.secureFilePath)" -Destination "$(Build.Repository.LocalPath)/telerik-license.txt" -Force
|
||||
```
|
||||
2. Build the code
|
||||
3. Delete the file (so you don't accidentally include it in your distribution)
|
||||
```powershell
|
||||
Remove-Item -Path "$(Build.Repository.LocalPath)/telerik-license.txt" -Force
|
||||
```
|
||||
|
||||
As you can see, there are a wide range of options. The one you choose highly depends on your environment and CI requirements.
|
||||
# DevOps - Pipeline and Workflow Examples
|
||||
|
||||
This repository contains a rich set of CI-CD demos where I show you how to:
|
||||
|
||||
- Connect to private nuget feeds; Azure, GitHub packages, and custom (eg Telerik).
|
||||
- Build .NET apps and publish to a container registry; Docker, Azure, GitHub, etc.
|
||||
|
||||
Although I use Telerik's NuGet server because I have a license, these demos are good for any private feed type; just use your source URL and credentials instead!
|
||||
|
||||
## Table of Contents
|
||||
- [CI Systems](https://github.com/LanceMcCarthy/DevOpsExamples#ci-systems)
|
||||
- [Build Badges](https://github.com/LanceMcCarthy/DevOpsExamples#badges)
|
||||
- [Docker Examples](https://github.com/LanceMcCarthy/DevOpsExamples#docker-examples)
|
||||
- [Video: Authenticating in Azure DevOps](https://github.com/LanceMcCarthy/DevOpsExamples#videos)
|
||||
- [Tips and Troubleshooting](https://github.com/LanceMcCarthy/DevOpsExamples#tips-and-troubleshooting)
|
||||
- [Walkthrough: Use GitHub Secrets](https://github.com/LanceMcCarthy/DevOpsExamples#github-actions-using-secrets-to-set-environment-variables)
|
||||
- [Example: Update package source dynamically](https://github.com/LanceMcCarthy/DevOpsExamples#powershell-update-package-source-dynamically)
|
||||
- [Example: Using Telerik NuGet Keys](https://github.com/LanceMcCarthy/DevOpsExamples#using-telerik-nuget-keys)
|
||||
- [Dockerfile: Using Secrets](https://github.com/LanceMcCarthy/DevOpsExamples#dockerfile-using-secrets)
|
||||
- [Telerik License Approaches](https://github.com/LanceMcCarthy/DevOpsExamples#telerik-license-approaches)
|
||||
- Related Blog Posts
|
||||
- [Blog: DevOps and Telerik NuGet Packages](https://www.telerik.com/blogs/azure-devops-and-telerik-nuget-packages)
|
||||
- [Blog: Announcing Telerik NuGet Keys](https://www.telerik.com/blogs/announcing-nuget-keys)
|
||||
|
||||
## CI Systems
|
||||
|
||||
| System | CI/CD file(s) |
|
||||
|---------------|------------------|
|
||||
| GitHub Actions | [.github/workflows](/.github/workflows) |
|
||||
| Azure DevOps (YAML) | [azure-pipelines.yml](https://github.com/LanceMcCarthy/DevOpsExamples/blob/main/azure-pipelines.yml) |
|
||||
| Azure DevOps (classic) | click build badge |
|
||||
| GitLab CI/CD | [.gitlab-ci.yml](https://gitlab.com/LanceMcCarthy/DevOpsExamples/-/blob/main/.gitlab-ci.yml) ↗|
|
||||
|
||||
## Badges
|
||||
|
||||
| Project | GitHub Actions | Azure DevOps | GitLab CI |
|
||||
|---------|--------------|----------------|-----------|
|
||||
| **.NET MAUI** | [](https://github.com/LanceMcCarthy/DevOpsExamples/actions/workflows/main_build-maui.yml) | [](https://dev.azure.com/lance/DevOps%20Examples/_build/latest?definitionId=72) | [](https://gitlab.com/LanceMcCarthy/DevOpsExamples) |
|
||||
| **ASP.NET Core** | [](https://github.com/LanceMcCarthy/DevOpsExamples/actions/workflows/main_build-aspnetcore.yml) | [](https://dev.azure.com/lance/DevOps%20Examples/_build/latest?definitionId=45&branchName=main) | [](https://gitlab.com/LanceMcCarthy/DevOpsExamples) |
|
||||
| **ASP.NET Blazor** | [](https://github.com/LanceMcCarthy/DevOpsExamples/actions/workflows/main_build-blazor.yml) | [](https://dev.azure.com/lance/DevOps%20Examples/_build/latest?definitionId=45&branchName=main) | [](https://gitlab.com/LanceMcCarthy/DevOpsExamples) |
|
||||
| **WPF** (`net48`) | [](https://github.com/LanceMcCarthy/DevOpsExamples/actions/workflows/main_build-wpf.yml) | [](https://dev.azure.com/lance/DevOps%20Examples/_build/latest?definitionId=46) | [](https://gitlab.com/LanceMcCarthy/DevOpsExamples) |
|
||||
| **WinForms** (`net48`) | [](https://github.com/LanceMcCarthy/DevOpsExamples/actions/workflows/main_build-winforms.yml) | [](https://dev.azure.com/lance/DevOps%20Examples/_build/latest?definitionId=79&branchName=main) | [](https://gitlab.com/LanceMcCarthy/DevOpsExamples) |
|
||||
| **Console** | [](https://github.com/LanceMcCarthy/DevOpsExamples/actions/workflows/main_build-console.yml) | [](https://dev.azure.com/lance/DevOps%20Examples/_build/latest?definitionId=45&branchName=main) | [](https://gitlab.com/LanceMcCarthy/DevOpsExamples) |
|
||||
| **WinUI 3** | [](https://github.com/LanceMcCarthy/DevOpsExamples/actions/workflows/main_build-winui.yml) | [](https://dev.azure.com/lance/DevOps%20Examples/_build/latest?definitionId=45&branchName=main) | [](https://gitlab.com/LanceMcCarthy/DevOpsExamples) |
|
||||
| **Kendo Angular** | [](https://github.com/LanceMcCarthy/DevOpsExamples/actions/workflows/main_build-angular.yml) | [](https://dev.azure.com/lance/DevOps%20Examples/_build/latest?definitionId=45&branchName=main) | [](https://gitlab.com/LanceMcCarthy/DevOpsExamples) |
|
||||
| **ASP.NET AJAX** (`net48`) | [](https://github.com/LanceMcCarthy/DevOpsExamples/actions/workflows/main_build-ajax.yml) | [](https://dev.azure.com/lance/DevOps%20Examples/_build/latest?definitionId=45&branchName=main) | [](https://gitlab.com/LanceMcCarthy/DevOpsExamples) |
|
||||
|
||||
> All Azure DevOps status badges are for classic pipelines, except the `Console` project, which uses Azure DevOps YAML pipelines.
|
||||
|
||||
## Docker Examples
|
||||
|
||||
This repo also contains examples on how to build and publish a Telerik powered .NET project as a container image. The image names below are published to the `lancemccarthy` Docker Hub user, but the approach also works for any container registry.
|
||||
|
||||
| Image | GitHub Action | Dockerfile |
|
||||
|--------------|---------------|------------|
|
||||
| `aspnetcore-reporting-from-centosbase` | [](https://github.com/LanceMcCarthy/DevOpsExamples/actions/workflows/main_docker-aspnetcore.yml) | [link](https://github.com/LanceMcCarthy/DevOpsExamples/blob/main/src/AspNetCore/MyAspNetCoreApp/Dockerfile_CentOS "MyAspNetCoreApp/Dockerfile_CentOS") |
|
||||
| `aspnetcore-reporting-from-msftbase` | [](https://github.com/LanceMcCarthy/DevOpsExamples/actions/workflows/main_docker-aspnetcore.yml) | [link](https://github.com/LanceMcCarthy/DevOpsExamples/blob/main/src/AspNetCore/MyAspNetCoreApp/Dockerfile_MSRuntimeBase "MyAspNetCoreApp/Dockerfile_MSRuntimeBase") |
|
||||
| `myblazorapp` | [](https://github.com/LanceMcCarthy/DevOpsExamples/actions/workflows/main_docker-blazor.yml) | [link](https://github.com/LanceMcCarthy/DevOpsExamples/blob/main/src/Blazor/MyBlazorApp/Dockerfile "MyBlazorApp/Dockerfile") |
|
||||
|
||||
> [!NOTE]
|
||||
> When creating a container, forward port 8080 to the host. For example:
|
||||
> 1. Run `docker run -d -p 9999:8080 lancemccarthy/myblazorapp:latest`
|
||||
> 2. Visit site on http://localhost:9999
|
||||
|
||||
## Videos
|
||||
|
||||
### Azure DevOps with Telerik NuGet Server
|
||||
|
||||
The following **4 minute** video takes you though all the steps on adding a private NuGet feed as a Service Connection and consuming that service in three different pipeline setups.
|
||||
|
||||
[](https://www.youtube.com/watch?v=rUWU2n6FwgA)
|
||||
|
||||
- [0:09](https://youtu.be/rUWU2n6FwgA?t=9) Add a Service connection to the Telerik server
|
||||
- [1:14](https://youtu.be/rUWU2n6FwgA?t=74) Classic pipeline for .NET Core
|
||||
- [1:47](https://youtu.be/rUWU2n6FwgA?t=107) Classic .NET Framework pipeline
|
||||
- [2:25](https://youtu.be/rUWU2n6FwgA?t=145) YAML pipeline setup for .NET Core
|
||||
|
||||
> [!IMPORTANT]
|
||||
> The recording has some outdated information, take the following updates into consideration when watching:
|
||||
> - Use the v3 server address `https://nuget.telerik.com/v3/index.json`
|
||||
> - Use an API key credential if your telerik.com account is SSO (see [Announcing NuGet Keys](https://www.telerik.com/blogs/announcing-nuget-keys)).
|
||||
|
||||
## Tips and Troubleshooting
|
||||
|
||||
### GitHub Actions: Using Secrets to Set Environment Variables
|
||||
|
||||
If you have environment variable placeholders in your nuget.config file, you can easily set them using GitHub Secrets. For example, let's say in your packageSourceCredentials, you have the following the environment variable placeholders `%TELERIK_USERNAME%` and `%TELERIK_PASSWORD%`
|
||||
|
||||
```xaml
|
||||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<configuration>
|
||||
...
|
||||
<packageSourceCredentials>
|
||||
<Telerik_v3_Feed>
|
||||
<add key="Username" value="%TELERIK_USERNAME%" />
|
||||
<add key="ClearTextPassword" value="%TELERIK_PASSWORD%" />
|
||||
</Telerik_v3_Feed>
|
||||
</packageSourceCredentials>
|
||||
...
|
||||
</configuration>
|
||||
```
|
||||
|
||||
You can directly set those vars on the same step which you invoke the `dotnet restore/build/publish` command. For example, here I use an API key from my GitHub Actions Secrets for credentials
|
||||
|
||||
```yaml
|
||||
- name: Restore NuGet Packages
|
||||
run: dotnet restore src/MyProject.csproj --configfile src/nuget.config
|
||||
env:
|
||||
TELERIK_USERNAME: "api-key"
|
||||
TELERIK_PASSWORD: ${{secrets.TELERIK_API_KEY}}
|
||||
```
|
||||
|
||||
> [!TIP]
|
||||
> This is also very useful for Dependabot runs. You can set a Dependabot secret (in the repo settings) and it will be able to restore packages during checks that were triggered by Dependabot.
|
||||
|
||||
### Powershell: Adding or Updating Package Source Dynamically
|
||||
|
||||
#### Option 1 - Update existing package source
|
||||
|
||||
You could also dynamically update the credentials of a Package Source defined in your nuget.config file This is a good option when you do not want to use a `packageSourceCredentials` section that uses environment variables.
|
||||
|
||||
```powershell
|
||||
# Setting credentials for the 'Telerik_v3_Feed' defined in the nuget.config file.
|
||||
dotnet nuget update source "Telerik_v3_Feed" -s "https://nuget.telerik.com/v3/index.json" -u '${{secrets.MyTelerikEmail}}' -p '${{secrets.MyTelerikPassword}}' --configfile "src/nuget.config" --store-password-in-clear-text
|
||||
```
|
||||
That command will look through the nuget.config for a package source with the key `Telerik_v3_Feed` and then add/update the credentials for that source.
|
||||
|
||||
#### Option 2 - Add a new package source
|
||||
|
||||
The other approach is a bit simpler because you dont need a custom nuget.config file. Just use the dotnet nuget add source command
|
||||
|
||||
```powershell
|
||||
dotnet nuget add source 'https://nuget.telerik.com/v3/index.json' -n "AddedTelerikServer" -u ${{secrets.MyTelerikEmail}} -p ${{secrets.MyTelerikPassword}} --store-password-in-clear-text
|
||||
```
|
||||
|
||||
> The `--store-password-in-clear-text` switch is important. It does *not* mean the password is visible, rather it means that you're using the password text and not a custom encrypted variant. For more information, please visit https://docs.microsoft.com/en-us/nuget/reference/nuget-config-file#packagesourcecredentials
|
||||
|
||||
### Using Telerik NuGet Keys
|
||||
|
||||
You can use the same approach in the previous section. Everything is exactly the same, except you use `api-key` for the username and the NuGet key for the password.
|
||||
|
||||
Please visit the [Announcing NuGet Keys](https://www.telerik.com/blogs/announcing-nuget-keys) blog post for more details how ot create the key and how to use it.
|
||||
|
||||
```powershell
|
||||
dotnet nuget update source "Telerik_v3_Feed" -s "https://nuget.telerik.com/v3/index.json" -u 'api-key' -p '${{secrets.MyNuGetKey}}' --configfile "src/nuget.config" --store-password-in-clear-text
|
||||
```
|
||||
|
||||
> [!CAUTION]
|
||||
> Protect your key by storing it in a GitHub Secret, then use the secret's ID in the command.
|
||||
|
||||
### Dockerfile: Using Secrets
|
||||
|
||||
When using a Dockerfile to build a .NET project that uses the Telerik NuGet server, you'll need a safe and secure way to handle your NuGet crednetials and your Telerik License Key. This can be done my mounting a Docker secret.
|
||||
|
||||
In your GitHub Actions workflow, you can define and set docker secrets in the docker build step. In the following example, notice how we are setting two docker secrets (`nuget-sec` and `license-sec`) using the values from GitHub secrets.
|
||||
|
||||
```yaml
|
||||
- uses: docker/build-push-action@v3
|
||||
with:
|
||||
secrets: |
|
||||
nuget-sec=${{secrets.MY_NUGET_KEY}}
|
||||
license-sec=${{secrets.MY_TELERIK_LICENSE_KEY}}
|
||||
```
|
||||
|
||||
Now, inside the Dockerfile, you can mount and use those secrets. See Stage 2 in the following example:
|
||||
|
||||
```Dockerfile
|
||||
### STAGE 1 ###
|
||||
FROM --platform=$BUILDPLATFORM mcr.microsoft.com/dotnet/aspnet:10.0 AS base
|
||||
WORKDIR /app
|
||||
|
||||
### STAGE 2 ###
|
||||
FROM mcr.microsoft.com/dotnet/sdk:10.0 AS build
|
||||
WORKDIR /src
|
||||
COPY . .
|
||||
# STEP 1. Mount the 'nuget-sec' secret, then:
|
||||
# a. add the Telerik package source
|
||||
# b. restore packages
|
||||
RUN --mount=type=secret,id=nuget-sec,required \
|
||||
dotnet nuget add source 'https://nuget.telerik.com/v3/index.json' -n "Telerik_v3_Feed" -u "api-key" -p "$(cat /run/secrets/nuget-sec)" --store-password-in-clear-text \
|
||||
&& \
|
||||
dotnet restore "MyBlazorApp.csproj"
|
||||
# STEP 2. Mount the "license-sec" secret, then:
|
||||
# a. create the license file
|
||||
# b. build the project
|
||||
# c. delete the file so you don't distribute it in your image (important!)
|
||||
RUN --mount=type=secret,id=license-key,required \
|
||||
mkdir -p ~/.telerik && echo "$(cat /run/secrets/license-sec)" > ~/.telerik/telerik-license.txt \
|
||||
&& \
|
||||
dotnet publish "Researcher.Web/Researcher.Web.csproj" -o /app/publish /p:UseAppHost=false --no-restore --self-contained false \
|
||||
&& \
|
||||
rm -rf ~/.telerik
|
||||
|
||||
### STAGE 3 ###
|
||||
# Build final from base, but copy ONLY THE PUBLISH ARTIFACTS from stage 2
|
||||
FROM base AS final
|
||||
WORKDIR /app
|
||||
COPY --from=build /app/publish .
|
||||
ENTRYPOINT ["dotnet", "MyBlazorApp.dll"]
|
||||
```
|
||||
|
||||
> [!CAUTION]
|
||||
> Pay attention to whether or not you are including any secrets in your final image. You can run your container to explore the files (and env vars in Exec) to make sure.
|
||||
|
||||
### Telerik License Approaches
|
||||
|
||||
Depending on how you're building our code, there are several ways to introduce the Telerik License Key at the right time for the build. Let me show you two; variable and file.
|
||||
|
||||
- [Approach 1 - Using an Environment Variable](https://github.com/LanceMcCarthy/DevOpsExamples?tab=readme-ov-file#approach-1---using-a-variable)
|
||||
- [Approach 2 - Using a License File](https://github.com/LanceMcCarthy/DevOpsExamples?tab=readme-ov-file#approach-2---using-a-file)
|
||||
- [In a YAML Pipeline](https://github.com/LanceMcCarthy/DevOpsExamples?tab=readme-ov-file#yaml-pipeline)
|
||||
- [In a Classic Pipeline](https://github.com/LanceMcCarthy/DevOpsExamples?tab=readme-ov-file#classic-pipeline)
|
||||
- [Approach 1 - Using a Variable](https://github.com/LanceMcCarthy/DevOpsExamples#approach-1---using-a-variable)
|
||||
- [Approach 2 - Using a File](https://github.com/LanceMcCarthy/DevOpsExamples#approach-2---using-a-file)
|
||||
- [Secure File - YAML Pipeline](https://github.com/LanceMcCarthy/DevOpsExamples#secure-file---yaml-pipeline)
|
||||
- [Secure File - Classic Pipeline](https://github.com/LanceMcCarthy/DevOpsExamples#secure-file---classic-pipeline)
|
||||
- [Scenario 1 - Task With Env Vars Inputs](https://github.com/LanceMcCarthy/DevOpsExamples#scenario-1---task-with-env-var-inputs)
|
||||
- [Scenario 2 - Task Without Env Var Inputs](https://github.com/LanceMcCarthy/DevOpsExamples#scenario-2---task-without-env-var-inputs)
|
||||
- [Scenario 3 - Move Secure File](https://github.com/LanceMcCarthy/DevOpsExamples#scenario-3---move-secure-file)
|
||||
|
||||
#### Approach 1 - Using a Variable
|
||||
|
||||
This is by far the easiest and safest way. You can use a secret (GitHub Action secret or AzDO Variable secret) and set the `TELERIK_LICENSE` environment variable before the project is compiled.
|
||||
|
||||
In a YAML workflow/pipeline, you can set the environment variable at the beginning of the job or on a step that needs it.
|
||||
|
||||
GH Actions
|
||||
```yaml
|
||||
- run: dotnet publish MyApp.csproj -o /app/publish /p:UseAppHost=false --no-restore
|
||||
env:
|
||||
TELERIK_LICENSE: ${{secrets.TELERIK_LICENSE_KEY}}
|
||||
```
|
||||
|
||||
Azure Pipelines YAML
|
||||
|
||||
```yaml
|
||||
- powershell: dotnet publish MyApp.csproj -o /app/publish /p:UseAppHost=false --no-restore
|
||||
displayName: 'Build and publish the project'
|
||||
env:
|
||||
TELERIK_LICENSE: $(MY_TELERIK_LICENSE_KEY) # AzDO pipeline secret variable
|
||||
```
|
||||
|
||||
If you're using classic pipelines, you can use a pipeline variable:
|
||||
|
||||

|
||||
|
||||
> [!IMPORTANT]
|
||||
> License key length - If you are using a Library **Variable Group**, there is a character limit for the variable values. The only way to have a long value in the Variable Group is to link it from Azure KeyVault. If you cannot use Azure KeyVault, then use a normal pipeline variable instead (seen above) or use the Secure File approach instead (see below).
|
||||
|
||||
|
||||
#### Approach 2 - Using a File
|
||||
|
||||
You have two options for a file-base option. Set the TELERIK_LICENSE_PATH variable or add a file named **telerik-license.txt** to the project directory. The licensing runtime will do a recursive check from the project directory to root, and then finally %appdata%/telerik/.
|
||||
|
||||
On Azure DevOps, there is a powerful feature called Secure Files. It lets you upload a file and then use it in a pipeline. Go to your Library tab, then select Secure File. After you've uploaded the Secure File to your Azure DevOps project, you can use it in a pipeline.
|
||||
|
||||
Here are several ways to use that Secure File.
|
||||
|
||||
> [!CAUTION]
|
||||
> Never include the **telerik-license.txt** file inside your application/docker image!
|
||||
|
||||
##### YAML Pipeline
|
||||
|
||||
With a YAML pipeline, you can use the **DownloadSecureFile@1** task, then use `$(name.secureFilePath)` to reference it. For example:
|
||||
|
||||
```yaml
|
||||
- task: DownloadSecureFile@1
|
||||
name: DownloadTelerikLicenseFile # defining the 'name' is important
|
||||
displayName: 'Download Telerik License Key File'
|
||||
inputs:
|
||||
secureFile: 'telerik-license.txt'
|
||||
|
||||
- task: MSBuild@1
|
||||
displayName: 'Build Project'
|
||||
inputs:
|
||||
solution: 'myapp.csproj'
|
||||
platform: Any CPU
|
||||
configuration: Release
|
||||
msbuildArguments: '/p:RestorePackages=false'
|
||||
env:
|
||||
# use the name.secureFilePath value to set the special TELERIK_LICENSE_PATH
|
||||
TELERIK_LICENSE_PATH: $(DownloadTelerikLicenseFile.secureFilePath)
|
||||
```
|
||||
|
||||
##### Classic Pipeline
|
||||
|
||||
With a classic pipeline, you can use the same `DownloadSecureFile` Task
|
||||
|
||||

|
||||
|
||||
> [!IMPORTANT]
|
||||
> Make sure you set the **reference name** which gets prefixed to the `.secureFilePath` output variable.
|
||||
|
||||
###### Scenario 1 - Task With Env Var Inputs
|
||||
|
||||
With the secure file downloaded to the runner, you can now set the **TELERIK_LICENSE_PATH** variable using `$(telerik.secureFilePath)`.
|
||||
|
||||
<img width="700" alt="image" src="https://github.com/user-attachments/assets/e6bb5425-a721-4307-9837-0ef2e6f8cefa" />
|
||||
|
||||
###### Scenario 2 - Task Without Env Var Inputs
|
||||
|
||||
Not all AzDO tasks have the "Environment variables" section (e.g. MsBuild task doesn't have it). To solve this, you can set a pipeline variable before that task. Using the secure file
|
||||
|
||||
1. Add a new Powershell or Bash task (_after_ the Download Secure File task)
|
||||
2. Set the **TELERIK_LICENSE_PATH** using `task.setvariable` command with `issecret=true`and the secure file task's output variable
|
||||
```powershell
|
||||
# If using Powershell
|
||||
Write-Host "##vso[task.setvariable variable=TELERIK_LICENSE_PATH;issecret=true]$(telerik.secureFilePath)"
|
||||
|
||||
# If using Bash
|
||||
echo "##vso[task.setvariable variable=TELERIK_LICENSE_PATH;issecret=true]$(telerik.secureFilePath)"
|
||||
```
|
||||
|
||||
<img width="700" alt="image" src="https://github.com/user-attachments/assets/9f1bcecd-a2d2-45f2-95b6-76bdfbda6516" />
|
||||
|
||||
###### Scenario 3 - Move Secure File
|
||||
|
||||
If you have nay trouble with the TELERIK_LICENSE_PATH variable, you can just simply move the file to the root build directory.
|
||||
|
||||
1. Add a new Powershell or Bash task (_after_ the Download Secure File task)
|
||||
```powershell
|
||||
Move-Item -Path "$(telerik.secureFilePath)" -Destination "$(Build.Repository.LocalPath)/telerik-license.txt" -Force
|
||||
```
|
||||
2. Build the code
|
||||
3. Delete the file (so you don't accidentally include it in your distribution)
|
||||
```powershell
|
||||
Remove-Item -Path "$(Build.Repository.LocalPath)/telerik-license.txt" -Force
|
||||
```
|
||||
|
||||
As you can see, there are a wide range of options. The one you choose highly depends on your environment and CI requirements.
|
||||
|
||||
@@ -0,0 +1,406 @@
|
||||
trigger:
|
||||
branches:
|
||||
include:
|
||||
- main
|
||||
paths:
|
||||
include:
|
||||
- 'azure-pipelines.yml'
|
||||
- 'src/Kendo/angular_demo/**/*'
|
||||
- 'src/Console/**/*'
|
||||
- 'src/Ajax/**/*'
|
||||
- 'src/Blazor/**/*'
|
||||
- 'src/AspNetCore/**/*'
|
||||
- 'src/WinUI/**/*'
|
||||
- 'src/MAUI/**/*'
|
||||
- 'src/Wpf/**/*'
|
||||
|
||||
variables:
|
||||
DOTNET_SDK_VERSION: '10.0.x'
|
||||
buildConfiguration: 'Release'
|
||||
nugetConfigPath: 'src/NuGet.Config'
|
||||
consoleProjectPath: 'src/Console/MyDocProcApp/MyDocProcApp.csproj'
|
||||
ajaxProjectPath: 'src/Ajax/MySite.sln'
|
||||
blazorProjectPath: 'src/Blazor/MyBlazorApp.sln'
|
||||
aspnetProjectPath: 'src/AspNetCore/MyAspNetCoreApp.sln'
|
||||
winuiProjectPath: 'src/WinUI/MyDemo.sln'
|
||||
mauiProjectPath: 'src/MAUI/MauiDemo.csproj'
|
||||
wpfProjectPath: 'src/Wpf/MyWpfApp/MyWpfApp.csproj'
|
||||
# These pipeline variables (secrets) have been set using the AzDO yaml editor at dev.azure.com.
|
||||
# AKEYLESS_ACCESS_ID
|
||||
# MY_TELERIK_NUGET_KEY
|
||||
# MY_TELERIK_LICENSE_KEY
|
||||
|
||||
jobs:
|
||||
# *************************************************************** #
|
||||
# * KENDO ANGULAR (env var) * #
|
||||
# *************************************************************** #
|
||||
- job: BuildAngularAppWithVariables
|
||||
pool:
|
||||
vmImage: 'ubuntu-latest'
|
||||
steps:
|
||||
- powershell: |
|
||||
# 1. Clean the angular cache, to avoid using any expired keys
|
||||
rm -rf .angular/cache
|
||||
|
||||
# 2. Install your project dependencies
|
||||
npm install
|
||||
# npm install --save @progress/kendo-licensing; # if missing from package.json
|
||||
|
||||
#3. Activate
|
||||
npx kendo-ui-license activate
|
||||
|
||||
#4. Build the project
|
||||
npm run build
|
||||
workingDirectory: "src/Kendo/angular_demo"
|
||||
displayName: "Install Dependencies and Activate Kendo"
|
||||
env:
|
||||
# AzDO pipeline secret variable. Note: YAML variable editor supports 14k string values, classic pipelines do not!
|
||||
TELERIK_LICENSE: $(MY_TELERIK_LICENSE_KEY)
|
||||
|
||||
|
||||
# *************************************************************** #
|
||||
# * KENDO ANGULAR (secure file) * #
|
||||
# *************************************************************** #
|
||||
- job: BuildAngularAppWithSecureFile
|
||||
pool:
|
||||
vmImage: 'ubuntu-latest'
|
||||
steps:
|
||||
# Download the license key file (this MUST have a 'name' so it can be referenced later).
|
||||
- task: DownloadSecureFile@1
|
||||
name: GetLicenseFileTask
|
||||
displayName: 'Download SecureFile'
|
||||
inputs:
|
||||
secureFile: 'telerik-license.txt'
|
||||
|
||||
- powershell: |
|
||||
# 1. Clean the angular cache, to avoid using any expired keys
|
||||
rm -rf .angular/cache
|
||||
|
||||
# 2. Install your project dependencies
|
||||
npm install
|
||||
# npm install --save @progress/kendo-licensing; # if missing from package.json
|
||||
|
||||
#3. Activate
|
||||
npx kendo-ui-license activate
|
||||
|
||||
#4. Build the project
|
||||
npm run build
|
||||
workingDirectory: "src/Kendo/angular_demo"
|
||||
displayName: "Install Dependencies and Activate Kendo"
|
||||
env:
|
||||
TELERIK_LICENSE_PATH: $(GetLicenseFileTask.secureFilePath)
|
||||
|
||||
|
||||
# *************************************************************** #
|
||||
# * CONSOLE (without nuget.config) * #
|
||||
# *************************************************************** #
|
||||
- job: BuildConsoleApp_Akeyless
|
||||
pool:
|
||||
vmImage: 'windows-latest'
|
||||
steps:
|
||||
# Get an authentication token from Azure so we can authenticate with Akeyless
|
||||
- task: AzureCLI@2
|
||||
name: 'AzureCLI'
|
||||
displayName: 'Get JWT from Azure Service Principal'
|
||||
inputs:
|
||||
azureSubscription: 'Azure MSA Account'
|
||||
scriptType: ps
|
||||
scriptLocation: inlineScript
|
||||
inlineScript: |
|
||||
$JWT=$(az account get-access-token --query accessToken --output tsv)
|
||||
echo "##vso[task.setvariable variable=azure_jwt;isoutput=true;issecret=true]$JWT"
|
||||
|
||||
# Uses LanceMcCarthy/akeyless-extension-azdo to get a secret (uses azureJwt, see https://github.com/LanceMcCarthy/akeyless-extension-azdo/blob/main/docs/getting-started.md)
|
||||
- task: akeyless-secrets@1
|
||||
name: 'Akeyless1'
|
||||
displayName: 'Get Secrets from Akeyless'
|
||||
inputs:
|
||||
accessid: 'p-sxfgaph9urt4om' # Auth Method ID (see https://github.com/LanceMcCarthy/akeyless-extension-azdo/blob/main/docs/getting-started.md#akeyless-setup)
|
||||
azureJwt: '$(AzureCLI.azure_jwt)' # Output variable from the previous step
|
||||
staticSecrets: '{"/progress/TELERIK_NUGET_KEY":"NUGET_KEY"}'
|
||||
|
||||
- task: UseDotNet@2
|
||||
inputs:
|
||||
packageType: 'sdk'
|
||||
version: $(DOTNET_SDK_VERSION)
|
||||
|
||||
- powershell: dotnet nuget update source 'Telerik_v3_Feed' --source 'https://nuget.telerik.com/v3/index.json' --username 'api-key' --password '$(Akeyless1.NUGET_KEY)' --configfile $(nugetConfigPath) --store-password-in-clear-text
|
||||
displayName: 'Update package source credentials'
|
||||
|
||||
- powershell: dotnet restore $(consoleProjectPath) --configfile $(nugetConfigPath)
|
||||
displayName: 'restore packages'
|
||||
|
||||
- powershell: dotnet publish $(consoleProjectPath) -o /app/publish /p:UseAppHost=false --no-restore
|
||||
displayName: 'Publish the project'
|
||||
env:
|
||||
# AzDO pipeline secret variable. Note: YAML variable editor supports 14k string values, classic pipelines do not!
|
||||
TELERIK_LICENSE: $(MY_TELERIK_LICENSE_KEY)
|
||||
|
||||
|
||||
# *************************************************************** #
|
||||
# * CONSOLE (uses Service connection) * #
|
||||
# *************************************************************** #
|
||||
- job: BuildConsoleApp_ServiceConnection
|
||||
pool:
|
||||
vmImage: 'ubuntu-latest'
|
||||
steps:
|
||||
- task: UseDotNet@2
|
||||
inputs:
|
||||
packageType: 'sdk'
|
||||
version: $(DOTNET_SDK_VERSION)
|
||||
|
||||
# Using Service connection for credentials
|
||||
- task: DotNetCoreCLI@2
|
||||
displayName: 'NuGet restore MyDocProcApp'
|
||||
inputs:
|
||||
command: 'restore'
|
||||
projects: $(consoleProjectPath)
|
||||
feedsToUse: 'config'
|
||||
nugetConfigPath: $(nugetConfigPath)
|
||||
externalFeedCredentials: 'Telerik_v3'
|
||||
|
||||
# Build the project
|
||||
- task: DotNetCoreCLI@2
|
||||
displayName: 'Build MyDocProcApp'
|
||||
inputs:
|
||||
command: 'build'
|
||||
projects: $(consoleProjectPath)
|
||||
configuration: $(buildConfiguration)
|
||||
env:
|
||||
# AzDO pipeline secret variable. Note: YAML variable editor supports 14k string values, classic pipelines do not!
|
||||
TELERIK_LICENSE: $(MY_TELERIK_LICENSE_KEY)
|
||||
|
||||
|
||||
# ************************************************************* #
|
||||
# * BLAZOR * #
|
||||
# ************************************************************* #
|
||||
- job: BuildBlazorApp
|
||||
pool:
|
||||
vmImage: 'ubuntu-latest'
|
||||
steps:
|
||||
- task: UseDotNet@2
|
||||
inputs:
|
||||
packageType: 'sdk'
|
||||
version: $(DOTNET_SDK_VERSION)
|
||||
|
||||
- powershell: dotnet nuget update source 'Telerik_v3_Feed' -s 'https://nuget.telerik.com/v3/index.json' -u 'api-key' -p '$(MY_TELERIK_NUGET_KEY)' --store-password-in-clear-text --configfile $(nugetConfigPath)
|
||||
displayName: 'Update Package Source Credentials'
|
||||
|
||||
- powershell: dotnet restore $(blazorProjectPath) --configfile $(nugetConfigPath)
|
||||
displayName: 'Restore NuGet Packages'
|
||||
|
||||
- powershell: dotnet build $(blazorProjectPath) --no-restore
|
||||
displayName: 'Build and publish'
|
||||
env:
|
||||
# AzDO pipeline secret variable. Note: YAML variable editor supports 14k string values, classic pipelines do not!
|
||||
TELERIK_LICENSE: $(MY_TELERIK_LICENSE_KEY)
|
||||
|
||||
|
||||
# ************************************************************* #
|
||||
# * ASPNET Core * #
|
||||
# ************************************************************* #
|
||||
- job: BuildAspNetCoreApp
|
||||
pool:
|
||||
vmImage: 'ubuntu-latest'
|
||||
steps:
|
||||
- task: UseDotNet@2
|
||||
inputs:
|
||||
packageType: 'sdk'
|
||||
version: $(DOTNET_SDK_VERSION)
|
||||
|
||||
- powershell: dotnet nuget update source 'Telerik_v3_Feed' -s 'https://nuget.telerik.com/v3/index.json' -u 'api-key' -p '$(MY_TELERIK_NUGET_KEY)' --store-password-in-clear-text --configfile $(nugetConfigPath)
|
||||
displayName: 'Update Package Source Credentials'
|
||||
|
||||
- powershell: dotnet restore $(aspnetProjectPath) --configfile $(nugetConfigPath)
|
||||
displayName: 'Restore NuGet Packages'
|
||||
|
||||
- powershell: dotnet build $(aspnetProjectPath) --no-restore
|
||||
displayName: 'Build the project'
|
||||
env:
|
||||
# AzDO pipeline secret variable. Note: YAML variable editor supports 14k string values, classic pipelines do not!
|
||||
TELERIK_LICENSE: $(MY_TELERIK_LICENSE_KEY)
|
||||
|
||||
|
||||
# *************************************************************** #
|
||||
# * ASP.NET AJAX (.NET Framework - SecureFile) * #
|
||||
# *************************************************************** #
|
||||
- job: BuildAjaxApp
|
||||
pool:
|
||||
vmImage: 'windows-latest'
|
||||
steps:
|
||||
- task: DownloadSecureFile@1
|
||||
name: DownloadTelerikLicenseFile # Note 1: Make sure a name value is set, it's referenced later.
|
||||
displayName: 'Download Telerik License Key File'
|
||||
inputs:
|
||||
secureFile: 'telerik-license.txt'
|
||||
|
||||
- task: NuGetToolInstaller@1
|
||||
displayName: 'Use NuGet.exe'
|
||||
inputs:
|
||||
versionSpec: '4.x'
|
||||
|
||||
# You could also use nuget.exe's update command to set the credentials of the 'Telerik_v3_Feed' source defined in the nuget.config
|
||||
# - task: PowerShell@2
|
||||
# displayName: 'Set Package Source Credentials'
|
||||
# inputs:
|
||||
# targetType: 'inline'
|
||||
# script: nuget sources update -Name 'Telerik_v3_Feed' -Source 'https://nuget.telerik.com/v3/index.json' -Username 'api-key' -Password '$(MY_TELERIK_NUGET_KEY)' -ConfigFile '$(nugetConfigPath)' -StorePasswordInClearText
|
||||
|
||||
- task: NuGetCommand@2
|
||||
displayName: 'NuGet restore'
|
||||
inputs:
|
||||
restoreSolution: $(ajaxProjectPath)
|
||||
feedsToUse: config
|
||||
nugetConfigPath: $(nugetConfigPath)
|
||||
externalFeedCredentials: 'Telerik_v3'
|
||||
|
||||
- task: MSBuild@1
|
||||
displayName: 'Build AJAX Project'
|
||||
inputs:
|
||||
solution: '$(ajaxProjectPath)'
|
||||
platform: Any CPU
|
||||
configuration: Release
|
||||
msbuildArguments: '/t:Restore /p:Configuration=Release /p:RuntimeIdentifier=any'
|
||||
env:
|
||||
TELERIK_LICENSE_PATH: $(DownloadTelerikLicenseFile.secureFilePath) # Note 2: We use the name to reference the secureFilePath value
|
||||
|
||||
|
||||
# ************************************************************* #
|
||||
# * WinUI 3 * #
|
||||
# ************************************************************* #
|
||||
- job: BuildWinUI
|
||||
pool:
|
||||
vmImage: 'windows-latest'
|
||||
steps:
|
||||
- task: UseDotNet@2
|
||||
inputs:
|
||||
packageType: 'sdk'
|
||||
version: $(DOTNET_SDK_VERSION)
|
||||
|
||||
- powershell: dotnet nuget update source 'Telerik_v3_Feed' -s 'https://nuget.telerik.com/v3/index.json' -u 'api-key' -p '$(MY_TELERIK_NUGET_KEY)' --store-password-in-clear-text --configfile $(nugetConfigPath)
|
||||
displayName: 'Update Package Source Credentials'
|
||||
|
||||
- powershell: dotnet restore $(winuiProjectPath) --configfile $(nugetConfigPath)
|
||||
displayName: 'Restore NuGet Packages'
|
||||
|
||||
- task: MSBuild@1
|
||||
displayName: 'Restore RIDs'
|
||||
inputs:
|
||||
solution: '$(winuiProjectPath)'
|
||||
platform: x64
|
||||
configuration: Release
|
||||
msbuildArguments: '/t:Restore /p:Configuration=Release /p:RestorePackages=true /p:RestoreRIDs=true /p:RestoreProjectStyle=PackageReference'
|
||||
|
||||
# Note: PFX thumbprint is intentionally set to an empty string, this overrides any previous thumbprint from the project
|
||||
- task: MSBuild@1
|
||||
displayName: 'Build and Create MSIX'
|
||||
inputs:
|
||||
solution: '$(winuiProjectPath)'
|
||||
platform: x64
|
||||
configuration: Release
|
||||
msbuildArguments: '/p:AppxBundlePlatforms="x64|arm64"
|
||||
/p:UapAppxPackageBuildMode=CI
|
||||
/p:AppxBundle=Never
|
||||
/p:PackageCertificateKeyFile="$(PfxDownloadStep.secureFilePath)"
|
||||
/p:PackageCertificatePassword="$(PfxPassword)"
|
||||
/p:PackageCertificateThumbprint=""
|
||||
/p:AppxPackageDir="$(Build.ArtifactStagingDirectory)/AppPackages"
|
||||
/p:GenerateAppxPackageOnBuild=true
|
||||
/p:AppxPackageSigningEnabled=false
|
||||
/p:SelfContained=true'
|
||||
env:
|
||||
TELERIK_LICENSE: $(MY_TELERIK_LICENSE_KEY)
|
||||
|
||||
|
||||
# ************************************************************* #
|
||||
# * .NET MAUI * #
|
||||
# ************************************************************* #
|
||||
# https://learn.microsoft.com/en-us/azure/devops/pipelines/agents/hosted?view=azure-devops&tabs=windows-images%2Cyaml#software
|
||||
- job: BuildMauiApp
|
||||
strategy:
|
||||
matrix:
|
||||
android:
|
||||
TFM: 'net10.0-android'
|
||||
imageName: 'windows-2025' # windows-2025
|
||||
windows:
|
||||
TFM: 'net10.0-windows10.0.19041.0'
|
||||
imageName: 'windows-latest' # windows-2025
|
||||
ios:
|
||||
TFM: 'net10.0-ios'
|
||||
imageName: 'macOS-latest' # macOS-15
|
||||
maccatalyst:
|
||||
TFM: 'net10.0-maccatalyst'
|
||||
imageName: 'macOS-latest' # macOS-15
|
||||
maxParallel: 4
|
||||
pool:
|
||||
vmImage: $(imageName)
|
||||
steps:
|
||||
- task: UseDotNet@2
|
||||
inputs:
|
||||
packageType: 'sdk'
|
||||
version: $(DOTNET_SDK_VERSION)
|
||||
|
||||
- task: CmdLine@2
|
||||
displayName: 'Set Xcode to v26.1.0'
|
||||
condition: eq(variables['Agent.OS'], 'Darwin') # Only run this step on macOS
|
||||
inputs:
|
||||
script: |
|
||||
echo '##vso[task.setvariable variable=MD_APPLE_SDK_ROOT;]'/Applications/Xcode_26.1.app
|
||||
sudo xcode-select --switch /Applications/Xcode_26.1.app/Contents/Developer
|
||||
|
||||
- powershell: dotnet workload install maui --source https://api.nuget.org/v3/index.json
|
||||
displayName: 'Install maui workloads'
|
||||
|
||||
- powershell: dotnet nuget update source 'Telerik_v3_Feed' -s 'https://nuget.telerik.com/v3/index.json' -u 'api-key' -p '$(MY_TELERIK_NUGET_KEY)' --store-password-in-clear-text --configfile $(nugetConfigPath)
|
||||
displayName: 'Update Package Source Credentials'
|
||||
|
||||
- powershell: dotnet restore $(mauiProjectPath) --configfile $(nugetConfigPath)
|
||||
displayName: 'Restore NuGet Packages'
|
||||
|
||||
- powershell: dotnet build $(mauiProjectPath) -f $(TFM) -c Debug --no-restore
|
||||
displayName: 'Build $(TFM)'
|
||||
env:
|
||||
# AzDO pipeline secret variable. Note: YAML variable editor supports 14k string values, classic pipelines do not!
|
||||
TELERIK_LICENSE: $(MY_TELERIK_LICENSE_KEY)
|
||||
|
||||
# ************************************************************* #
|
||||
# * WPF * #
|
||||
# ************************************************************* #
|
||||
- job: BuildWpfApp
|
||||
pool:
|
||||
vmImage: windows-2025
|
||||
steps:
|
||||
- task: UseDotNet@2
|
||||
inputs:
|
||||
packageType: 'sdk'
|
||||
version: $(DOTNET_SDK_VERSION)
|
||||
|
||||
- task: NuGetToolInstaller@1
|
||||
displayName: 'Use NuGet.exe'
|
||||
inputs:
|
||||
versionSpec: '4.x'
|
||||
|
||||
- task: NuGetCommand@2
|
||||
displayName: 'NuGet restore'
|
||||
inputs:
|
||||
restoreSolution: $(wpfProjectPath)
|
||||
feedsToUse: config
|
||||
nugetConfigPath: $(nugetConfigPath)
|
||||
externalFeedCredentials: 'Telerik_v3'
|
||||
|
||||
- task: MSBuild@1
|
||||
displayName: 'Build WPF'
|
||||
inputs:
|
||||
solution: $(wpfProjectPath)
|
||||
platform: 'x86'
|
||||
configuration: 'Release'
|
||||
msbuildArguments: '/p:RestorePackages=true /p:OutputPath=$(Build.artifactStagingDirectory)'
|
||||
env:
|
||||
# AzDO pipeline secret variable. Note: YAML variable editor supports 14k string values, classic pipelines do not!
|
||||
TELERIK_LICENSE: $(MY_TELERIK_LICENSE_KEY)
|
||||
|
||||
# - task: PublishBuildArtifacts@1
|
||||
# inputs:
|
||||
# PathtoPublish: '$(Build.ArtifactStagingDirectory)'
|
||||
# ArtifactName: 'wpf_drop'
|
||||
# publishLocation: 'Container'
|
||||
@@ -0,0 +1,9 @@
|
||||
namespace MySite.Web
|
||||
{
|
||||
public class Article
|
||||
{
|
||||
public int ID { get; set; }
|
||||
public string Title { get; set; }
|
||||
public string Description { get; set; }
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,66 @@
|
||||
<%@ Page Title="" Language="C#" MasterPageFile="~/MasterPage.Master" AutoEventWireup="true" CodeBehind="Default.aspx.cs" Inherits="MySite.Web.Default" %>
|
||||
<%@ Register TagPrefix="telerik" Namespace="Telerik.Web.UI" Assembly="Telerik.Web.UI" %>
|
||||
|
||||
<asp:Content ID="Content0" ContentPlaceHolderID="head" Runat="Server">
|
||||
<link href="styles/default.css" rel="stylesheet" />
|
||||
</asp:Content>
|
||||
|
||||
<asp:Content ID="Content2" ContentPlaceHolderID="ContentPlaceHolder1" runat="Server">
|
||||
<telerik:RadPageLayout runat="server" ID="RadPageLayout1">
|
||||
<Rows>
|
||||
<telerik:LayoutRow>
|
||||
<Columns>
|
||||
<telerik:LayoutColumn CssClass="jumbotron">
|
||||
<h1>H1 title, font size 36px</h1>
|
||||
<h2>H2 Title, font size 30 px. Duis nibh dolor, rhoncus in euismod at, feugiat id magna.
|
||||
<telerik:RadButton runat="server" ID="RadButton0" Text="Button" ButtonType="SkinnedButton"></telerik:RadButton>
|
||||
</h2>
|
||||
|
||||
</telerik:LayoutColumn>
|
||||
</Columns>
|
||||
</telerik:LayoutRow>
|
||||
<telerik:LayoutRow>
|
||||
<Columns>
|
||||
<telerik:LayoutColumn HiddenMd="true" HiddenSm="true" HiddenXs="true">
|
||||
<h3>H3 text, font size 24 px </h3>
|
||||
Ut aliquam elit eget quam tincidunt, et aliquam libero congue. Phasellus aliquet sed quam vitae dictum. Aliquam erat volutpat. Morbi accumsan a mi quis pretium.
|
||||
</telerik:LayoutColumn>
|
||||
</Columns>
|
||||
</telerik:LayoutRow>
|
||||
</Rows>
|
||||
</telerik:RadPageLayout>
|
||||
|
||||
</asp:Content>
|
||||
|
||||
<asp:Content ID="Content3" ContentPlaceHolderID="ContentPlaceHolder2" runat="Server">
|
||||
<telerik:RadPageLayout runat="server" ID="Content1">
|
||||
<Rows>
|
||||
<telerik:LayoutRow>
|
||||
<Columns>
|
||||
<telerik:LayoutColumn Span="4" SpanMd="12" SpanSm="12" HiddenXs="true">
|
||||
<h4>H4 text font size 18 px.</h4>
|
||||
<p><strong>Main content text font size 16px</strong>, aliquam turpis sed nisl mattis sagittis. Class aptent taciti sociosqu ad litora torquent per conubia nostra, per inceptos himenaeos. Ut vitae sapien metus. In hac habitasse platea dictumst. Aenean velit mauris, lobortis eu lacinia sed</p>
|
||||
<p>Nullam facilisis neque ut aliquet imperdiet. Mauris ut odio augue. Curabitur in mi ac odio vestibulum lobortis. </p>
|
||||
<telerik:RadButton runat="server" ID="RadButton1" Text="Button" ButtonType="SkinnedButton"></telerik:RadButton>
|
||||
</telerik:LayoutColumn>
|
||||
|
||||
<telerik:LayoutColumn Span="4" SpanMd="12" SpanSm="12" HiddenXs="true">
|
||||
<h4>H4 text font size 18 px.</h4>
|
||||
<p><strong>Main content text font size 16px</strong>, aliquam turpis sed nisl mattis sagittis. Class aptent taciti sociosqu ad litora torquent per conubia nostra, per inceptos himenaeos. Ut vitae sapien metus. In hac habitasse platea dictumst. Aenean velit mauris, lobortis eu lacinia sed</p>
|
||||
|
||||
<p>Nullam facilisis neque ut aliquet imperdiet. Mauris ut odio augue. Curabitur in mi ac odio vestibulum lobortis. </p>
|
||||
<telerik:RadButton runat="server" ID="RadButton2" Text="Button" ButtonType="SkinnedButton"></telerik:RadButton>
|
||||
</telerik:LayoutColumn>
|
||||
|
||||
<telerik:LayoutColumn Span="4" SpanMd="12" SpanSm="12" HiddenXs="true">
|
||||
<h4>H4 text font size 18 px.</h4>
|
||||
<p><strong>Main content text font size 16px</strong>, aliquam turpis sed nisl mattis sagittis. Class aptent taciti sociosqu ad litora torquent per conubia nostra, per inceptos himenaeos. Ut vitae sapien metus. In hac habitasse platea dictumst. Aenean velit mauris, lobortis eu lacinia sed</p>
|
||||
|
||||
<p>Nullam facilisis neque ut aliquet imperdiet. Mauris ut odio augue. Curabitur in mi ac odio vestibulum lobortis. </p>
|
||||
<telerik:RadButton runat="server" ID="RadButton3" Text="Button" ButtonType="SkinnedButton"></telerik:RadButton>
|
||||
</telerik:LayoutColumn>
|
||||
</Columns>
|
||||
</telerik:LayoutRow>
|
||||
</Rows>
|
||||
</telerik:RadPageLayout>
|
||||
</asp:Content>
|
||||
@@ -0,0 +1,17 @@
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Linq;
|
||||
using System.Web;
|
||||
using System.Web.UI;
|
||||
using System.Web.UI.WebControls;
|
||||
|
||||
namespace MySite.Web
|
||||
{
|
||||
public partial class Default : System.Web.UI.Page
|
||||
{
|
||||
protected void Page_Load(object sender, EventArgs e)
|
||||
{
|
||||
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,71 @@
|
||||
//------------------------------------------------------------------------------
|
||||
// <auto-generated>
|
||||
// This code was generated by a tool.
|
||||
//
|
||||
// Changes to this file may cause incorrect behavior and will be lost if
|
||||
// the code is regenerated.
|
||||
// </auto-generated>
|
||||
//------------------------------------------------------------------------------
|
||||
|
||||
namespace MySite.Web
|
||||
{
|
||||
|
||||
|
||||
public partial class Default
|
||||
{
|
||||
|
||||
/// <summary>
|
||||
/// RadPageLayout1 control.
|
||||
/// </summary>
|
||||
/// <remarks>
|
||||
/// Auto-generated field.
|
||||
/// To modify move field declaration from designer file to code-behind file.
|
||||
/// </remarks>
|
||||
protected global::Telerik.Web.UI.RadPageLayout RadPageLayout1;
|
||||
|
||||
/// <summary>
|
||||
/// RadButton0 control.
|
||||
/// </summary>
|
||||
/// <remarks>
|
||||
/// Auto-generated field.
|
||||
/// To modify move field declaration from designer file to code-behind file.
|
||||
/// </remarks>
|
||||
protected global::Telerik.Web.UI.RadButton RadButton0;
|
||||
|
||||
/// <summary>
|
||||
/// Content1 control.
|
||||
/// </summary>
|
||||
/// <remarks>
|
||||
/// Auto-generated field.
|
||||
/// To modify move field declaration from designer file to code-behind file.
|
||||
/// </remarks>
|
||||
protected global::Telerik.Web.UI.RadPageLayout Content1;
|
||||
|
||||
/// <summary>
|
||||
/// RadButton1 control.
|
||||
/// </summary>
|
||||
/// <remarks>
|
||||
/// Auto-generated field.
|
||||
/// To modify move field declaration from designer file to code-behind file.
|
||||
/// </remarks>
|
||||
protected global::Telerik.Web.UI.RadButton RadButton1;
|
||||
|
||||
/// <summary>
|
||||
/// RadButton2 control.
|
||||
/// </summary>
|
||||
/// <remarks>
|
||||
/// Auto-generated field.
|
||||
/// To modify move field declaration from designer file to code-behind file.
|
||||
/// </remarks>
|
||||
protected global::Telerik.Web.UI.RadButton RadButton2;
|
||||
|
||||
/// <summary>
|
||||
/// RadButton3 control.
|
||||
/// </summary>
|
||||
/// <remarks>
|
||||
/// Auto-generated field.
|
||||
/// To modify move field declaration from designer file to code-behind file.
|
||||
/// </remarks>
|
||||
protected global::Telerik.Web.UI.RadButton RadButton3;
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,88 @@
|
||||
<%@ Page Title="" Language="C#" MasterPageFile="~/MasterPageSingleMenu.Master" AutoEventWireup="true" CodeBehind="Grid.aspx.cs" Inherits="MySite.Web.Grid" %>
|
||||
<%@ Register TagPrefix="telerik" Namespace="Telerik.Web.UI" Assembly="Telerik.Web.UI" %>
|
||||
|
||||
<asp:Content ID="Content1" ContentPlaceHolderID="head" runat="Server">
|
||||
<link href="styles/grid.css" rel="stylesheet" />
|
||||
</asp:Content>
|
||||
|
||||
<asp:Content ID="Content2" ContentPlaceHolderID="ContentPlaceHolder1" runat="Server">
|
||||
<telerik:RadPageLayout runat="server" ID="JumbotronLayout" CssClass="jumbotron" GridType="Fluid">
|
||||
<Rows>
|
||||
<telerik:LayoutRow>
|
||||
<Columns>
|
||||
<telerik:LayoutColumn Span="10" SpanMd="12" SpanSm="12" SpanXs="12">
|
||||
<h1>H1 title, font size 36px. Duis nibh dolor, rhoncus in euismod at, feugiat id magna.</h1>
|
||||
<h2>H2 Title, font size 30 px.</h2>
|
||||
<telerik:RadButton runat="server" ID="RadButton0" Text="Button" ButtonType="SkinnedButton"></telerik:RadButton>
|
||||
</telerik:LayoutColumn>
|
||||
<telerik:LayoutColumn Span="2" HiddenMd="true" HiddenSm="true" HiddenXs="true">
|
||||
<img src="images/Thumbnails/Desert.jpg" />
|
||||
</telerik:LayoutColumn>
|
||||
</Columns>
|
||||
</telerik:LayoutRow>
|
||||
</Rows>
|
||||
</telerik:RadPageLayout>
|
||||
</asp:Content>
|
||||
|
||||
<asp:Content ID="Content3" ContentPlaceHolderID="ContentPlaceHolder2" runat="Server">
|
||||
|
||||
<telerik:RadAjaxPanel ID="RadAjaxPanel1" ClientEvents-OnRequestStart="onRequestStart" runat="server" CssClass="grid_wrapper">
|
||||
<telerik:RadGrid ID="RadGrid1" runat="server" PageSize="10" PagerStyle-PageButtonCount="5"
|
||||
OnNeedDataSource="RadGrid1_NeedDataSource" OnItemCreated="RadGrid1_ItemCreated" OnItemDataBound="RadGrid1_ItemDataBound"
|
||||
OnUpdateCommand="RadGrid1_UpdateCommand" OnInsertCommand="RadGrid1_InsertCommand" OnDeleteCommand="RadGrid1_DeleteCommand"
|
||||
AllowPaging="True" AllowSorting="true" ShowGroupPanel="true" RenderMode="Auto">
|
||||
<GroupingSettings ShowUnGroupButton="true" />
|
||||
<ExportSettings ExportOnlyData="true" IgnorePaging="true"></ExportSettings>
|
||||
<MasterTableView AutoGenerateColumns="False"
|
||||
AllowFilteringByColumn="true" TableLayout="Fixed"
|
||||
DataKeyNames="ID" CommandItemDisplay="Top"
|
||||
InsertItemPageIndexAction="ShowItemOnFirstPage">
|
||||
<CommandItemSettings ShowExportToCsvButton="true" ShowExportToExcelButton="true" ShowExportToPdfButton="true" ShowExportToWordButton="true" />
|
||||
<Columns>
|
||||
<telerik:GridBoundColumn DataField="Name" HeaderText="Name" SortExpression="Name"
|
||||
UniqueName="Name">
|
||||
<HeaderStyle Width="150px" />
|
||||
</telerik:GridBoundColumn>
|
||||
<telerik:GridNumericColumn DataField="Age" HeaderText="Age" SortExpression="Age"
|
||||
UniqueName="Age">
|
||||
<HeaderStyle Width="150px" />
|
||||
</telerik:GridNumericColumn>
|
||||
<telerik:GridDateTimeColumn DataField="BirthDate" HeaderText="BirthDate" SortExpression="BirthDate"
|
||||
UniqueName="BirthDate" PickerType="DatePicker" DataFormatString="{0:MM/dd/yyyy}">
|
||||
<HeaderStyle Width="150px" />
|
||||
</telerik:GridDateTimeColumn>
|
||||
<telerik:GridRatingColumn DataField="Rating" HeaderText="Rating" SortExpression="Rating"
|
||||
UniqueName="Rating" GroupByExpression="Rating Group By Rating">
|
||||
<HeaderStyle Width="150px" />
|
||||
</telerik:GridRatingColumn>
|
||||
<telerik:GridDropDownColumn DataField="City" HeaderText="City" SortExpression="City"
|
||||
ListDataMember="City" ListTextField="City"
|
||||
UniqueName="City" DropDownControlType="RadComboBox">
|
||||
<HeaderStyle Width="150px" />
|
||||
</telerik:GridDropDownColumn>
|
||||
<telerik:GridEditCommandColumn UniqueName="EditColumn" HeaderText="Edit Command Column">
|
||||
<HeaderStyle Width="70px" />
|
||||
</telerik:GridEditCommandColumn>
|
||||
<telerik:GridButtonColumn CommandName="Delete" Text="Delete" UniqueName="DeleteColumn" HeaderText="Delete Command Column">
|
||||
<HeaderStyle Width="70px" />
|
||||
</telerik:GridButtonColumn>
|
||||
</Columns>
|
||||
</MasterTableView>
|
||||
<ClientSettings AllowColumnsReorder="true" AllowColumnHide="true" AllowDragToGroup="true">
|
||||
<Selecting AllowRowSelect="true" />
|
||||
<Scrolling AllowScroll="true" UseStaticHeaders="true" />
|
||||
</ClientSettings>
|
||||
</telerik:RadGrid>
|
||||
</telerik:RadAjaxPanel>
|
||||
<telerik:RadCodeBlock runat="server">
|
||||
<script type="text/javascript">
|
||||
function onRequestStart(sender, args) {
|
||||
if (args.get_eventTarget().indexOf("Button") >= 0) {
|
||||
args.set_enableAjax(false);
|
||||
}
|
||||
}
|
||||
</script>
|
||||
</telerik:RadCodeBlock>
|
||||
</asp:Content>
|
||||
|
||||
|
||||
@@ -0,0 +1,161 @@
|
||||
using System;
|
||||
using System.Collections;
|
||||
using System.Collections.Generic;
|
||||
using System.Data;
|
||||
using System.Web.UI.WebControls;
|
||||
using Telerik.Web.UI;
|
||||
|
||||
namespace MySite.Web
|
||||
{
|
||||
public partial class Grid : System.Web.UI.Page
|
||||
{
|
||||
public DataTable Sellers
|
||||
{
|
||||
get
|
||||
{
|
||||
DataTable data = Session["Data"] as DataTable;
|
||||
|
||||
if (data == null)
|
||||
{
|
||||
data = GetSellers();
|
||||
Session["Data"] = data;
|
||||
}
|
||||
|
||||
return data;
|
||||
}
|
||||
}
|
||||
|
||||
public DataTable GetSellers()
|
||||
{
|
||||
DataTable data = new DataTable();
|
||||
data.Columns.Add("ID", typeof(int));
|
||||
data.Columns.Add("Name");
|
||||
data.Columns.Add("Age", typeof(int)).DefaultValue = 0;
|
||||
data.Columns.Add("BirthDate", typeof(DateTime));
|
||||
data.Columns.Add("Rating", typeof(int)).DefaultValue = 0;
|
||||
data.Columns.Add("City");
|
||||
data.PrimaryKey = new DataColumn[] { data.Columns["ID"] };
|
||||
|
||||
List<string> firstNames = new List<string>() { "Nancy", "Andrew", "Janet", "Margaret", "Steven", "Michael", "Robert", "Laura", "Anne", "Nige" };
|
||||
List<string> cities = this.GetCities();
|
||||
List<DateTime> birthDates = new List<DateTime>() { DateTime.Parse("1948/12/08"), DateTime.Parse("1952/02/19"), DateTime.Parse("1963/08/30"), DateTime.Parse("1937/09/19"), DateTime.Parse("1955/03/04"), DateTime.Parse("1963/07/02"), DateTime.Parse("1960/05/29"), DateTime.Parse("1958/01/09"), DateTime.Parse("1966/01/27"), DateTime.Parse("1966/03/27") };
|
||||
Random random = new Random();
|
||||
|
||||
for (int i = 0; i < 84; i++)
|
||||
{
|
||||
DateTime birthDate = birthDates[random.Next(birthDates.Count - 1)];
|
||||
data.Rows.Add(
|
||||
random.Next(10000, int.MaxValue),
|
||||
firstNames[random.Next(firstNames.Count - 1)],
|
||||
DateTime.Now.Year - birthDate.Year, birthDate, random.Next(1, 5),
|
||||
cities[random.Next(cities.Count - 1)]);
|
||||
}
|
||||
|
||||
return data;
|
||||
}
|
||||
|
||||
public List<string> GetCities()
|
||||
{
|
||||
return new List<string>()
|
||||
{
|
||||
"Seattle",
|
||||
"Tacoma",
|
||||
"Kirkland",
|
||||
"Redmond",
|
||||
"London",
|
||||
"Philadelphia",
|
||||
"New York",
|
||||
"Seattle",
|
||||
"London",
|
||||
"Boston"
|
||||
};
|
||||
}
|
||||
|
||||
protected void RadGrid1_NeedDataSource(object sender, Telerik.Web.UI.GridNeedDataSourceEventArgs e)
|
||||
{
|
||||
RadGrid1.DataSource = this.Sellers;
|
||||
}
|
||||
|
||||
protected void RadGrid1_UpdateCommand(object sender, Telerik.Web.UI.GridCommandEventArgs e)
|
||||
{
|
||||
Hashtable table = new Hashtable();
|
||||
(e.Item as GridEditableItem).ExtractValues(table);
|
||||
|
||||
DataRow row = this.Sellers.Rows.Find((e.Item as GridEditableItem).GetDataKeyValue("ID"));
|
||||
|
||||
foreach (string key in table.Keys)
|
||||
{
|
||||
row[key] = table[key] ?? DBNull.Value;
|
||||
}
|
||||
DateTime date;
|
||||
if (DateTime.TryParse((row["BirthDate"].ToString()), out date))
|
||||
{
|
||||
row["Age"] = DateTime.Now.Year - date.Year;
|
||||
}
|
||||
else
|
||||
{
|
||||
row["Age"] = 0;
|
||||
}
|
||||
}
|
||||
|
||||
protected void RadGrid1_InsertCommand(object sender, GridCommandEventArgs e)
|
||||
{
|
||||
Hashtable table = new Hashtable();
|
||||
(e.Item as GridEditableItem).ExtractValues(table);
|
||||
DataRow row = this.Sellers.NewRow();
|
||||
|
||||
foreach (string key in table.Keys)
|
||||
{
|
||||
if (table[key] != null)
|
||||
{
|
||||
row[key] = table[key];
|
||||
}
|
||||
}
|
||||
row["ID"] = new Random().Next(int.MaxValue);
|
||||
DateTime date;
|
||||
if (DateTime.TryParse((row["BirthDate"].ToString()), out date))
|
||||
{
|
||||
row["Age"] = DateTime.Now.Date.Year - date.Year;
|
||||
}
|
||||
this.Sellers.Rows.InsertAt(row, 0);
|
||||
}
|
||||
|
||||
protected void RadGrid1_DeleteCommand(object sender, GridCommandEventArgs e)
|
||||
{
|
||||
this.Sellers.Rows.Remove(this.Sellers.Rows.Find((e.Item as GridEditableItem).GetDataKeyValue("ID")));
|
||||
}
|
||||
|
||||
protected void RadGrid1_ItemDataBound(object sender, GridItemEventArgs e)
|
||||
{
|
||||
RadComboBox comboBox = e.Item.FindControl("RCB_City") as RadComboBox;
|
||||
if (comboBox != null)
|
||||
{
|
||||
if (!(e.Item.DataItem is GridInsertionObject))
|
||||
{
|
||||
comboBox.SelectedValue = (e.Item.DataItem as DataRowView)["City"].ToString();
|
||||
}
|
||||
comboBox.DataTextField = string.Empty;
|
||||
comboBox.DataSource = this.GetCities();
|
||||
comboBox.DataBind();
|
||||
if (this.RadGrid1.ResolvedRenderMode == RenderMode.Mobile)
|
||||
{
|
||||
(e.Item.FindControl("TB_Age") as WebControl).Enabled = false;
|
||||
}
|
||||
else
|
||||
{
|
||||
((e.Item as GridEditableItem)["Age"].Controls[0] as WebControl).Enabled = false;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
protected void RadGrid1_ItemCreated(object sender, GridItemEventArgs e)
|
||||
{
|
||||
GridHeaderItem headerItem = e.Item as GridHeaderItem;
|
||||
if (headerItem != null)
|
||||
{
|
||||
headerItem["EditColumn"].Text = string.Empty;
|
||||
headerItem["DeleteColumn"].Text = string.Empty;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,53 @@
|
||||
//------------------------------------------------------------------------------
|
||||
// <auto-generated>
|
||||
// This code was generated by a tool.
|
||||
//
|
||||
// Changes to this file may cause incorrect behavior and will be lost if
|
||||
// the code is regenerated.
|
||||
// </auto-generated>
|
||||
//------------------------------------------------------------------------------
|
||||
|
||||
namespace MySite.Web
|
||||
{
|
||||
|
||||
|
||||
public partial class Grid
|
||||
{
|
||||
|
||||
/// <summary>
|
||||
/// JumbotronLayout control.
|
||||
/// </summary>
|
||||
/// <remarks>
|
||||
/// Auto-generated field.
|
||||
/// To modify move field declaration from designer file to code-behind file.
|
||||
/// </remarks>
|
||||
protected global::Telerik.Web.UI.RadPageLayout JumbotronLayout;
|
||||
|
||||
/// <summary>
|
||||
/// RadButton0 control.
|
||||
/// </summary>
|
||||
/// <remarks>
|
||||
/// Auto-generated field.
|
||||
/// To modify move field declaration from designer file to code-behind file.
|
||||
/// </remarks>
|
||||
protected global::Telerik.Web.UI.RadButton RadButton0;
|
||||
|
||||
/// <summary>
|
||||
/// RadAjaxPanel1 control.
|
||||
/// </summary>
|
||||
/// <remarks>
|
||||
/// Auto-generated field.
|
||||
/// To modify move field declaration from designer file to code-behind file.
|
||||
/// </remarks>
|
||||
protected global::Telerik.Web.UI.RadAjaxPanel RadAjaxPanel1;
|
||||
|
||||
/// <summary>
|
||||
/// RadGrid1 control.
|
||||
/// </summary>
|
||||
/// <remarks>
|
||||
/// Auto-generated field.
|
||||
/// To modify move field declaration from designer file to code-behind file.
|
||||
/// </remarks>
|
||||
protected global::Telerik.Web.UI.RadGrid RadGrid1;
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,11 @@
|
||||
namespace MySite.Web
|
||||
{
|
||||
public class Image
|
||||
{
|
||||
public int ID { get; set; }
|
||||
public string Name { get; set; }
|
||||
public string Description { get; set; }
|
||||
public string ImageUrl { get; set; }
|
||||
public string ThumbnailUrl { get; set; }
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,67 @@
|
||||
<%@ Page Title="" Language="C#" MasterPageFile="~/MasterPageSingleMenu.Master" AutoEventWireup="true" CodeBehind="ListView.aspx.cs" Inherits="MySite.Web.ListView" %>
|
||||
<%@ Register TagPrefix="telerik" Namespace="Telerik.Web.UI" Assembly="Telerik.Web.UI" %>
|
||||
|
||||
<asp:Content ID="Content1" ContentPlaceHolderID="head" runat="Server">
|
||||
<script src="scripts/scripts.js"></script>
|
||||
<link href="styles/listView.css" rel="stylesheet" />
|
||||
</asp:Content>
|
||||
|
||||
<asp:Content ID="Content2" ContentPlaceHolderID="ContentPlaceHolder1" runat="Server">
|
||||
<telerik:RadPageLayout runat="server" ID="JumbotronLayout" CssClass="jumbotron" GridType="Fluid">
|
||||
<Rows>
|
||||
<telerik:LayoutRow>
|
||||
<Columns>
|
||||
<telerik:LayoutColumn Span="10" SpanMd="12" SpanSm="12" SpanXs="12">
|
||||
<h1>H1 title, font size 36px. Duis nibh dolor, rhoncus in euismod at, feugiat id magna.</h1>
|
||||
<h2>H2 Title, font size 30 px.</h2>
|
||||
<telerik:RadButton runat="server" ID="RadButton0" Text="Button" ButtonType="SkinnedButton"></telerik:RadButton>
|
||||
</telerik:LayoutColumn>
|
||||
<telerik:LayoutColumn Span="2" HiddenMd="true" HiddenSm="true" HiddenXs="true">
|
||||
<img src="images/Thumbnails/Desert.jpg" />
|
||||
</telerik:LayoutColumn>
|
||||
</Columns>
|
||||
</telerik:LayoutRow>
|
||||
</Rows>
|
||||
</telerik:RadPageLayout>
|
||||
|
||||
</asp:Content>
|
||||
|
||||
<asp:Content ID="Content3" ContentPlaceHolderID="ContentPlaceHolder2" runat="Server">
|
||||
<telerik:RadListView runat="server" OnItemDataBound="RadListViewImages_ItemDataBound" OnNeedDataSource="RadListViewImages_NeedDataSource" ID="RadListViewImages" AllowPaging="true" PageSize="3">
|
||||
<LayoutTemplate>
|
||||
<div class="listView1">
|
||||
<asp:Panel ID="itemPlaceholder" runat="server">
|
||||
</asp:Panel>
|
||||
</div>
|
||||
</LayoutTemplate>
|
||||
<ItemTemplate>
|
||||
<div class="listViewItem" onclick="example.imageClicked('<%# Eval("ID") %>')">
|
||||
<asp:Image ImageUrl='<%# Eval("ThumbnailUrl") %>' Width="200px" Height="150px" runat="server" ToolTip="Click to view larger image" />
|
||||
<p>
|
||||
<asp:Literal runat="server" ID="LabelShortDescription"></asp:Literal></p>
|
||||
|
||||
</div>
|
||||
</ItemTemplate>
|
||||
</telerik:RadListView>
|
||||
<hr />
|
||||
<telerik:RadListView runat="server" OnNeedDataSource="RadListViewArticles_NeedDataSource" ID="RadListViewArticles" AllowPaging="true" PageSize="4">
|
||||
<LayoutTemplate>
|
||||
<div class="listView2">
|
||||
<asp:Panel ID="itemPlaceholder" runat="server">
|
||||
</asp:Panel>
|
||||
</div>
|
||||
</LayoutTemplate>
|
||||
<ItemTemplate>
|
||||
<div class="listViewItem article">
|
||||
<h4><%# Eval("Title") %></h4>
|
||||
<%# Eval("Description") %>
|
||||
</div>
|
||||
</ItemTemplate>
|
||||
</telerik:RadListView>
|
||||
<telerik:RadLightBox DataImageUrlField="ImageUrl" DataDescriptionField="Description" DataTitleField="Name" runat="server" ID="RadLightBoxImageDetails">
|
||||
<ClientSettings>
|
||||
<ClientEvents OnLoad="example.radLightBoxLoad" />
|
||||
</ClientSettings>
|
||||
</telerik:RadLightBox>
|
||||
</asp:Content>
|
||||
|
||||
@@ -0,0 +1,95 @@
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Web.UI.WebControls;
|
||||
using Telerik.Web.UI;
|
||||
|
||||
namespace MySite.Web
|
||||
{
|
||||
public partial class ListView : System.Web.UI.Page
|
||||
{
|
||||
public List<Image> Images
|
||||
{
|
||||
get
|
||||
{
|
||||
List<Image> data = Session["DataImages"] as List<Image>;
|
||||
|
||||
if (data == null)
|
||||
{
|
||||
data = GetImages();
|
||||
Session["DataImages"] = data;
|
||||
}
|
||||
|
||||
return data;
|
||||
}
|
||||
}
|
||||
|
||||
public List<Image> GetImages()
|
||||
{
|
||||
return new List<Image>() {
|
||||
new Image() { ID=1, Name="Chrysanthemum", ImageUrl="~/images/Chrysanthemum.jpg", ThumbnailUrl="~/images/Thumbnails/Chrysanthemum.jpg", Description="Lorem Ipsum is simply dummy text of the printing and typesetting industry. Lorem Ipsum has been the industry's standard dummy text ever since the 1500s"},
|
||||
new Image() { ID=2, Name="Desert", ImageUrl="~/images/Desert.jpg", ThumbnailUrl="~/images/Thumbnails/Desert.jpg", Description="Lorem Ipsum is simply dummy text of the printing and typesetting industry. Lorem Ipsum has been the industry's standard dummy text ever since the 1500s"},
|
||||
new Image() { ID=3, Name="Hydrangeas", ImageUrl="~/images/Hydrangeas.jpg", ThumbnailUrl="~/images/Thumbnails/Hydrangeas.jpg", Description="The point of using Lorem Ipsum is that it has a more-or-less normal distribution of letters, as opposed to using 'Content here, content here', making it look like readable English."},
|
||||
new Image() { ID=4, Name="Jellyfish", ImageUrl="~/images/Jellyfish.jpg", ThumbnailUrl="~/images/Thumbnails/Jellyfish.jpg", Description="Lorem Ipsum is simply dummy text of the printing and typesetting industry. Lorem Ipsum has been the industry's standard dummy text ever since the 1500s"},
|
||||
new Image() { ID=5, Name="Koala", ImageUrl="~/images/Koala.jpg", ThumbnailUrl="~/images/Thumbnails/Koala.jpg", Description="The point of using Lorem Ipsum is that it has a more-or-less normal distribution of letters, as opposed to using 'Content here, content here', making it look like readable English"},
|
||||
new Image() { ID=6, Name="Lighthouse", ImageUrl="~/images/Lighthouse.jpg", ThumbnailUrl="~/images/Thumbnails/Lighthouse.jpg", Description="Lorem Ipsum is simply dummy text of the printing and typesetting industry. Lorem Ipsum has been the industry's standard dummy text ever since the 1500s"},
|
||||
new Image() { ID=7, Name="Penguins", ImageUrl="~/images/Penguins.jpg", ThumbnailUrl="~/images/Thumbnails/Penguins.jpg", Description="The point of using Lorem Ipsum is that it has a more-or-less normal distribution of letters, as opposed to using 'Content here, content here', making it look like readable English"},
|
||||
new Image() { ID=8, Name="Tulips", ImageUrl="~/images/Tulips.jpg", ThumbnailUrl="~/images/Thumbnails/Tulips.jpg", Description="Lorem Ipsum is simply dummy text of the printing and typesetting industry. Lorem Ipsum has been the industry's standard dummy text ever since the 1500s"}
|
||||
};
|
||||
}
|
||||
|
||||
public List<Article> Articles
|
||||
{
|
||||
get
|
||||
{
|
||||
List<Article> data = Session["DataArticles"] as List<Article>;
|
||||
|
||||
if (data == null)
|
||||
{
|
||||
data = GetArticles();
|
||||
Session["DataArticles"] = data;
|
||||
}
|
||||
|
||||
return data;
|
||||
}
|
||||
}
|
||||
|
||||
public List<Article> GetArticles()
|
||||
{
|
||||
return new List<Article>() {
|
||||
new Article(){ ID=1, Title="Phasellus auctor nisi dolor", Description="Donec aliquam turpis sed nisl mattis sagittis. Class aptent taciti sociosqu ad litora torquent per conubia nostra, per inceptos himenaeos. Ut vitae sapien metus. In hac habitasse platea dictumst. Aenean velit mauris, lobortis eu lacinia sed, imperdiet quis dui. Vestibulum ut metus sagittis dui lacinia mollis ornare eget urna. Mauris vehicula scelerisque sagittis"},
|
||||
new Article(){ ID=1, Title="In magna mi, dapibus ut tortor", Description="Nullam facilisis neque ut aliquet imperdiet. Mauris ut odio augue. Curabitur in mi ac odio vestibulum lobortis. Donec sed mollis nibh, vitae varius lorem. Fusce ac neque lacinia dui facilisis posuere. Fusce pharetra rhoncus vulputate"},
|
||||
new Article(){ ID=1, Title="Aenean ut lacus enim", Description="Aenean euismod est tortor, et pharetra mauris ultricies ut. Vivamus fringilla libero nec est tincidunt, sit amet venenatis felis accumsan. Vestibulum ante ipsum primis in faucibus orci luctus et ultrices posuere cubilia Curae"},
|
||||
new Article(){ ID=1, Title="Aenean luctus bibendum", Description="Mauris blandit sit amet diam eget dictum. Ut sit amet tortor sit amet nibh elementum scelerisque. Nullam felis turpis, suscipit ut nunc at, euismod condimentum massa. Ut finibus odio vitae euismod dapibus. Fusce luctus elit leo, at ultrices orci imperdiet quis"},
|
||||
new Article(){ ID=1, Title="Lorem ipsum dolor sit amet", Description="Etiam nisi felis, ullamcorper et sagittis sed, posuere et lorem. Mauris non rutrum tortor. Suspendisse eu leo nec justo facilisis imperdiet sed vel felis. Nullam eros urna, efficitur in eros at, interdum iaculis massa"}
|
||||
};
|
||||
}
|
||||
|
||||
protected void RadListViewImages_NeedDataSource(object sender, Telerik.Web.UI.RadListViewNeedDataSourceEventArgs e)
|
||||
{
|
||||
RadListViewImages.DataSource = Images;
|
||||
}
|
||||
|
||||
protected override void OnLoad(EventArgs e)
|
||||
{
|
||||
base.OnLoad(e);
|
||||
|
||||
RadLightBoxImageDetails.DataSource = Images;
|
||||
RadLightBoxImageDetails.DataBind();
|
||||
}
|
||||
|
||||
protected void RadListViewImages_ItemDataBound(object sender, Telerik.Web.UI.RadListViewItemEventArgs e)
|
||||
{
|
||||
RadListViewDataItem item = e.Item as RadListViewDataItem;
|
||||
string description = (item.DataItem as Image).Description;
|
||||
if (description.Length > 100)
|
||||
{
|
||||
description = description.Substring(0, 97) + "...";
|
||||
(item.FindControl("LabelShortDescription") as Literal).Text = description;
|
||||
}
|
||||
}
|
||||
protected void RadListViewArticles_NeedDataSource(object sender, RadListViewNeedDataSourceEventArgs e)
|
||||
{
|
||||
RadListViewArticles.DataSource = Articles;
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,62 @@
|
||||
//------------------------------------------------------------------------------
|
||||
// <auto-generated>
|
||||
// This code was generated by a tool.
|
||||
//
|
||||
// Changes to this file may cause incorrect behavior and will be lost if
|
||||
// the code is regenerated.
|
||||
// </auto-generated>
|
||||
//------------------------------------------------------------------------------
|
||||
|
||||
namespace MySite.Web
|
||||
{
|
||||
|
||||
|
||||
public partial class ListView
|
||||
{
|
||||
|
||||
/// <summary>
|
||||
/// JumbotronLayout control.
|
||||
/// </summary>
|
||||
/// <remarks>
|
||||
/// Auto-generated field.
|
||||
/// To modify move field declaration from designer file to code-behind file.
|
||||
/// </remarks>
|
||||
protected global::Telerik.Web.UI.RadPageLayout JumbotronLayout;
|
||||
|
||||
/// <summary>
|
||||
/// RadButton0 control.
|
||||
/// </summary>
|
||||
/// <remarks>
|
||||
/// Auto-generated field.
|
||||
/// To modify move field declaration from designer file to code-behind file.
|
||||
/// </remarks>
|
||||
protected global::Telerik.Web.UI.RadButton RadButton0;
|
||||
|
||||
/// <summary>
|
||||
/// RadListViewImages control.
|
||||
/// </summary>
|
||||
/// <remarks>
|
||||
/// Auto-generated field.
|
||||
/// To modify move field declaration from designer file to code-behind file.
|
||||
/// </remarks>
|
||||
protected global::Telerik.Web.UI.RadListView RadListViewImages;
|
||||
|
||||
/// <summary>
|
||||
/// RadListViewArticles control.
|
||||
/// </summary>
|
||||
/// <remarks>
|
||||
/// Auto-generated field.
|
||||
/// To modify move field declaration from designer file to code-behind file.
|
||||
/// </remarks>
|
||||
protected global::Telerik.Web.UI.RadListView RadListViewArticles;
|
||||
|
||||
/// <summary>
|
||||
/// RadLightBoxImageDetails control.
|
||||
/// </summary>
|
||||
/// <remarks>
|
||||
/// Auto-generated field.
|
||||
/// To modify move field declaration from designer file to code-behind file.
|
||||
/// </remarks>
|
||||
protected global::Telerik.Web.UI.RadLightBox RadLightBoxImageDetails;
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,108 @@
|
||||
<%@ Master Language="C#" AutoEventWireup="true" CodeBehind="MasterPage.master.cs" Inherits="MySite.Web.MasterPage" %>
|
||||
<%@ Register TagPrefix="telerik" Namespace="Telerik.Web.UI" Assembly="Telerik.Web.UI" %>
|
||||
<!DOCTYPE html>
|
||||
|
||||
<html xmlns="http://www.w3.org/1999/xhtml">
|
||||
<head runat="server">
|
||||
<title></title>
|
||||
<meta name="viewport" content="initial-scale=1.0, minimum-scale=1, maximum-scale=1.0, user-scalable=no" />
|
||||
<link href="styles/base.css" rel="stylesheet" />
|
||||
<asp:ContentPlaceHolder ID="head" runat="server">
|
||||
</asp:ContentPlaceHolder>
|
||||
</head>
|
||||
<body>
|
||||
<form id="form1" runat="server">
|
||||
<telerik:RadScriptManager runat="server"></telerik:RadScriptManager>
|
||||
<div id="wrapper">
|
||||
<telerik:RadPageLayout runat="server" ID="MasterLayout" GridType="Fluid">
|
||||
<Rows>
|
||||
<%--Header--%>
|
||||
<telerik:LayoutRow CssClass="header">
|
||||
<Columns>
|
||||
<%--Logo--%>
|
||||
<telerik:LayoutColumn Span="2" SpanMd="3" SpanSm="12" SpanXs="12">
|
||||
<a href="#" class="logo">
|
||||
<img src="images/logo.png" alt="site logo"/>
|
||||
</a>
|
||||
</telerik:LayoutColumn>
|
||||
|
||||
<%--Main Nav--%>
|
||||
<telerik:LayoutColumn Span="10" SpanMd="9" SpanSm="12" SpanXs="12">
|
||||
<telerik:RadMenu ID="RadMenu1" runat="server" RenderMode="Auto">
|
||||
<Items>
|
||||
<telerik:RadMenuItem Text="Home" NavigateUrl="Default.aspx" />
|
||||
<telerik:RadMenuItem IsSeparator="true" />
|
||||
<telerik:RadMenuItem Text="Grid Page" NavigateUrl="Grid.aspx" />
|
||||
<telerik:RadMenuItem IsSeparator="true" />
|
||||
<telerik:RadMenuItem Text="ListView Page" NavigateUrl="ListView.aspx" />
|
||||
<telerik:RadMenuItem IsSeparator="true" />
|
||||
<telerik:RadMenuItem Text="About" />
|
||||
<telerik:RadMenuItem IsSeparator="true" />
|
||||
<telerik:RadMenuItem Text="Projects" />
|
||||
<telerik:RadMenuItem IsSeparator="true" />
|
||||
<telerik:RadMenuItem Text="Dashboard" />
|
||||
<telerik:RadMenuItem IsSeparator="true" />
|
||||
<telerik:RadMenuItem Text="..." />
|
||||
<telerik:RadMenuItem IsSeparator="true" />
|
||||
<telerik:RadMenuItem Text="..." />
|
||||
<telerik:RadMenuItem IsSeparator="true" />
|
||||
<telerik:RadMenuItem Text="Contacts" />
|
||||
</Items>
|
||||
</telerik:RadMenu>
|
||||
</telerik:LayoutColumn>
|
||||
</Columns>
|
||||
</telerik:LayoutRow>
|
||||
|
||||
<%--Main--%>
|
||||
<telerik:LayoutRow>
|
||||
<Columns>
|
||||
<%--Sidebar--%>
|
||||
<telerik:LayoutColumn Span="2" HiddenMd="true" HiddenSm="true" HiddenXs="true">
|
||||
<telerik:RadMenu ID="RadMenu2" CssClass="sidebar" Flow="Vertical" runat="server" >
|
||||
<Items>
|
||||
<telerik:RadMenuItem Text="Menu item 1" />
|
||||
<telerik:RadMenuItem IsSeparator="true" />
|
||||
<telerik:RadMenuItem Text="Menu item 2" />
|
||||
<telerik:RadMenuItem IsSeparator="true" />
|
||||
<telerik:RadMenuItem Text="Menu item 3" />
|
||||
<telerik:RadMenuItem IsSeparator="true" />
|
||||
<telerik:RadMenuItem Text="Menu item 4" />
|
||||
<telerik:RadMenuItem IsSeparator="true" />
|
||||
<telerik:RadMenuItem Text="Menu item 5" />
|
||||
<telerik:RadMenuItem IsSeparator="true" />
|
||||
<telerik:RadMenuItem Text="Menu item 6" />
|
||||
<telerik:RadMenuItem IsSeparator="true" />
|
||||
<telerik:RadMenuItem Text="Menu item 7" />
|
||||
<telerik:RadMenuItem IsSeparator="true" />
|
||||
<telerik:RadMenuItem Text="Menu item 8" />
|
||||
</Items>
|
||||
</telerik:RadMenu>
|
||||
</telerik:LayoutColumn>
|
||||
|
||||
<%--Content--%>
|
||||
<telerik:CompositeLayoutColumn Span="10" SpanMd="12" SpanSm="12" SpanXs="12">
|
||||
<Content>
|
||||
<asp:ContentPlaceHolder ID="ContentPlaceHolder1" runat="server">
|
||||
</asp:ContentPlaceHolder>
|
||||
<asp:ContentPlaceHolder ID="ContentPlaceHolder2" runat="server">
|
||||
</asp:ContentPlaceHolder>
|
||||
</Content>
|
||||
</telerik:CompositeLayoutColumn>
|
||||
</Columns>
|
||||
</telerik:LayoutRow>
|
||||
|
||||
<%--Footer--%>
|
||||
<telerik:LayoutRow>
|
||||
<Columns>
|
||||
<telerik:LayoutColumn CssClass="footer">
|
||||
<hr />
|
||||
Footer: © 2002-2015 Company Inc, 201 Jones Rd, Waltham, MA 03451
|
||||
</telerik:LayoutColumn>
|
||||
</Columns>
|
||||
</telerik:LayoutRow>
|
||||
</Rows>
|
||||
</telerik:RadPageLayout>
|
||||
</div>
|
||||
</form>
|
||||
</body>
|
||||
</html>
|
||||
@@ -0,0 +1,12 @@
|
||||
using System;
|
||||
|
||||
namespace MySite.Web
|
||||
{
|
||||
public partial class MasterPage : System.Web.UI.MasterPage
|
||||
{
|
||||
protected void Page_Load(object sender, EventArgs e)
|
||||
{
|
||||
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,80 @@
|
||||
//------------------------------------------------------------------------------
|
||||
// <auto-generated>
|
||||
// This code was generated by a tool.
|
||||
//
|
||||
// Changes to this file may cause incorrect behavior and will be lost if
|
||||
// the code is regenerated.
|
||||
// </auto-generated>
|
||||
//------------------------------------------------------------------------------
|
||||
|
||||
namespace MySite.Web
|
||||
{
|
||||
|
||||
|
||||
public partial class MasterPage
|
||||
{
|
||||
|
||||
/// <summary>
|
||||
/// head control.
|
||||
/// </summary>
|
||||
/// <remarks>
|
||||
/// Auto-generated field.
|
||||
/// To modify move field declaration from designer file to code-behind file.
|
||||
/// </remarks>
|
||||
protected global::System.Web.UI.WebControls.ContentPlaceHolder head;
|
||||
|
||||
/// <summary>
|
||||
/// form1 control.
|
||||
/// </summary>
|
||||
/// <remarks>
|
||||
/// Auto-generated field.
|
||||
/// To modify move field declaration from designer file to code-behind file.
|
||||
/// </remarks>
|
||||
protected global::System.Web.UI.HtmlControls.HtmlForm form1;
|
||||
|
||||
/// <summary>
|
||||
/// MasterLayout control.
|
||||
/// </summary>
|
||||
/// <remarks>
|
||||
/// Auto-generated field.
|
||||
/// To modify move field declaration from designer file to code-behind file.
|
||||
/// </remarks>
|
||||
protected global::Telerik.Web.UI.RadPageLayout MasterLayout;
|
||||
|
||||
/// <summary>
|
||||
/// RadMenu1 control.
|
||||
/// </summary>
|
||||
/// <remarks>
|
||||
/// Auto-generated field.
|
||||
/// To modify move field declaration from designer file to code-behind file.
|
||||
/// </remarks>
|
||||
protected global::Telerik.Web.UI.RadMenu RadMenu1;
|
||||
|
||||
/// <summary>
|
||||
/// RadMenu2 control.
|
||||
/// </summary>
|
||||
/// <remarks>
|
||||
/// Auto-generated field.
|
||||
/// To modify move field declaration from designer file to code-behind file.
|
||||
/// </remarks>
|
||||
protected global::Telerik.Web.UI.RadMenu RadMenu2;
|
||||
|
||||
/// <summary>
|
||||
/// ContentPlaceHolder1 control.
|
||||
/// </summary>
|
||||
/// <remarks>
|
||||
/// Auto-generated field.
|
||||
/// To modify move field declaration from designer file to code-behind file.
|
||||
/// </remarks>
|
||||
protected global::System.Web.UI.WebControls.ContentPlaceHolder ContentPlaceHolder1;
|
||||
|
||||
/// <summary>
|
||||
/// ContentPlaceHolder2 control.
|
||||
/// </summary>
|
||||
/// <remarks>
|
||||
/// Auto-generated field.
|
||||
/// To modify move field declaration from designer file to code-behind file.
|
||||
/// </remarks>
|
||||
protected global::System.Web.UI.WebControls.ContentPlaceHolder ContentPlaceHolder2;
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,54 @@
|
||||
<%@ Master Language="C#" AutoEventWireup="true" CodeBehind="MasterPageSingleMenu.master.cs" Inherits="MySite.Web.MasterPageSingleMenu" %>
|
||||
<%@ Register TagPrefix="telerik" Namespace="Telerik.Web.UI" Assembly="Telerik.Web.UI" %>
|
||||
<!DOCTYPE html>
|
||||
|
||||
<html xmlns="http://www.w3.org/1999/xhtml">
|
||||
<head runat="server">
|
||||
<title></title>
|
||||
<meta name="viewport" content="initial-scale=1.0, minimum-scale=1, maximum-scale=1.0, user-scalable=no" />
|
||||
<link href="styles/base.css" rel="stylesheet" />
|
||||
<asp:ContentPlaceHolder ID="head" runat="server">
|
||||
</asp:ContentPlaceHolder>
|
||||
</head>
|
||||
<body>
|
||||
<form id="form1" runat="server">
|
||||
<telerik:RadScriptManager runat="server"></telerik:RadScriptManager>
|
||||
<div id="wrapper">
|
||||
<a href="#" class="logo">
|
||||
<img src="images/logo.png" alt="site logo" />
|
||||
</a>
|
||||
<div class="header">
|
||||
<telerik:RadMenu ID="RadMenu1" CssClass="mainMenu" runat="server" RenderMode="Auto">
|
||||
<Items>
|
||||
<telerik:RadMenuItem Text="Home" NavigateUrl="Default.aspx" />
|
||||
<telerik:RadMenuItem IsSeparator="true" />
|
||||
<telerik:RadMenuItem Text="Grid Page" NavigateUrl="Grid.aspx" />
|
||||
<telerik:RadMenuItem IsSeparator="true" />
|
||||
<telerik:RadMenuItem Text="ListView Page" NavigateUrl="ListView.aspx" />
|
||||
<telerik:RadMenuItem IsSeparator="true" />
|
||||
<telerik:RadMenuItem Text="About" />
|
||||
<telerik:RadMenuItem IsSeparator="true" />
|
||||
<telerik:RadMenuItem Text="Projects" />
|
||||
<telerik:RadMenuItem IsSeparator="true" />
|
||||
<telerik:RadMenuItem Text="Dashboard" />
|
||||
<telerik:RadMenuItem IsSeparator="true" />
|
||||
<telerik:RadMenuItem Text="..." />
|
||||
<telerik:RadMenuItem IsSeparator="true" />
|
||||
<telerik:RadMenuItem Text="..." />
|
||||
<telerik:RadMenuItem IsSeparator="true" />
|
||||
<telerik:RadMenuItem Text="Contacts" />
|
||||
</Items>
|
||||
</telerik:RadMenu>
|
||||
</div>
|
||||
<asp:ContentPlaceHolder ID="ContentPlaceHolder1" runat="server">
|
||||
</asp:ContentPlaceHolder>
|
||||
<asp:ContentPlaceHolder ID="ContentPlaceHolder2" runat="server">
|
||||
</asp:ContentPlaceHolder>
|
||||
<hr style="margin-top: 40px" />
|
||||
<div class="footer">
|
||||
Footer: © 2002-2015 Company Inc, 201 Jones Rd, Waltham, MA 03451
|
||||
</div>
|
||||
</div>
|
||||
</form>
|
||||
</body>
|
||||
</html>
|
||||
@@ -0,0 +1,17 @@
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Linq;
|
||||
using System.Web;
|
||||
using System.Web.UI;
|
||||
using System.Web.UI.WebControls;
|
||||
|
||||
namespace MySite.Web
|
||||
{
|
||||
public partial class MasterPageSingleMenu : System.Web.UI.MasterPage
|
||||
{
|
||||
protected void Page_Load(object sender, EventArgs e)
|
||||
{
|
||||
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,62 @@
|
||||
//------------------------------------------------------------------------------
|
||||
// <auto-generated>
|
||||
// This code was generated by a tool.
|
||||
//
|
||||
// Changes to this file may cause incorrect behavior and will be lost if
|
||||
// the code is regenerated.
|
||||
// </auto-generated>
|
||||
//------------------------------------------------------------------------------
|
||||
|
||||
namespace MySite.Web
|
||||
{
|
||||
|
||||
|
||||
public partial class MasterPageSingleMenu
|
||||
{
|
||||
|
||||
/// <summary>
|
||||
/// head control.
|
||||
/// </summary>
|
||||
/// <remarks>
|
||||
/// Auto-generated field.
|
||||
/// To modify move field declaration from designer file to code-behind file.
|
||||
/// </remarks>
|
||||
protected global::System.Web.UI.WebControls.ContentPlaceHolder head;
|
||||
|
||||
/// <summary>
|
||||
/// form1 control.
|
||||
/// </summary>
|
||||
/// <remarks>
|
||||
/// Auto-generated field.
|
||||
/// To modify move field declaration from designer file to code-behind file.
|
||||
/// </remarks>
|
||||
protected global::System.Web.UI.HtmlControls.HtmlForm form1;
|
||||
|
||||
/// <summary>
|
||||
/// RadMenu1 control.
|
||||
/// </summary>
|
||||
/// <remarks>
|
||||
/// Auto-generated field.
|
||||
/// To modify move field declaration from designer file to code-behind file.
|
||||
/// </remarks>
|
||||
protected global::Telerik.Web.UI.RadMenu RadMenu1;
|
||||
|
||||
/// <summary>
|
||||
/// ContentPlaceHolder1 control.
|
||||
/// </summary>
|
||||
/// <remarks>
|
||||
/// Auto-generated field.
|
||||
/// To modify move field declaration from designer file to code-behind file.
|
||||
/// </remarks>
|
||||
protected global::System.Web.UI.WebControls.ContentPlaceHolder ContentPlaceHolder1;
|
||||
|
||||
/// <summary>
|
||||
/// ContentPlaceHolder2 control.
|
||||
/// </summary>
|
||||
/// <remarks>
|
||||
/// Auto-generated field.
|
||||
/// To modify move field declaration from designer file to code-behind file.
|
||||
/// </remarks>
|
||||
protected global::System.Web.UI.WebControls.ContentPlaceHolder ContentPlaceHolder2;
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,239 @@
|
||||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<Project ToolsVersion="Current" DefaultTargets="Build" xmlns="http://schemas.microsoft.com/developer/msbuild/2003">
|
||||
<Import Project="$(MSBuildExtensionsPath)\$(MSBuildToolsVersion)\Microsoft.Common.props" Condition="Exists('$(MSBuildExtensionsPath)\$(MSBuildToolsVersion)\Microsoft.Common.props')" />
|
||||
<PropertyGroup>
|
||||
<VisualStudioVersion Condition="'$(VisualStudioVersion)' == ''">10.0</VisualStudioVersion>
|
||||
<VSToolsPath Condition="'$(VSToolsPath)' == ''">$(MSBuildExtensionsPath32)\Microsoft\VisualStudio\v$(VisualStudioVersion)</VSToolsPath>
|
||||
<FileUpgradeFlags>
|
||||
</FileUpgradeFlags>
|
||||
<OldToolsVersion>3.5</OldToolsVersion>
|
||||
<Use64BitIISExpress />
|
||||
<UseGlobalApplicationHostFile />
|
||||
<UpgradeBackupLocation />
|
||||
<NuGetPackageImportStamp>
|
||||
</NuGetPackageImportStamp>
|
||||
</PropertyGroup>
|
||||
<PropertyGroup>
|
||||
<Configuration Condition=" '$(Configuration)' == '' ">Debug</Configuration>
|
||||
<Platform Condition=" '$(Platform)' == '' ">AnyCPU</Platform>
|
||||
<ProductVersion>
|
||||
</ProductVersion>
|
||||
<SchemaVersion>2.0</SchemaVersion>
|
||||
<ProjectGuid>{ED3D7A4C-2473-41E1-87E7-428DBB517BD8}</ProjectGuid>
|
||||
<ProjectTypeGuids>{349c5851-65df-11da-9384-00065b846f21};{fae04ec0-301f-11d3-bf4b-00c04f79efbc}</ProjectTypeGuids>
|
||||
<OutputType>Library</OutputType>
|
||||
<AppDesignerFolder>Properties</AppDesignerFolder>
|
||||
<RootNamespace>MySite.Web</RootNamespace>
|
||||
<AssemblyName>MySite.Web</AssemblyName>
|
||||
<TargetFrameworkVersion>v4.8</TargetFrameworkVersion>
|
||||
<UseIISExpress>true</UseIISExpress>
|
||||
<IISExpressSSLPort />
|
||||
<IISExpressAnonymousAuthentication />
|
||||
<IISExpressWindowsAuthentication />
|
||||
<IISExpressUseClassicPipelineMode />
|
||||
</PropertyGroup>
|
||||
<PropertyGroup Condition=" '$(Configuration)|$(Platform)' == 'Debug|AnyCPU' ">
|
||||
<DebugSymbols>true</DebugSymbols>
|
||||
<DebugType>full</DebugType>
|
||||
<Optimize>false</Optimize>
|
||||
<OutputPath>bin\</OutputPath>
|
||||
<DefineConstants>DEBUG;TRACE</DefineConstants>
|
||||
<ErrorReport>prompt</ErrorReport>
|
||||
<WarningLevel>4</WarningLevel>
|
||||
</PropertyGroup>
|
||||
<PropertyGroup Condition=" '$(Configuration)|$(Platform)' == 'Release|AnyCPU' ">
|
||||
<DebugType>pdbonly</DebugType>
|
||||
<Optimize>true</Optimize>
|
||||
<OutputPath>bin\</OutputPath>
|
||||
<DefineConstants>TRACE</DefineConstants>
|
||||
<ErrorReport>prompt</ErrorReport>
|
||||
<WarningLevel>4</WarningLevel>
|
||||
</PropertyGroup>
|
||||
<ItemGroup>
|
||||
<Reference Include="PresentationCore" />
|
||||
<Reference Include="PresentationFramework" />
|
||||
<Reference Include="System.IO.Compression, Version=4.3.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089, processorArchitecture=MSIL">
|
||||
<HintPath>..\packages\System.IO.Compression.4.3.0\lib\net46\System.IO.Compression.dll</HintPath>
|
||||
<Private>True</Private>
|
||||
</Reference>
|
||||
<Reference Include="System.Numerics" />
|
||||
<Reference Include="System.Web.DynamicData" />
|
||||
<Reference Include="System.Web.Entity" />
|
||||
<Reference Include="System.ComponentModel.DataAnnotations" />
|
||||
<Reference Include="System" />
|
||||
<Reference Include="System.Data" />
|
||||
<Reference Include="System.Core" />
|
||||
<Reference Include="System.Data.DataSetExtensions" />
|
||||
<Reference Include="System.Web.Extensions" />
|
||||
<Reference Include="System.Xaml" />
|
||||
<Reference Include="System.Xml.Linq" />
|
||||
<Reference Include="System.Drawing" />
|
||||
<Reference Include="System.Web" />
|
||||
<Reference Include="System.Xml" />
|
||||
<Reference Include="System.Configuration" />
|
||||
<Reference Include="System.Web.Services" />
|
||||
<Reference Include="System.EnterpriseServices" />
|
||||
<Reference Include="Telerik.Licensing.Runtime, Version=1.6.23.0, Culture=neutral, PublicKeyToken=98bb5b04e55c09ef, processorArchitecture=MSIL">
|
||||
<HintPath>..\..\packages\Telerik.Licensing.1.8.2\lib\net462\Telerik.Licensing.Runtime.dll</HintPath>
|
||||
<Private>True</Private>
|
||||
</Reference>
|
||||
<Reference Include="Telerik.Web.Design, Version=2025.3.825.462, Culture=neutral, PublicKeyToken=121fae78165ba3d4, processorArchitecture=MSIL">
|
||||
<HintPath>..\..\packages\Telerik.UI.for.AspNet.Ajax.Net462.2026.2.519\lib\net462\Telerik.Web.Design.dll</HintPath>
|
||||
<Private>True</Private>
|
||||
</Reference>
|
||||
<Reference Include="Telerik.Web.Device.Detection, Version=2025.3.825.462, Culture=neutral, PublicKeyToken=121fae78165ba3d4, processorArchitecture=MSIL">
|
||||
<HintPath>..\..\packages\Telerik.UI.for.AspNet.Ajax.Net462.2026.2.519\lib\net462\Telerik.Web.Device.Detection.dll</HintPath>
|
||||
<Private>True</Private>
|
||||
</Reference>
|
||||
<Reference Include="Telerik.Web.UI, Version=2025.3.825.462, Culture=neutral, PublicKeyToken=121fae78165ba3d4, processorArchitecture=MSIL">
|
||||
<HintPath>..\..\packages\Telerik.UI.for.AspNet.Ajax.Net462.2026.2.519\lib\net462\Telerik.Web.UI.dll</HintPath>
|
||||
<Private>True</Private>
|
||||
</Reference>
|
||||
<Reference Include="Telerik.Web.UI.Skins, Version=2025.3.825.462, Culture=neutral, PublicKeyToken=121fae78165ba3d4, processorArchitecture=MSIL">
|
||||
<HintPath>..\..\packages\Telerik.UI.for.AspNet.Ajax.Net462.2026.2.519\lib\net462\Telerik.Web.UI.Skins.dll</HintPath>
|
||||
<Private>True</Private>
|
||||
</Reference>
|
||||
<Reference Include="Telerik.Windows.Documents.Core, Version=2025.3.806.462, Culture=neutral, PublicKeyToken=5803cfa389c90ce7, processorArchitecture=MSIL">
|
||||
<HintPath>..\..\packages\Telerik.Windows.Documents.Core.2026.2.519\lib\net462\Telerik.Windows.Documents.Core.dll</HintPath>
|
||||
<Private>True</Private>
|
||||
</Reference>
|
||||
<Reference Include="Telerik.Windows.Documents.Flow, Version=2025.3.806.462, Culture=neutral, PublicKeyToken=5803cfa389c90ce7, processorArchitecture=MSIL">
|
||||
<HintPath>..\..\packages\Telerik.Windows.Documents.Flow.2026.2.519\lib\net462\Telerik.Windows.Documents.Flow.dll</HintPath>
|
||||
<Private>True</Private>
|
||||
</Reference>
|
||||
<Reference Include="Telerik.Windows.Documents.Spreadsheet, Version=2025.3.806.462, Culture=neutral, PublicKeyToken=5803cfa389c90ce7, processorArchitecture=MSIL">
|
||||
<HintPath>..\..\packages\Telerik.Windows.Documents.Spreadsheet.2026.2.519\lib\net462\Telerik.Windows.Documents.Spreadsheet.dll</HintPath>
|
||||
<Private>True</Private>
|
||||
</Reference>
|
||||
<Reference Include="Telerik.Windows.Documents.Spreadsheet.FormatProviders.OpenXml, Version=2025.3.806.462, Culture=neutral, PublicKeyToken=5803cfa389c90ce7, processorArchitecture=MSIL">
|
||||
<HintPath>..\..\packages\Telerik.Windows.Documents.Spreadsheet.FormatProviders.OpenXml.2026.2.519\lib\net462\Telerik.Windows.Documents.Spreadsheet.FormatProviders.OpenXml.dll</HintPath>
|
||||
<Private>True</Private>
|
||||
</Reference>
|
||||
<Reference Include="Telerik.Windows.Zip, Version=2025.3.806.462, Culture=neutral, PublicKeyToken=5803cfa389c90ce7, processorArchitecture=MSIL">
|
||||
<HintPath>..\..\packages\Telerik.Windows.Zip.2026.2.519\lib\net462\Telerik.Windows.Zip.dll</HintPath>
|
||||
<Private>True</Private>
|
||||
</Reference>
|
||||
<Reference Include="WindowsBase" />
|
||||
</ItemGroup>
|
||||
<ItemGroup>
|
||||
<Content Include="MasterPage.Master" />
|
||||
<Content Include="MasterPageSingleMenu.Master" />
|
||||
</ItemGroup>
|
||||
<ItemGroup>
|
||||
<Content Include="Default.aspx" />
|
||||
<Content Include="Grid.aspx" />
|
||||
<Content Include="images\Chrysanthemum.jpg" />
|
||||
<Content Include="images\Desert.jpg" />
|
||||
<Content Include="images\Hydrangeas.jpg" />
|
||||
<Content Include="images\Jellyfish.jpg" />
|
||||
<Content Include="images\Koala.jpg" />
|
||||
<Content Include="images\Lighthouse.jpg" />
|
||||
<Content Include="images\logo.png" />
|
||||
<Content Include="images\Penguins.jpg" />
|
||||
<Content Include="images\Thumbnails\Chrysanthemum.jpg" />
|
||||
<Content Include="images\Thumbnails\Desert.jpg" />
|
||||
<Content Include="images\Thumbnails\Hydrangeas.jpg" />
|
||||
<Content Include="images\Thumbnails\Jellyfish.jpg" />
|
||||
<Content Include="images\Thumbnails\Koala.jpg" />
|
||||
<Content Include="images\Thumbnails\Lighthouse.jpg" />
|
||||
<Content Include="images\Thumbnails\Penguins.jpg" />
|
||||
<Content Include="images\Thumbnails\Tulips.jpg" />
|
||||
<Content Include="images\Tulips.jpg" />
|
||||
<Content Include="ListView.aspx" />
|
||||
<Content Include="scripts\scripts.js" />
|
||||
<Content Include="styles\base.css" />
|
||||
<Content Include="styles\default.css" />
|
||||
<Content Include="styles\grid.css" />
|
||||
<Content Include="styles\listView.css" />
|
||||
</ItemGroup>
|
||||
<ItemGroup>
|
||||
<Compile Include="Article.cs" />
|
||||
<Compile Include="Default.aspx.cs">
|
||||
<DependentUpon>Default.aspx</DependentUpon>
|
||||
<SubType>ASPXCodeBehind</SubType>
|
||||
</Compile>
|
||||
<Compile Include="Default.aspx.designer.cs">
|
||||
<DependentUpon>Default.aspx</DependentUpon>
|
||||
</Compile>
|
||||
<Compile Include="Grid.aspx.cs">
|
||||
<DependentUpon>Grid.aspx</DependentUpon>
|
||||
<SubType>ASPXCodeBehind</SubType>
|
||||
</Compile>
|
||||
<Compile Include="Grid.aspx.designer.cs">
|
||||
<DependentUpon>Grid.aspx</DependentUpon>
|
||||
</Compile>
|
||||
<Compile Include="Image.cs" />
|
||||
<Compile Include="ListView.aspx.cs">
|
||||
<DependentUpon>ListView.aspx</DependentUpon>
|
||||
<SubType>ASPXCodeBehind</SubType>
|
||||
</Compile>
|
||||
<Compile Include="ListView.aspx.designer.cs">
|
||||
<DependentUpon>ListView.aspx</DependentUpon>
|
||||
</Compile>
|
||||
<Compile Include="MasterPage.Master.cs">
|
||||
<DependentUpon>MasterPage.Master</DependentUpon>
|
||||
<SubType>ASPXCodeBehind</SubType>
|
||||
</Compile>
|
||||
<Compile Include="MasterPage.Master.designer.cs">
|
||||
<DependentUpon>MasterPage.Master</DependentUpon>
|
||||
</Compile>
|
||||
<Compile Include="MasterPageSingleMenu.Master.cs">
|
||||
<DependentUpon>MasterPageSingleMenu.Master</DependentUpon>
|
||||
<SubType>ASPXCodeBehind</SubType>
|
||||
</Compile>
|
||||
<Compile Include="MasterPageSingleMenu.Master.designer.cs">
|
||||
<DependentUpon>MasterPageSingleMenu.Master</DependentUpon>
|
||||
</Compile>
|
||||
<Compile Include="Properties\AssemblyInfo.cs" />
|
||||
</ItemGroup>
|
||||
<ItemGroup>
|
||||
<Content Include="web.config" />
|
||||
<None Include="packages.config" />
|
||||
<None Include="web.Debug.config">
|
||||
<DependentUpon>web.config</DependentUpon>
|
||||
</None>
|
||||
<None Include="web.Release.config">
|
||||
<DependentUpon>web.config</DependentUpon>
|
||||
</None>
|
||||
</ItemGroup>
|
||||
<ItemGroup>
|
||||
<Folder Include="App_Data\" />
|
||||
</ItemGroup>
|
||||
<Import Project="$(MSBuildBinPath)\Microsoft.CSharp.targets" />
|
||||
<Import Project="$(VSToolsPath)\WebApplications\Microsoft.WebApplication.targets" Condition="'$(VSToolsPath)' != ''" />
|
||||
<Import Project="$(MSBuildExtensionsPath32)\Microsoft\VisualStudio\v10.0\WebApplications\Microsoft.WebApplication.targets" Condition="false" />
|
||||
<Import Project="$(VSToolsPath)\TypeScript\Microsoft.TypeScript.targets" Condition="Exists('$(VSToolsPath)\TypeScript\Microsoft.TypeScript.targets')" />
|
||||
<ProjectExtensions>
|
||||
<VisualStudio>
|
||||
<FlavorProperties GUID="{349c5851-65df-11da-9384-00065b846f21}">
|
||||
<WebProjectProperties>
|
||||
<UseIIS>True</UseIIS>
|
||||
<AutoAssignPort>True</AutoAssignPort>
|
||||
<DevelopmentServerPort>49573</DevelopmentServerPort>
|
||||
<DevelopmentServerVPath>/</DevelopmentServerVPath>
|
||||
<IISUrl>http://localhost:49573/</IISUrl>
|
||||
<NTLMAuthentication>False</NTLMAuthentication>
|
||||
<UseCustomServer>False</UseCustomServer>
|
||||
<CustomServerUrl>
|
||||
</CustomServerUrl>
|
||||
<SaveServerSettingsInUserFile>False</SaveServerSettingsInUserFile>
|
||||
</WebProjectProperties>
|
||||
</FlavorProperties>
|
||||
<UserProperties UseAjaxifiedTemplates="True" UseJQuerySupport="True" />
|
||||
</VisualStudio>
|
||||
</ProjectExtensions>
|
||||
<!-- To modify your build process, add your task inside one of the targets below and uncomment it.
|
||||
Other similar extension points exist, see Microsoft.Common.targets.
|
||||
<Target Name="BeforeBuild">
|
||||
</Target>
|
||||
<Target Name="AfterBuild">
|
||||
</Target>
|
||||
-->
|
||||
<Import Project="..\..\packages\Telerik.Licensing.1.8.2\build\Telerik.Licensing.targets" Condition="Exists('..\..\packages\Telerik.Licensing.1.8.2\build\Telerik.Licensing.targets')" />
|
||||
<Target Name="EnsureNuGetPackageBuildImports" BeforeTargets="PrepareForBuild">
|
||||
<PropertyGroup>
|
||||
<ErrorText>This project references NuGet package(s) that are missing on this computer. Use NuGet Package Restore to download them. For more information, see http://go.microsoft.com/fwlink/?LinkID=322105. The missing file is {0}.</ErrorText>
|
||||
</PropertyGroup>
|
||||
<Error Condition="!Exists('..\..\packages\Telerik.Licensing.1.8.2\build\Telerik.Licensing.targets')" Text="$([System.String]::Format('$(ErrorText)', '..\..\packages\Telerik.Licensing.1.8.2\build\Telerik.Licensing.targets'))" />
|
||||
</Target>
|
||||
</Project>
|
||||
@@ -0,0 +1,35 @@
|
||||
using System.Reflection;
|
||||
using System.Runtime.CompilerServices;
|
||||
using System.Runtime.InteropServices;
|
||||
|
||||
// General Information about an assembly is controlled through the following
|
||||
// set of attributes. Change these attribute values to modify the information
|
||||
// associated with an assembly.
|
||||
[assembly: AssemblyTitle("MySite.Web")]
|
||||
[assembly: AssemblyDescription("")]
|
||||
[assembly: AssemblyConfiguration("")]
|
||||
[assembly: AssemblyCompany("")]
|
||||
[assembly: AssemblyProduct("MySite.Web")]
|
||||
[assembly: AssemblyCopyright("Copyright © 2015")]
|
||||
[assembly: AssemblyTrademark("")]
|
||||
[assembly: AssemblyCulture("")]
|
||||
|
||||
// Setting ComVisible to false makes the types in this assembly not visible
|
||||
// to COM components. If you need to access a type in this assembly from
|
||||
// COM, set the ComVisible attribute to true on that type.
|
||||
[assembly: ComVisible(false)]
|
||||
|
||||
// The following GUID is for the ID of the typelib if this project is exposed to COM
|
||||
[assembly: Guid("d8c45981-3ae0-463b-9b00-1e4df634fc0b")]
|
||||
|
||||
// Version information for an assembly consists of the following four values:
|
||||
//
|
||||
// Major Version
|
||||
// Minor Version
|
||||
// Build Number
|
||||
// Revision
|
||||
//
|
||||
// You can specify all the values or you can default the Revision and Build Numbers
|
||||
// by using the '*' as shown below:
|
||||
[assembly: AssemblyVersion("1.0.0.0")]
|
||||
[assembly: AssemblyFileVersion("1.0.0.0")]
|
||||
|
After Width: | Height: | Size: 63 KiB |
|
After Width: | Height: | Size: 58 KiB |
|
After Width: | Height: | Size: 48 KiB |
|
After Width: | Height: | Size: 33 KiB |
|
After Width: | Height: | Size: 73 KiB |
|
After Width: | Height: | Size: 47 KiB |
|
After Width: | Height: | Size: 54 KiB |
|
After Width: | Height: | Size: 19 KiB |
|
After Width: | Height: | Size: 13 KiB |
|
After Width: | Height: | Size: 15 KiB |
|
After Width: | Height: | Size: 10 KiB |
|
After Width: | Height: | Size: 17 KiB |
|
After Width: | Height: | Size: 12 KiB |
|
After Width: | Height: | Size: 14 KiB |
|
After Width: | Height: | Size: 17 KiB |
|
After Width: | Height: | Size: 50 KiB |
|
After Width: | Height: | Size: 2.7 KiB |
@@ -0,0 +1,11 @@
|
||||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<packages>
|
||||
<package id="System.IO.Compression" version="4.3.0" targetFramework="net48" />
|
||||
<package id="Telerik.Licensing" version="1.8.2" targetFramework="net48" />
|
||||
<package id="Telerik.UI.for.AspNet.Ajax.Net462" version="2026.2.519" targetFramework="net48" />
|
||||
<package id="Telerik.Windows.Documents.Core" version="2026.2.519" targetFramework="net48" />
|
||||
<package id="Telerik.Windows.Documents.Flow" version="2026.2.519" targetFramework="net48" />
|
||||
<package id="Telerik.Windows.Documents.Spreadsheet" version="2026.2.519" targetFramework="net48" />
|
||||
<package id="Telerik.Windows.Documents.Spreadsheet.FormatProviders.OpenXml" version="2026.2.519" targetFramework="net48" />
|
||||
<package id="Telerik.Windows.Zip" version="2026.2.519" targetFramework="net48" />
|
||||
</packages>
|
||||
@@ -0,0 +1,14 @@
|
||||
;(function () {
|
||||
|
||||
var example = window.example = window.example || {};
|
||||
var lightBox;
|
||||
|
||||
example.imageClicked = function (id) {
|
||||
lightBox.set_currentItemIndex(parseInt(id, 10) - 1);
|
||||
lightBox.show();
|
||||
}
|
||||
|
||||
example.radLightBoxLoad = function (sender, eventArgs) {
|
||||
lightBox = sender;
|
||||
}
|
||||
})();
|
||||
@@ -0,0 +1,97 @@
|
||||
/*normalize*/
|
||||
html,
|
||||
body,
|
||||
form {
|
||||
height: 100%;
|
||||
margin: 0;
|
||||
padding: 0;
|
||||
}
|
||||
|
||||
body {
|
||||
font: normal 16px "Segoe UI", Arial, sans-serif;
|
||||
color: #555555;
|
||||
}
|
||||
|
||||
@media only screen and (min-width: 481px) and (max-width: 720px) {
|
||||
body {
|
||||
font-size: 18px;
|
||||
}
|
||||
}
|
||||
|
||||
@media only screen and (max-width: 480px) {
|
||||
body {
|
||||
font-size: 20px;
|
||||
}
|
||||
}
|
||||
a {
|
||||
background: transparent;
|
||||
}
|
||||
|
||||
img {
|
||||
border: 0;
|
||||
}
|
||||
|
||||
button,
|
||||
input {
|
||||
-webkit-appearance: none;
|
||||
cursor: pointer;
|
||||
}
|
||||
|
||||
hr {
|
||||
border-width: 1px 0 0 0;
|
||||
border-color: #767676;
|
||||
border-style: solid;
|
||||
}
|
||||
|
||||
/*typography*/
|
||||
h1, h2, h3, h4, h5, h6 {
|
||||
line-height: normal;
|
||||
}
|
||||
|
||||
h1, h2, h3 {
|
||||
font-weight: normal;
|
||||
margin: .5em 0;
|
||||
}
|
||||
|
||||
h4, h5, h6 {
|
||||
font-weight: bold;
|
||||
}
|
||||
|
||||
h1 {
|
||||
font-size: 2.25em;
|
||||
}
|
||||
|
||||
h2 {
|
||||
font-size: 1.875em;
|
||||
}
|
||||
|
||||
h3 {
|
||||
font-size: 1.5em;
|
||||
}
|
||||
|
||||
h4 {
|
||||
font-size: 1.125em
|
||||
}
|
||||
|
||||
h5 {
|
||||
font-size: 1em;
|
||||
}
|
||||
|
||||
h6 {
|
||||
font-size: .875em;
|
||||
}
|
||||
|
||||
/*template*/
|
||||
#wrapper .t-container-fluid {
|
||||
max-width: 100%;
|
||||
}
|
||||
|
||||
#wrapper .RadButton {
|
||||
font-size: 1em;
|
||||
}
|
||||
|
||||
#wrapper .RadMenu,
|
||||
div.RadMenuPopup,
|
||||
#wrapper .RadMenu_Default, #wrapper .RadMenu_Default a.rmLink {
|
||||
font-size: 1em;
|
||||
}
|
||||
@@ -0,0 +1,38 @@
|
||||
#wrapper .header {
|
||||
background-color: #2a2d33;
|
||||
padding: 10px 0;
|
||||
margin-bottom: 40px;
|
||||
}
|
||||
|
||||
#wrapper .header .RadMenu {
|
||||
margin: 10px 0;
|
||||
float: none;
|
||||
}
|
||||
|
||||
#wrapper .logo {
|
||||
margin: 10px 0;
|
||||
width: 100%;
|
||||
display: inline-block;
|
||||
}
|
||||
|
||||
#wrapper .logo img {
|
||||
max-width: 100%;
|
||||
}
|
||||
|
||||
#wrapper .jumbotron {
|
||||
padding: 1.875em;
|
||||
padding-top: 1em;
|
||||
background-color: #e9eaea;
|
||||
}
|
||||
|
||||
#wrapper .jumbotron .RadButton {
|
||||
float: right;
|
||||
margin-top: .667em;
|
||||
font-size: .5em;
|
||||
}
|
||||
|
||||
#wrapper .footer {
|
||||
width:100%;
|
||||
padding: 30px 15px;
|
||||
line-height: 30px;
|
||||
}
|
||||
@@ -0,0 +1,47 @@
|
||||
#wrapper .header {
|
||||
background-color: #2a2d33;
|
||||
padding: 10px 0;
|
||||
margin: 0;
|
||||
text-align: center;
|
||||
}
|
||||
|
||||
#wrapper .header .RadMenu {
|
||||
float: none;
|
||||
display: inline-block;
|
||||
vertical-align: top;
|
||||
}
|
||||
|
||||
#wrapper .logo {
|
||||
padding: 10px 0;
|
||||
display: block;
|
||||
text-align: center;
|
||||
}
|
||||
|
||||
#wrapper .jumbotron {
|
||||
margin-bottom: 20px;
|
||||
padding: 0 1.875em 1.875em 1.875em;
|
||||
border: 1px solid transparent;
|
||||
background-color: #e9eaea;
|
||||
overflow: hidden;
|
||||
}
|
||||
|
||||
#wrapper .jumbotron img {
|
||||
float: right;
|
||||
margin: 20px 0 0 0;
|
||||
max-width: 100%;
|
||||
}
|
||||
|
||||
#wrapper .jumbotron h1 {
|
||||
border-bottom: 1px solid #767676;
|
||||
display: inline-block;
|
||||
padding-bottom: 20px;
|
||||
}
|
||||
|
||||
#wrapper .grid_wrapper {
|
||||
margin: 0 40px;
|
||||
}
|
||||
|
||||
#wrapper .footer {
|
||||
padding: 20px 15px;
|
||||
line-height: 30px;
|
||||
}
|
||||
@@ -0,0 +1,85 @@
|
||||
#wrapper .header {
|
||||
background-color: #2a2d33;
|
||||
padding: 10px 0;
|
||||
margin: 0;
|
||||
text-align: center;
|
||||
}
|
||||
|
||||
@media only screen and (max-width: 720px) {
|
||||
#wrapper .header {
|
||||
text-align: left;
|
||||
padding: 10px 2em;
|
||||
}
|
||||
}
|
||||
#wrapper .header .RadMenu {
|
||||
float: none;
|
||||
display: inline-block;
|
||||
vertical-align: top;
|
||||
}
|
||||
|
||||
#wrapper .logo {
|
||||
padding: 10px 0;
|
||||
display: block;
|
||||
text-align: center;
|
||||
}
|
||||
|
||||
#wrapper .jumbotron {
|
||||
margin-bottom: 20px;
|
||||
padding: 0 1.875em 1.875em 1.875em;
|
||||
border: 1px solid transparent;
|
||||
background-color: #e9eaea;
|
||||
overflow: hidden;
|
||||
}
|
||||
|
||||
#wrapper .jumbotron img {
|
||||
|
||||
margin: 20px 0 0 0;
|
||||
max-width: 100%;
|
||||
}
|
||||
|
||||
#wrapper .jumbotron h1 {
|
||||
border-bottom: 1px solid #767676;
|
||||
display: inline-block;
|
||||
padding-bottom: 20px;
|
||||
}
|
||||
|
||||
#wrapper .grid_wrapper {
|
||||
margin: 0 40px;
|
||||
}
|
||||
|
||||
.listView1,
|
||||
.listView2 {
|
||||
padding: 0 20px;
|
||||
overflow: hidden;
|
||||
text-align: center;
|
||||
}
|
||||
|
||||
#wrapper .listViewItem {
|
||||
display:inline-block;
|
||||
vertical-align: top;
|
||||
}
|
||||
|
||||
#wrapper .listView1 .listViewItem {
|
||||
max-width: 440px;
|
||||
width: auto;
|
||||
}
|
||||
|
||||
#wrapper .listView2 .listViewItem {
|
||||
max-width: 340px;
|
||||
}
|
||||
|
||||
* + html #wrapper .listViewItem {
|
||||
display: inline;
|
||||
zoom: 1;
|
||||
}
|
||||
|
||||
#wrapper .footer {
|
||||
padding: 20px 15px;
|
||||
line-height: 30px;
|
||||
}
|
||||
.listViewItem img {
|
||||
cursor: pointer;
|
||||
}
|
||||
div .RadMenu {
|
||||
z-index: 700;
|
||||
}
|
||||
@@ -0,0 +1,30 @@
|
||||
<?xml version="1.0" encoding="utf-8"?>
|
||||
|
||||
<!-- For more information on using web.config transformation visit https://go.microsoft.com/fwlink/?LinkId=125889 -->
|
||||
|
||||
<configuration xmlns:xdt="http://schemas.microsoft.com/XML-Document-Transform">
|
||||
<!--
|
||||
In the example below, the "SetAttributes" transform will change the value of
|
||||
"connectionString" to use "ReleaseSQLServer" only when the "Match" locator
|
||||
finds an attribute "name" that has a value of "MyDB".
|
||||
|
||||
<connectionStrings>
|
||||
<add name="MyDB"
|
||||
connectionString="Data Source=ReleaseSQLServer;Initial Catalog=MyReleaseDB;Integrated Security=True"
|
||||
xdt:Transform="SetAttributes" xdt:Locator="Match(name)"/>
|
||||
</connectionStrings>
|
||||
-->
|
||||
<system.web>
|
||||
<!--
|
||||
In the example below, the "Replace" transform will replace the entire
|
||||
<customErrors> section of your web.config file.
|
||||
Note that because there is only one customErrors section under the
|
||||
<system.web> node, there is no need to use the "xdt:Locator" attribute.
|
||||
|
||||
<customErrors defaultRedirect="GenericError.htm"
|
||||
mode="RemoteOnly" xdt:Transform="Replace">
|
||||
<error statusCode="500" redirect="InternalError.htm"/>
|
||||
</customErrors>
|
||||
-->
|
||||
</system.web>
|
||||
</configuration>
|
||||
@@ -0,0 +1,31 @@
|
||||
<?xml version="1.0" encoding="utf-8"?>
|
||||
|
||||
<!-- For more information on using web.config transformation visit https://go.microsoft.com/fwlink/?LinkId=125889 -->
|
||||
|
||||
<configuration xmlns:xdt="http://schemas.microsoft.com/XML-Document-Transform">
|
||||
<!--
|
||||
In the example below, the "SetAttributes" transform will change the value of
|
||||
"connectionString" to use "ReleaseSQLServer" only when the "Match" locator
|
||||
finds an attribute "name" that has a value of "MyDB".
|
||||
|
||||
<connectionStrings>
|
||||
<add name="MyDB"
|
||||
connectionString="Data Source=ReleaseSQLServer;Initial Catalog=MyReleaseDB;Integrated Security=True"
|
||||
xdt:Transform="SetAttributes" xdt:Locator="Match(name)"/>
|
||||
</connectionStrings>
|
||||
-->
|
||||
<system.web>
|
||||
<compilation xdt:Transform="RemoveAttributes(debug)" />
|
||||
<!--
|
||||
In the example below, the "Replace" transform will replace the entire
|
||||
<customErrors> section of your web.config file.
|
||||
Note that because there is only one customErrors section under the
|
||||
<system.web> node, there is no need to use the "xdt:Locator" attribute.
|
||||
|
||||
<customErrors defaultRedirect="GenericError.htm"
|
||||
mode="RemoteOnly" xdt:Transform="Replace">
|
||||
<error statusCode="500" redirect="InternalError.htm"/>
|
||||
</customErrors>
|
||||
-->
|
||||
</system.web>
|
||||
</configuration>
|
||||
@@ -0,0 +1,67 @@
|
||||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<configuration>
|
||||
<appSettings>
|
||||
<add key="Telerik.Skin" value="Bootstrap" />
|
||||
<add key="Telerik.ScriptManager.TelerikCdn" value="Disabled" />
|
||||
<add key="Telerik.StyleSheetManager.TelerikCdn" value="Disabled" />
|
||||
<add key="Telerik.Web.UI.RenderMode" value="lightweight" />
|
||||
</appSettings>
|
||||
|
||||
<system.web>
|
||||
<compilation debug="false" targetFramework="4.8" />
|
||||
<httpRuntime targetFramework="4.8" />
|
||||
|
||||
|
||||
|
||||
<pages>
|
||||
<controls>
|
||||
<add tagPrefix="telerik" namespace="Telerik.Web.UI" assembly="Telerik.Web.UI" />
|
||||
</controls>
|
||||
</pages><httpHandlers>
|
||||
<add path="ChartImage.axd" type="Telerik.Web.UI.ChartHttpHandler" verb="*" validate="false" />
|
||||
<add path="Telerik.Web.UI.SpellCheckHandler.axd" type="Telerik.Web.UI.SpellCheckHandler" verb="*" validate="false" />
|
||||
<add path="Telerik.Web.UI.DialogHandler.aspx" type="Telerik.Web.UI.DialogHandler" verb="*" validate="false" />
|
||||
<add path="Telerik.RadUploadProgressHandler.ashx" type="Telerik.Web.UI.RadUploadProgressHandler" verb="*" validate="false" />
|
||||
<add path="Telerik.Web.UI.WebResource.axd" type="Telerik.Web.UI.WebResource" verb="*" validate="false" /></httpHandlers><httpModules /></system.web>
|
||||
|
||||
<runtime>
|
||||
<assemblyBinding xmlns="urn:schemas-microsoft-com:asm.v1">
|
||||
<dependentAssembly>
|
||||
<assemblyIdentity name="Telerik.Windows.Documents.Flow" publicKeyToken="5803cfa389c90ce7" culture="neutral" />
|
||||
<bindingRedirect oldVersion="0.0.0.0-2025.2.701.462" newVersion="2025.2.701.462" />
|
||||
</dependentAssembly>
|
||||
<dependentAssembly>
|
||||
<assemblyIdentity name="Telerik.Windows.Documents.Core" publicKeyToken="5803cfa389c90ce7" culture="neutral" />
|
||||
<bindingRedirect oldVersion="0.0.0.0-2025.2.701.462" newVersion="2025.2.701.462" />
|
||||
</dependentAssembly>
|
||||
<dependentAssembly>
|
||||
<assemblyIdentity name="Telerik.Windows.Documents.Spreadsheet" publicKeyToken="5803cfa389c90ce7" culture="neutral" />
|
||||
<bindingRedirect oldVersion="0.0.0.0-2025.2.701.462" newVersion="2025.2.701.462" />
|
||||
</dependentAssembly>
|
||||
<dependentAssembly>
|
||||
<assemblyIdentity name="Telerik.Windows.Documents.Spreadsheet.FormatProviders.OpenXml" publicKeyToken="5803cfa389c90ce7" culture="neutral" />
|
||||
<bindingRedirect oldVersion="0.0.0.0-2025.2.701.462" newVersion="2025.2.701.462" />
|
||||
</dependentAssembly>
|
||||
<dependentAssembly>
|
||||
<assemblyIdentity name="Telerik.Licensing.Runtime" publicKeyToken="98bb5b04e55c09ef" culture="neutral" />
|
||||
<bindingRedirect oldVersion="0.0.0.0-1.6.40.0" newVersion="1.6.40.0" />
|
||||
</dependentAssembly>
|
||||
</assemblyBinding>
|
||||
</runtime>
|
||||
|
||||
|
||||
|
||||
<system.webServer>
|
||||
<validation validateIntegratedModeConfiguration="false" />
|
||||
<handlers>
|
||||
<remove name="ChartImage_axd" />
|
||||
<remove name="Telerik_Web_UI_SpellCheckHandler_axd" />
|
||||
<remove name="Telerik_Web_UI_DialogHandler_aspx" />
|
||||
<remove name="Telerik_RadUploadProgressHandler_ashx" />
|
||||
<remove name="Telerik_Web_UI_WebResource_axd" /><add name="ChartImage_axd" path="ChartImage.axd" type="Telerik.Web.UI.ChartHttpHandler" verb="*" preCondition="integratedMode" />
|
||||
<add name="Telerik_Web_UI_SpellCheckHandler_axd" path="Telerik.Web.UI.SpellCheckHandler.axd" type="Telerik.Web.UI.SpellCheckHandler" verb="*" preCondition="integratedMode" />
|
||||
<add name="Telerik_Web_UI_DialogHandler_aspx" path="Telerik.Web.UI.DialogHandler.aspx" type="Telerik.Web.UI.DialogHandler" verb="*" preCondition="integratedMode" />
|
||||
<add name="Telerik_RadUploadProgressHandler_ashx" path="Telerik.RadUploadProgressHandler.ashx" type="Telerik.Web.UI.RadUploadProgressHandler" verb="*" preCondition="integratedMode" />
|
||||
<add name="Telerik_Web_UI_WebResource_axd" path="Telerik.Web.UI.WebResource.axd" type="Telerik.Web.UI.WebResource" verb="*" preCondition="integratedMode" />
|
||||
</handlers>
|
||||
</system.webServer></configuration>
|
||||
@@ -0,0 +1,25 @@
|
||||
|
||||
Microsoft Visual Studio Solution File, Format Version 12.00
|
||||
# Visual Studio Version 17
|
||||
VisualStudioVersion = 17.2.32526.322
|
||||
MinimumVisualStudioVersion = 10.0.40219.1
|
||||
Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "MySite.Web", "MySite.Web\MySite.Web.csproj", "{ED3D7A4C-2473-41E1-87E7-428DBB517BD8}"
|
||||
EndProject
|
||||
Global
|
||||
GlobalSection(SolutionConfigurationPlatforms) = preSolution
|
||||
Debug|Any CPU = Debug|Any CPU
|
||||
Release|Any CPU = Release|Any CPU
|
||||
EndGlobalSection
|
||||
GlobalSection(ProjectConfigurationPlatforms) = postSolution
|
||||
{ED3D7A4C-2473-41E1-87E7-428DBB517BD8}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
|
||||
{ED3D7A4C-2473-41E1-87E7-428DBB517BD8}.Debug|Any CPU.Build.0 = Debug|Any CPU
|
||||
{ED3D7A4C-2473-41E1-87E7-428DBB517BD8}.Release|Any CPU.ActiveCfg = Release|Any CPU
|
||||
{ED3D7A4C-2473-41E1-87E7-428DBB517BD8}.Release|Any CPU.Build.0 = Release|Any CPU
|
||||
EndGlobalSection
|
||||
GlobalSection(SolutionProperties) = preSolution
|
||||
HideSolutionNode = FALSE
|
||||
EndGlobalSection
|
||||
GlobalSection(ExtensibilityGlobals) = postSolution
|
||||
SolutionGuid = {C7458BCE-5F5A-49A9-8C8C-8955E59F8B66}
|
||||
EndGlobalSection
|
||||
EndGlobal
|
||||
@@ -0,0 +1,505 @@
|
||||
|
||||
Microsoft Visual Studio Solution File, Format Version 12.00
|
||||
# Visual Studio Version 17
|
||||
VisualStudioVersion = 17.2.32526.322
|
||||
MinimumVisualStudioVersion = 10.0.40219.1
|
||||
Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "MySite.Web", "Ajax\MySite.Web\MySite.Web.csproj", "{ED3D7A4C-2473-41E1-87E7-428DBB517BD8}"
|
||||
EndProject
|
||||
Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "Web", "Web", "{5D445349-E40E-4936-AE11-7C07276AC4A3}"
|
||||
EndProject
|
||||
Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "Desktop", "Desktop", "{C5094142-9DAB-405B-9B46-DBA0AC3B9627}"
|
||||
EndProject
|
||||
Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "Maui", "Maui", "{07F120B6-65CD-4EDB-9BC5-F47281F268B3}"
|
||||
EndProject
|
||||
Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "MyDocProcApp", "Console\MyDocProcApp\MyDocProcApp.csproj", "{8DA97FE4-645B-4951-92A5-A740D6DD3E5C}"
|
||||
EndProject
|
||||
Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "MyWinFormsApp", "WinForms\MyWinFormsApp\MyWinFormsApp.csproj", "{999DDEB3-4CDA-441D-B980-3BC43B654237}"
|
||||
EndProject
|
||||
Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "MyWpfApp", "Wpf\MyWpfApp\MyWpfApp.csproj", "{2F4484CA-D992-44F2-AB3B-5C9F1AD83AB0}"
|
||||
EndProject
|
||||
Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "MyBlazorApp", "Blazor\MyBlazorApp\MyBlazorApp.csproj", "{8D741D81-6120-472A-BEE0-45F298D74D75}"
|
||||
EndProject
|
||||
Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "MyAspNetCoreApp", "AspNetCore\MyAspNetCoreApp\MyAspNetCoreApp.csproj", "{D75E5A16-6863-4A53-84F4-CC0360782292}"
|
||||
EndProject
|
||||
Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "MauiDemo", "MAUI\MauiDemo.csproj", "{5FD17957-3AD1-42E5-AAC4-D9B09E0B7E14}"
|
||||
EndProject
|
||||
Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "MyDemo", "WinUI\MyDemo\MyDemo.csproj", "{71C1E85B-1A79-C0C4-22BD-49A8DE57B8E7}"
|
||||
EndProject
|
||||
Global
|
||||
GlobalSection(SolutionConfigurationPlatforms) = preSolution
|
||||
Ad-Hoc|Any CPU = Ad-Hoc|Any CPU
|
||||
Ad-Hoc|ARM = Ad-Hoc|ARM
|
||||
Ad-Hoc|iPhone = Ad-Hoc|iPhone
|
||||
Ad-Hoc|iPhoneSimulator = Ad-Hoc|iPhoneSimulator
|
||||
Ad-Hoc|x64 = Ad-Hoc|x64
|
||||
Ad-Hoc|x86 = Ad-Hoc|x86
|
||||
AppStore|Any CPU = AppStore|Any CPU
|
||||
AppStore|ARM = AppStore|ARM
|
||||
AppStore|iPhone = AppStore|iPhone
|
||||
AppStore|iPhoneSimulator = AppStore|iPhoneSimulator
|
||||
AppStore|x64 = AppStore|x64
|
||||
AppStore|x86 = AppStore|x86
|
||||
Debug|Any CPU = Debug|Any CPU
|
||||
Debug|ARM = Debug|ARM
|
||||
Debug|iPhone = Debug|iPhone
|
||||
Debug|iPhoneSimulator = Debug|iPhoneSimulator
|
||||
Debug|x64 = Debug|x64
|
||||
Debug|x86 = Debug|x86
|
||||
Release|Any CPU = Release|Any CPU
|
||||
Release|ARM = Release|ARM
|
||||
Release|iPhone = Release|iPhone
|
||||
Release|iPhoneSimulator = Release|iPhoneSimulator
|
||||
Release|x64 = Release|x64
|
||||
Release|x86 = Release|x86
|
||||
EndGlobalSection
|
||||
GlobalSection(ProjectConfigurationPlatforms) = postSolution
|
||||
{ED3D7A4C-2473-41E1-87E7-428DBB517BD8}.Ad-Hoc|Any CPU.ActiveCfg = Release|Any CPU
|
||||
{ED3D7A4C-2473-41E1-87E7-428DBB517BD8}.Ad-Hoc|Any CPU.Build.0 = Release|Any CPU
|
||||
{ED3D7A4C-2473-41E1-87E7-428DBB517BD8}.Ad-Hoc|ARM.ActiveCfg = Release|Any CPU
|
||||
{ED3D7A4C-2473-41E1-87E7-428DBB517BD8}.Ad-Hoc|ARM.Build.0 = Release|Any CPU
|
||||
{ED3D7A4C-2473-41E1-87E7-428DBB517BD8}.Ad-Hoc|iPhone.ActiveCfg = Release|Any CPU
|
||||
{ED3D7A4C-2473-41E1-87E7-428DBB517BD8}.Ad-Hoc|iPhone.Build.0 = Release|Any CPU
|
||||
{ED3D7A4C-2473-41E1-87E7-428DBB517BD8}.Ad-Hoc|iPhoneSimulator.ActiveCfg = Release|Any CPU
|
||||
{ED3D7A4C-2473-41E1-87E7-428DBB517BD8}.Ad-Hoc|iPhoneSimulator.Build.0 = Release|Any CPU
|
||||
{ED3D7A4C-2473-41E1-87E7-428DBB517BD8}.Ad-Hoc|x64.ActiveCfg = Release|Any CPU
|
||||
{ED3D7A4C-2473-41E1-87E7-428DBB517BD8}.Ad-Hoc|x64.Build.0 = Release|Any CPU
|
||||
{ED3D7A4C-2473-41E1-87E7-428DBB517BD8}.Ad-Hoc|x86.ActiveCfg = Release|Any CPU
|
||||
{ED3D7A4C-2473-41E1-87E7-428DBB517BD8}.Ad-Hoc|x86.Build.0 = Release|Any CPU
|
||||
{ED3D7A4C-2473-41E1-87E7-428DBB517BD8}.AppStore|Any CPU.ActiveCfg = Release|Any CPU
|
||||
{ED3D7A4C-2473-41E1-87E7-428DBB517BD8}.AppStore|Any CPU.Build.0 = Release|Any CPU
|
||||
{ED3D7A4C-2473-41E1-87E7-428DBB517BD8}.AppStore|ARM.ActiveCfg = Release|Any CPU
|
||||
{ED3D7A4C-2473-41E1-87E7-428DBB517BD8}.AppStore|ARM.Build.0 = Release|Any CPU
|
||||
{ED3D7A4C-2473-41E1-87E7-428DBB517BD8}.AppStore|iPhone.ActiveCfg = Release|Any CPU
|
||||
{ED3D7A4C-2473-41E1-87E7-428DBB517BD8}.AppStore|iPhone.Build.0 = Release|Any CPU
|
||||
{ED3D7A4C-2473-41E1-87E7-428DBB517BD8}.AppStore|iPhoneSimulator.ActiveCfg = Release|Any CPU
|
||||
{ED3D7A4C-2473-41E1-87E7-428DBB517BD8}.AppStore|iPhoneSimulator.Build.0 = Release|Any CPU
|
||||
{ED3D7A4C-2473-41E1-87E7-428DBB517BD8}.AppStore|x64.ActiveCfg = Release|Any CPU
|
||||
{ED3D7A4C-2473-41E1-87E7-428DBB517BD8}.AppStore|x64.Build.0 = Release|Any CPU
|
||||
{ED3D7A4C-2473-41E1-87E7-428DBB517BD8}.AppStore|x86.ActiveCfg = Release|Any CPU
|
||||
{ED3D7A4C-2473-41E1-87E7-428DBB517BD8}.AppStore|x86.Build.0 = Release|Any CPU
|
||||
{ED3D7A4C-2473-41E1-87E7-428DBB517BD8}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
|
||||
{ED3D7A4C-2473-41E1-87E7-428DBB517BD8}.Debug|Any CPU.Build.0 = Debug|Any CPU
|
||||
{ED3D7A4C-2473-41E1-87E7-428DBB517BD8}.Debug|ARM.ActiveCfg = Debug|Any CPU
|
||||
{ED3D7A4C-2473-41E1-87E7-428DBB517BD8}.Debug|ARM.Build.0 = Debug|Any CPU
|
||||
{ED3D7A4C-2473-41E1-87E7-428DBB517BD8}.Debug|iPhone.ActiveCfg = Debug|Any CPU
|
||||
{ED3D7A4C-2473-41E1-87E7-428DBB517BD8}.Debug|iPhone.Build.0 = Debug|Any CPU
|
||||
{ED3D7A4C-2473-41E1-87E7-428DBB517BD8}.Debug|iPhoneSimulator.ActiveCfg = Debug|Any CPU
|
||||
{ED3D7A4C-2473-41E1-87E7-428DBB517BD8}.Debug|iPhoneSimulator.Build.0 = Debug|Any CPU
|
||||
{ED3D7A4C-2473-41E1-87E7-428DBB517BD8}.Debug|x64.ActiveCfg = Debug|Any CPU
|
||||
{ED3D7A4C-2473-41E1-87E7-428DBB517BD8}.Debug|x64.Build.0 = Debug|Any CPU
|
||||
{ED3D7A4C-2473-41E1-87E7-428DBB517BD8}.Debug|x86.ActiveCfg = Debug|Any CPU
|
||||
{ED3D7A4C-2473-41E1-87E7-428DBB517BD8}.Debug|x86.Build.0 = Debug|Any CPU
|
||||
{ED3D7A4C-2473-41E1-87E7-428DBB517BD8}.Release|Any CPU.ActiveCfg = Release|Any CPU
|
||||
{ED3D7A4C-2473-41E1-87E7-428DBB517BD8}.Release|Any CPU.Build.0 = Release|Any CPU
|
||||
{ED3D7A4C-2473-41E1-87E7-428DBB517BD8}.Release|ARM.ActiveCfg = Release|Any CPU
|
||||
{ED3D7A4C-2473-41E1-87E7-428DBB517BD8}.Release|ARM.Build.0 = Release|Any CPU
|
||||
{ED3D7A4C-2473-41E1-87E7-428DBB517BD8}.Release|iPhone.ActiveCfg = Release|Any CPU
|
||||
{ED3D7A4C-2473-41E1-87E7-428DBB517BD8}.Release|iPhone.Build.0 = Release|Any CPU
|
||||
{ED3D7A4C-2473-41E1-87E7-428DBB517BD8}.Release|iPhoneSimulator.ActiveCfg = Release|Any CPU
|
||||
{ED3D7A4C-2473-41E1-87E7-428DBB517BD8}.Release|iPhoneSimulator.Build.0 = Release|Any CPU
|
||||
{ED3D7A4C-2473-41E1-87E7-428DBB517BD8}.Release|x64.ActiveCfg = Release|Any CPU
|
||||
{ED3D7A4C-2473-41E1-87E7-428DBB517BD8}.Release|x64.Build.0 = Release|Any CPU
|
||||
{ED3D7A4C-2473-41E1-87E7-428DBB517BD8}.Release|x86.ActiveCfg = Release|Any CPU
|
||||
{ED3D7A4C-2473-41E1-87E7-428DBB517BD8}.Release|x86.Build.0 = Release|Any CPU
|
||||
{8DA97FE4-645B-4951-92A5-A740D6DD3E5C}.Ad-Hoc|Any CPU.ActiveCfg = Release|Any CPU
|
||||
{8DA97FE4-645B-4951-92A5-A740D6DD3E5C}.Ad-Hoc|Any CPU.Build.0 = Release|Any CPU
|
||||
{8DA97FE4-645B-4951-92A5-A740D6DD3E5C}.Ad-Hoc|ARM.ActiveCfg = Release|Any CPU
|
||||
{8DA97FE4-645B-4951-92A5-A740D6DD3E5C}.Ad-Hoc|ARM.Build.0 = Release|Any CPU
|
||||
{8DA97FE4-645B-4951-92A5-A740D6DD3E5C}.Ad-Hoc|iPhone.ActiveCfg = Release|Any CPU
|
||||
{8DA97FE4-645B-4951-92A5-A740D6DD3E5C}.Ad-Hoc|iPhone.Build.0 = Release|Any CPU
|
||||
{8DA97FE4-645B-4951-92A5-A740D6DD3E5C}.Ad-Hoc|iPhoneSimulator.ActiveCfg = Release|Any CPU
|
||||
{8DA97FE4-645B-4951-92A5-A740D6DD3E5C}.Ad-Hoc|iPhoneSimulator.Build.0 = Release|Any CPU
|
||||
{8DA97FE4-645B-4951-92A5-A740D6DD3E5C}.Ad-Hoc|x64.ActiveCfg = Release|Any CPU
|
||||
{8DA97FE4-645B-4951-92A5-A740D6DD3E5C}.Ad-Hoc|x64.Build.0 = Release|Any CPU
|
||||
{8DA97FE4-645B-4951-92A5-A740D6DD3E5C}.Ad-Hoc|x86.ActiveCfg = Release|Any CPU
|
||||
{8DA97FE4-645B-4951-92A5-A740D6DD3E5C}.Ad-Hoc|x86.Build.0 = Release|Any CPU
|
||||
{8DA97FE4-645B-4951-92A5-A740D6DD3E5C}.AppStore|Any CPU.ActiveCfg = Release|Any CPU
|
||||
{8DA97FE4-645B-4951-92A5-A740D6DD3E5C}.AppStore|Any CPU.Build.0 = Release|Any CPU
|
||||
{8DA97FE4-645B-4951-92A5-A740D6DD3E5C}.AppStore|ARM.ActiveCfg = Release|Any CPU
|
||||
{8DA97FE4-645B-4951-92A5-A740D6DD3E5C}.AppStore|ARM.Build.0 = Release|Any CPU
|
||||
{8DA97FE4-645B-4951-92A5-A740D6DD3E5C}.AppStore|iPhone.ActiveCfg = Release|Any CPU
|
||||
{8DA97FE4-645B-4951-92A5-A740D6DD3E5C}.AppStore|iPhone.Build.0 = Release|Any CPU
|
||||
{8DA97FE4-645B-4951-92A5-A740D6DD3E5C}.AppStore|iPhoneSimulator.ActiveCfg = Release|Any CPU
|
||||
{8DA97FE4-645B-4951-92A5-A740D6DD3E5C}.AppStore|iPhoneSimulator.Build.0 = Release|Any CPU
|
||||
{8DA97FE4-645B-4951-92A5-A740D6DD3E5C}.AppStore|x64.ActiveCfg = Release|Any CPU
|
||||
{8DA97FE4-645B-4951-92A5-A740D6DD3E5C}.AppStore|x64.Build.0 = Release|Any CPU
|
||||
{8DA97FE4-645B-4951-92A5-A740D6DD3E5C}.AppStore|x86.ActiveCfg = Release|Any CPU
|
||||
{8DA97FE4-645B-4951-92A5-A740D6DD3E5C}.AppStore|x86.Build.0 = Release|Any CPU
|
||||
{8DA97FE4-645B-4951-92A5-A740D6DD3E5C}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
|
||||
{8DA97FE4-645B-4951-92A5-A740D6DD3E5C}.Debug|Any CPU.Build.0 = Debug|Any CPU
|
||||
{8DA97FE4-645B-4951-92A5-A740D6DD3E5C}.Debug|ARM.ActiveCfg = Debug|Any CPU
|
||||
{8DA97FE4-645B-4951-92A5-A740D6DD3E5C}.Debug|ARM.Build.0 = Debug|Any CPU
|
||||
{8DA97FE4-645B-4951-92A5-A740D6DD3E5C}.Debug|iPhone.ActiveCfg = Debug|Any CPU
|
||||
{8DA97FE4-645B-4951-92A5-A740D6DD3E5C}.Debug|iPhone.Build.0 = Debug|Any CPU
|
||||
{8DA97FE4-645B-4951-92A5-A740D6DD3E5C}.Debug|iPhoneSimulator.ActiveCfg = Debug|Any CPU
|
||||
{8DA97FE4-645B-4951-92A5-A740D6DD3E5C}.Debug|iPhoneSimulator.Build.0 = Debug|Any CPU
|
||||
{8DA97FE4-645B-4951-92A5-A740D6DD3E5C}.Debug|x64.ActiveCfg = Debug|Any CPU
|
||||
{8DA97FE4-645B-4951-92A5-A740D6DD3E5C}.Debug|x64.Build.0 = Debug|Any CPU
|
||||
{8DA97FE4-645B-4951-92A5-A740D6DD3E5C}.Debug|x86.ActiveCfg = Debug|Any CPU
|
||||
{8DA97FE4-645B-4951-92A5-A740D6DD3E5C}.Debug|x86.Build.0 = Debug|Any CPU
|
||||
{8DA97FE4-645B-4951-92A5-A740D6DD3E5C}.Release|Any CPU.ActiveCfg = Release|Any CPU
|
||||
{8DA97FE4-645B-4951-92A5-A740D6DD3E5C}.Release|Any CPU.Build.0 = Release|Any CPU
|
||||
{8DA97FE4-645B-4951-92A5-A740D6DD3E5C}.Release|ARM.ActiveCfg = Release|Any CPU
|
||||
{8DA97FE4-645B-4951-92A5-A740D6DD3E5C}.Release|ARM.Build.0 = Release|Any CPU
|
||||
{8DA97FE4-645B-4951-92A5-A740D6DD3E5C}.Release|iPhone.ActiveCfg = Release|Any CPU
|
||||
{8DA97FE4-645B-4951-92A5-A740D6DD3E5C}.Release|iPhone.Build.0 = Release|Any CPU
|
||||
{8DA97FE4-645B-4951-92A5-A740D6DD3E5C}.Release|iPhoneSimulator.ActiveCfg = Release|Any CPU
|
||||
{8DA97FE4-645B-4951-92A5-A740D6DD3E5C}.Release|iPhoneSimulator.Build.0 = Release|Any CPU
|
||||
{8DA97FE4-645B-4951-92A5-A740D6DD3E5C}.Release|x64.ActiveCfg = Release|Any CPU
|
||||
{8DA97FE4-645B-4951-92A5-A740D6DD3E5C}.Release|x64.Build.0 = Release|Any CPU
|
||||
{8DA97FE4-645B-4951-92A5-A740D6DD3E5C}.Release|x86.ActiveCfg = Release|Any CPU
|
||||
{8DA97FE4-645B-4951-92A5-A740D6DD3E5C}.Release|x86.Build.0 = Release|Any CPU
|
||||
{999DDEB3-4CDA-441D-B980-3BC43B654237}.Ad-Hoc|Any CPU.ActiveCfg = Debug|x86
|
||||
{999DDEB3-4CDA-441D-B980-3BC43B654237}.Ad-Hoc|Any CPU.Build.0 = Debug|x86
|
||||
{999DDEB3-4CDA-441D-B980-3BC43B654237}.Ad-Hoc|ARM.ActiveCfg = Debug|x86
|
||||
{999DDEB3-4CDA-441D-B980-3BC43B654237}.Ad-Hoc|ARM.Build.0 = Debug|x86
|
||||
{999DDEB3-4CDA-441D-B980-3BC43B654237}.Ad-Hoc|iPhone.ActiveCfg = Debug|x86
|
||||
{999DDEB3-4CDA-441D-B980-3BC43B654237}.Ad-Hoc|iPhone.Build.0 = Debug|x86
|
||||
{999DDEB3-4CDA-441D-B980-3BC43B654237}.Ad-Hoc|iPhoneSimulator.ActiveCfg = Debug|x86
|
||||
{999DDEB3-4CDA-441D-B980-3BC43B654237}.Ad-Hoc|iPhoneSimulator.Build.0 = Debug|x86
|
||||
{999DDEB3-4CDA-441D-B980-3BC43B654237}.Ad-Hoc|x64.ActiveCfg = Debug|x86
|
||||
{999DDEB3-4CDA-441D-B980-3BC43B654237}.Ad-Hoc|x64.Build.0 = Debug|x86
|
||||
{999DDEB3-4CDA-441D-B980-3BC43B654237}.Ad-Hoc|x86.ActiveCfg = Debug|x86
|
||||
{999DDEB3-4CDA-441D-B980-3BC43B654237}.Ad-Hoc|x86.Build.0 = Debug|x86
|
||||
{999DDEB3-4CDA-441D-B980-3BC43B654237}.AppStore|Any CPU.ActiveCfg = Debug|x86
|
||||
{999DDEB3-4CDA-441D-B980-3BC43B654237}.AppStore|Any CPU.Build.0 = Debug|x86
|
||||
{999DDEB3-4CDA-441D-B980-3BC43B654237}.AppStore|ARM.ActiveCfg = Debug|x86
|
||||
{999DDEB3-4CDA-441D-B980-3BC43B654237}.AppStore|ARM.Build.0 = Debug|x86
|
||||
{999DDEB3-4CDA-441D-B980-3BC43B654237}.AppStore|iPhone.ActiveCfg = Debug|x86
|
||||
{999DDEB3-4CDA-441D-B980-3BC43B654237}.AppStore|iPhone.Build.0 = Debug|x86
|
||||
{999DDEB3-4CDA-441D-B980-3BC43B654237}.AppStore|iPhoneSimulator.ActiveCfg = Debug|x86
|
||||
{999DDEB3-4CDA-441D-B980-3BC43B654237}.AppStore|iPhoneSimulator.Build.0 = Debug|x86
|
||||
{999DDEB3-4CDA-441D-B980-3BC43B654237}.AppStore|x64.ActiveCfg = Debug|x86
|
||||
{999DDEB3-4CDA-441D-B980-3BC43B654237}.AppStore|x64.Build.0 = Debug|x86
|
||||
{999DDEB3-4CDA-441D-B980-3BC43B654237}.AppStore|x86.ActiveCfg = Debug|x86
|
||||
{999DDEB3-4CDA-441D-B980-3BC43B654237}.AppStore|x86.Build.0 = Debug|x86
|
||||
{999DDEB3-4CDA-441D-B980-3BC43B654237}.Debug|Any CPU.ActiveCfg = Debug|x86
|
||||
{999DDEB3-4CDA-441D-B980-3BC43B654237}.Debug|Any CPU.Build.0 = Debug|x86
|
||||
{999DDEB3-4CDA-441D-B980-3BC43B654237}.Debug|ARM.ActiveCfg = Debug|x86
|
||||
{999DDEB3-4CDA-441D-B980-3BC43B654237}.Debug|ARM.Build.0 = Debug|x86
|
||||
{999DDEB3-4CDA-441D-B980-3BC43B654237}.Debug|iPhone.ActiveCfg = Debug|x86
|
||||
{999DDEB3-4CDA-441D-B980-3BC43B654237}.Debug|iPhone.Build.0 = Debug|x86
|
||||
{999DDEB3-4CDA-441D-B980-3BC43B654237}.Debug|iPhoneSimulator.ActiveCfg = Debug|x86
|
||||
{999DDEB3-4CDA-441D-B980-3BC43B654237}.Debug|iPhoneSimulator.Build.0 = Debug|x86
|
||||
{999DDEB3-4CDA-441D-B980-3BC43B654237}.Debug|x64.ActiveCfg = Debug|x86
|
||||
{999DDEB3-4CDA-441D-B980-3BC43B654237}.Debug|x64.Build.0 = Debug|x86
|
||||
{999DDEB3-4CDA-441D-B980-3BC43B654237}.Debug|x86.ActiveCfg = Debug|x86
|
||||
{999DDEB3-4CDA-441D-B980-3BC43B654237}.Debug|x86.Build.0 = Debug|x86
|
||||
{999DDEB3-4CDA-441D-B980-3BC43B654237}.Release|Any CPU.ActiveCfg = Release|x86
|
||||
{999DDEB3-4CDA-441D-B980-3BC43B654237}.Release|Any CPU.Build.0 = Release|x86
|
||||
{999DDEB3-4CDA-441D-B980-3BC43B654237}.Release|ARM.ActiveCfg = Release|x86
|
||||
{999DDEB3-4CDA-441D-B980-3BC43B654237}.Release|ARM.Build.0 = Release|x86
|
||||
{999DDEB3-4CDA-441D-B980-3BC43B654237}.Release|iPhone.ActiveCfg = Release|x86
|
||||
{999DDEB3-4CDA-441D-B980-3BC43B654237}.Release|iPhone.Build.0 = Release|x86
|
||||
{999DDEB3-4CDA-441D-B980-3BC43B654237}.Release|iPhoneSimulator.ActiveCfg = Release|x86
|
||||
{999DDEB3-4CDA-441D-B980-3BC43B654237}.Release|iPhoneSimulator.Build.0 = Release|x86
|
||||
{999DDEB3-4CDA-441D-B980-3BC43B654237}.Release|x64.ActiveCfg = Release|x86
|
||||
{999DDEB3-4CDA-441D-B980-3BC43B654237}.Release|x64.Build.0 = Release|x86
|
||||
{999DDEB3-4CDA-441D-B980-3BC43B654237}.Release|x86.ActiveCfg = Release|x86
|
||||
{999DDEB3-4CDA-441D-B980-3BC43B654237}.Release|x86.Build.0 = Release|x86
|
||||
{2F4484CA-D992-44F2-AB3B-5C9F1AD83AB0}.Ad-Hoc|Any CPU.ActiveCfg = Debug|x86
|
||||
{2F4484CA-D992-44F2-AB3B-5C9F1AD83AB0}.Ad-Hoc|Any CPU.Build.0 = Debug|x86
|
||||
{2F4484CA-D992-44F2-AB3B-5C9F1AD83AB0}.Ad-Hoc|ARM.ActiveCfg = Debug|x86
|
||||
{2F4484CA-D992-44F2-AB3B-5C9F1AD83AB0}.Ad-Hoc|ARM.Build.0 = Debug|x86
|
||||
{2F4484CA-D992-44F2-AB3B-5C9F1AD83AB0}.Ad-Hoc|iPhone.ActiveCfg = Debug|x86
|
||||
{2F4484CA-D992-44F2-AB3B-5C9F1AD83AB0}.Ad-Hoc|iPhone.Build.0 = Debug|x86
|
||||
{2F4484CA-D992-44F2-AB3B-5C9F1AD83AB0}.Ad-Hoc|iPhoneSimulator.ActiveCfg = Debug|x86
|
||||
{2F4484CA-D992-44F2-AB3B-5C9F1AD83AB0}.Ad-Hoc|iPhoneSimulator.Build.0 = Debug|x86
|
||||
{2F4484CA-D992-44F2-AB3B-5C9F1AD83AB0}.Ad-Hoc|x64.ActiveCfg = Debug|x86
|
||||
{2F4484CA-D992-44F2-AB3B-5C9F1AD83AB0}.Ad-Hoc|x64.Build.0 = Debug|x86
|
||||
{2F4484CA-D992-44F2-AB3B-5C9F1AD83AB0}.Ad-Hoc|x86.ActiveCfg = Debug|x86
|
||||
{2F4484CA-D992-44F2-AB3B-5C9F1AD83AB0}.Ad-Hoc|x86.Build.0 = Debug|x86
|
||||
{2F4484CA-D992-44F2-AB3B-5C9F1AD83AB0}.AppStore|Any CPU.ActiveCfg = Debug|x86
|
||||
{2F4484CA-D992-44F2-AB3B-5C9F1AD83AB0}.AppStore|Any CPU.Build.0 = Debug|x86
|
||||
{2F4484CA-D992-44F2-AB3B-5C9F1AD83AB0}.AppStore|ARM.ActiveCfg = Debug|x86
|
||||
{2F4484CA-D992-44F2-AB3B-5C9F1AD83AB0}.AppStore|ARM.Build.0 = Debug|x86
|
||||
{2F4484CA-D992-44F2-AB3B-5C9F1AD83AB0}.AppStore|iPhone.ActiveCfg = Debug|x86
|
||||
{2F4484CA-D992-44F2-AB3B-5C9F1AD83AB0}.AppStore|iPhone.Build.0 = Debug|x86
|
||||
{2F4484CA-D992-44F2-AB3B-5C9F1AD83AB0}.AppStore|iPhoneSimulator.ActiveCfg = Debug|x86
|
||||
{2F4484CA-D992-44F2-AB3B-5C9F1AD83AB0}.AppStore|iPhoneSimulator.Build.0 = Debug|x86
|
||||
{2F4484CA-D992-44F2-AB3B-5C9F1AD83AB0}.AppStore|x64.ActiveCfg = Debug|x86
|
||||
{2F4484CA-D992-44F2-AB3B-5C9F1AD83AB0}.AppStore|x64.Build.0 = Debug|x86
|
||||
{2F4484CA-D992-44F2-AB3B-5C9F1AD83AB0}.AppStore|x86.ActiveCfg = Debug|x86
|
||||
{2F4484CA-D992-44F2-AB3B-5C9F1AD83AB0}.AppStore|x86.Build.0 = Debug|x86
|
||||
{2F4484CA-D992-44F2-AB3B-5C9F1AD83AB0}.Debug|Any CPU.ActiveCfg = Debug|x86
|
||||
{2F4484CA-D992-44F2-AB3B-5C9F1AD83AB0}.Debug|Any CPU.Build.0 = Debug|x86
|
||||
{2F4484CA-D992-44F2-AB3B-5C9F1AD83AB0}.Debug|ARM.ActiveCfg = Debug|x86
|
||||
{2F4484CA-D992-44F2-AB3B-5C9F1AD83AB0}.Debug|ARM.Build.0 = Debug|x86
|
||||
{2F4484CA-D992-44F2-AB3B-5C9F1AD83AB0}.Debug|iPhone.ActiveCfg = Debug|x86
|
||||
{2F4484CA-D992-44F2-AB3B-5C9F1AD83AB0}.Debug|iPhone.Build.0 = Debug|x86
|
||||
{2F4484CA-D992-44F2-AB3B-5C9F1AD83AB0}.Debug|iPhoneSimulator.ActiveCfg = Debug|x86
|
||||
{2F4484CA-D992-44F2-AB3B-5C9F1AD83AB0}.Debug|iPhoneSimulator.Build.0 = Debug|x86
|
||||
{2F4484CA-D992-44F2-AB3B-5C9F1AD83AB0}.Debug|x64.ActiveCfg = Debug|x86
|
||||
{2F4484CA-D992-44F2-AB3B-5C9F1AD83AB0}.Debug|x64.Build.0 = Debug|x86
|
||||
{2F4484CA-D992-44F2-AB3B-5C9F1AD83AB0}.Debug|x86.ActiveCfg = Debug|x86
|
||||
{2F4484CA-D992-44F2-AB3B-5C9F1AD83AB0}.Debug|x86.Build.0 = Debug|x86
|
||||
{2F4484CA-D992-44F2-AB3B-5C9F1AD83AB0}.Release|Any CPU.ActiveCfg = Release|x86
|
||||
{2F4484CA-D992-44F2-AB3B-5C9F1AD83AB0}.Release|Any CPU.Build.0 = Release|x86
|
||||
{2F4484CA-D992-44F2-AB3B-5C9F1AD83AB0}.Release|ARM.ActiveCfg = Release|x86
|
||||
{2F4484CA-D992-44F2-AB3B-5C9F1AD83AB0}.Release|ARM.Build.0 = Release|x86
|
||||
{2F4484CA-D992-44F2-AB3B-5C9F1AD83AB0}.Release|iPhone.ActiveCfg = Release|x86
|
||||
{2F4484CA-D992-44F2-AB3B-5C9F1AD83AB0}.Release|iPhone.Build.0 = Release|x86
|
||||
{2F4484CA-D992-44F2-AB3B-5C9F1AD83AB0}.Release|iPhoneSimulator.ActiveCfg = Release|x86
|
||||
{2F4484CA-D992-44F2-AB3B-5C9F1AD83AB0}.Release|iPhoneSimulator.Build.0 = Release|x86
|
||||
{2F4484CA-D992-44F2-AB3B-5C9F1AD83AB0}.Release|x64.ActiveCfg = Release|x86
|
||||
{2F4484CA-D992-44F2-AB3B-5C9F1AD83AB0}.Release|x64.Build.0 = Release|x86
|
||||
{2F4484CA-D992-44F2-AB3B-5C9F1AD83AB0}.Release|x86.ActiveCfg = Release|x86
|
||||
{2F4484CA-D992-44F2-AB3B-5C9F1AD83AB0}.Release|x86.Build.0 = Release|x86
|
||||
{8D741D81-6120-472A-BEE0-45F298D74D75}.Ad-Hoc|Any CPU.ActiveCfg = Debug|Any CPU
|
||||
{8D741D81-6120-472A-BEE0-45F298D74D75}.Ad-Hoc|Any CPU.Build.0 = Debug|Any CPU
|
||||
{8D741D81-6120-472A-BEE0-45F298D74D75}.Ad-Hoc|ARM.ActiveCfg = Debug|Any CPU
|
||||
{8D741D81-6120-472A-BEE0-45F298D74D75}.Ad-Hoc|ARM.Build.0 = Debug|Any CPU
|
||||
{8D741D81-6120-472A-BEE0-45F298D74D75}.Ad-Hoc|iPhone.ActiveCfg = Debug|Any CPU
|
||||
{8D741D81-6120-472A-BEE0-45F298D74D75}.Ad-Hoc|iPhone.Build.0 = Debug|Any CPU
|
||||
{8D741D81-6120-472A-BEE0-45F298D74D75}.Ad-Hoc|iPhoneSimulator.ActiveCfg = Debug|Any CPU
|
||||
{8D741D81-6120-472A-BEE0-45F298D74D75}.Ad-Hoc|iPhoneSimulator.Build.0 = Debug|Any CPU
|
||||
{8D741D81-6120-472A-BEE0-45F298D74D75}.Ad-Hoc|x64.ActiveCfg = Debug|Any CPU
|
||||
{8D741D81-6120-472A-BEE0-45F298D74D75}.Ad-Hoc|x64.Build.0 = Debug|Any CPU
|
||||
{8D741D81-6120-472A-BEE0-45F298D74D75}.Ad-Hoc|x86.ActiveCfg = Debug|Any CPU
|
||||
{8D741D81-6120-472A-BEE0-45F298D74D75}.Ad-Hoc|x86.Build.0 = Debug|Any CPU
|
||||
{8D741D81-6120-472A-BEE0-45F298D74D75}.AppStore|Any CPU.ActiveCfg = Debug|Any CPU
|
||||
{8D741D81-6120-472A-BEE0-45F298D74D75}.AppStore|Any CPU.Build.0 = Debug|Any CPU
|
||||
{8D741D81-6120-472A-BEE0-45F298D74D75}.AppStore|ARM.ActiveCfg = Debug|Any CPU
|
||||
{8D741D81-6120-472A-BEE0-45F298D74D75}.AppStore|ARM.Build.0 = Debug|Any CPU
|
||||
{8D741D81-6120-472A-BEE0-45F298D74D75}.AppStore|iPhone.ActiveCfg = Debug|Any CPU
|
||||
{8D741D81-6120-472A-BEE0-45F298D74D75}.AppStore|iPhone.Build.0 = Debug|Any CPU
|
||||
{8D741D81-6120-472A-BEE0-45F298D74D75}.AppStore|iPhoneSimulator.ActiveCfg = Debug|Any CPU
|
||||
{8D741D81-6120-472A-BEE0-45F298D74D75}.AppStore|iPhoneSimulator.Build.0 = Debug|Any CPU
|
||||
{8D741D81-6120-472A-BEE0-45F298D74D75}.AppStore|x64.ActiveCfg = Debug|Any CPU
|
||||
{8D741D81-6120-472A-BEE0-45F298D74D75}.AppStore|x64.Build.0 = Debug|Any CPU
|
||||
{8D741D81-6120-472A-BEE0-45F298D74D75}.AppStore|x86.ActiveCfg = Debug|Any CPU
|
||||
{8D741D81-6120-472A-BEE0-45F298D74D75}.AppStore|x86.Build.0 = Debug|Any CPU
|
||||
{8D741D81-6120-472A-BEE0-45F298D74D75}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
|
||||
{8D741D81-6120-472A-BEE0-45F298D74D75}.Debug|Any CPU.Build.0 = Debug|Any CPU
|
||||
{8D741D81-6120-472A-BEE0-45F298D74D75}.Debug|ARM.ActiveCfg = Debug|Any CPU
|
||||
{8D741D81-6120-472A-BEE0-45F298D74D75}.Debug|ARM.Build.0 = Debug|Any CPU
|
||||
{8D741D81-6120-472A-BEE0-45F298D74D75}.Debug|iPhone.ActiveCfg = Debug|Any CPU
|
||||
{8D741D81-6120-472A-BEE0-45F298D74D75}.Debug|iPhone.Build.0 = Debug|Any CPU
|
||||
{8D741D81-6120-472A-BEE0-45F298D74D75}.Debug|iPhoneSimulator.ActiveCfg = Debug|Any CPU
|
||||
{8D741D81-6120-472A-BEE0-45F298D74D75}.Debug|iPhoneSimulator.Build.0 = Debug|Any CPU
|
||||
{8D741D81-6120-472A-BEE0-45F298D74D75}.Debug|x64.ActiveCfg = Debug|Any CPU
|
||||
{8D741D81-6120-472A-BEE0-45F298D74D75}.Debug|x64.Build.0 = Debug|Any CPU
|
||||
{8D741D81-6120-472A-BEE0-45F298D74D75}.Debug|x86.ActiveCfg = Debug|Any CPU
|
||||
{8D741D81-6120-472A-BEE0-45F298D74D75}.Debug|x86.Build.0 = Debug|Any CPU
|
||||
{8D741D81-6120-472A-BEE0-45F298D74D75}.Release|Any CPU.ActiveCfg = Release|Any CPU
|
||||
{8D741D81-6120-472A-BEE0-45F298D74D75}.Release|Any CPU.Build.0 = Release|Any CPU
|
||||
{8D741D81-6120-472A-BEE0-45F298D74D75}.Release|ARM.ActiveCfg = Release|Any CPU
|
||||
{8D741D81-6120-472A-BEE0-45F298D74D75}.Release|ARM.Build.0 = Release|Any CPU
|
||||
{8D741D81-6120-472A-BEE0-45F298D74D75}.Release|iPhone.ActiveCfg = Release|Any CPU
|
||||
{8D741D81-6120-472A-BEE0-45F298D74D75}.Release|iPhone.Build.0 = Release|Any CPU
|
||||
{8D741D81-6120-472A-BEE0-45F298D74D75}.Release|iPhoneSimulator.ActiveCfg = Release|Any CPU
|
||||
{8D741D81-6120-472A-BEE0-45F298D74D75}.Release|iPhoneSimulator.Build.0 = Release|Any CPU
|
||||
{8D741D81-6120-472A-BEE0-45F298D74D75}.Release|x64.ActiveCfg = Release|Any CPU
|
||||
{8D741D81-6120-472A-BEE0-45F298D74D75}.Release|x64.Build.0 = Release|Any CPU
|
||||
{8D741D81-6120-472A-BEE0-45F298D74D75}.Release|x86.ActiveCfg = Release|Any CPU
|
||||
{8D741D81-6120-472A-BEE0-45F298D74D75}.Release|x86.Build.0 = Release|Any CPU
|
||||
{D75E5A16-6863-4A53-84F4-CC0360782292}.Ad-Hoc|Any CPU.ActiveCfg = Debug|Any CPU
|
||||
{D75E5A16-6863-4A53-84F4-CC0360782292}.Ad-Hoc|Any CPU.Build.0 = Debug|Any CPU
|
||||
{D75E5A16-6863-4A53-84F4-CC0360782292}.Ad-Hoc|ARM.ActiveCfg = Debug|Any CPU
|
||||
{D75E5A16-6863-4A53-84F4-CC0360782292}.Ad-Hoc|ARM.Build.0 = Debug|Any CPU
|
||||
{D75E5A16-6863-4A53-84F4-CC0360782292}.Ad-Hoc|iPhone.ActiveCfg = Debug|Any CPU
|
||||
{D75E5A16-6863-4A53-84F4-CC0360782292}.Ad-Hoc|iPhone.Build.0 = Debug|Any CPU
|
||||
{D75E5A16-6863-4A53-84F4-CC0360782292}.Ad-Hoc|iPhoneSimulator.ActiveCfg = Debug|Any CPU
|
||||
{D75E5A16-6863-4A53-84F4-CC0360782292}.Ad-Hoc|iPhoneSimulator.Build.0 = Debug|Any CPU
|
||||
{D75E5A16-6863-4A53-84F4-CC0360782292}.Ad-Hoc|x64.ActiveCfg = Debug|Any CPU
|
||||
{D75E5A16-6863-4A53-84F4-CC0360782292}.Ad-Hoc|x64.Build.0 = Debug|Any CPU
|
||||
{D75E5A16-6863-4A53-84F4-CC0360782292}.Ad-Hoc|x86.ActiveCfg = Debug|Any CPU
|
||||
{D75E5A16-6863-4A53-84F4-CC0360782292}.Ad-Hoc|x86.Build.0 = Debug|Any CPU
|
||||
{D75E5A16-6863-4A53-84F4-CC0360782292}.AppStore|Any CPU.ActiveCfg = Debug|Any CPU
|
||||
{D75E5A16-6863-4A53-84F4-CC0360782292}.AppStore|Any CPU.Build.0 = Debug|Any CPU
|
||||
{D75E5A16-6863-4A53-84F4-CC0360782292}.AppStore|ARM.ActiveCfg = Debug|Any CPU
|
||||
{D75E5A16-6863-4A53-84F4-CC0360782292}.AppStore|ARM.Build.0 = Debug|Any CPU
|
||||
{D75E5A16-6863-4A53-84F4-CC0360782292}.AppStore|iPhone.ActiveCfg = Debug|Any CPU
|
||||
{D75E5A16-6863-4A53-84F4-CC0360782292}.AppStore|iPhone.Build.0 = Debug|Any CPU
|
||||
{D75E5A16-6863-4A53-84F4-CC0360782292}.AppStore|iPhoneSimulator.ActiveCfg = Debug|Any CPU
|
||||
{D75E5A16-6863-4A53-84F4-CC0360782292}.AppStore|iPhoneSimulator.Build.0 = Debug|Any CPU
|
||||
{D75E5A16-6863-4A53-84F4-CC0360782292}.AppStore|x64.ActiveCfg = Debug|Any CPU
|
||||
{D75E5A16-6863-4A53-84F4-CC0360782292}.AppStore|x64.Build.0 = Debug|Any CPU
|
||||
{D75E5A16-6863-4A53-84F4-CC0360782292}.AppStore|x86.ActiveCfg = Debug|Any CPU
|
||||
{D75E5A16-6863-4A53-84F4-CC0360782292}.AppStore|x86.Build.0 = Debug|Any CPU
|
||||
{D75E5A16-6863-4A53-84F4-CC0360782292}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
|
||||
{D75E5A16-6863-4A53-84F4-CC0360782292}.Debug|Any CPU.Build.0 = Debug|Any CPU
|
||||
{D75E5A16-6863-4A53-84F4-CC0360782292}.Debug|ARM.ActiveCfg = Debug|Any CPU
|
||||
{D75E5A16-6863-4A53-84F4-CC0360782292}.Debug|ARM.Build.0 = Debug|Any CPU
|
||||
{D75E5A16-6863-4A53-84F4-CC0360782292}.Debug|iPhone.ActiveCfg = Debug|Any CPU
|
||||
{D75E5A16-6863-4A53-84F4-CC0360782292}.Debug|iPhone.Build.0 = Debug|Any CPU
|
||||
{D75E5A16-6863-4A53-84F4-CC0360782292}.Debug|iPhoneSimulator.ActiveCfg = Debug|Any CPU
|
||||
{D75E5A16-6863-4A53-84F4-CC0360782292}.Debug|iPhoneSimulator.Build.0 = Debug|Any CPU
|
||||
{D75E5A16-6863-4A53-84F4-CC0360782292}.Debug|x64.ActiveCfg = Debug|Any CPU
|
||||
{D75E5A16-6863-4A53-84F4-CC0360782292}.Debug|x64.Build.0 = Debug|Any CPU
|
||||
{D75E5A16-6863-4A53-84F4-CC0360782292}.Debug|x86.ActiveCfg = Debug|Any CPU
|
||||
{D75E5A16-6863-4A53-84F4-CC0360782292}.Debug|x86.Build.0 = Debug|Any CPU
|
||||
{D75E5A16-6863-4A53-84F4-CC0360782292}.Release|Any CPU.ActiveCfg = Release|Any CPU
|
||||
{D75E5A16-6863-4A53-84F4-CC0360782292}.Release|Any CPU.Build.0 = Release|Any CPU
|
||||
{D75E5A16-6863-4A53-84F4-CC0360782292}.Release|ARM.ActiveCfg = Release|Any CPU
|
||||
{D75E5A16-6863-4A53-84F4-CC0360782292}.Release|ARM.Build.0 = Release|Any CPU
|
||||
{D75E5A16-6863-4A53-84F4-CC0360782292}.Release|iPhone.ActiveCfg = Release|Any CPU
|
||||
{D75E5A16-6863-4A53-84F4-CC0360782292}.Release|iPhone.Build.0 = Release|Any CPU
|
||||
{D75E5A16-6863-4A53-84F4-CC0360782292}.Release|iPhoneSimulator.ActiveCfg = Release|Any CPU
|
||||
{D75E5A16-6863-4A53-84F4-CC0360782292}.Release|iPhoneSimulator.Build.0 = Release|Any CPU
|
||||
{D75E5A16-6863-4A53-84F4-CC0360782292}.Release|x64.ActiveCfg = Release|Any CPU
|
||||
{D75E5A16-6863-4A53-84F4-CC0360782292}.Release|x64.Build.0 = Release|Any CPU
|
||||
{D75E5A16-6863-4A53-84F4-CC0360782292}.Release|x86.ActiveCfg = Release|Any CPU
|
||||
{D75E5A16-6863-4A53-84F4-CC0360782292}.Release|x86.Build.0 = Release|Any CPU
|
||||
{5FD17957-3AD1-42E5-AAC4-D9B09E0B7E14}.Ad-Hoc|Any CPU.ActiveCfg = Debug|Any CPU
|
||||
{5FD17957-3AD1-42E5-AAC4-D9B09E0B7E14}.Ad-Hoc|Any CPU.Build.0 = Debug|Any CPU
|
||||
{5FD17957-3AD1-42E5-AAC4-D9B09E0B7E14}.Ad-Hoc|Any CPU.Deploy.0 = Debug|Any CPU
|
||||
{5FD17957-3AD1-42E5-AAC4-D9B09E0B7E14}.Ad-Hoc|ARM.ActiveCfg = Debug|Any CPU
|
||||
{5FD17957-3AD1-42E5-AAC4-D9B09E0B7E14}.Ad-Hoc|ARM.Build.0 = Debug|Any CPU
|
||||
{5FD17957-3AD1-42E5-AAC4-D9B09E0B7E14}.Ad-Hoc|ARM.Deploy.0 = Debug|Any CPU
|
||||
{5FD17957-3AD1-42E5-AAC4-D9B09E0B7E14}.Ad-Hoc|iPhone.ActiveCfg = Debug|Any CPU
|
||||
{5FD17957-3AD1-42E5-AAC4-D9B09E0B7E14}.Ad-Hoc|iPhone.Build.0 = Debug|Any CPU
|
||||
{5FD17957-3AD1-42E5-AAC4-D9B09E0B7E14}.Ad-Hoc|iPhone.Deploy.0 = Debug|Any CPU
|
||||
{5FD17957-3AD1-42E5-AAC4-D9B09E0B7E14}.Ad-Hoc|iPhoneSimulator.ActiveCfg = Debug|Any CPU
|
||||
{5FD17957-3AD1-42E5-AAC4-D9B09E0B7E14}.Ad-Hoc|iPhoneSimulator.Build.0 = Debug|Any CPU
|
||||
{5FD17957-3AD1-42E5-AAC4-D9B09E0B7E14}.Ad-Hoc|iPhoneSimulator.Deploy.0 = Debug|Any CPU
|
||||
{5FD17957-3AD1-42E5-AAC4-D9B09E0B7E14}.Ad-Hoc|x64.ActiveCfg = Debug|Any CPU
|
||||
{5FD17957-3AD1-42E5-AAC4-D9B09E0B7E14}.Ad-Hoc|x64.Build.0 = Debug|Any CPU
|
||||
{5FD17957-3AD1-42E5-AAC4-D9B09E0B7E14}.Ad-Hoc|x64.Deploy.0 = Debug|Any CPU
|
||||
{5FD17957-3AD1-42E5-AAC4-D9B09E0B7E14}.Ad-Hoc|x86.ActiveCfg = Debug|Any CPU
|
||||
{5FD17957-3AD1-42E5-AAC4-D9B09E0B7E14}.Ad-Hoc|x86.Build.0 = Debug|Any CPU
|
||||
{5FD17957-3AD1-42E5-AAC4-D9B09E0B7E14}.Ad-Hoc|x86.Deploy.0 = Debug|Any CPU
|
||||
{5FD17957-3AD1-42E5-AAC4-D9B09E0B7E14}.AppStore|Any CPU.ActiveCfg = Debug|Any CPU
|
||||
{5FD17957-3AD1-42E5-AAC4-D9B09E0B7E14}.AppStore|Any CPU.Build.0 = Debug|Any CPU
|
||||
{5FD17957-3AD1-42E5-AAC4-D9B09E0B7E14}.AppStore|Any CPU.Deploy.0 = Debug|Any CPU
|
||||
{5FD17957-3AD1-42E5-AAC4-D9B09E0B7E14}.AppStore|ARM.ActiveCfg = Debug|Any CPU
|
||||
{5FD17957-3AD1-42E5-AAC4-D9B09E0B7E14}.AppStore|ARM.Build.0 = Debug|Any CPU
|
||||
{5FD17957-3AD1-42E5-AAC4-D9B09E0B7E14}.AppStore|ARM.Deploy.0 = Debug|Any CPU
|
||||
{5FD17957-3AD1-42E5-AAC4-D9B09E0B7E14}.AppStore|iPhone.ActiveCfg = Debug|Any CPU
|
||||
{5FD17957-3AD1-42E5-AAC4-D9B09E0B7E14}.AppStore|iPhone.Build.0 = Debug|Any CPU
|
||||
{5FD17957-3AD1-42E5-AAC4-D9B09E0B7E14}.AppStore|iPhone.Deploy.0 = Debug|Any CPU
|
||||
{5FD17957-3AD1-42E5-AAC4-D9B09E0B7E14}.AppStore|iPhoneSimulator.ActiveCfg = Debug|Any CPU
|
||||
{5FD17957-3AD1-42E5-AAC4-D9B09E0B7E14}.AppStore|iPhoneSimulator.Build.0 = Debug|Any CPU
|
||||
{5FD17957-3AD1-42E5-AAC4-D9B09E0B7E14}.AppStore|iPhoneSimulator.Deploy.0 = Debug|Any CPU
|
||||
{5FD17957-3AD1-42E5-AAC4-D9B09E0B7E14}.AppStore|x64.ActiveCfg = Debug|Any CPU
|
||||
{5FD17957-3AD1-42E5-AAC4-D9B09E0B7E14}.AppStore|x64.Build.0 = Debug|Any CPU
|
||||
{5FD17957-3AD1-42E5-AAC4-D9B09E0B7E14}.AppStore|x64.Deploy.0 = Debug|Any CPU
|
||||
{5FD17957-3AD1-42E5-AAC4-D9B09E0B7E14}.AppStore|x86.ActiveCfg = Debug|Any CPU
|
||||
{5FD17957-3AD1-42E5-AAC4-D9B09E0B7E14}.AppStore|x86.Build.0 = Debug|Any CPU
|
||||
{5FD17957-3AD1-42E5-AAC4-D9B09E0B7E14}.AppStore|x86.Deploy.0 = Debug|Any CPU
|
||||
{5FD17957-3AD1-42E5-AAC4-D9B09E0B7E14}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
|
||||
{5FD17957-3AD1-42E5-AAC4-D9B09E0B7E14}.Debug|Any CPU.Build.0 = Debug|Any CPU
|
||||
{5FD17957-3AD1-42E5-AAC4-D9B09E0B7E14}.Debug|Any CPU.Deploy.0 = Debug|Any CPU
|
||||
{5FD17957-3AD1-42E5-AAC4-D9B09E0B7E14}.Debug|ARM.ActiveCfg = Debug|Any CPU
|
||||
{5FD17957-3AD1-42E5-AAC4-D9B09E0B7E14}.Debug|ARM.Build.0 = Debug|Any CPU
|
||||
{5FD17957-3AD1-42E5-AAC4-D9B09E0B7E14}.Debug|ARM.Deploy.0 = Debug|Any CPU
|
||||
{5FD17957-3AD1-42E5-AAC4-D9B09E0B7E14}.Debug|iPhone.ActiveCfg = Debug|Any CPU
|
||||
{5FD17957-3AD1-42E5-AAC4-D9B09E0B7E14}.Debug|iPhone.Build.0 = Debug|Any CPU
|
||||
{5FD17957-3AD1-42E5-AAC4-D9B09E0B7E14}.Debug|iPhone.Deploy.0 = Debug|Any CPU
|
||||
{5FD17957-3AD1-42E5-AAC4-D9B09E0B7E14}.Debug|iPhoneSimulator.ActiveCfg = Debug|Any CPU
|
||||
{5FD17957-3AD1-42E5-AAC4-D9B09E0B7E14}.Debug|iPhoneSimulator.Build.0 = Debug|Any CPU
|
||||
{5FD17957-3AD1-42E5-AAC4-D9B09E0B7E14}.Debug|iPhoneSimulator.Deploy.0 = Debug|Any CPU
|
||||
{5FD17957-3AD1-42E5-AAC4-D9B09E0B7E14}.Debug|x64.ActiveCfg = Debug|Any CPU
|
||||
{5FD17957-3AD1-42E5-AAC4-D9B09E0B7E14}.Debug|x64.Build.0 = Debug|Any CPU
|
||||
{5FD17957-3AD1-42E5-AAC4-D9B09E0B7E14}.Debug|x64.Deploy.0 = Debug|Any CPU
|
||||
{5FD17957-3AD1-42E5-AAC4-D9B09E0B7E14}.Debug|x86.ActiveCfg = Debug|Any CPU
|
||||
{5FD17957-3AD1-42E5-AAC4-D9B09E0B7E14}.Debug|x86.Build.0 = Debug|Any CPU
|
||||
{5FD17957-3AD1-42E5-AAC4-D9B09E0B7E14}.Debug|x86.Deploy.0 = Debug|Any CPU
|
||||
{5FD17957-3AD1-42E5-AAC4-D9B09E0B7E14}.Release|Any CPU.ActiveCfg = Release|Any CPU
|
||||
{5FD17957-3AD1-42E5-AAC4-D9B09E0B7E14}.Release|Any CPU.Build.0 = Release|Any CPU
|
||||
{5FD17957-3AD1-42E5-AAC4-D9B09E0B7E14}.Release|Any CPU.Deploy.0 = Release|Any CPU
|
||||
{5FD17957-3AD1-42E5-AAC4-D9B09E0B7E14}.Release|ARM.ActiveCfg = Release|Any CPU
|
||||
{5FD17957-3AD1-42E5-AAC4-D9B09E0B7E14}.Release|ARM.Build.0 = Release|Any CPU
|
||||
{5FD17957-3AD1-42E5-AAC4-D9B09E0B7E14}.Release|ARM.Deploy.0 = Release|Any CPU
|
||||
{5FD17957-3AD1-42E5-AAC4-D9B09E0B7E14}.Release|iPhone.ActiveCfg = Release|Any CPU
|
||||
{5FD17957-3AD1-42E5-AAC4-D9B09E0B7E14}.Release|iPhone.Build.0 = Release|Any CPU
|
||||
{5FD17957-3AD1-42E5-AAC4-D9B09E0B7E14}.Release|iPhone.Deploy.0 = Release|Any CPU
|
||||
{5FD17957-3AD1-42E5-AAC4-D9B09E0B7E14}.Release|iPhoneSimulator.ActiveCfg = Release|Any CPU
|
||||
{5FD17957-3AD1-42E5-AAC4-D9B09E0B7E14}.Release|iPhoneSimulator.Build.0 = Release|Any CPU
|
||||
{5FD17957-3AD1-42E5-AAC4-D9B09E0B7E14}.Release|iPhoneSimulator.Deploy.0 = Release|Any CPU
|
||||
{5FD17957-3AD1-42E5-AAC4-D9B09E0B7E14}.Release|x64.ActiveCfg = Release|Any CPU
|
||||
{5FD17957-3AD1-42E5-AAC4-D9B09E0B7E14}.Release|x64.Build.0 = Release|Any CPU
|
||||
{5FD17957-3AD1-42E5-AAC4-D9B09E0B7E14}.Release|x64.Deploy.0 = Release|Any CPU
|
||||
{5FD17957-3AD1-42E5-AAC4-D9B09E0B7E14}.Release|x86.ActiveCfg = Release|Any CPU
|
||||
{5FD17957-3AD1-42E5-AAC4-D9B09E0B7E14}.Release|x86.Build.0 = Release|Any CPU
|
||||
{5FD17957-3AD1-42E5-AAC4-D9B09E0B7E14}.Release|x86.Deploy.0 = Release|Any CPU
|
||||
{71C1E85B-1A79-C0C4-22BD-49A8DE57B8E7}.Ad-Hoc|Any CPU.ActiveCfg = Release|x64
|
||||
{71C1E85B-1A79-C0C4-22BD-49A8DE57B8E7}.Ad-Hoc|Any CPU.Build.0 = Release|x64
|
||||
{71C1E85B-1A79-C0C4-22BD-49A8DE57B8E7}.Ad-Hoc|Any CPU.Deploy.0 = Release|x64
|
||||
{71C1E85B-1A79-C0C4-22BD-49A8DE57B8E7}.Ad-Hoc|ARM.ActiveCfg = Release|x64
|
||||
{71C1E85B-1A79-C0C4-22BD-49A8DE57B8E7}.Ad-Hoc|ARM.Build.0 = Release|x64
|
||||
{71C1E85B-1A79-C0C4-22BD-49A8DE57B8E7}.Ad-Hoc|ARM.Deploy.0 = Release|x64
|
||||
{71C1E85B-1A79-C0C4-22BD-49A8DE57B8E7}.Ad-Hoc|iPhone.ActiveCfg = Release|x64
|
||||
{71C1E85B-1A79-C0C4-22BD-49A8DE57B8E7}.Ad-Hoc|iPhone.Build.0 = Release|x64
|
||||
{71C1E85B-1A79-C0C4-22BD-49A8DE57B8E7}.Ad-Hoc|iPhone.Deploy.0 = Release|x64
|
||||
{71C1E85B-1A79-C0C4-22BD-49A8DE57B8E7}.Ad-Hoc|iPhoneSimulator.ActiveCfg = Release|x64
|
||||
{71C1E85B-1A79-C0C4-22BD-49A8DE57B8E7}.Ad-Hoc|iPhoneSimulator.Build.0 = Release|x64
|
||||
{71C1E85B-1A79-C0C4-22BD-49A8DE57B8E7}.Ad-Hoc|iPhoneSimulator.Deploy.0 = Release|x64
|
||||
{71C1E85B-1A79-C0C4-22BD-49A8DE57B8E7}.Ad-Hoc|x64.ActiveCfg = Release|x64
|
||||
{71C1E85B-1A79-C0C4-22BD-49A8DE57B8E7}.Ad-Hoc|x64.Build.0 = Release|x64
|
||||
{71C1E85B-1A79-C0C4-22BD-49A8DE57B8E7}.Ad-Hoc|x64.Deploy.0 = Release|x64
|
||||
{71C1E85B-1A79-C0C4-22BD-49A8DE57B8E7}.Ad-Hoc|x86.ActiveCfg = Release|x86
|
||||
{71C1E85B-1A79-C0C4-22BD-49A8DE57B8E7}.Ad-Hoc|x86.Build.0 = Release|x86
|
||||
{71C1E85B-1A79-C0C4-22BD-49A8DE57B8E7}.Ad-Hoc|x86.Deploy.0 = Release|x86
|
||||
{71C1E85B-1A79-C0C4-22BD-49A8DE57B8E7}.AppStore|Any CPU.ActiveCfg = Release|x64
|
||||
{71C1E85B-1A79-C0C4-22BD-49A8DE57B8E7}.AppStore|Any CPU.Build.0 = Release|x64
|
||||
{71C1E85B-1A79-C0C4-22BD-49A8DE57B8E7}.AppStore|Any CPU.Deploy.0 = Release|x64
|
||||
{71C1E85B-1A79-C0C4-22BD-49A8DE57B8E7}.AppStore|ARM.ActiveCfg = Release|x64
|
||||
{71C1E85B-1A79-C0C4-22BD-49A8DE57B8E7}.AppStore|ARM.Build.0 = Release|x64
|
||||
{71C1E85B-1A79-C0C4-22BD-49A8DE57B8E7}.AppStore|ARM.Deploy.0 = Release|x64
|
||||
{71C1E85B-1A79-C0C4-22BD-49A8DE57B8E7}.AppStore|iPhone.ActiveCfg = Release|x64
|
||||
{71C1E85B-1A79-C0C4-22BD-49A8DE57B8E7}.AppStore|iPhone.Build.0 = Release|x64
|
||||
{71C1E85B-1A79-C0C4-22BD-49A8DE57B8E7}.AppStore|iPhone.Deploy.0 = Release|x64
|
||||
{71C1E85B-1A79-C0C4-22BD-49A8DE57B8E7}.AppStore|iPhoneSimulator.ActiveCfg = Release|x64
|
||||
{71C1E85B-1A79-C0C4-22BD-49A8DE57B8E7}.AppStore|iPhoneSimulator.Build.0 = Release|x64
|
||||
{71C1E85B-1A79-C0C4-22BD-49A8DE57B8E7}.AppStore|iPhoneSimulator.Deploy.0 = Release|x64
|
||||
{71C1E85B-1A79-C0C4-22BD-49A8DE57B8E7}.AppStore|x64.ActiveCfg = Release|x64
|
||||
{71C1E85B-1A79-C0C4-22BD-49A8DE57B8E7}.AppStore|x64.Build.0 = Release|x64
|
||||
{71C1E85B-1A79-C0C4-22BD-49A8DE57B8E7}.AppStore|x64.Deploy.0 = Release|x64
|
||||
{71C1E85B-1A79-C0C4-22BD-49A8DE57B8E7}.AppStore|x86.ActiveCfg = Release|x86
|
||||
{71C1E85B-1A79-C0C4-22BD-49A8DE57B8E7}.AppStore|x86.Build.0 = Release|x86
|
||||
{71C1E85B-1A79-C0C4-22BD-49A8DE57B8E7}.AppStore|x86.Deploy.0 = Release|x86
|
||||
{71C1E85B-1A79-C0C4-22BD-49A8DE57B8E7}.Debug|Any CPU.ActiveCfg = Debug|x64
|
||||
{71C1E85B-1A79-C0C4-22BD-49A8DE57B8E7}.Debug|Any CPU.Build.0 = Debug|x64
|
||||
{71C1E85B-1A79-C0C4-22BD-49A8DE57B8E7}.Debug|Any CPU.Deploy.0 = Debug|x64
|
||||
{71C1E85B-1A79-C0C4-22BD-49A8DE57B8E7}.Debug|ARM.ActiveCfg = Debug|x64
|
||||
{71C1E85B-1A79-C0C4-22BD-49A8DE57B8E7}.Debug|ARM.Build.0 = Debug|x64
|
||||
{71C1E85B-1A79-C0C4-22BD-49A8DE57B8E7}.Debug|ARM.Deploy.0 = Debug|x64
|
||||
{71C1E85B-1A79-C0C4-22BD-49A8DE57B8E7}.Debug|iPhone.ActiveCfg = Debug|x64
|
||||
{71C1E85B-1A79-C0C4-22BD-49A8DE57B8E7}.Debug|iPhone.Build.0 = Debug|x64
|
||||
{71C1E85B-1A79-C0C4-22BD-49A8DE57B8E7}.Debug|iPhone.Deploy.0 = Debug|x64
|
||||
{71C1E85B-1A79-C0C4-22BD-49A8DE57B8E7}.Debug|iPhoneSimulator.ActiveCfg = Debug|x64
|
||||
{71C1E85B-1A79-C0C4-22BD-49A8DE57B8E7}.Debug|iPhoneSimulator.Build.0 = Debug|x64
|
||||
{71C1E85B-1A79-C0C4-22BD-49A8DE57B8E7}.Debug|iPhoneSimulator.Deploy.0 = Debug|x64
|
||||
{71C1E85B-1A79-C0C4-22BD-49A8DE57B8E7}.Debug|x64.ActiveCfg = Debug|x64
|
||||
{71C1E85B-1A79-C0C4-22BD-49A8DE57B8E7}.Debug|x64.Build.0 = Debug|x64
|
||||
{71C1E85B-1A79-C0C4-22BD-49A8DE57B8E7}.Debug|x64.Deploy.0 = Debug|x64
|
||||
{71C1E85B-1A79-C0C4-22BD-49A8DE57B8E7}.Debug|x86.ActiveCfg = Debug|x86
|
||||
{71C1E85B-1A79-C0C4-22BD-49A8DE57B8E7}.Debug|x86.Build.0 = Debug|x86
|
||||
{71C1E85B-1A79-C0C4-22BD-49A8DE57B8E7}.Debug|x86.Deploy.0 = Debug|x86
|
||||
{71C1E85B-1A79-C0C4-22BD-49A8DE57B8E7}.Release|Any CPU.ActiveCfg = Release|x64
|
||||
{71C1E85B-1A79-C0C4-22BD-49A8DE57B8E7}.Release|Any CPU.Build.0 = Release|x64
|
||||
{71C1E85B-1A79-C0C4-22BD-49A8DE57B8E7}.Release|Any CPU.Deploy.0 = Release|x64
|
||||
{71C1E85B-1A79-C0C4-22BD-49A8DE57B8E7}.Release|ARM.ActiveCfg = Release|x64
|
||||
{71C1E85B-1A79-C0C4-22BD-49A8DE57B8E7}.Release|ARM.Build.0 = Release|x64
|
||||
{71C1E85B-1A79-C0C4-22BD-49A8DE57B8E7}.Release|ARM.Deploy.0 = Release|x64
|
||||
{71C1E85B-1A79-C0C4-22BD-49A8DE57B8E7}.Release|iPhone.ActiveCfg = Release|x64
|
||||
{71C1E85B-1A79-C0C4-22BD-49A8DE57B8E7}.Release|iPhone.Build.0 = Release|x64
|
||||
{71C1E85B-1A79-C0C4-22BD-49A8DE57B8E7}.Release|iPhone.Deploy.0 = Release|x64
|
||||
{71C1E85B-1A79-C0C4-22BD-49A8DE57B8E7}.Release|iPhoneSimulator.ActiveCfg = Release|x64
|
||||
{71C1E85B-1A79-C0C4-22BD-49A8DE57B8E7}.Release|iPhoneSimulator.Build.0 = Release|x64
|
||||
{71C1E85B-1A79-C0C4-22BD-49A8DE57B8E7}.Release|iPhoneSimulator.Deploy.0 = Release|x64
|
||||
{71C1E85B-1A79-C0C4-22BD-49A8DE57B8E7}.Release|x64.ActiveCfg = Release|x64
|
||||
{71C1E85B-1A79-C0C4-22BD-49A8DE57B8E7}.Release|x64.Build.0 = Release|x64
|
||||
{71C1E85B-1A79-C0C4-22BD-49A8DE57B8E7}.Release|x64.Deploy.0 = Release|x64
|
||||
{71C1E85B-1A79-C0C4-22BD-49A8DE57B8E7}.Release|x86.ActiveCfg = Release|x86
|
||||
{71C1E85B-1A79-C0C4-22BD-49A8DE57B8E7}.Release|x86.Build.0 = Release|x86
|
||||
{71C1E85B-1A79-C0C4-22BD-49A8DE57B8E7}.Release|x86.Deploy.0 = Release|x86
|
||||
EndGlobalSection
|
||||
GlobalSection(SolutionProperties) = preSolution
|
||||
HideSolutionNode = FALSE
|
||||
EndGlobalSection
|
||||
GlobalSection(NestedProjects) = preSolution
|
||||
{ED3D7A4C-2473-41E1-87E7-428DBB517BD8} = {5D445349-E40E-4936-AE11-7C07276AC4A3}
|
||||
{8DA97FE4-645B-4951-92A5-A740D6DD3E5C} = {C5094142-9DAB-405B-9B46-DBA0AC3B9627}
|
||||
{999DDEB3-4CDA-441D-B980-3BC43B654237} = {C5094142-9DAB-405B-9B46-DBA0AC3B9627}
|
||||
{2F4484CA-D992-44F2-AB3B-5C9F1AD83AB0} = {C5094142-9DAB-405B-9B46-DBA0AC3B9627}
|
||||
{8D741D81-6120-472A-BEE0-45F298D74D75} = {5D445349-E40E-4936-AE11-7C07276AC4A3}
|
||||
{D75E5A16-6863-4A53-84F4-CC0360782292} = {5D445349-E40E-4936-AE11-7C07276AC4A3}
|
||||
{5FD17957-3AD1-42E5-AAC4-D9B09E0B7E14} = {07F120B6-65CD-4EDB-9BC5-F47281F268B3}
|
||||
{71C1E85B-1A79-C0C4-22BD-49A8DE57B8E7} = {C5094142-9DAB-405B-9B46-DBA0AC3B9627}
|
||||
EndGlobalSection
|
||||
GlobalSection(ExtensibilityGlobals) = postSolution
|
||||
SolutionGuid = {C7458BCE-5F5A-49A9-8C8C-8955E59F8B66}
|
||||
EndGlobalSection
|
||||
EndGlobal
|
||||
@@ -0,0 +1,3 @@
|
||||
<wpf:ResourceDictionary xml:space="preserve" xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml" xmlns:s="clr-namespace:System;assembly=mscorlib" xmlns:ss="urn:shemas-jetbrains-com:settings-storage-xaml" xmlns:wpf="http://schemas.microsoft.com/winfx/2006/xaml/presentation">
|
||||
<s:Boolean x:Key="/Default/UserDictionary/Words/=Carthy/@EntryIndexedValue">True</s:Boolean>
|
||||
</wpf:ResourceDictionary>
|
||||
@@ -0,0 +1,25 @@
|
||||
|
||||
Microsoft Visual Studio Solution File, Format Version 12.00
|
||||
# Visual Studio Version 17
|
||||
VisualStudioVersion = 17.2.32630.192
|
||||
MinimumVisualStudioVersion = 10.0.40219.1
|
||||
Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "MyAspNetCoreApp", "MyAspNetCoreApp\MyAspNetCoreApp.csproj", "{F44DA130-BCF4-493B-AC08-D60560DA2A87}"
|
||||
EndProject
|
||||
Global
|
||||
GlobalSection(SolutionConfigurationPlatforms) = preSolution
|
||||
Debug|Any CPU = Debug|Any CPU
|
||||
Release|Any CPU = Release|Any CPU
|
||||
EndGlobalSection
|
||||
GlobalSection(ProjectConfigurationPlatforms) = postSolution
|
||||
{F44DA130-BCF4-493B-AC08-D60560DA2A87}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
|
||||
{F44DA130-BCF4-493B-AC08-D60560DA2A87}.Debug|Any CPU.Build.0 = Debug|Any CPU
|
||||
{F44DA130-BCF4-493B-AC08-D60560DA2A87}.Release|Any CPU.ActiveCfg = Release|Any CPU
|
||||
{F44DA130-BCF4-493B-AC08-D60560DA2A87}.Release|Any CPU.Build.0 = Release|Any CPU
|
||||
EndGlobalSection
|
||||
GlobalSection(SolutionProperties) = preSolution
|
||||
HideSolutionNode = FALSE
|
||||
EndGlobalSection
|
||||
GlobalSection(ExtensibilityGlobals) = postSolution
|
||||
SolutionGuid = {60534E9C-E75A-42A7-ADA8-05C2ADD0D730}
|
||||
EndGlobalSection
|
||||
EndGlobal
|
||||
@@ -0,0 +1,3 @@
|
||||
<wpf:ResourceDictionary xml:space="preserve" xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml" xmlns:s="clr-namespace:System;assembly=mscorlib" xmlns:ss="urn:shemas-jetbrains-com:settings-storage-xaml" xmlns:wpf="http://schemas.microsoft.com/winfx/2006/xaml/presentation">
|
||||
<s:Boolean x:Key="/Default/UserDictionary/Words/=Carthy/@EntryIndexedValue">True</s:Boolean>
|
||||
<s:Boolean x:Key="/Default/UserDictionary/Words/=Podcasts/@EntryIndexedValue">True</s:Boolean></wpf:ResourceDictionary>
|
||||
@@ -0,0 +1,129 @@
|
||||
using Kendo.Mvc.Extensions;
|
||||
using Kendo.Mvc.UI;
|
||||
using Microsoft.AspNetCore.Mvc;
|
||||
using MyAspNetCoreApp.Models;
|
||||
using Telerik.Documents.Common.Model;
|
||||
using Telerik.Documents.Media;
|
||||
using Telerik.Windows.Documents.Spreadsheet.FormatProviders.OpenXml.Xlsx;
|
||||
using Telerik.Windows.Documents.Spreadsheet.Model;
|
||||
|
||||
namespace MyAspNetCoreApp.Controllers;
|
||||
|
||||
public class DashboardController : Controller
|
||||
{
|
||||
private readonly List<string> firstNames = ["Nancy", "Andrew", "Janet", "Margaret", "Steven", "Michael", "Robert", "Laura", "Anne", "Nige"];
|
||||
private readonly List<string> lastNames = ["Davolio", "Fuller", "Leverling", "Peacock", "Buchanan", "Suyama", "King", "Callahan", "Dodsworth", "White"];
|
||||
private readonly List<string> platforms = ["Apple Podcasts", "Spotify", "Other", "Overcast", "Anchor", "Stitcher"];
|
||||
private readonly List<string> devices = ["iOS", "Android", "Other", "Web"];
|
||||
|
||||
private static readonly Random Random = new();
|
||||
|
||||
private static readonly List<PodcastViewModel> Podcasts = [];
|
||||
|
||||
public ActionResult Podcasts_Read([DataSourceRequest] DataSourceRequest request)
|
||||
{
|
||||
var result = GetPodcasts().ToDataSourceResult(request);
|
||||
ViewData["test"] = result.AggregateResults;
|
||||
return Json(result);
|
||||
}
|
||||
|
||||
public ActionResult Downloads_Read([DataSourceRequest] DataSourceRequest request)
|
||||
{
|
||||
return Json(GetPodcasts());
|
||||
}
|
||||
|
||||
public ActionResult Devices_Read([DataSourceRequest] DataSourceRequest request)
|
||||
{
|
||||
var deviceViews = GetPodcasts()
|
||||
.GroupBy(x => x.Device)
|
||||
.Select(x => new
|
||||
{
|
||||
Device = x.Key,
|
||||
Views = x.Sum(v => v.Views)
|
||||
});
|
||||
|
||||
return Json(deviceViews);
|
||||
}
|
||||
|
||||
public ActionResult Platforms_Read([DataSourceRequest] DataSourceRequest request)
|
||||
{
|
||||
var platformViews = GetPodcasts()
|
||||
.GroupBy(x => x.PlatformName)
|
||||
.Select(x => new
|
||||
{
|
||||
PlatformName = x.Key,
|
||||
Views = x.Sum(v => v.Views)
|
||||
});
|
||||
|
||||
return Json(platformViews);
|
||||
}
|
||||
|
||||
public ActionResult Generate_PodcastsExcel()
|
||||
{
|
||||
var workbook = new Workbook();
|
||||
var worksheet = workbook.Worksheets.Add();
|
||||
worksheet.Name = "Podcasts";
|
||||
|
||||
string[] headers = ["Podcast Episode", "Downloads", "Streams", "Views", "Date", "Reach", "Device", "Platform"];
|
||||
|
||||
for (var column = 0; column < headers.Length; column++)
|
||||
{
|
||||
worksheet.Cells[0, column].SetValue(headers[column]);
|
||||
}
|
||||
|
||||
var headerRow = worksheet.Cells[0, 0, 0, headers.Length - 1];
|
||||
headerRow.SetFill(PatternFill.CreateSolidFill(Color.FromRgb(0, 51, 102)));
|
||||
headerRow.SetForeColor(new ThemableColor(Color.FromRgb(255, 255, 255)));
|
||||
|
||||
var podcasts = GetPodcasts();
|
||||
|
||||
for (var row = 0; row < podcasts.Count; row++)
|
||||
{
|
||||
var podcast = podcasts[row];
|
||||
var worksheetRow = row + 1;
|
||||
|
||||
worksheet.Cells[worksheetRow, 0].SetValue(podcast.Name ?? string.Empty);
|
||||
worksheet.Cells[worksheetRow, 1].SetValue(podcast.Downloads);
|
||||
worksheet.Cells[worksheetRow, 2].SetValue(podcast.Streams);
|
||||
worksheet.Cells[worksheetRow, 3].SetValue(podcast.Views);
|
||||
worksheet.Cells[worksheetRow, 4].SetValue(podcast.Date.ToShortDateString());
|
||||
worksheet.Cells[worksheetRow, 5].SetValue(podcast.Reach);
|
||||
worksheet.Cells[worksheetRow, 6].SetValue(podcast.Device ?? string.Empty);
|
||||
worksheet.Cells[worksheetRow, 7].SetValue(podcast.PlatformName ?? string.Empty);
|
||||
}
|
||||
|
||||
worksheet.Columns[0].SetWidth(new ColumnWidth(290, true));
|
||||
worksheet.Columns[1].SetWidth(new ColumnWidth(85, true));
|
||||
worksheet.Columns[4].SetWidth(new ColumnWidth(90, true));
|
||||
worksheet.Columns[7].SetWidth(new ColumnWidth(120, true));
|
||||
|
||||
var formatProvider = new XlsxFormatProvider();
|
||||
|
||||
using var stream = new MemoryStream();
|
||||
formatProvider.Export(workbook, stream, TimeSpan.FromMinutes(2));
|
||||
|
||||
return File(stream.ToArray(), "application/vnd.openxmlformats-officedocument.spreadsheetml.sheet", "podcasts.xlsx");
|
||||
}
|
||||
|
||||
|
||||
// HELPER METHODS
|
||||
|
||||
private List<PodcastViewModel> GetPodcasts()
|
||||
{
|
||||
if (Podcasts.Count == 0)
|
||||
{
|
||||
Podcasts.AddRange(Enumerable.Range(1, 50).Select(x => new PodcastViewModel()
|
||||
{
|
||||
Name = $"Episode #{Random.Next(0, 200)} with guest {firstNames[Random.Next(0, firstNames.Count)]} {lastNames[Random.Next(0, lastNames.Count)]}",
|
||||
Streams = Random.Next(0, 18000),
|
||||
Downloads = Random.Next(0, 15000),
|
||||
PlatformName = platforms[Random.Next(0, platforms.Count)],
|
||||
Device = devices[Random.Next(0, devices.Count)],
|
||||
Date = DateTime.Now.AddDays(-x),
|
||||
Reach = x * Random.Next(0, 1000)
|
||||
}));
|
||||
}
|
||||
|
||||
return Podcasts;
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,35 @@
|
||||
using Microsoft.AspNetCore.Mvc;
|
||||
using MyAspNetCoreApp.Models;
|
||||
using System.Diagnostics;
|
||||
|
||||
namespace MyAspNetCoreApp.Controllers;
|
||||
|
||||
public class HomeController(ILogger<HomeController> logger, IWebHostEnvironment environment) : Controller
|
||||
{
|
||||
public IActionResult Index()
|
||||
{
|
||||
return View();
|
||||
}
|
||||
|
||||
public IActionResult ReportViewer()
|
||||
{
|
||||
var reportsPath = Path.Combine(environment.ContentRootPath, "Reports");
|
||||
|
||||
var reports = Directory.GetFiles(reportsPath, "*.trdp")
|
||||
.Select(Path.GetFileName)
|
||||
.OrderBy(n => n)
|
||||
.ToList();
|
||||
|
||||
ViewBag.Reports = reports;
|
||||
|
||||
return View();
|
||||
}
|
||||
|
||||
[ResponseCache(Duration = 0, Location = ResponseCacheLocation.None, NoStore = true)]
|
||||
public IActionResult Error()
|
||||
{
|
||||
logger.LogError($"An error occurred while processing the request. {Activity.Current?.Id ?? HttpContext.TraceIdentifier}");
|
||||
|
||||
return View(new ErrorViewModel { RequestId = Activity.Current?.Id ?? HttpContext.TraceIdentifier });
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,25 @@
|
||||
using Microsoft.AspNetCore.Mvc;
|
||||
using System.Net;
|
||||
using System.Net.Mail;
|
||||
using Telerik.Reporting.Services;
|
||||
using Telerik.Reporting.Services.AspNetCore;
|
||||
|
||||
namespace MyAspNetCoreApp.Controllers;
|
||||
|
||||
[Route("api/reports")]
|
||||
[ApiController]
|
||||
public class ReportsController(IReportServiceConfiguration reportServiceConfiguration) : ReportsControllerBase(reportServiceConfiguration)
|
||||
{
|
||||
protected override HttpStatusCode SendMailMessage(MailMessage mailMessage)
|
||||
{
|
||||
throw new NotImplementedException("This method should be implemented in order to send mail messages");
|
||||
|
||||
// using (var smtpClient = new SmtpClient("smtp01.mycompany.com", 25))
|
||||
// {
|
||||
// smtpClient.DeliveryMethod = SmtpDeliveryMethod.Network;
|
||||
// smtpClient.EnableSsl = false;
|
||||
// smtpClient.Send(mailMessage);
|
||||
// }
|
||||
// return HttpStatusCode.OK;
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,65 @@
|
||||
# Written by Lance McCarthy as an example only. Use at your own risk, carefully review how you are handling your secrets and what is included in your final image.
|
||||
|
||||
###############
|
||||
### STAGE 1 ###
|
||||
###############
|
||||
# Install required dependencies into the stripped-down base image
|
||||
FROM tgagor/centos:latest AS base
|
||||
WORKDIR /app
|
||||
EXPOSE 80
|
||||
EXPOSE 443
|
||||
|
||||
# Update the repositories
|
||||
RUN cd /etc/yum.repos.d/
|
||||
# For CentOS 7
|
||||
# RUN sed -i 's/mirrorlist/#mirrorlist/g' /etc/yum.repos.d/CentOS-*
|
||||
# RUN sed -i 's|#baseurl=http://mirror.centos.org|baseurl=http://vault.centos.org|g' /etc/yum.repos.d/CentOS-*
|
||||
# For newer CentOS:latest
|
||||
RUN sed -i 's/mirrorlist/#mirrorlist/g' /etc/yum.repos.d/centos.repo
|
||||
RUN sed -i 's|#baseurl=http://mirror.centos.org|baseurl=http://vault.centos.org|g' /etc/yum.repos.d/centos.repo
|
||||
|
||||
RUN yum update -y
|
||||
|
||||
# IMPORTANT - Enable EPEL repostitory (if this doesn't work, use `RUN rpm -ihv --nodeps https://dl.fedoraproject.org/pub/epel/epel-release-latest-8.noarch.rpm` instead)
|
||||
RUN yum install epel-release -y
|
||||
|
||||
# REPORTING DEPENDENCIES - See https://docs.telerik.com/reporting/knowledge-base/how-to-build-and-install-libgdiplus-linux#solution-for-centos-and-amazon-linux
|
||||
# Install Skia dependencies for new Telerik report rendering with Skia
|
||||
RUN yum install freetype fontconfig -y
|
||||
|
||||
# DOTNET RUNTIME - Install aspnetcore runtime (if your base image does not have it already)
|
||||
RUN rpm -Uvh https://packages.microsoft.com/config/centos/7/packages-microsoft-prod.rpm
|
||||
RUN yum install aspnetcore-runtime-10.0 -y
|
||||
|
||||
|
||||
###############
|
||||
### STAGE 2 ###
|
||||
###############
|
||||
|
||||
# Compile the project and create production-ready artifacts
|
||||
FROM --platform=$BUILDPLATFORM mcr.microsoft.com/dotnet/sdk:10.0 AS build
|
||||
WORKDIR /src
|
||||
COPY . .
|
||||
|
||||
# 1. Mount the "telerik-nuget-key" secret and immediately use it to add the Telerik server as a package source
|
||||
RUN --mount=type=secret,id=telerik-nuget-key \
|
||||
dotnet nuget add source 'https://nuget.telerik.com/v3/index.json' -n "TelerikNuGetServer" -u "api-key" -p $(cat /run/secrets/telerik-nuget-key) --store-password-in-clear-text
|
||||
|
||||
# 2. Restore NuGet packages
|
||||
RUN dotnet restore "./MyAspNetCoreApp.csproj"
|
||||
|
||||
# 3. Mount the "telerik-license-key" secret as an env var and build the project
|
||||
RUN --mount=type=secret,id=telerik-license-key \
|
||||
TELERIK_LICENSE="$(cat /run/secrets/telerik-license-key)" \
|
||||
dotnet publish "./MyAspNetCoreApp.csproj" -o /app/publish /p:UseAppHost=false --no-restore --self-contained false
|
||||
|
||||
|
||||
###############
|
||||
### STAGE 3 ###
|
||||
###############
|
||||
|
||||
# Build the final image from the base, but copy the pubilsh artifacts from the intermediate stage
|
||||
FROM base AS final
|
||||
WORKDIR /app
|
||||
COPY --from=build /app/publish .
|
||||
ENTRYPOINT ["dotnet", "MyAspNetCoreApp.dll"]
|
||||
@@ -0,0 +1,35 @@
|
||||
# Written by Lance McCarthy as an example only. Use at your own risk, carefully review how you are handling your secrets and what is included in your final image.
|
||||
|
||||
### STAGE 1 ###
|
||||
# Create our base image from the aspnet image, and prep any neccessary settings
|
||||
FROM mcr.microsoft.com/dotnet/aspnet:10.0 AS base
|
||||
WORKDIR /app
|
||||
EXPOSE 80
|
||||
EXPOSE 443
|
||||
# Install Telerik Reporting's modern Linux dependencies
|
||||
RUN apt-get update
|
||||
RUN apt-get install libfreetype6 libfontconfig1 -y
|
||||
|
||||
|
||||
### STAGE 2 ###
|
||||
# Compile the project and create production-ready artifacts
|
||||
FROM --platform=$BUILDPLATFORM mcr.microsoft.com/dotnet/sdk:10.0 AS build
|
||||
WORKDIR /src
|
||||
COPY . .
|
||||
# 1. Mount the "telerik-nuget-key" secret and immediately use it to add the Telerik server as a package source
|
||||
RUN --mount=type=secret,id=telerik-nuget-key \
|
||||
dotnet nuget add source 'https://nuget.telerik.com/v3/index.json' -n "TelerikNuGetServer" -u "api-key" -p $(cat /run/secrets/telerik-nuget-key) --store-password-in-clear-text
|
||||
# 2. Restore NuGet packages
|
||||
RUN dotnet restore "./MyAspNetCoreApp.csproj"
|
||||
# 3. Mount the "telerik-license-key" secret as an env var and build the project
|
||||
RUN --mount=type=secret,id=telerik-license-key \
|
||||
TELERIK_LICENSE="$(cat /run/secrets/telerik-license-key)" \
|
||||
dotnet publish "./MyAspNetCoreApp.csproj" -o /app/publish /p:UseAppHost=false --no-restore --self-contained false
|
||||
|
||||
|
||||
### STAGE 3 ###
|
||||
# Build the final image from the base, but copy the pubilsh artifacts from the intermediate stage
|
||||
FROM base AS final
|
||||
WORKDIR /app
|
||||
COPY --from=build /app/publish .
|
||||
ENTRYPOINT ["dotnet", "MyAspNetCoreApp.dll"]
|
||||
@@ -0,0 +1,30 @@
|
||||
FROM mcr.microsoft.com/dotnet/aspnet:10.0 AS base
|
||||
WORKDIR /app
|
||||
EXPOSE 80
|
||||
EXPOSE 443
|
||||
# Dependencies for Telerik Reporting on Linux using older GDI+
|
||||
RUN apt-get update \
|
||||
&& apt-get install -y --allow-unauthenticated \
|
||||
libc6-dev \
|
||||
libgdiplus \
|
||||
libx11-dev \
|
||||
&& rm -rf /var/lib/apt/lists/*
|
||||
|
||||
|
||||
FROM --platform=$BUILDPLATFORM mcr.microsoft.com/dotnet/sdk:10.0 AS build
|
||||
WORKDIR /src
|
||||
COPY ./NuGet.Config ./NuGet.Config
|
||||
WORKDIR /src/MyAspNetCoreApp
|
||||
COPY . .
|
||||
# Here we use a docker secret to update the 'Telerik' package source in the nuget.config.
|
||||
RUN --mount=type=secret,id=telerik_key \
|
||||
echo $(cat /run/secrets/telerik_key) \
|
||||
&& dotnet nuget update source "Telerik" -s "https://nuget.telerik.com/v3/index.json" -u "api-key" -p $(cat /run/secrets/telerik_key) --configfile "./NuGet.Config" --store-password-in-clear-text \
|
||||
&& dotnet restore "MyAspNetCoreApp.csproj" --configfile "./NuGet.Config" \
|
||||
&& dotnet publish "MyAspNetCoreApp.csproj" -c Release -o /app/publish /p:UseAppHost=false --self-contained false
|
||||
|
||||
|
||||
FROM base AS final
|
||||
WORKDIR /app
|
||||
COPY --from=build /app/publish .
|
||||
ENTRYPOINT ["dotnet", "MyAspNetCoreApp.dll"]
|
||||
@@ -0,0 +1,8 @@
|
||||
namespace MyAspNetCoreApp.Models;
|
||||
|
||||
public class ErrorViewModel
|
||||
{
|
||||
public string? RequestId { get; set; }
|
||||
|
||||
public bool ShowRequestId => !string.IsNullOrEmpty(RequestId);
|
||||
}
|
||||
@@ -0,0 +1,20 @@
|
||||
namespace MyAspNetCoreApp.Models;
|
||||
|
||||
public class PodcastViewModel
|
||||
{
|
||||
public string? Name { get; set; }
|
||||
|
||||
public int Downloads { get; set; }
|
||||
|
||||
public int Streams { get; set; }
|
||||
|
||||
public int Views => Downloads + Streams;
|
||||
|
||||
public DateTime Date { get; set; }
|
||||
|
||||
public int Reach { get; set; }
|
||||
|
||||
public string? Device { get; set; }
|
||||
|
||||
public string? PlatformName { get; set; }
|
||||
}
|
||||
@@ -0,0 +1,74 @@
|
||||
<Project Sdk="Microsoft.NET.Sdk.Web">
|
||||
<PropertyGroup>
|
||||
<TargetFramework>net10.0</TargetFramework>
|
||||
<Nullable>enable</Nullable>
|
||||
<ImplicitUsings>enable</ImplicitUsings>
|
||||
<UserSecretsId>6ca2a36f-6cc7-4d98-9cd4-724a3953a16b</UserSecretsId>
|
||||
<DockerDefaultTargetOS>Linux</DockerDefaultTargetOS>
|
||||
<ContainerBaseImage>ghcr.io/lancemccarthy/skia-aspnet:10.0</ContainerBaseImage>
|
||||
</PropertyGroup>
|
||||
|
||||
<ItemGroup>
|
||||
<PackageReference Include="Microsoft.SemanticKernel.Core" Version="1.76.0" />
|
||||
<PackageReference Include="Microsoft.VisualStudio.Azure.Containers.Tools.Targets" Version="1.23.0" />
|
||||
<PackageReference Include="Telerik.Documents.Spreadsheet" Version="2026.2.519" />
|
||||
<PackageReference Include="Telerik.Documents.Spreadsheet.FormatProviders.OpenXml" Version="2026.2.519" />
|
||||
<PackageReference Include="Telerik.Drawing.Skia" Version="20.1.26.520" />
|
||||
<PackageReference Include="Telerik.Licensing" Version="1.8.2" />
|
||||
<PackageReference Include="Telerik.Reporting.AI.Microsoft.Extensions.AzureOpenAI" Version="20.1.26.520" />
|
||||
<PackageReference Include="Telerik.Reporting.OpenXmlRendering" Version="20.1.26.520" />
|
||||
<PackageReference Include="Telerik.Reporting.Services.AspNetCore" Version="20.1.26.520" />
|
||||
<PackageReference Include="Telerik.UI.for.AspNet.Core" Version="2026.2.520" />
|
||||
<PackageReference Include="Microsoft.AspNetCore.Mvc.NewtonsoftJson" Version="10.0.8" />
|
||||
|
||||
<!-- For stripped down container environments -->
|
||||
<PackageReference Include="SkiaSharp" Version="3.119.2" />
|
||||
<PackageReference Include="SkiaSharp.NativeAssets.Linux" Version="3.119.2" />
|
||||
<PackageReference Include="SkiaSharp.NativeAssets.macOS" Version="3.119.2" />
|
||||
<PackageReference Include="SkiaSharp.NativeAssets.Win32" Version="3.119.2" />
|
||||
</ItemGroup>
|
||||
|
||||
<PropertyGroup Condition=" '$(Configuration)' == 'Release' ">
|
||||
<DefineConstants>$(DefineConstants);RELEASE</DefineConstants>
|
||||
</PropertyGroup>
|
||||
|
||||
<ItemGroup>
|
||||
<Compile Remove="Templates\**" />
|
||||
<Content Remove="Templates\**" />
|
||||
<EmbeddedResource Remove="Templates\**" />
|
||||
<None Remove="Templates\**" />
|
||||
</ItemGroup>
|
||||
|
||||
<ItemGroup>
|
||||
<None Update="Reports\Barcodes Report.trdp">
|
||||
<CopyToOutputDirectory>PreserveNewest</CopyToOutputDirectory>
|
||||
</None>
|
||||
<None Update="Reports\Dashboard.trdp">
|
||||
<CopyToOutputDirectory>PreserveNewest</CopyToOutputDirectory>
|
||||
</None>
|
||||
<None Update="Reports\Employee Sales Summary.trdp">
|
||||
<CopyToOutputDirectory>PreserveNewest</CopyToOutputDirectory>
|
||||
</None>
|
||||
<None Update="Reports\Invoice.trdp">
|
||||
<CopyToOutputDirectory>PreserveNewest</CopyToOutputDirectory>
|
||||
</None>
|
||||
<None Update="Reports\Product Line Sales.trdp">
|
||||
<CopyToOutputDirectory>PreserveNewest</CopyToOutputDirectory>
|
||||
</None>
|
||||
<None Update="Reports\Product Sales.trdp">
|
||||
<CopyToOutputDirectory>PreserveNewest</CopyToOutputDirectory>
|
||||
</None>
|
||||
<None Update="Reports\ReportBook.trbp">
|
||||
<CopyToOutputDirectory>PreserveNewest</CopyToOutputDirectory>
|
||||
</None>
|
||||
<None Update="Reports\Sales Order Details.trdp">
|
||||
<CopyToOutputDirectory>PreserveNewest</CopyToOutputDirectory>
|
||||
</None>
|
||||
</ItemGroup>
|
||||
|
||||
<ProjectExtensions>
|
||||
<VisualStudio>
|
||||
<UserProperties UseCdnSupport="" />
|
||||
</VisualStudio>
|
||||
</ProjectExtensions>
|
||||
</Project>
|
||||
@@ -0,0 +1,53 @@
|
||||
using Microsoft.Extensions.DependencyInjection.Extensions;
|
||||
using Telerik.Reporting.Cache.File;
|
||||
using Telerik.Reporting.Services;
|
||||
|
||||
var builder = WebApplication.CreateBuilder(args);
|
||||
|
||||
|
||||
builder.Services.AddCors(corsOption => corsOption
|
||||
// CORS policy for ReportsController
|
||||
.AddPolicy("ReportingRestPolicy", corsBuilder => corsBuilder.AllowAnyOrigin().AllowAnyMethod().AllowAnyHeader()
|
||||
));
|
||||
|
||||
// Add services to the container (important: Uses System.Text.Json instead of json.net from now on).
|
||||
builder.Services.AddControllersWithViews()
|
||||
.AddJsonOptions(options =>
|
||||
{
|
||||
options.JsonSerializerOptions.PropertyNamingPolicy = null;
|
||||
});
|
||||
|
||||
|
||||
// Add Kendo UI services to the services container"
|
||||
builder.Services.AddKendo();
|
||||
|
||||
// Configure dependencies for ReportsController.
|
||||
builder.Services.TryAddSingleton<IReportServiceConfiguration>(sp =>
|
||||
new ReportServiceConfiguration
|
||||
{
|
||||
ReportingEngineConfiguration = sp.GetService<IConfiguration>(),
|
||||
HostAppId = "MyAspNetCoreApp",
|
||||
Storage = new FileStorage(),
|
||||
ReportSourceResolver = new UriReportSourceResolver(System.IO.Path.Combine(sp.GetService<IWebHostEnvironment>().ContentRootPath, "Reports"))
|
||||
});
|
||||
|
||||
|
||||
var app = builder.Build();
|
||||
|
||||
// Configure the HTTP request pipeline.
|
||||
if (!app.Environment.IsDevelopment())
|
||||
{
|
||||
app.UseExceptionHandler("/Home/Error");
|
||||
// The default HSTS value is 30 days. You may want to change this for production scenarios, see https://aka.ms/aspnetcore-hsts.
|
||||
app.UseHsts();
|
||||
}
|
||||
|
||||
app.UseHttpsRedirection();
|
||||
app.UseStaticFiles();
|
||||
app.UseRouting();
|
||||
app.UseCors("ReportingRestPolicy");
|
||||
app.UseAuthorization();
|
||||
app.MapControllers();
|
||||
app.MapControllerRoute(name: "default", pattern: "{controller=Home}/{action=Index}/{id?}");
|
||||
|
||||
app.Run();
|
||||
@@ -0,0 +1,29 @@
|
||||
{
|
||||
"profiles": {
|
||||
"MyAspNetCoreApp": {
|
||||
"commandName": "Project",
|
||||
"launchBrowser": true,
|
||||
"environmentVariables": {
|
||||
"ASPNETCORE_ENVIRONMENT": "Development"
|
||||
},
|
||||
"applicationUrl": "https://localhost:61922;http://localhost:61923"
|
||||
},
|
||||
"Docker": {
|
||||
"commandName": "Docker",
|
||||
"launchBrowser": true,
|
||||
"launchUrl": "{Scheme}://{ServiceHost}:{ServicePort}",
|
||||
"publishAllPorts": true,
|
||||
"useSSL": true
|
||||
},
|
||||
"WSL": {
|
||||
"commandName": "WSL2",
|
||||
"launchBrowser": true,
|
||||
"launchUrl": "https://localhost:61922",
|
||||
"environmentVariables": {
|
||||
"ASPNETCORE_ENVIRONMENT": "Development",
|
||||
"ASPNETCORE_URLS": "https://localhost:61922;http://localhost:61923"
|
||||
},
|
||||
"distributionName": ""
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,176 @@
|
||||
@inherits Microsoft.VisualStudio.Web.CodeGeneration.Templating.RazorTemplateBase
|
||||
@using Microsoft.VisualStudio.Web.CodeGeneration.EntityFrameworkCore
|
||||
@using System.Collections.Generic
|
||||
@using System.Linq
|
||||
@@model @Model.ViewDataTypeName
|
||||
|
||||
@{
|
||||
if (Model.IsPartialView)
|
||||
{
|
||||
}
|
||||
else if (Model.IsLayoutPageSelected)
|
||||
{
|
||||
@:@@{
|
||||
@:ViewData["Title"] = "@Model.ViewName";
|
||||
if (!string.IsNullOrEmpty(Model.LayoutPageFile))
|
||||
{
|
||||
@:Layout = "@Model.LayoutPageFile";
|
||||
}
|
||||
@:}
|
||||
@:
|
||||
@:<h1>@Model.ViewName</h1>
|
||||
@:
|
||||
}
|
||||
else
|
||||
{
|
||||
@:@@{
|
||||
@:Layout = null;
|
||||
@:}
|
||||
@:
|
||||
@:<!DOCTYPE html>
|
||||
@:
|
||||
@:<html>
|
||||
@:<head>
|
||||
@:<meta name="viewport" content="width=device-width" />
|
||||
@:<title>@Model.ViewName</title>
|
||||
@:</head>
|
||||
@:<body>
|
||||
@:
|
||||
// PushIndent(" ");
|
||||
}
|
||||
@:<h4>@Model.ViewDataTypeShortName</h4>
|
||||
@:<hr />
|
||||
@:<div class="row">
|
||||
@:<div class="col-md-4">
|
||||
string formId = Model.ViewDataTypeShortName + "Form";
|
||||
@:<form asp-action="@Model.ViewName" id="@formId">
|
||||
@:<div asp-validation-summary="ModelOnly" class="text-danger"></div>
|
||||
foreach (var property in Model.ModelMetadata.Properties)
|
||||
{
|
||||
if (property.Scaffold && !property.IsAutoGenerated && !property.IsReadOnly)
|
||||
{
|
||||
if (property.IsForeignKey)
|
||||
{
|
||||
@:<div class="form-group">
|
||||
@:<label asp-for="@property.PropertyName"></label>
|
||||
@:<select asp-for="@property.PropertyName" asp-items="ViewBag.@property.PropertyName"></select>
|
||||
@:</div>
|
||||
continue;
|
||||
}
|
||||
|
||||
bool isCheckbox = property.TypeName.Equals("System.Boolean");
|
||||
bool isDatetime = property.TypeName.Contains("System.DateTime");
|
||||
|
||||
if (isCheckbox)
|
||||
{
|
||||
@:<div class="form-group">
|
||||
@:@@Html.Kendo().CheckBoxFor(m => m.@property.PropertyName)
|
||||
@:<label asp-for="@property.PropertyName"></label>
|
||||
@:<span asp-validation-for="@property.PropertyName" class="text-danger k-invalid-msg" data-for="@property.PropertyName"></span>
|
||||
@:</div>
|
||||
}
|
||||
else if (isDatetime)
|
||||
{
|
||||
@:<div class="form-group">
|
||||
@:<label asp-for="@property.PropertyName"></label>
|
||||
@:<kendo-datetimepicker for="@property.PropertyName" />
|
||||
@:<span asp-validation-for="@property.PropertyName" class="text-danger k-invalid-msg" data-for="@property.PropertyName"></span>
|
||||
@:</div>
|
||||
}
|
||||
else if (IsNumericType(property))
|
||||
{
|
||||
@:<div class="form-group">
|
||||
@:<label asp-for="@property.PropertyName"></label>
|
||||
@:<kendo-numerictextbox for="@property.PropertyName" />
|
||||
@:<span asp-validation-for="@property.PropertyName" class="text-danger k-invalid-msg" data-for="@property.PropertyName"></span>
|
||||
@:</div>
|
||||
}
|
||||
else if (property.IsEnum && !property.IsEnumFlags)
|
||||
{
|
||||
@:<div class="form-group">
|
||||
@:<label asp-for="@property.PropertyName"></label>
|
||||
@:<select asp-for="@property.PropertyName"></select>
|
||||
@:<span asp-validation-for="@property.PropertyName" class="text-danger k-invalid-msg" data-for="@property.PropertyName"></span>
|
||||
@:</div>
|
||||
}
|
||||
else if (property.IsMultilineText)
|
||||
{
|
||||
@:<div class="form-group">
|
||||
@:<label asp-for="@property.PropertyName"></label>
|
||||
@:<textarea asp-for="@property.PropertyName" class="k-textbox"></textarea>
|
||||
@:<span asp-validation-for="@property.PropertyName" class="text-danger k-invalid-msg" data-for="@property.PropertyName"></span>
|
||||
@:</div>
|
||||
}
|
||||
else
|
||||
{
|
||||
@:<div class="form-group">
|
||||
@:<label asp-for="@property.PropertyName"></label>
|
||||
@:<input asp-for="@property.PropertyName" class="k-textbox" />
|
||||
@:<span asp-validation-for="@property.PropertyName" class="text-danger k-invalid-msg" data-for="@property.PropertyName"></span>
|
||||
@:</div>
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
<div class="form-group">
|
||||
<input type="submit" value="Create" class="k-button k-button-md k-rounded-md k-button-solid-primary" />
|
||||
</div>
|
||||
</form>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div>
|
||||
<a asp-action="Index" class="k-button k-button-md k-rounded-md k-button-solid">Back to List</a>
|
||||
</div>
|
||||
|
||||
@{
|
||||
if (Model.ReferenceScriptLibraries)
|
||||
{
|
||||
@:<script>
|
||||
@:$(document).ready(function () {
|
||||
@:$("#@formId").kendoValidator({
|
||||
@:// You can define your custom rules here:
|
||||
@://rules: {}
|
||||
@:});
|
||||
@:})
|
||||
@:</script>
|
||||
}
|
||||
// The following code closes the tag used in the case of a view using a layout page and the body and html tags in the case of a regular view page
|
||||
if (!Model.IsPartialView && !Model.IsLayoutPageSelected)
|
||||
{
|
||||
@:</body>
|
||||
@:</html>
|
||||
}
|
||||
}
|
||||
@functions
|
||||
{
|
||||
// Do we need to use this in conjunction with the PrimaryKey check?
|
||||
bool IsPropertyGuid(IPropertyMetadata property)
|
||||
{
|
||||
return string.Equals("System.Guid", property.TypeName, StringComparison.OrdinalIgnoreCase);
|
||||
}
|
||||
|
||||
string GetValueExpression(IPropertyMetadata property)
|
||||
{
|
||||
return property.PropertyName;
|
||||
}
|
||||
|
||||
bool IsNumericType(IPropertyMetadata property)
|
||||
{
|
||||
var types = new[] {
|
||||
"System.Byte",
|
||||
"System.SByte",
|
||||
"System.UInt16",
|
||||
"System.UInt32",
|
||||
"System.UInt64",
|
||||
"System.Int16",
|
||||
"System.Int32",
|
||||
"System.Int64",
|
||||
"System.Decimal",
|
||||
"System.Double",
|
||||
"System.Single"
|
||||
};
|
||||
|
||||
return types.Any(property.TypeName.Contains);
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,104 @@
|
||||
@inherits Microsoft.VisualStudio.Web.CodeGeneration.Templating.RazorTemplateBase
|
||||
@using Microsoft.VisualStudio.Web.CodeGeneration.EntityFrameworkCore
|
||||
@using System.Collections.Generic
|
||||
@using System.Linq
|
||||
@@model @Model.ViewDataTypeName
|
||||
|
||||
@{
|
||||
if (Model.IsPartialView)
|
||||
{
|
||||
}
|
||||
else if (Model.IsLayoutPageSelected)
|
||||
{
|
||||
@:@@{
|
||||
@:ViewData["Title"] = "@Model.ViewName";
|
||||
if (!string.IsNullOrEmpty(Model.LayoutPageFile))
|
||||
{
|
||||
@:Layout = "@Model.LayoutPageFile";
|
||||
}
|
||||
@:}
|
||||
@:
|
||||
@:<h1>@Model.ViewName</h1>
|
||||
@:
|
||||
}
|
||||
else
|
||||
{
|
||||
@:@@{
|
||||
@:Layout = null;
|
||||
@:}
|
||||
@:
|
||||
@:<!DOCTYPE html>
|
||||
@:
|
||||
@:<html>
|
||||
@:<head>
|
||||
@:<meta name="viewport" content="width=device-width" />
|
||||
@:<title>@Model.ViewName</title>
|
||||
@:</head>
|
||||
@:<body>
|
||||
@:
|
||||
// PushIndent(" ");
|
||||
}
|
||||
}
|
||||
<h3>Are you sure you want to delete this?</h3>
|
||||
<div>
|
||||
<h4>@Model.ViewDataTypeShortName</h4>
|
||||
<hr />
|
||||
<dl class="row">
|
||||
@{
|
||||
Dictionary<string, IPropertyMetadata> propertyLookup = ((IModelMetadata)Model.ModelMetadata).Properties.ToDictionary(x => x.PropertyName, x => x);
|
||||
Dictionary<string, INavigationMetadata> navigationLookup = ((IModelMetadata)Model.ModelMetadata).Navigations.ToDictionary(x => x.AssociationPropertyName, x => x);
|
||||
|
||||
foreach (var item in Model.ModelMetadata.ModelType.GetProperties())
|
||||
{
|
||||
if (propertyLookup.TryGetValue(item.Name, out IPropertyMetadata property)
|
||||
&& property.Scaffold && !property.IsForeignKey && !property.IsPrimaryKey)
|
||||
{
|
||||
<dt class = "col-sm-2">
|
||||
@@Html.DisplayNameFor(model => model.@GetValueExpression(property))
|
||||
</dt>
|
||||
<dd class = "col-sm-10">
|
||||
@@Html.DisplayFor(model => model.@GetValueExpression(property))
|
||||
</dd>
|
||||
}
|
||||
else if (navigationLookup.TryGetValue(item.Name, out INavigationMetadata navigation))
|
||||
{
|
||||
<dt class = "col-sm-2">
|
||||
@@Html.DisplayNameFor(model => model.@GetValueExpression(navigation))
|
||||
</dt>
|
||||
<dd class = "col-sm-10">
|
||||
@@Html.DisplayFor(model => model.@GetValueExpression(navigation).@navigation.DisplayPropertyName)
|
||||
</dd class>
|
||||
}
|
||||
}
|
||||
@:</dl>
|
||||
@:
|
||||
@:<form asp-action="@Model.ViewName">
|
||||
foreach (var property in Model.ModelMetadata.Properties)
|
||||
{
|
||||
if(property.IsPrimaryKey){
|
||||
@:<input type="hidden" asp-for="@GetValueExpression(property)" />
|
||||
}
|
||||
}
|
||||
@:<input type="submit" value="Delete" class="k-button k-button-md k-rounded-md k-button-solid-primary" /> |
|
||||
@:<a asp-action="Index" class="k-button k-button-md k-rounded-md k-button-solid">Back to List</a>
|
||||
@:</form>
|
||||
@:</div>
|
||||
if (!Model.IsPartialView && !Model.IsLayoutPageSelected)
|
||||
{
|
||||
//ClearIndent();
|
||||
@:</body>
|
||||
@:</html>
|
||||
}
|
||||
}
|
||||
@functions
|
||||
{
|
||||
string GetValueExpression(IPropertyMetadata property)
|
||||
{
|
||||
return property.PropertyName;
|
||||
}
|
||||
|
||||
string GetValueExpression(INavigationMetadata navigation)
|
||||
{
|
||||
return navigation.AssociationPropertyName;
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,114 @@
|
||||
@inherits Microsoft.VisualStudio.Web.CodeGeneration.Templating.RazorTemplateBase
|
||||
@using Microsoft.VisualStudio.Web.CodeGeneration.EntityFrameworkCore
|
||||
@using System.Collections.Generic
|
||||
@using System.Linq
|
||||
@@model @Model.ViewDataTypeName
|
||||
b4
|
||||
@{
|
||||
if (Model.IsPartialView)
|
||||
{
|
||||
}
|
||||
else if (Model.IsLayoutPageSelected)
|
||||
{
|
||||
@:@@{
|
||||
@:ViewData["Title"] = "@Model.ViewName";
|
||||
if (!string.IsNullOrEmpty(Model.LayoutPageFile))
|
||||
{
|
||||
@:Layout = "@Model.LayoutPageFile";
|
||||
}
|
||||
@:}
|
||||
@:
|
||||
@:<h1>@Model.ViewName</h1>
|
||||
@:
|
||||
}
|
||||
else
|
||||
{
|
||||
@:@@{
|
||||
@:Layout = null;
|
||||
@:}
|
||||
@:
|
||||
@:<!DOCTYPE html>
|
||||
@:
|
||||
@:<html>
|
||||
@:<head>
|
||||
@:<meta name="viewport" content="width=device-width" />
|
||||
@:<title>@Model.ViewName</title>
|
||||
@:</head>
|
||||
@:<body>
|
||||
@:
|
||||
// PushIndent(" ");
|
||||
}
|
||||
}
|
||||
<div>
|
||||
<h4>@Model.ViewDataTypeShortName</h4>
|
||||
<hr />
|
||||
<dl class="row">
|
||||
@{
|
||||
Dictionary<string, IPropertyMetadata> propertyLookup = ((IModelMetadata)Model.ModelMetadata).Properties.ToDictionary(x => x.PropertyName, x => x);
|
||||
Dictionary<string, INavigationMetadata> navigationLookup = ((IModelMetadata)Model.ModelMetadata).Navigations.ToDictionary(x => x.AssociationPropertyName, x => x);
|
||||
|
||||
foreach (var item in Model.ModelMetadata.ModelType.GetProperties())
|
||||
{
|
||||
if (propertyLookup.TryGetValue(item.Name, out IPropertyMetadata property)
|
||||
&& property.Scaffold && !property.IsForeignKey && !property.IsPrimaryKey)
|
||||
{
|
||||
<dt class = "col-sm-2">
|
||||
@@Html.DisplayNameFor(model => model.@GetValueExpression(property))
|
||||
</dt>
|
||||
<dd class = "col-sm-10">
|
||||
@@Html.DisplayFor(model => model.@GetValueExpression(property))
|
||||
</dd>
|
||||
}
|
||||
else if (navigationLookup.TryGetValue(item.Name, out INavigationMetadata navigation))
|
||||
{
|
||||
<dt class = "col-sm-2">
|
||||
@@Html.DisplayNameFor(model => model.@GetValueExpression(navigation))
|
||||
</dt>
|
||||
<dd class = "col-sm-10">
|
||||
@@Html.DisplayFor(model => model.@GetValueExpression(navigation).@navigation.DisplayPropertyName)
|
||||
</dd>
|
||||
}
|
||||
}
|
||||
} </dl>
|
||||
</div>
|
||||
<div>
|
||||
@{
|
||||
string pkName = GetPrimaryKeyName();
|
||||
if (pkName != null)
|
||||
{
|
||||
@:<a asp-action="Edit" asp-route-id="@@Model.@pkName" class="k-button k-button-md k-rounded-md k-button-solid-primary">Edit</a> |
|
||||
@:<a asp-action="Index" class="k-button k-button-md k-rounded-md k-button-solid">Back to List</a>
|
||||
}
|
||||
else
|
||||
{
|
||||
@:@@Html.ActionLink("Edit", "Edit", new { /* id = Model.PrimaryKey */ }) |
|
||||
@:<a asp-action="Index" class="k-button k-button-md k-rounded-md k-button-solid">Back to List</a>
|
||||
}
|
||||
}</div>
|
||||
@{
|
||||
if (!Model.IsPartialView && !Model.IsLayoutPageSelected)
|
||||
{
|
||||
//ClearIndent();
|
||||
@:</body>
|
||||
@:</html>
|
||||
}
|
||||
}
|
||||
@functions
|
||||
{
|
||||
string GetPrimaryKeyName()
|
||||
{
|
||||
return (Model.ModelMetadata.PrimaryKeys != null && Model.ModelMetadata.PrimaryKeys.Length == 1)
|
||||
? Model.ModelMetadata.PrimaryKeys[0].PropertyName
|
||||
: null;
|
||||
}
|
||||
|
||||
string GetValueExpression(IPropertyMetadata property)
|
||||
{
|
||||
return property.PropertyName;
|
||||
}
|
||||
|
||||
string GetValueExpression(INavigationMetadata navigation)
|
||||
{
|
||||
return navigation.AssociationPropertyName;
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,194 @@
|
||||
@inherits Microsoft.VisualStudio.Web.CodeGeneration.Templating.RazorTemplateBase
|
||||
@using Microsoft.VisualStudio.Web.CodeGeneration.EntityFrameworkCore
|
||||
@using System.Collections.Generic
|
||||
@using System.Linq
|
||||
@@model @Model.ViewDataTypeName
|
||||
|
||||
@{
|
||||
if (Model.IsPartialView)
|
||||
{
|
||||
}
|
||||
else if (Model.IsLayoutPageSelected)
|
||||
{
|
||||
@:@@{
|
||||
@:ViewData["Title"] = "@Model.ViewName";
|
||||
if (!string.IsNullOrEmpty(Model.LayoutPageFile))
|
||||
{
|
||||
@:Layout = "@Model.LayoutPageFile";
|
||||
}
|
||||
@:}
|
||||
@:
|
||||
@:<h1>@Model.ViewName</h1>
|
||||
@:
|
||||
}
|
||||
else
|
||||
{
|
||||
@:@@{
|
||||
@:Layout = null;
|
||||
@:}
|
||||
@:
|
||||
@:<!DOCTYPE html>
|
||||
@:
|
||||
@:<html>
|
||||
@:<head>
|
||||
@:<meta name="viewport" content="width=device-width" />
|
||||
@:<title>@Model.ViewName</title>
|
||||
@:</head>
|
||||
@:<body>
|
||||
@:
|
||||
// PushIndent(" ");
|
||||
}
|
||||
@:<h4>@Model.ViewDataTypeShortName</h4>
|
||||
@:<hr />
|
||||
@:<div class="row">
|
||||
@:<div class="col-md-4">
|
||||
string formId = Model.ViewDataTypeShortName + "Form";
|
||||
@:<form asp-action="@Model.ViewName" id="@formId">
|
||||
@:<div asp-validation-summary="ModelOnly" class="text-danger"></div>
|
||||
foreach (PropertyMetadata property in Model.ModelMetadata.Properties)
|
||||
{
|
||||
if (property.IsPrimaryKey)
|
||||
{
|
||||
@:<input type="hidden" asp-for="@property.PropertyName" />
|
||||
continue;
|
||||
}
|
||||
|
||||
if (property.Scaffold)
|
||||
{
|
||||
if (property.IsReadOnly)
|
||||
{
|
||||
continue;
|
||||
}
|
||||
|
||||
if (property.IsForeignKey)
|
||||
{
|
||||
@:<div class="form-group">
|
||||
@:<label asp-for="@property.PropertyName" class="control-label"></label>
|
||||
@:<select asp-for="@property.PropertyName" class="form-control" asp-items="ViewBag.@property.PropertyName"></select>
|
||||
@:<span asp-validation-for="@property.PropertyName" class="text-danger"></span>
|
||||
@:
|
||||
@:</div>
|
||||
continue;
|
||||
}
|
||||
|
||||
bool isCheckbox = property.TypeName.Equals("System.Boolean");
|
||||
bool isDatetime = property.TypeName.Contains("System.DateTime");
|
||||
if (isCheckbox)
|
||||
{
|
||||
@:<div class="form-group">
|
||||
@:@@Html.Kendo().CheckBoxFor(m => m.@property.PropertyName)
|
||||
@:<label asp-for="@property.PropertyName"></label>
|
||||
@:<span asp-validation-for="@property.PropertyName" class="text-danger k-invalid-msg" data-for="@property.PropertyName"></span>
|
||||
@:</div>
|
||||
}
|
||||
else if (isDatetime)
|
||||
{
|
||||
@:<div class="form-group">
|
||||
@:<label asp-for="@property.PropertyName"></label>
|
||||
@:<kendo-datetimepicker for="@property.PropertyName" />
|
||||
@:<span asp-validation-for="@property.PropertyName" class="text-danger k-invalid-msg" data-for="@property.PropertyName"></span>
|
||||
@:</div>
|
||||
}
|
||||
else if (IsNumericType(property))
|
||||
{
|
||||
@:<div class="form-group">
|
||||
@:<label asp-for="@property.PropertyName"></label>
|
||||
@:<kendo-numerictextbox for="@property.PropertyName" />
|
||||
@:<span asp-validation-for="@property.PropertyName" class="text-danger k-invalid-msg" data-for="@property.PropertyName"></span>
|
||||
@:</div>
|
||||
}
|
||||
else if (property.IsEnum && !property.IsEnumFlags)
|
||||
{
|
||||
@:<div class="form-group">
|
||||
@:<label asp-for="@property.PropertyName"></label>
|
||||
@:<select asp-for="@property.PropertyName"></select>
|
||||
@:<span asp-validation-for="@property.PropertyName" class="text-danger k-invalid-msg" data-for="@property.PropertyName"></span>
|
||||
@:</div>
|
||||
}
|
||||
else if (property.IsMultilineText)
|
||||
{
|
||||
@:<div class="form-group">
|
||||
@:<label asp-for="@property.PropertyName"></label>
|
||||
@:<textarea asp-for="@property.PropertyName" class="k-textbox"></textarea>
|
||||
@:<span asp-validation-for="@property.PropertyName" class="text-danger k-invalid-msg" data-for="@property.PropertyName"></span>
|
||||
@:</div>
|
||||
}
|
||||
else
|
||||
{
|
||||
@:<div class="form-group">
|
||||
@:<label asp-for="@property.PropertyName"></label>
|
||||
@:<input asp-for="@property.PropertyName" class="k-textbox" />
|
||||
@:<span asp-validation-for="@property.PropertyName" class="text-danger k-invalid-msg" data-for="@property.PropertyName"></span>
|
||||
@:</div>
|
||||
}
|
||||
}
|
||||
// Ideally we shouldn't be here but if the user marks the foreign key as [ScaffoldColumn(false)], we want to atleast try to make it work.
|
||||
else if (property.IsForeignKey)
|
||||
{
|
||||
@:<input type="hidden" asp-for="@property.PropertyName" />
|
||||
continue;
|
||||
}
|
||||
}
|
||||
}
|
||||
<div class="form-group">
|
||||
<input type="submit" value="Save" class="k-button k-button-md k-rounded-md k-button-solid-primary" />
|
||||
</div>
|
||||
</form>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div>
|
||||
<a asp-action="Index" class="k-button k-button-md k-rounded-md k-button-solid">Back to List</a>
|
||||
</div>
|
||||
|
||||
@{
|
||||
if (Model.ReferenceScriptLibraries)
|
||||
{
|
||||
@:<script>
|
||||
@:$(document).ready(function () {
|
||||
@:$("#@formId").kendoValidator({
|
||||
@:// You can define your custom rules here:
|
||||
@://rules: {}
|
||||
@:});
|
||||
@:})
|
||||
@:</script>
|
||||
}
|
||||
// The following code closes the tag used in the case of a view using a layout page and the body and html tags in the case of a regular view page
|
||||
if (!Model.IsPartialView && !Model.IsLayoutPageSelected)
|
||||
{
|
||||
@:</body>
|
||||
@:</html>
|
||||
}
|
||||
}
|
||||
@functions
|
||||
{
|
||||
string GetAssociationName(IPropertyMetadata property)
|
||||
{
|
||||
//Todo: Implement properly.
|
||||
return property.PropertyName;
|
||||
}
|
||||
|
||||
string GetValueExpression(IPropertyMetadata property)
|
||||
{
|
||||
return property.PropertyName;
|
||||
}
|
||||
|
||||
bool IsNumericType(IPropertyMetadata property)
|
||||
{
|
||||
var types = new[] {
|
||||
"System.Byte",
|
||||
"System.SByte",
|
||||
"System.UInt16",
|
||||
"System.UInt32",
|
||||
"System.UInt64",
|
||||
"System.Int16",
|
||||
"System.Int32",
|
||||
"System.Int64",
|
||||
"System.Decimal",
|
||||
"System.Double",
|
||||
"System.Single"
|
||||
};
|
||||
|
||||
return types.Any(property.TypeName.Contains);
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,52 @@
|
||||
@inherits Microsoft.VisualStudio.Web.CodeGeneration.Templating.RazorTemplateBase
|
||||
@using Microsoft.VisualStudio.Web.CodeGeneration.EntityFrameworkCore
|
||||
@using System.Collections.Generic
|
||||
@using System.Linq
|
||||
|
||||
@{
|
||||
if (Model.IsPartialView)
|
||||
{
|
||||
@:@@*
|
||||
@: For more information on enabling MVC for empty projects, visit http://go.microsoft.com/fwlink/?LinkID=397860
|
||||
@:*@@
|
||||
|
||||
}
|
||||
else if (Model.IsLayoutPageSelected)
|
||||
{
|
||||
@:@@{
|
||||
@:ViewData["Title"] = "@Model.ViewName";
|
||||
if (!string.IsNullOrEmpty(Model.LayoutPageFile))
|
||||
{
|
||||
@:Layout = "@Model.LayoutPageFile";
|
||||
}
|
||||
@:}
|
||||
@:
|
||||
@:<h1>@Model.ViewName</h1>
|
||||
@:
|
||||
}
|
||||
else
|
||||
{
|
||||
@:@@{
|
||||
@:Layout = null;
|
||||
@:}
|
||||
@:
|
||||
@:<!DOCTYPE html>
|
||||
@:
|
||||
@:<html>
|
||||
@:<head>
|
||||
@:<meta name="viewport" content="width=device-width" />
|
||||
@:<title>@Model.ViewName</title>
|
||||
@:</head>
|
||||
@:<body>
|
||||
}
|
||||
if (Model.ReferenceScriptLibraries)
|
||||
{
|
||||
|
||||
}
|
||||
// The following code closes the tag used in the case of a view using a layout page and the body and html tags in the case of a regular view page
|
||||
if (!Model.IsPartialView && !Model.IsLayoutPageSelected)
|
||||
{
|
||||
@:</body>
|
||||
@:</html>
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,139 @@
|
||||
@inherits Microsoft.VisualStudio.Web.CodeGeneration.Templating.RazorTemplateBase
|
||||
@using Microsoft.VisualStudio.Web.CodeGeneration.EntityFrameworkCore
|
||||
@using System.Collections.Generic
|
||||
@using System.Linq
|
||||
@@model @GetEnumerableTypeExpression(Model.ViewDataTypeName)
|
||||
|
||||
@{
|
||||
if (Model.IsPartialView)
|
||||
{
|
||||
}
|
||||
else if (Model.IsLayoutPageSelected)
|
||||
{
|
||||
@:@@{
|
||||
@:ViewData["Title"] = "@Model.ViewName";
|
||||
if (!string.IsNullOrEmpty(Model.LayoutPageFile))
|
||||
{
|
||||
@:Layout = "@Model.LayoutPageFile";
|
||||
}
|
||||
@:}
|
||||
@:
|
||||
@:<h1>@Model.ViewName</h1>
|
||||
@:
|
||||
}
|
||||
else
|
||||
{
|
||||
@:@@{
|
||||
@:Layout = null;
|
||||
@:}
|
||||
@:
|
||||
@:<!DOCTYPE html>
|
||||
@:
|
||||
@:<html>
|
||||
@:<head>
|
||||
@:<meta name="viewport" content="width=device-width" />
|
||||
@:<title>@Model.ViewName</title>
|
||||
@:</head>
|
||||
@:<body>
|
||||
// PushIndent(" ");
|
||||
}
|
||||
@:<p>
|
||||
@:<a asp-action="Create" class="k-button k-button-md k-rounded-md k-button-solid">Create New</a>
|
||||
@:</p>
|
||||
@:<table class="table">
|
||||
@:<thead>
|
||||
@:<tr>
|
||||
Dictionary<string, IPropertyMetadata> propertyLookup = ((IModelMetadata)Model.ModelMetadata).Properties.ToDictionary(x => x.PropertyName, x => x);
|
||||
Dictionary<string, INavigationMetadata> navigationLookup = ((IModelMetadata)Model.ModelMetadata).Navigations.ToDictionary(x => x.AssociationPropertyName, x => x);
|
||||
|
||||
foreach (var item in Model.ModelMetadata.ModelType.GetProperties())
|
||||
{
|
||||
if (propertyLookup.TryGetValue(item.Name, out IPropertyMetadata property)
|
||||
&& property.Scaffold && !property.IsForeignKey && !property.IsPrimaryKey)
|
||||
{
|
||||
<th>
|
||||
@@Html.DisplayNameFor(model => model.@GetValueExpression(property))
|
||||
</th>
|
||||
}
|
||||
else if (navigationLookup.TryGetValue(item.Name, out INavigationMetadata navigation))
|
||||
{
|
||||
<th>
|
||||
@@Html.DisplayNameFor(model => model.@GetValueExpression(navigation))
|
||||
</th>
|
||||
}
|
||||
}
|
||||
@:<th></th>
|
||||
@:</tr>
|
||||
@:</thead>
|
||||
@:<tbody>
|
||||
@:@@foreach (var item in Model) {
|
||||
@:<tr>
|
||||
foreach (var item in Model.ModelMetadata.ModelType.GetProperties())
|
||||
{
|
||||
if (propertyLookup.TryGetValue(item.Name, out IPropertyMetadata property)
|
||||
&& property.Scaffold && !property.IsForeignKey && !property.IsPrimaryKey)
|
||||
{
|
||||
<td>
|
||||
@@Html.DisplayFor(modelItem => item.@GetValueExpression(property))
|
||||
</td>
|
||||
}
|
||||
else if (navigationLookup.TryGetValue(item.Name, out INavigationMetadata navigation))
|
||||
{
|
||||
<td>
|
||||
@@Html.DisplayFor(modelItem => item.@GetValueExpression(navigation).@navigation.DisplayPropertyName)
|
||||
</td>
|
||||
}
|
||||
}
|
||||
string pkName = GetPrimaryKeyName();
|
||||
if (pkName != null)
|
||||
{
|
||||
@:<td>
|
||||
@:<a asp-action="Edit" asp-route-id="@@item.@pkName" class="k-button k-button-md k-rounded-md k-button-solid-primary">Edit</a> |
|
||||
@:<a asp-action="Details" asp-route-id="@@item.@pkName" class="k-button k-button-md k-rounded-md k-button-solid">Details</a> |
|
||||
@:<a asp-action="Delete" asp-route-id="@@item.@pkName" class="k-button k-button-md k-rounded-md k-button-solid">Delete</a>
|
||||
@:</td>
|
||||
}
|
||||
else
|
||||
{
|
||||
<td>
|
||||
@@Html.ActionLink("Edit", "Edit", new { /* id=item.PrimaryKey */ }) |
|
||||
@@Html.ActionLink("Details", "Details", new { /* id=item.PrimaryKey */ }) |
|
||||
@@Html.ActionLink("Delete", "Delete", new { /* id=item.PrimaryKey */ })
|
||||
</td>
|
||||
}
|
||||
@:</tr>
|
||||
@:}
|
||||
@:</tbody>
|
||||
|
||||
@:</table>
|
||||
if(!Model.IsPartialView && !Model.IsLayoutPageSelected)
|
||||
{
|
||||
//ClearIndent();
|
||||
@:</body>
|
||||
@:</html>
|
||||
}
|
||||
}
|
||||
@functions
|
||||
{
|
||||
string GetPrimaryKeyName()
|
||||
{
|
||||
return (Model.ModelMetadata.PrimaryKeys != null && Model.ModelMetadata.PrimaryKeys.Length == 1)
|
||||
? Model.ModelMetadata.PrimaryKeys[0].PropertyName
|
||||
: null;
|
||||
}
|
||||
|
||||
string GetValueExpression(IPropertyMetadata property)
|
||||
{
|
||||
return property.PropertyName;
|
||||
}
|
||||
|
||||
string GetValueExpression(INavigationMetadata navigation)
|
||||
{
|
||||
return navigation.AssociationPropertyName;
|
||||
}
|
||||
|
||||
string GetEnumerableTypeExpression(string typeName)
|
||||
{
|
||||
return "IEnumerable<" + typeName + ">";
|
||||
}
|
||||
}
|
||||