Compare commits
44 Commits
main
...
551a7f4017
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
551a7f4017 | ||
|
|
2632c340c5 | ||
|
|
e089781795 | ||
|
|
6cbafa0f35 | ||
|
|
5ba8d23bcc | ||
|
|
c95a6c1145 | ||
|
|
9a07024fdd | ||
|
|
c12c1ab7d2 | ||
|
|
bdab9f37ba | ||
|
|
6cb9e3b5fd | ||
|
|
80265ec1da | ||
|
|
8ba97b6baf | ||
|
|
3ef49054ca | ||
|
|
e9be853362 | ||
|
|
5e489cdae0 | ||
|
|
1b780c4c44 | ||
|
|
6f30452ed8 | ||
|
|
d1b41814a2 | ||
|
|
f84d840e51 | ||
|
|
258ca8a837 | ||
|
|
45b8e1d223 | ||
|
|
d472923442 | ||
|
|
62a44568d1 | ||
|
|
1e3ec1cc22 | ||
|
|
587a38b149 | ||
|
|
661c2b388c | ||
|
|
5acaaa75b4 | ||
|
|
3d6a8f514c | ||
|
|
ec69a95c22 | ||
|
|
0eca913fde | ||
|
|
d0ac84f12c | ||
|
|
d8fbd445d1 | ||
|
|
66f1131863 | ||
|
|
de9a226272 | ||
|
|
a9a9e28924 | ||
|
|
5e9ad806d6 | ||
|
|
b9060d3ca1 | ||
|
|
592d0e109f | ||
|
|
92c41d3aa0 | ||
|
|
01589d617e | ||
|
|
c59acbd30c | ||
|
|
942473501e | ||
|
|
12ebd1fce9 | ||
|
|
063098808f |
89
.gitignore
vendored
89
.gitignore
vendored
@@ -1,81 +1,14 @@
|
||||
# --------------------------------------------------------------------------------------------------
|
||||
# Core Visual Studio / .NET build outputs
|
||||
# --------------------------------------------------------------------------------------------------
|
||||
bin/
|
||||
obj/
|
||||
[Bb]uild/
|
||||
[Dd]ebug*/
|
||||
[Rr]elease*/
|
||||
x64/
|
||||
x86/
|
||||
[Aa][Rr][Mm]/
|
||||
[Aa][Rr][Mm]64/
|
||||
_ReSharper.*/
|
||||
*.user
|
||||
*.userosscache
|
||||
*.suo
|
||||
*.cache
|
||||
*.pdb
|
||||
*.mpdb
|
||||
*.opendb
|
||||
*.VC.db
|
||||
*.vscode/
|
||||
|
||||
# --------------------------------------------------------------------------------------------------
|
||||
# Package artefacts (NuGet, npm, etc.)
|
||||
# --------------------------------------------------------------------------------------------------
|
||||
/packages/
|
||||
*.nupkg
|
||||
*.snupkg
|
||||
*.nuspec
|
||||
package-lock.json
|
||||
packages.config
|
||||
npm-debug.log*
|
||||
yarn-error.log
|
||||
|
||||
# --------------------------------------------------------------------------------------------------
|
||||
# TFS / TFVC specific files and folders
|
||||
# --------------------------------------------------------------------------------------------------
|
||||
$tf/
|
||||
*$tf/
|
||||
*.tf
|
||||
*.tfs
|
||||
.tfignore
|
||||
|
||||
# --------------------------------------------------------------------------------------------------
|
||||
# IDE tooling and workspace settings
|
||||
# --------------------------------------------------------------------------------------------------
|
||||
.vs/
|
||||
.vscode/
|
||||
*.swp
|
||||
*.sln.docstates
|
||||
*.VC.VC.opendb
|
||||
.idea/
|
||||
.DS_Store
|
||||
Thumbs.db
|
||||
|
||||
# --------------------------------------------------------------------------------------------------
|
||||
# Test results and profiling data
|
||||
# --------------------------------------------------------------------------------------------------
|
||||
[Tt]est[Rr]esult*/
|
||||
[Bb]uild[Ll]og.*
|
||||
*.trx
|
||||
*.coverage
|
||||
*.coveragexml
|
||||
*.opencover.xml
|
||||
*.dotCover
|
||||
BenchmarkDotNet.Artifacts/
|
||||
|
||||
# --------------------------------------------------------------------------------------------------
|
||||
# Miscellaneous recommended ignores
|
||||
# --------------------------------------------------------------------------------------------------
|
||||
_UpgradeReport_Files/
|
||||
Backup*/
|
||||
UpgradeLog*.XML
|
||||
*.tmp
|
||||
*.temp
|
||||
*.log
|
||||
*.bak
|
||||
*.orig
|
||||
*.scc
|
||||
|
||||
*.user
|
||||
packages/
|
||||
F4SDHelper/packages.config
|
||||
F4SDM42WebApi/packages.config
|
||||
F4SDM42WebApi/BasePackage/Assemblies/
|
||||
F4SDM42WebApi/Root/InstalledPackages/
|
||||
F4SDHelper/bin/
|
||||
F4SDHelper/obj/
|
||||
F4SDM42WebApi/bin/
|
||||
F4SDM42WebApi/obj/
|
||||
artifacts/
|
||||
|
||||
@@ -1,7 +1,7 @@
|
||||
|
||||
Microsoft Visual Studio Solution File, Format Version 12.00
|
||||
# Visual Studio Version 17
|
||||
VisualStudioVersion = 17.5.33424.131
|
||||
# Visual Studio Version 18
|
||||
VisualStudioVersion = 18.7.11919.86 stable
|
||||
MinimumVisualStudioVersion = 10.0.40219.1
|
||||
Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "F4SD - M42WebApi", "F4SDM42WebApi\F4SD - M42WebApi.csproj", "{D8CBFFCA-0B43-4ACC-80EA-C944E7420CEE}"
|
||||
EndProject
|
||||
@@ -19,6 +19,7 @@ Global
|
||||
Debug_and_copy|Any CPU = Debug_and_copy|Any CPU
|
||||
Debug|Any CPU = Debug|Any CPU
|
||||
Release_and_copy|Any CPU = Release_and_copy|Any CPU
|
||||
Release_signed|Any CPU = Release_signed|Any CPU
|
||||
Release|Any CPU = Release|Any CPU
|
||||
EndGlobalSection
|
||||
GlobalSection(ProjectConfigurationPlatforms) = postSolution
|
||||
@@ -28,6 +29,8 @@ Global
|
||||
{D8CBFFCA-0B43-4ACC-80EA-C944E7420CEE}.Debug|Any CPU.Build.0 = Debug|Any CPU
|
||||
{D8CBFFCA-0B43-4ACC-80EA-C944E7420CEE}.Release_and_copy|Any CPU.ActiveCfg = Release_and_copy|Any CPU
|
||||
{D8CBFFCA-0B43-4ACC-80EA-C944E7420CEE}.Release_and_copy|Any CPU.Build.0 = Release_and_copy|Any CPU
|
||||
{D8CBFFCA-0B43-4ACC-80EA-C944E7420CEE}.Release_signed|Any CPU.ActiveCfg = Release_signed|Any CPU
|
||||
{D8CBFFCA-0B43-4ACC-80EA-C944E7420CEE}.Release_signed|Any CPU.Build.0 = Release_signed|Any CPU
|
||||
{D8CBFFCA-0B43-4ACC-80EA-C944E7420CEE}.Release|Any CPU.ActiveCfg = Release|Any CPU
|
||||
{D8CBFFCA-0B43-4ACC-80EA-C944E7420CEE}.Release|Any CPU.Build.0 = Release|Any CPU
|
||||
{EB95E1FB-7A9E-4894-BD28-2D0BE2715EBE}.Debug_and_copy|Any CPU.ActiveCfg = Debug|Any CPU
|
||||
@@ -36,6 +39,8 @@ Global
|
||||
{EB95E1FB-7A9E-4894-BD28-2D0BE2715EBE}.Debug|Any CPU.Build.0 = Debug|Any CPU
|
||||
{EB95E1FB-7A9E-4894-BD28-2D0BE2715EBE}.Release_and_copy|Any CPU.ActiveCfg = Release_and_copy|Any CPU
|
||||
{EB95E1FB-7A9E-4894-BD28-2D0BE2715EBE}.Release_and_copy|Any CPU.Build.0 = Release_and_copy|Any CPU
|
||||
{EB95E1FB-7A9E-4894-BD28-2D0BE2715EBE}.Release_signed|Any CPU.ActiveCfg = Release|Any CPU
|
||||
{EB95E1FB-7A9E-4894-BD28-2D0BE2715EBE}.Release_signed|Any CPU.Build.0 = Release|Any CPU
|
||||
{EB95E1FB-7A9E-4894-BD28-2D0BE2715EBE}.Release|Any CPU.ActiveCfg = Release|Any CPU
|
||||
{EB95E1FB-7A9E-4894-BD28-2D0BE2715EBE}.Release|Any CPU.Build.0 = Release|Any CPU
|
||||
EndGlobalSection
|
||||
@@ -47,25 +52,6 @@ Global
|
||||
EndGlobalSection
|
||||
GlobalSection(SharedMSBuildProjectFiles) = preSolution
|
||||
M42F4SDUUXWorkspace\M42F4SDUUXWorkspace.projitems*{c3d52a04-2461-4f35-8edf-de7226add677}*SharedItemsImports = 13
|
||||
M42F4SDUUXWorkspace\M42F4SDUUXWorkspace.projitems*{d8cbffca-0b43-4acc-80ea-c944e7420cee}*SharedItemsImports = 4
|
||||
EndGlobalSection
|
||||
GlobalSection(TeamFoundationVersionControl) = preSolution
|
||||
SccNumberOfProjects = 5
|
||||
SccEnterpriseProvider = {4CA58AB2-18FA-4F8D-95D4-32DDF27D184C}
|
||||
SccTeamFoundationServer = https://consulting4it.visualstudio.com/
|
||||
SccLocalPath0 = .
|
||||
SccProjectUniqueName1 = F4SDHelper\\F4SD\u0020-\u0020Helper.csproj
|
||||
SccProjectName1 = F4SDHelper
|
||||
SccLocalPath1 = F4SDHelper
|
||||
SccProjectUniqueName2 = F4SDM42WebApi\\F4SD\u0020-\u0020M42WebApi.csproj
|
||||
SccProjectName2 = F4SDM42WebApi
|
||||
SccLocalPath2 = F4SDM42WebApi
|
||||
SccProjectUniqueName3 = M42F4SDUUXWorkspace\\F4SD\u0020-\u0020M42\u0020UUX\u0020Workspace.shproj
|
||||
SccProjectName3 = M42F4SDUUXWorkspace
|
||||
SccLocalPath3 = M42F4SDUUXWorkspace
|
||||
SccProjectUniqueName4 = M42F4SDUUXWorkspace\\M42F4SDUUXWorkspace.projitems
|
||||
SccProjectTopLevelParentUniqueName4 = M42F4SDUUXWorkspace\\F4SD\u0020-\u0020M42\u0020UUX\u0020Workspace.shproj
|
||||
SccProjectName4 = M42F4SDUUXWorkspace
|
||||
SccLocalPath4 = M42F4SDUUXWorkspace
|
||||
M42F4SDUUXWorkspace\M42F4SDUUXWorkspace.projitems*{d8cbffca-0b43-4acc-80ea-c944e7420cee}*SharedItemsImports = 5
|
||||
EndGlobalSection
|
||||
EndGlobal
|
||||
|
||||
@@ -1,11 +1,2 @@
|
||||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<configuration>
|
||||
<runtime>
|
||||
<assemblyBinding xmlns="urn:schemas-microsoft-com:asm.v1">
|
||||
<dependentAssembly>
|
||||
<assemblyIdentity name="Newtonsoft.Json" publicKeyToken="30ad4fe6b2a6aeed" culture="neutral" />
|
||||
<bindingRedirect oldVersion="0.0.0.0-13.0.0.0" newVersion="13.0.0.0" />
|
||||
</dependentAssembly>
|
||||
</assemblyBinding>
|
||||
</runtime>
|
||||
</configuration>
|
||||
<configuration />
|
||||
|
||||
@@ -1,75 +1,32 @@
|
||||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<Project ToolsVersion="15.0" xmlns="http://schemas.microsoft.com/developer/msbuild/2003">
|
||||
<Import Project="$(MSBuildExtensionsPath)\$(MSBuildToolsVersion)\Microsoft.Common.props" Condition="Exists('$(MSBuildExtensionsPath)\$(MSBuildToolsVersion)\Microsoft.Common.props')" />
|
||||
<Project Sdk="Microsoft.NET.Sdk">
|
||||
<PropertyGroup>
|
||||
<Configuration Condition=" '$(Configuration)' == '' ">Debug</Configuration>
|
||||
<Platform Condition=" '$(Platform)' == '' ">AnyCPU</Platform>
|
||||
<ProjectGuid>{EB95E1FB-7A9E-4894-BD28-2D0BE2715EBE}</ProjectGuid>
|
||||
<TargetFramework>net8.0</TargetFramework>
|
||||
<OutputType>Library</OutputType>
|
||||
<AppDesignerFolder>Properties</AppDesignerFolder>
|
||||
<RootNamespace>C4IT.F4SDM</RootNamespace>
|
||||
<AssemblyName>C4ITF4SDM42WebApiHelper</AssemblyName>
|
||||
<TargetFrameworkVersion>v4.7.2</TargetFrameworkVersion>
|
||||
<FileAlignment>512</FileAlignment>
|
||||
<Deterministic>true</Deterministic>
|
||||
<TargetFrameworkProfile />
|
||||
<SccProjectName>SAK</SccProjectName>
|
||||
<SccLocalPath>SAK</SccLocalPath>
|
||||
<SccAuxPath>SAK</SccAuxPath>
|
||||
<SccProvider>SAK</SccProvider>
|
||||
</PropertyGroup>
|
||||
<PropertyGroup Condition=" '$(Configuration)|$(Platform)' == 'Debug|AnyCPU' ">
|
||||
<DebugSymbols>true</DebugSymbols>
|
||||
<DebugType>full</DebugType>
|
||||
<Optimize>false</Optimize>
|
||||
<OutputPath>bin\Debug\</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\Release\</OutputPath>
|
||||
<DefineConstants>TRACE</DefineConstants>
|
||||
<ErrorReport>prompt</ErrorReport>
|
||||
<WarningLevel>4</WarningLevel>
|
||||
</PropertyGroup>
|
||||
<PropertyGroup Condition="'$(Configuration)|$(Platform)' == 'Release_and_copy|AnyCPU'">
|
||||
<OutputPath>bin\Release_and_copy\</OutputPath>
|
||||
<DefineConstants>TRACE</DefineConstants>
|
||||
<Optimize>true</Optimize>
|
||||
<DebugType>pdbonly</DebugType>
|
||||
<PlatformTarget>AnyCPU</PlatformTarget>
|
||||
<LangVersion>7.3</LangVersion>
|
||||
<ErrorReport>prompt</ErrorReport>
|
||||
<Nullable>disable</Nullable>
|
||||
<ImplicitUsings>disable</ImplicitUsings>
|
||||
<LangVersion>latestmajor</LangVersion>
|
||||
<GenerateAssemblyInfo>false</GenerateAssemblyInfo>
|
||||
<EnableDefaultCompileItems>false</EnableDefaultCompileItems>
|
||||
</PropertyGroup>
|
||||
|
||||
<ItemGroup>
|
||||
<Reference Include="Newtonsoft.Json, Version=13.0.0.0, Culture=neutral, PublicKeyToken=30ad4fe6b2a6aeed, processorArchitecture=MSIL">
|
||||
<HintPath>..\packages\Newtonsoft.Json.13.0.3\lib\net45\Newtonsoft.Json.dll</HintPath>
|
||||
<Reference Include="Newtonsoft.Json">
|
||||
<HintPath>..\F4SDM42WebApi\M42Libraries\26.1\Newtonsoft.Json.dll</HintPath>
|
||||
<Private>false</Private>
|
||||
</Reference>
|
||||
<Reference Include="System" />
|
||||
<Reference Include="System.Core" />
|
||||
<Reference Include="System.Xml.Linq" />
|
||||
<Reference Include="System.Data.DataSetExtensions" />
|
||||
<Reference Include="Microsoft.CSharp" />
|
||||
<Reference Include="System.Data" />
|
||||
<Reference Include="System.Net.Http" />
|
||||
<Reference Include="System.Xml" />
|
||||
</ItemGroup>
|
||||
|
||||
<ItemGroup>
|
||||
<Compile Include="Properties\AssemblyInfo.cs" />
|
||||
<Compile Include="..\..\..\Common Code\Logging\C4IT.Logging.LogManager.cs">
|
||||
<Link>Common\C4IT.Logging.LogManager.cs</Link>
|
||||
</Compile>
|
||||
<Compile Include="Common\C4IT.FASD.Base.cs" />
|
||||
<Compile Include="..\SharedAssemblyInfo.cs">
|
||||
<Link>Properties\SharedAssemblyInfo.cs</Link>
|
||||
</Compile>
|
||||
<Compile Include="Common\C4IT.FASD.Base.cs" />
|
||||
<Compile Include="Properties\AssemblyInfo.cs" />
|
||||
</ItemGroup>
|
||||
<ItemGroup>
|
||||
<None Include="App.config" />
|
||||
<None Include="packages.config" />
|
||||
</ItemGroup>
|
||||
<Import Project="$(MSBuildToolsPath)\Microsoft.CSharp.targets" />
|
||||
|
||||
</Project>
|
||||
@@ -1,15 +1,2 @@
|
||||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<configuration>
|
||||
<runtime>
|
||||
<assemblyBinding xmlns="urn:schemas-microsoft-com:asm.v1">
|
||||
<dependentAssembly>
|
||||
<assemblyIdentity name="Newtonsoft.Json" publicKeyToken="30ad4fe6b2a6aeed" culture="neutral" />
|
||||
<bindingRedirect oldVersion="0.0.0.0-12.0.0.0" newVersion="12.0.0.0" />
|
||||
</dependentAssembly>
|
||||
<dependentAssembly>
|
||||
<assemblyIdentity name="System.Web.Http" publicKeyToken="31bf3856ad364e35" culture="neutral" />
|
||||
<bindingRedirect oldVersion="0.0.0.0-5.2.3.0" newVersion="5.2.3.0" />
|
||||
</dependentAssembly>
|
||||
</assemblyBinding>
|
||||
</runtime>
|
||||
</configuration>
|
||||
<configuration />
|
||||
|
||||
73
F4SDM42WebApi/BuildM42Package.ps1
Normal file
73
F4SDM42WebApi/BuildM42Package.ps1
Normal file
@@ -0,0 +1,73 @@
|
||||
param(
|
||||
[Parameter(Mandatory = $true)]
|
||||
[string]$TemplateDir,
|
||||
|
||||
[Parameter(Mandatory = $true)]
|
||||
[string]$AssembliesDir,
|
||||
|
||||
[Parameter(Mandatory = $true)]
|
||||
[string]$OutputRoot,
|
||||
|
||||
[Parameter(Mandatory = $true)]
|
||||
[string]$PackageName,
|
||||
|
||||
[Parameter(Mandatory = $true)]
|
||||
[string]$PackageVersion
|
||||
)
|
||||
|
||||
$ErrorActionPreference = 'Stop'
|
||||
|
||||
function Normalize-FullPath {
|
||||
param([string]$Path)
|
||||
return [System.IO.Path]::GetFullPath($Path)
|
||||
}
|
||||
|
||||
function Normalize-TextFileLineEndings {
|
||||
param([string]$Path)
|
||||
|
||||
$content = [System.IO.File]::ReadAllText($Path)
|
||||
$content = [regex]::Replace($content, '(?<!\r)\n', "`r`n")
|
||||
[System.IO.File]::WriteAllText($Path, $content, [System.Text.UTF8Encoding]::new($true))
|
||||
}
|
||||
|
||||
$templateDirFull = Normalize-FullPath $TemplateDir
|
||||
$assembliesDirFull = Normalize-FullPath $AssembliesDir
|
||||
$outputRootFull = Normalize-FullPath $OutputRoot
|
||||
$packageDir = Join-Path $outputRootFull "$PackageName v$PackageVersion"
|
||||
$zipPath = "$packageDir.zip"
|
||||
|
||||
if (-not (Test-Path -LiteralPath (Join-Path $templateDirFull 'package.json'))) {
|
||||
throw "Package template not found: $templateDirFull"
|
||||
}
|
||||
|
||||
if (-not (Test-Path -LiteralPath (Join-Path $assembliesDirFull 'C4ITF4SDM42WebApi.dll'))) {
|
||||
throw "Package assemblies not found: $assembliesDirFull"
|
||||
}
|
||||
|
||||
if (Test-Path -LiteralPath $packageDir) {
|
||||
Remove-Item -LiteralPath $packageDir -Recurse -Force
|
||||
}
|
||||
|
||||
if (Test-Path -LiteralPath $zipPath) {
|
||||
Remove-Item -LiteralPath $zipPath -Force
|
||||
}
|
||||
|
||||
New-Item -ItemType Directory -Path $packageDir -Force | Out-Null
|
||||
Copy-Item -Path (Join-Path $templateDirFull '*') -Destination $packageDir -Recurse -Force
|
||||
Copy-Item -Path $assembliesDirFull -Destination (Join-Path $packageDir 'Assemblies') -Recurse -Force
|
||||
|
||||
$packageJsonPath = Join-Path $packageDir 'package.json'
|
||||
$packageJson = [System.IO.File]::ReadAllText($packageJsonPath)
|
||||
$packageJson = [regex]::Replace($packageJson, '"Version"\s*:\s*"[^"]+"', "`"Version`": `"$PackageVersion`"")
|
||||
$packageJson = [regex]::Replace($packageJson, '"LastUpdatedDate"\s*:\s*"[^"]+"', "`"LastUpdatedDate`": `"$(Get-Date -Format 'yyyy-MM-ddTHH:mm:ss')`"")
|
||||
[System.IO.File]::WriteAllText($packageJsonPath, $packageJson, [System.Text.UTF8Encoding]::new($true))
|
||||
|
||||
$textFileExtensions = @('.json', '.xml', '.dat', '.type', '.class', '.config', '.host')
|
||||
Get-ChildItem -LiteralPath $packageDir -Recurse -File |
|
||||
Where-Object { $textFileExtensions -contains $_.Extension.ToLowerInvariant() } |
|
||||
ForEach-Object { Normalize-TextFileLineEndings $_.FullName }
|
||||
|
||||
Compress-Archive -Path (Join-Path $packageDir '*') -DestinationPath $zipPath -Force
|
||||
|
||||
Write-Host "Matrix42 package folder: $packageDir"
|
||||
Write-Host "Matrix42 package zip: $zipPath"
|
||||
26
F4SDM42WebApi/C4ITF4SDM42WebApi.dll.host.config
Normal file
26
F4SDM42WebApi/C4ITF4SDM42WebApi.dll.host.config
Normal file
@@ -0,0 +1,26 @@
|
||||
<?xml version="1.0" encoding="utf-8" ?>
|
||||
<host xmlns="urn:m42/host.config">
|
||||
<modules>
|
||||
<module assembly="C4ITF4SDM42WebApi" />
|
||||
<module assembly="Matrix42.DataLayer.Persistence" />
|
||||
<module assembly="Matrix42.Services.WebApi" />
|
||||
<module assembly="Matrix42.ServiceRepository.BizLogic" />
|
||||
<module assembly="Matrix42.Pandora.ServiceStore" />
|
||||
<module assembly="Matrix42.Pandora.Persistence" />
|
||||
<module assembly="Matrix42.Pandora.BizLogic" />
|
||||
<module assembly="Matrix42.Pandora.Services" />
|
||||
<module assembly="Matrix42.Distributed.Redis.Cache" />
|
||||
<module assembly="Matrix42.StorageService.BizLogic" />
|
||||
<module assembly="Matrix42.MsTeamsNotification.BizLogic" />
|
||||
<module assembly="Matrix42.ServiceConnection.Persistence" />
|
||||
<module assembly="Matrix42.Auth.BizLogic" />
|
||||
<module assembly="Matrix42.ServiceConnection.BizLogic" />
|
||||
<module assembly="Matrix42.Integration.Aurora.General" />
|
||||
<module assembly="Matrix42.Integration.Aurora.Search.BizLogic" />
|
||||
<module assembly="update4u.SPS.ComplianceRules.BizLogic" />
|
||||
<module assembly="update4u.SPS.Security" />
|
||||
<module assembly="Matrix42.BizLogic.Journal" />
|
||||
<module assembly="Matrix42.ServiceManager.BizLogic" />
|
||||
</modules>
|
||||
<sections></sections>
|
||||
</host>
|
||||
@@ -1,143 +1,108 @@
|
||||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<Project ToolsVersion="15.0" xmlns="http://schemas.microsoft.com/developer/msbuild/2003">
|
||||
<Import Project="$(MSBuildExtensionsPath)\$(MSBuildToolsVersion)\Microsoft.Common.props" Condition="Exists('$(MSBuildExtensionsPath)\$(MSBuildToolsVersion)\Microsoft.Common.props')" />
|
||||
<Project Sdk="Microsoft.NET.Sdk">
|
||||
<PropertyGroup>
|
||||
<Configuration Condition=" '$(Configuration)' == '' ">Debug</Configuration>
|
||||
<Platform Condition=" '$(Platform)' == '' ">AnyCPU</Platform>
|
||||
<ProjectGuid>{D8CBFFCA-0B43-4ACC-80EA-C944E7420CEE}</ProjectGuid>
|
||||
<TargetFramework>net8.0</TargetFramework>
|
||||
<OutputType>Library</OutputType>
|
||||
<AppDesignerFolder>Properties</AppDesignerFolder>
|
||||
<RootNamespace>C4IT.F4SDM</RootNamespace>
|
||||
<AssemblyName>C4ITF4SDM42WebApi</AssemblyName>
|
||||
<TargetFrameworkVersion>v4.7.2</TargetFrameworkVersion>
|
||||
<FileAlignment>512</FileAlignment>
|
||||
<Deterministic>true</Deterministic>
|
||||
<TargetFrameworkProfile />
|
||||
<SccProjectName>SAK</SccProjectName>
|
||||
<SccLocalPath>SAK</SccLocalPath>
|
||||
<SccAuxPath>SAK</SccAuxPath>
|
||||
<SccProvider>SAK</SccProvider>
|
||||
<RuntimeIdentifiers>win-x64;linux-x64</RuntimeIdentifiers>
|
||||
<AppendRuntimeIdentifierToOutputPath>true</AppendRuntimeIdentifierToOutputPath>
|
||||
<Nullable>disable</Nullable>
|
||||
<ImplicitUsings>disable</ImplicitUsings>
|
||||
<LangVersion>latestmajor</LangVersion>
|
||||
<GenerateAssemblyInfo>false</GenerateAssemblyInfo>
|
||||
<EnableDefaultCompileItems>false</EnableDefaultCompileItems>
|
||||
<M42ExtensionId>6673a25d-33d6-4072-91d9-abed4be1a966</M42ExtensionId>
|
||||
<M42AssemblyPattern>C4ITF4SD*.*</M42AssemblyPattern>
|
||||
<M42BuildPackage>true</M42BuildPackage>
|
||||
</PropertyGroup>
|
||||
<PropertyGroup Condition=" '$(Configuration)|$(Platform)' == 'Debug|AnyCPU' ">
|
||||
<DebugSymbols>true</DebugSymbols>
|
||||
<DebugType>full</DebugType>
|
||||
<Optimize>false</Optimize>
|
||||
<OutputPath>bin\Debug\</OutputPath>
|
||||
<DefineConstants>DEBUG;TRACE</DefineConstants>
|
||||
<ErrorReport>prompt</ErrorReport>
|
||||
<WarningLevel>4</WarningLevel>
|
||||
<DocumentationFile>
|
||||
</DocumentationFile>
|
||||
</PropertyGroup>
|
||||
<PropertyGroup Condition=" '$(Configuration)|$(Platform)' == 'Release|AnyCPU' ">
|
||||
<DebugType>pdbonly</DebugType>
|
||||
|
||||
<PropertyGroup Condition="'$(Configuration)' == 'Release_signed'">
|
||||
<Optimize>true</Optimize>
|
||||
<OutputPath>bin\Release\</OutputPath>
|
||||
<DefineConstants>TRACE</DefineConstants>
|
||||
<ErrorReport>prompt</ErrorReport>
|
||||
<WarningLevel>4</WarningLevel>
|
||||
</PropertyGroup>
|
||||
<PropertyGroup Condition="'$(Configuration)|$(Platform)' == 'Debug_and_copy|AnyCPU'">
|
||||
<DebugSymbols>true</DebugSymbols>
|
||||
<OutputPath>bin\Debug_and_copy\</OutputPath>
|
||||
<DefineConstants>DEBUG;TRACE</DefineConstants>
|
||||
<DebugType>full</DebugType>
|
||||
<PlatformTarget>AnyCPU</PlatformTarget>
|
||||
<LangVersion>7.3</LangVersion>
|
||||
<ErrorReport>prompt</ErrorReport>
|
||||
</PropertyGroup>
|
||||
<PropertyGroup Condition="'$(Configuration)|$(Platform)' == 'Release_and_copy|AnyCPU'">
|
||||
<OutputPath>bin\Release_and_copy\</OutputPath>
|
||||
<DefineConstants>TRACE</DefineConstants>
|
||||
<Optimize>true</Optimize>
|
||||
<DebugType>pdbonly</DebugType>
|
||||
<PlatformTarget>AnyCPU</PlatformTarget>
|
||||
<LangVersion>7.3</LangVersion>
|
||||
<ErrorReport>prompt</ErrorReport>
|
||||
<M42SignAssemblies>true</M42SignAssemblies>
|
||||
</PropertyGroup>
|
||||
|
||||
<ItemGroup>
|
||||
<Reference Include="Matrix42.Common, Version=12.0.3.3096, Culture=neutral, processorArchitecture=MSIL">
|
||||
<SpecificVersion>False</SpecificVersion>
|
||||
<HintPath>M42Libraries\Matrix42.Common.dll</HintPath>
|
||||
<Reference Include="Matrix42.Common">
|
||||
<HintPath>M42Libraries\26.1\Matrix42.Common.dll</HintPath>
|
||||
<Private>false</Private>
|
||||
</Reference>
|
||||
<Reference Include="Matrix42.Contracts.Common, Version=12.0.3.3096, Culture=neutral, processorArchitecture=MSIL">
|
||||
<SpecificVersion>False</SpecificVersion>
|
||||
<HintPath>M42Libraries\Matrix42.Contracts.Common.dll</HintPath>
|
||||
<Reference Include="Matrix42.Contracts.Common">
|
||||
<HintPath>M42Libraries\26.1\Matrix42.Contracts.Common.dll</HintPath>
|
||||
<Private>false</Private>
|
||||
</Reference>
|
||||
<Reference Include="Matrix42.Contracts.Platform, Version=12.0.3.3096, Culture=neutral, processorArchitecture=MSIL">
|
||||
<SpecificVersion>False</SpecificVersion>
|
||||
<HintPath>M42Libraries\Matrix42.Contracts.Platform.dll</HintPath>
|
||||
<Reference Include="Matrix42.Contracts.Platform">
|
||||
<HintPath>M42Libraries\26.1\Matrix42.Contracts.Platform.dll</HintPath>
|
||||
<Private>false</Private>
|
||||
</Reference>
|
||||
<Reference Include="Matrix42.Contracts.ServiceManagement, Version=12.0.3.3096, Culture=neutral, processorArchitecture=MSIL">
|
||||
<SpecificVersion>False</SpecificVersion>
|
||||
<HintPath>M42Libraries\Matrix42.Contracts.ServiceManagement.dll</HintPath>
|
||||
<Reference Include="Matrix42.Contracts.ServiceManagement">
|
||||
<HintPath>M42Libraries\26.1\Matrix42.Contracts.ServiceManagement.dll</HintPath>
|
||||
<Private>false</Private>
|
||||
</Reference>
|
||||
<Reference Include="Matrix42.Pandora.Contracts, Version=12.0.3.3096, Culture=neutral, processorArchitecture=MSIL">
|
||||
<SpecificVersion>False</SpecificVersion>
|
||||
<HintPath>M42Libraries\Matrix42.Pandora.Contracts.dll</HintPath>
|
||||
<Reference Include="Matrix42.Hosting.Contracts">
|
||||
<HintPath>M42Libraries\26.1\Matrix42.Hosting.Contracts.dll</HintPath>
|
||||
<Private>false</Private>
|
||||
</Reference>
|
||||
<Reference Include="Matrix42.Services.Description.Contracts, Version=12.0.3.3096, Culture=neutral, processorArchitecture=MSIL">
|
||||
<SpecificVersion>False</SpecificVersion>
|
||||
<HintPath>M42Libraries\Matrix42.Services.Description.Contracts.dll</HintPath>
|
||||
<Reference Include="Matrix42.Configuration.Global">
|
||||
<HintPath>M42Libraries\26.1\Matrix42.Configuration.Global.dll</HintPath>
|
||||
<Private>false</Private>
|
||||
</Reference>
|
||||
<Reference Include="Microsoft.QualityTools.Testing.Fakes, Version=12.0.0.0, Culture=neutral, PublicKeyToken=b03f5f7f11d50a3a, processorArchitecture=MSIL">
|
||||
<SpecificVersion>False</SpecificVersion>
|
||||
<Reference Include="Matrix42.Pandora.Contracts">
|
||||
<HintPath>M42Libraries\26.1\Matrix42.Pandora.Contracts.dll</HintPath>
|
||||
<Private>false</Private>
|
||||
</Reference>
|
||||
<Reference Include="Newtonsoft.Json, Version=12.0.0.0, Culture=neutral, PublicKeyToken=30ad4fe6b2a6aeed, processorArchitecture=MSIL">
|
||||
<HintPath>..\packages\Newtonsoft.Json.12.0.2\lib\net45\Newtonsoft.Json.dll</HintPath>
|
||||
<Reference Include="Matrix42.Persistence.Contracts">
|
||||
<HintPath>M42Libraries\26.1\Matrix42.Persistence.Contracts.dll</HintPath>
|
||||
<Private>false</Private>
|
||||
</Reference>
|
||||
<Reference Include="System" />
|
||||
<Reference Include="System.Core" />
|
||||
<Reference Include="System.IO.Compression" />
|
||||
<Reference Include="System.Web" />
|
||||
<Reference Include="System.Web.Http, Version=5.2.3.0, Culture=neutral, PublicKeyToken=31bf3856ad364e35, processorArchitecture=MSIL">
|
||||
<SpecificVersion>False</SpecificVersion>
|
||||
<HintPath>M42Libraries\System.Web.Http.dll</HintPath>
|
||||
<Reference Include="Matrix42.Services.Description.Contracts">
|
||||
<HintPath>M42Libraries\26.1\Matrix42.Services.Description.Contracts.dll</HintPath>
|
||||
<Private>false</Private>
|
||||
</Reference>
|
||||
<Reference Include="System.Web.OData, Version=5.9.0.0, Culture=neutral, PublicKeyToken=31bf3856ad364e35, processorArchitecture=MSIL">
|
||||
<SpecificVersion>False</SpecificVersion>
|
||||
<HintPath>M42Libraries\System.Web.OData.dll</HintPath>
|
||||
<Reference Include="Matrix42.WebApi.Contracts">
|
||||
<HintPath>M42Libraries\26.1\Matrix42.WebApi.Contracts.dll</HintPath>
|
||||
<Private>false</Private>
|
||||
</Reference>
|
||||
<Reference Include="System.Xml.Linq" />
|
||||
<Reference Include="System.Data.DataSetExtensions" />
|
||||
<Reference Include="Microsoft.CSharp" />
|
||||
<Reference Include="System.Data" />
|
||||
<Reference Include="System.Net.Http" />
|
||||
<Reference Include="System.Xml" />
|
||||
<Reference Include="update4u.SPS.DataLayer, Version=12.0.3.3096, Culture=neutral, processorArchitecture=MSIL">
|
||||
<SpecificVersion>False</SpecificVersion>
|
||||
<HintPath>M42Libraries\update4u.SPS.DataLayer.dll</HintPath>
|
||||
<Reference Include="Newtonsoft.Json">
|
||||
<HintPath>M42Libraries\26.1\Newtonsoft.Json.dll</HintPath>
|
||||
<Private>false</Private>
|
||||
</Reference>
|
||||
<Reference Include="update4u.SPS.Utility, Version=12.0.3.3096, Culture=neutral, processorArchitecture=MSIL">
|
||||
<SpecificVersion>False</SpecificVersion>
|
||||
<HintPath>M42Libraries\update4u.SPS.Utility.dll</HintPath>
|
||||
<Reference Include="System.Net.Http.Formatting">
|
||||
<HintPath>M42Libraries\26.1\System.Net.Http.Formatting.dll</HintPath>
|
||||
<Private>false</Private>
|
||||
</Reference>
|
||||
<Reference Include="System.Web.Http">
|
||||
<HintPath>M42Libraries\26.1\System.Web.Http.dll</HintPath>
|
||||
<Private>false</Private>
|
||||
</Reference>
|
||||
<Reference Include="update4u.SPS.DataLayer">
|
||||
<HintPath>M42Libraries\26.1\update4u.SPS.DataLayer.dll</HintPath>
|
||||
<Private>false</Private>
|
||||
</Reference>
|
||||
<Reference Include="update4u.SPS.Utility">
|
||||
<HintPath>M42Libraries\26.1\update4u.SPS.Utility.dll</HintPath>
|
||||
<Private>false</Private>
|
||||
</Reference>
|
||||
</ItemGroup>
|
||||
|
||||
<ItemGroup>
|
||||
<ProjectReference Include="..\F4SDHelper\F4SD - Helper.csproj" />
|
||||
</ItemGroup>
|
||||
|
||||
<ItemGroup>
|
||||
<Compile Include="..\SharedAssemblyInfo.cs">
|
||||
<Link>Properties\SharedAssemblyInfo.cs</Link>
|
||||
</Compile>
|
||||
<Compile Include="cM42LogEntry.cs" />
|
||||
<Compile Include="F4SDM42DependencyRegistrator.cs" />
|
||||
<Compile Include="F4SDHelperService.cs" />
|
||||
<Compile Include="F4SDM42WebApiController.cs" />
|
||||
<Compile Include="Properties\AssemblyInfo.cs" />
|
||||
<Compile Include="..\SharedAssemblyInfo.cs">
|
||||
<Link>Properties\SharedAssemblyInfo.cs</Link>
|
||||
</Compile>
|
||||
</ItemGroup>
|
||||
|
||||
<ItemGroup>
|
||||
<ProjectReference Include="..\F4SDHelper\F4SD - Helper.csproj">
|
||||
<Project>{eb95e1fb-7a9e-4894-bd28-2d0be2715ebe}</Project>
|
||||
<Name>F4SD - Helper</Name>
|
||||
<Private>True</Private>
|
||||
</ProjectReference>
|
||||
</ItemGroup>
|
||||
<ItemGroup>
|
||||
<None Include="App.config" />
|
||||
<None Include="deploy.ps1" />
|
||||
<None Include="packages.config" />
|
||||
<None Include="SignSourceFiles.cmd" />
|
||||
<None Update="C4ITF4SDM42WebApi.dll.host.config" CopyToOutputDirectory="PreserveNewest" />
|
||||
</ItemGroup>
|
||||
|
||||
<Import Project="..\M42F4SDUUXWorkspace\M42F4SDUUXWorkspace.projitems" Label="Shared" />
|
||||
<Import Project="$(MSBuildToolsPath)\Microsoft.CSharp.targets" />
|
||||
<PropertyGroup>
|
||||
<PostBuildEvent>@echo powershell -ExecutionPolicy Unrestricted $(ProjectDir)deploy.ps1 -ProjectDir $(ProjectDir) -SolutionDir $(SolutionDir) -OutDir $(OutDir) -ConfigurationName $(ConfigurationName)</PostBuildEvent>
|
||||
</PropertyGroup>
|
||||
<Import Project="M42SandboxedExtension.targets" Condition="Exists('M42SandboxedExtension.targets')" />
|
||||
</Project>
|
||||
@@ -4,6 +4,7 @@ using C4IT.Logging;
|
||||
using Matrix42.Common;
|
||||
using Newtonsoft.Json;
|
||||
using System;
|
||||
using System.Collections.Specialized;
|
||||
using System.Collections.Generic;
|
||||
using System.Data;
|
||||
using System.Data.SqlClient;
|
||||
@@ -19,7 +20,6 @@ using System.Reflection;
|
||||
using System.Text;
|
||||
using System.Text.RegularExpressions;
|
||||
using System.Threading.Tasks;
|
||||
using System.Web;
|
||||
using update4u.SPS.DataLayer;
|
||||
using update4u.SPS.DataLayer.Transaction;
|
||||
using static C4IT.FASD.Base.cF4SDTicket;
|
||||
@@ -54,6 +54,7 @@ namespace C4IT.F4SD
|
||||
|
||||
private const string F4SDTicketTableName = "M42WPM-TICKETS-INFOS";
|
||||
private const string F4SDTicketStatusColumnName = "STATUS";
|
||||
private static bool? ticketAndServiceRequestEnabledCache;
|
||||
|
||||
|
||||
public static IEnumerable<string> ReadLines(Func<Stream> streamProvider,
|
||||
@@ -70,6 +71,39 @@ namespace C4IT.F4SD
|
||||
}
|
||||
}
|
||||
|
||||
private static NameValueCollection ParseQueryString(string query)
|
||||
{
|
||||
var values = new NameValueCollection();
|
||||
query = (query ?? string.Empty).TrimStart('?');
|
||||
|
||||
if (string.IsNullOrWhiteSpace(query))
|
||||
return values;
|
||||
|
||||
foreach (var pair in query.Split(new[] { '&' }, StringSplitOptions.RemoveEmptyEntries))
|
||||
{
|
||||
var parts = pair.Split(new[] { '=' }, 2);
|
||||
var key = WebUtility.UrlDecode(parts[0]);
|
||||
var value = parts.Length > 1 ? WebUtility.UrlDecode(parts[1]) : string.Empty;
|
||||
|
||||
if (!string.IsNullOrEmpty(key))
|
||||
values.Add(key, value);
|
||||
}
|
||||
|
||||
return values;
|
||||
}
|
||||
|
||||
private static string ToQueryString(NameValueCollection queryString)
|
||||
{
|
||||
if (queryString == null || queryString.Count == 0)
|
||||
return string.Empty;
|
||||
|
||||
return string.Join("&",
|
||||
queryString.AllKeys
|
||||
.Where(key => !string.IsNullOrEmpty(key))
|
||||
.SelectMany(key => (queryString.GetValues(key) ?? new[] { string.Empty })
|
||||
.Select(value => $"{WebUtility.UrlEncode(key)}={WebUtility.UrlEncode(value)}")));
|
||||
}
|
||||
|
||||
internal async Task<string> getDirectLinkF4SD(Guid EOID, string type)
|
||||
{
|
||||
var CM = MethodBase.GetCurrentMethod();
|
||||
@@ -78,7 +112,7 @@ namespace C4IT.F4SD
|
||||
{
|
||||
LogEntry($"Generating F4SD URI for type: '{type}', GUID: '{EOID}'", LogLevels.Debug);
|
||||
var builder = new UriBuilder(c4itf4sdmonLinkBase);
|
||||
var queryString = HttpUtility.ParseQueryString(builder.Query);
|
||||
var queryString = ParseQueryString(builder.Query);
|
||||
|
||||
switch (type.ToLowerInvariant().Split('.').Last())
|
||||
{
|
||||
@@ -137,7 +171,7 @@ namespace C4IT.F4SD
|
||||
break;
|
||||
}
|
||||
|
||||
builder.Query = queryString.ToString();
|
||||
builder.Query = ToQueryString(queryString);
|
||||
return string.IsNullOrEmpty(builder.Query) ? null : builder.ToString();
|
||||
}
|
||||
catch (Exception E)
|
||||
@@ -176,7 +210,7 @@ namespace C4IT.F4SD
|
||||
if (activityTable?.Rows == null || activityTable.Rows.Count == 0)
|
||||
{
|
||||
LogEntry($"No activity entries found for userSid: '{userSid}'", LogLevels.Warning);
|
||||
return null;
|
||||
return new List<cF4SDTicketSummary>();
|
||||
}
|
||||
|
||||
for (int i = 0; i < activityTable.Rows.Count; i++)
|
||||
@@ -257,7 +291,7 @@ namespace C4IT.F4SD
|
||||
catch (Exception E)
|
||||
{
|
||||
LogException(E);
|
||||
return null;
|
||||
return new List<cF4SDTicketSummary>();
|
||||
}
|
||||
finally
|
||||
{
|
||||
@@ -642,7 +676,7 @@ namespace C4IT.F4SD
|
||||
", SolutionTimeEscalated" +
|
||||
", UsedInTypeSPSActivityTypeTicket as TicketEoid" +
|
||||
", UsedInTypeSPSActivityTypeIncident as IncidentEoid" +
|
||||
", UsedInTypeSPSActivityTypeAlert as AlertEoid" +
|
||||
//", UsedInTypeSPSActivityTypeAlert as AlertEoid" +
|
||||
", UsedInTypeSPSActivityTypeGroupTicket as ProblemEoid" +
|
||||
", UsedInTypeSPSActivityTypeServiceRequest as ServiceRequestEoid" +
|
||||
", UsedInTypeSPSActivityTypeBase as TaskEoid" +
|
||||
@@ -661,7 +695,7 @@ namespace C4IT.F4SD
|
||||
|
||||
var ticketEoid = getGuidFromObject(row["TicketEoid"]);
|
||||
var incidentEoid = getGuidFromObject(row["IncidentEoid"]);
|
||||
var alertEoid = getGuidFromObject(row["AlertEoid"]);
|
||||
//var alertEoid = getGuidFromObject(row["AlertEoid"]);
|
||||
var problemEoid = getGuidFromObject(row["ProblemEoid"]);
|
||||
var serviceRequestEoid = getGuidFromObject(row["ServiceRequestEoid"]);
|
||||
var taskEoid = getGuidFromObject(row["TaskEoid"]);
|
||||
@@ -670,7 +704,7 @@ namespace C4IT.F4SD
|
||||
var activityType = ResolveTicketOverviewActivityType(
|
||||
ticketEoid,
|
||||
incidentEoid,
|
||||
alertEoid,
|
||||
//alertEoid,
|
||||
problemEoid,
|
||||
serviceRequestEoid,
|
||||
taskEoid,
|
||||
@@ -714,7 +748,7 @@ namespace C4IT.F4SD
|
||||
private static string ResolveTicketOverviewActivityType(
|
||||
Guid ticketEoid,
|
||||
Guid incidentEoid,
|
||||
Guid alertEoid,
|
||||
//Guid alertEoid,
|
||||
Guid problemEoid,
|
||||
Guid serviceRequestEoid,
|
||||
Guid taskEoid,
|
||||
@@ -724,8 +758,8 @@ namespace C4IT.F4SD
|
||||
return "SPSActivityTypeIncident";
|
||||
if (ticketEoid != Guid.Empty)
|
||||
return "SPSActivityTypeTicket";
|
||||
if (alertEoid != Guid.Empty)
|
||||
return "SPSActivityTypeAlert";
|
||||
//if (alerteoid != guid.empty)
|
||||
// return "spsactivitytypealert";
|
||||
if (problemEoid != Guid.Empty)
|
||||
return "SPSActivityTypeGroupTicket";
|
||||
if (serviceRequestEoid != Guid.Empty)
|
||||
@@ -1101,7 +1135,7 @@ namespace C4IT.F4SD
|
||||
presetParamsDyn.SPSActivityClassIncident.Asset = asset.Id;
|
||||
}
|
||||
var type = TicketAndServiceRequestEnabled ? "SPSActivityTypeTicket" : "SPSActivityTypeIncident";
|
||||
var presetParams = HttpUtility.UrlEncode(JsonConvert.SerializeObject(presetParamsDyn));
|
||||
var presetParams = WebUtility.UrlEncode(JsonConvert.SerializeObject(presetParamsDyn));
|
||||
var directLink = string.Format(TicketDirectLinkCreateTemplate, F4SDM42WebApiController.defaultInstance.BaseUrl, type, presetParams);
|
||||
return new DirectLink()
|
||||
{
|
||||
@@ -1123,18 +1157,23 @@ namespace C4IT.F4SD
|
||||
|
||||
private static bool ticketAndServiceRequestEnabled()
|
||||
{
|
||||
var configProvider = F4SDM42WebApiController.defaultInstance._globalConfigurationProvider;
|
||||
if (ticketAndServiceRequestEnabledCache.HasValue)
|
||||
return ticketAndServiceRequestEnabledCache.Value;
|
||||
|
||||
// using reflection because signature of "ReloadSettings" changed in ESM v12
|
||||
var method = configProvider.GetType().GetMethod("ReloadSettings");
|
||||
|
||||
if (method != null)
|
||||
try
|
||||
{
|
||||
var defaultParameters = method.GetParameters().Select(p => p.HasDefaultValue ? p.DefaultValue : null).ToArray();
|
||||
method.Invoke(configProvider, defaultParameters);
|
||||
var configProvider = F4SDM42WebApiController.defaultInstance?._globalConfigurationProvider;
|
||||
var enabled = configProvider?.ServiceDeskConfiguration?.TicketAndServiceRequestEnabled ?? true;
|
||||
ticketAndServiceRequestEnabledCache = enabled;
|
||||
return enabled;
|
||||
}
|
||||
catch (Exception E)
|
||||
{
|
||||
LogException(E);
|
||||
LogEntry("Could not read ServiceDeskConfiguration.TicketAndServiceRequestEnabled. Falling back to enabled ticket/service request mode.", LogLevels.Warning);
|
||||
ticketAndServiceRequestEnabledCache = true;
|
||||
return true;
|
||||
}
|
||||
|
||||
return configProvider.ServiceDeskConfiguration.TicketAndServiceRequestEnabled;
|
||||
}
|
||||
|
||||
internal async Task<List<cF4SDTicket>> getTicketDetails(List<Guid> ticketObjectIds)
|
||||
@@ -1286,7 +1325,7 @@ namespace C4IT.F4SD
|
||||
viewOptionsDyn.type = CIName;
|
||||
viewOptionsDyn.viewType = "action";
|
||||
viewOptionsDyn.actionId = TicketCloseActionId;
|
||||
var viewOptions = HttpUtility.UrlEncode(JsonConvert.SerializeObject(viewOptionsDyn));
|
||||
var viewOptions = WebUtility.UrlEncode(JsonConvert.SerializeObject(viewOptionsDyn));
|
||||
|
||||
var ticketDirectLinkPreview = string.Format(TicketDirectLinkPreviewTemplate, F4SDM42WebApiController.defaultInstance.BaseUrl, CIName, ActivityEOID);
|
||||
var ticketDirectLinkEdit = string.Format(TicketDirectLinkEditTemplate, F4SDM42WebApiController.defaultInstance.BaseUrl, CIName, ActivityEOID);
|
||||
@@ -1368,26 +1407,9 @@ namespace C4IT.F4SD
|
||||
try
|
||||
{
|
||||
await Task.Delay(0);
|
||||
List<cTicketJournalItem> journalEntries = new List<cTicketJournalItem>();
|
||||
var entries = F4SDM42WebApiController.defaultInstance._journalService.GetJournalList(activityEOID, false, 0, 50, "<a href=\"#\" class=\"mx-object-journal--link {0} {1}\">{2}</a>", 120);
|
||||
LogEntry($"{entries.Length} Journal entries found for ObjectID={activityEOID}", LogLevels.Debug);
|
||||
for (int i = 0; i < entries.Length; i++)
|
||||
{
|
||||
Matrix42.Contracts.Platform.Data.JournalEntryInfo item = entries[i];
|
||||
LogEntry($"Journal entry {i + 1}/{entries.Length}: ID={item.Id}, CreatedDate={item.CreatedDate}, CreatedBy={item.Creator}, Header={item.Header}", LogLevels.Debug);
|
||||
journalEntries.Add(new cTicketJournalItem()
|
||||
{
|
||||
JournalId = item.Id,
|
||||
ActivityObjectId = activityEOID,
|
||||
CreatedBy = item.Creator,
|
||||
CreationDate = (DateTime)item.CreatedDate,
|
||||
DescriptionHtml = item.Text,
|
||||
Description = Matrix42.Common.Html.HtmlConverter.ConvertHtmlToPlainText(item.Text),
|
||||
Header = item.Header,
|
||||
IsVisibleForUser = item.VisibleInPortal
|
||||
});
|
||||
}
|
||||
return journalEntries;
|
||||
var entries = LoadJournalEntries(activityEOID);
|
||||
LogEntry($"{entries.Count} Journal entries found for ObjectID={activityEOID}", LogLevels.Debug);
|
||||
return CreateTicketJournalItems(activityEOID, entries);
|
||||
}
|
||||
catch (Exception E)
|
||||
{
|
||||
@@ -1400,6 +1422,151 @@ namespace C4IT.F4SD
|
||||
}
|
||||
}
|
||||
|
||||
internal static List<cTicketJournalItem> CreateTicketJournalItems(Guid activityEOID, IReadOnlyList<Matrix42.Contracts.Platform.Data.JournalEntryInfo> entries)
|
||||
{
|
||||
List<cTicketJournalItem> journalEntries = new List<cTicketJournalItem>();
|
||||
for (int i = 0; i < entries.Count; i++)
|
||||
{
|
||||
Matrix42.Contracts.Platform.Data.JournalEntryInfo item = entries[i];
|
||||
var text = item.Text ?? string.Empty;
|
||||
var createdDate = item.CreatedDate ?? DateTime.MinValue;
|
||||
|
||||
LogEntry($"Journal entry {i + 1}/{entries.Count}: ID={item.Id}, CreatedDate={createdDate}, CreatedBy={item.Creator}, Header={item.Header}", LogLevels.Debug);
|
||||
journalEntries.Add(new cTicketJournalItem()
|
||||
{
|
||||
JournalId = item.Id,
|
||||
ActivityObjectId = activityEOID,
|
||||
CreatedBy = item.Creator,
|
||||
CreationDate = createdDate,
|
||||
DescriptionHtml = text,
|
||||
Description = string.IsNullOrEmpty(text) ? string.Empty : Matrix42.Common.Html.HtmlConverter.ConvertHtmlToPlainText(text),
|
||||
Header = item.Header,
|
||||
IsVisibleForUser = item.VisibleInPortal
|
||||
});
|
||||
}
|
||||
|
||||
return journalEntries;
|
||||
}
|
||||
|
||||
private static IReadOnlyList<Matrix42.Contracts.Platform.Data.JournalEntryInfo> LoadJournalEntries(Guid activityEOID)
|
||||
{
|
||||
var journalService = F4SDM42WebApiController.defaultInstance.GetJournalService();
|
||||
var serviceType = journalService.GetType();
|
||||
var objectLinkTemplate = "<a href=\"#\" class=\"mx-object-journal--link {0} {1}\">{2}</a>";
|
||||
var methods = serviceType
|
||||
.GetMethods(BindingFlags.Instance | BindingFlags.Public | BindingFlags.NonPublic)
|
||||
.Where(IsJournalReaderMethod)
|
||||
.OrderByDescending(method => method.GetParameters().Length)
|
||||
.ToList();
|
||||
|
||||
foreach (var method in methods)
|
||||
{
|
||||
if (!TryBuildJournalListArguments(method, activityEOID, objectLinkTemplate, out var arguments))
|
||||
continue;
|
||||
|
||||
try
|
||||
{
|
||||
var result = method.Invoke(journalService, arguments);
|
||||
if (result is Matrix42.Contracts.Platform.Data.JournalEntryInfo[] arrayResult)
|
||||
return arrayResult;
|
||||
|
||||
if (result is IEnumerable<Matrix42.Contracts.Platform.Data.JournalEntryInfo> enumerableResult)
|
||||
return enumerableResult.ToList();
|
||||
|
||||
throw new MissingMethodException($"IJournalService.GetJournalList returned unsupported type '{result?.GetType().FullName ?? "<null>"}'.");
|
||||
}
|
||||
catch (TargetInvocationException ex) when (ex.InnerException != null)
|
||||
{
|
||||
throw ex.InnerException;
|
||||
}
|
||||
}
|
||||
|
||||
throw new MissingMethodException($"No compatible IJournalService.GetJournalList overload was found on '{serviceType.FullName}'. Available overloads: {string.Join("; ", methods.Select(FormatMethodSignature))}");
|
||||
}
|
||||
|
||||
private static bool IsJournalReaderMethod(MethodInfo method)
|
||||
{
|
||||
var methodName = method.Name;
|
||||
if (methodName.Contains("."))
|
||||
methodName = methodName.Substring(methodName.LastIndexOf(".", StringComparison.Ordinal) + 1);
|
||||
|
||||
if (!(methodName.StartsWith("Get", StringComparison.OrdinalIgnoreCase) || methodName.StartsWith("Load", StringComparison.OrdinalIgnoreCase)))
|
||||
return false;
|
||||
|
||||
if (!methodName.Contains("Journal", StringComparison.OrdinalIgnoreCase))
|
||||
return false;
|
||||
|
||||
if (!method.GetParameters().Any(parameter => parameter.ParameterType == typeof(Guid)))
|
||||
return false;
|
||||
|
||||
var returnType = method.ReturnType;
|
||||
if (returnType.IsArray)
|
||||
return returnType.GetElementType()?.FullName == typeof(Matrix42.Contracts.Platform.Data.JournalEntryInfo).FullName;
|
||||
|
||||
if (returnType.FullName == typeof(Matrix42.Contracts.Platform.Data.JournalEntryInfo).FullName)
|
||||
return true;
|
||||
|
||||
return returnType.GetInterfaces()
|
||||
.Where(type => type.IsGenericType)
|
||||
.Select(type => type.GetGenericArguments().FirstOrDefault())
|
||||
.Any(type => type?.FullName == typeof(Matrix42.Contracts.Platform.Data.JournalEntryInfo).FullName);
|
||||
}
|
||||
|
||||
private static bool TryBuildJournalListArguments(MethodInfo method, Guid activityEOID, string objectLinkTemplate, out object[] arguments)
|
||||
{
|
||||
var parameters = method.GetParameters();
|
||||
arguments = new object[parameters.Length];
|
||||
|
||||
for (int i = 0; i < parameters.Length; i++)
|
||||
{
|
||||
var parameter = parameters[i];
|
||||
var parameterType = parameter.ParameterType;
|
||||
var parameterName = parameter.Name ?? string.Empty;
|
||||
var lowerName = parameterName.ToLowerInvariant();
|
||||
|
||||
if (parameterType == typeof(Guid))
|
||||
{
|
||||
arguments[i] = activityEOID;
|
||||
}
|
||||
else if (parameterType == typeof(bool))
|
||||
{
|
||||
arguments[i] = false;
|
||||
}
|
||||
else if (parameterType == typeof(int))
|
||||
{
|
||||
if (lowerName.Contains("time"))
|
||||
arguments[i] = 120;
|
||||
else if (lowerName.Contains("count") || lowerName.Contains("take") || lowerName.Contains("limit") || lowerName.Contains("size"))
|
||||
arguments[i] = 50;
|
||||
else
|
||||
arguments[i] = 0;
|
||||
}
|
||||
else if (parameterType == typeof(string))
|
||||
{
|
||||
arguments[i] = lowerName.Contains("template") || lowerName.Contains("link") ? objectLinkTemplate : null;
|
||||
}
|
||||
else if (parameterType == typeof(string[]))
|
||||
{
|
||||
arguments[i] = null;
|
||||
}
|
||||
else if (parameter.HasDefaultValue)
|
||||
{
|
||||
arguments[i] = parameter.DefaultValue;
|
||||
}
|
||||
else
|
||||
{
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
private static string FormatMethodSignature(MethodInfo method)
|
||||
{
|
||||
return $"{method.ReturnType.FullName} {method.Name}({string.Join(", ", method.GetParameters().Select(parameter => $"{parameter.ParameterType.FullName} {parameter.Name}"))})";
|
||||
}
|
||||
|
||||
internal async Task<bool> updateActivitySolution(Guid objectId, string solutionHtml)
|
||||
{
|
||||
|
||||
@@ -2056,18 +2223,6 @@ namespace C4IT.F4SD
|
||||
retVal.User = m42Users[0];
|
||||
|
||||
|
||||
var user = F4SDM42WebApiController.defaultInstance._userProfile.GetInteractiveUserInfo(retVal.User.Id);
|
||||
if (user != null)
|
||||
{
|
||||
retVal.User.Id = user.Id;
|
||||
retVal.User.Currency = user.Currency;
|
||||
retVal.User.Email = user.Email;
|
||||
retVal.User.FirstName = user.FirstName;
|
||||
retVal.User.LastName = user.LastName;
|
||||
retVal.User.Phone = user.Phone;
|
||||
retVal.User.Photo = user.Photo;
|
||||
}
|
||||
|
||||
retVal.Roles = await getRoleMembershipById(retVal.User.Id);
|
||||
retVal.User.IsAdmin = retVal.Roles?.Where(i => i.Id == Administrators).FirstOrDefault() != null;
|
||||
return retVal;
|
||||
|
||||
38
F4SDM42WebApi/F4SDM42DependencyRegistrator.cs
Normal file
38
F4SDM42WebApi/F4SDM42DependencyRegistrator.cs
Normal file
@@ -0,0 +1,38 @@
|
||||
using System;
|
||||
using System.Web.Http;
|
||||
using System.Web.Http.Description;
|
||||
|
||||
using Matrix42.Hosting.Contracts;
|
||||
|
||||
using C4IT.Logging;
|
||||
|
||||
using static C4IT.Logging.cLogManager;
|
||||
|
||||
namespace C4IT.F4SD
|
||||
{
|
||||
public class F4SDM42DependencyRegistrator : IDependencyRegistrator
|
||||
{
|
||||
public void Register(IDependencyContainer container, IDependencyResolver resolver)
|
||||
{
|
||||
if (container == null)
|
||||
throw new ArgumentNullException(nameof(container));
|
||||
|
||||
if (resolver == null)
|
||||
throw new ArgumentNullException(nameof(resolver));
|
||||
|
||||
try
|
||||
{
|
||||
if (resolver.TryGet(typeof(IApiExplorer)) != null)
|
||||
return;
|
||||
}
|
||||
catch
|
||||
{
|
||||
// Existing mapping is incomplete in the sandbox host. Register a concrete instance below.
|
||||
}
|
||||
|
||||
var httpConfiguration = new HttpConfiguration();
|
||||
container.RegisterInstance(typeof(IApiExplorer), new ApiExplorer(httpConfiguration));
|
||||
LogEntry("Registered System.Web.Http.Description.IApiExplorer for Matrix42 sandbox host.", LogLevels.Debug);
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -1,10 +1,3 @@
|
||||
using C4IT.F4SDM;
|
||||
using C4IT.FASD.Base;
|
||||
using C4IT.Logging;
|
||||
using Matrix42.Common;
|
||||
using Matrix42.Contracts.ServiceManagement.ServiceContracts;
|
||||
using Matrix42.Pandora.Contracts;
|
||||
using Matrix42.Services.Description.Contracts;
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Data;
|
||||
@@ -12,13 +5,24 @@ using System.Linq;
|
||||
using System.Net;
|
||||
using System.Net.Http;
|
||||
using System.Reflection;
|
||||
using System.Threading;
|
||||
using System.Threading.Tasks;
|
||||
using System.Web;
|
||||
using System.Web.Http;
|
||||
using System.Web.Http.Controllers;
|
||||
using System.Web.OData;
|
||||
using System.Web.OData.Query;
|
||||
|
||||
using Matrix42.Common;
|
||||
using Matrix42.Contracts.Common.Security;
|
||||
using Matrix42.Contracts.ServiceManagement.ServiceContracts;
|
||||
using Matrix42.Hosting.Contracts;
|
||||
using Matrix42.Pandora.Contracts;
|
||||
using Matrix42.Persistence.Contracts;
|
||||
using Matrix42.Services.Description.Contracts;
|
||||
using Matrix42.WebApi.Contracts;
|
||||
using Matrix42.WebApi.Contracts.OData;
|
||||
using update4u.SPS.Utility.GlobalConfiguration;
|
||||
|
||||
using C4IT.F4SDM;
|
||||
using C4IT.FASD.Base;
|
||||
using C4IT.Logging;
|
||||
|
||||
using static C4IT.FASD.Base.cF4SDTicket;
|
||||
using static C4IT.Logging.cLogManager;
|
||||
|
||||
@@ -31,44 +35,35 @@ namespace C4IT.F4SD
|
||||
public static F4SDM42WebApiController defaultInstance;
|
||||
//private readonly IIncidentService _incidentService;
|
||||
internal readonly GlobalConfigurationProvider _globalConfigurationProvider;
|
||||
public readonly IJournalService _journalService;
|
||||
//public readonly IObjectService _objectService;
|
||||
//public readonly IFragmentService _fragmentService;
|
||||
internal readonly IEntityDataService _entityDataService;
|
||||
internal readonly IPandoraUserProfile _userProfile;
|
||||
private readonly IDependencyResolver _resolver;
|
||||
private readonly IEnumerationProvider _enumerationProvider;
|
||||
|
||||
|
||||
private readonly F4SDHelperService _f4stHelperService;
|
||||
public string BaseUrl => $"{Request.RequestUri.Scheme}://{Request.RequestUri.Host}";
|
||||
public string BaseUrl => Request?.RequestUri == null ? string.Empty : $"{Request.RequestUri.Scheme}://{Request.RequestUri.Host}";
|
||||
public string EndpointBaseUrl => $"{BaseUrl}/m42Services/api/c4itf4sdwebapi";
|
||||
public F4SDM42WebApiController(
|
||||
//IObjectService objectService,
|
||||
//IIncidentService incidentService,
|
||||
IJournalService journalService
|
||||
//IFragmentService fragmentService,
|
||||
, IEntityDataService entityDataService
|
||||
, IPandoraUserProfile userProfile
|
||||
)
|
||||
|
||||
public F4SDM42WebApiController(IDependencyResolver resolver, IEnumerationProvider enumerationProvider)
|
||||
{
|
||||
_resolver = resolver ?? throw new ArgumentNullException(nameof(resolver));
|
||||
_enumerationProvider = enumerationProvider ?? throw new ArgumentNullException(nameof(enumerationProvider));
|
||||
defaultInstance = this;
|
||||
//_objectService = objectService;
|
||||
//_fragmentService = fragmentService;
|
||||
//_incidentService = Guard.NullArgument(incidentService, "incidentService");
|
||||
|
||||
_entityDataService = entityDataService;
|
||||
_journalService = journalService;
|
||||
_globalConfigurationProvider = GlobalConfigurationProvider.Instance;
|
||||
_f4stHelperService = new F4SDHelperService();
|
||||
_userProfile = userProfile;
|
||||
EnsureInitialized();
|
||||
}
|
||||
|
||||
private static object initLock = new object();
|
||||
protected override void Initialize(HttpControllerContext controllerContext)
|
||||
private static readonly object initLock = new object();
|
||||
private static void EnsureInitialized()
|
||||
{
|
||||
base.Initialize(controllerContext);
|
||||
try
|
||||
{
|
||||
//System.Diagnostics.Debugger.Launch();
|
||||
lock (initLock)
|
||||
{
|
||||
if (IsInitialized || F4SDM42LogsWebApiController.IsInitialized)
|
||||
@@ -85,16 +80,31 @@ namespace C4IT.F4SD
|
||||
catch { };
|
||||
}
|
||||
|
||||
private T GetRequiredService<T>() where T : class
|
||||
{
|
||||
var service = _resolver.TryGet<T>();
|
||||
if (service != null)
|
||||
return service;
|
||||
|
||||
throw new InvalidOperationException($"Required Matrix42 service is not registered: {typeof(T).FullName}");
|
||||
}
|
||||
|
||||
internal IJournalService GetJournalService()
|
||||
{
|
||||
return GetRequiredService<IJournalService>();
|
||||
}
|
||||
|
||||
[Route("getDirectLinkCreateTicket"), HttpGet]
|
||||
public async Task<F4SDHelperService.DirectLink> getDirectLinkCreateTicket(string sid = "", string assetname = "")
|
||||
{
|
||||
await Task.Delay(0);
|
||||
return await _f4stHelperService.getDirectLinkCreateTicket(sid, assetname);
|
||||
return await _f4stHelperService.getDirectLinkCreateTicket(sid, assetname)
|
||||
?? new F4SDHelperService.DirectLink();
|
||||
}
|
||||
[Route("getDirectLinkF4SD"), HttpGet]
|
||||
public async Task<string> getDirectLinkF4SD(Guid EOID, string Type)
|
||||
public async Task<string> getDirectLinkF4SD(Guid eoid, string type)
|
||||
{
|
||||
return await _f4stHelperService.getDirectLinkF4SD(EOID, Type);
|
||||
return await _f4stHelperService.getDirectLinkF4SD(eoid, type) ?? string.Empty;
|
||||
}
|
||||
|
||||
[Route("getTicketList"), HttpGet]
|
||||
@@ -113,7 +123,7 @@ namespace C4IT.F4SD
|
||||
hours,
|
||||
queueoption,
|
||||
decodedPairs
|
||||
);
|
||||
) ?? new List<cF4SDTicketSummary>();
|
||||
}
|
||||
|
||||
|
||||
@@ -121,16 +131,16 @@ namespace C4IT.F4SD
|
||||
public async Task<cF4SDTicket> getTicketDetails(Guid objectId)
|
||||
{
|
||||
var tickets = await _f4stHelperService.getTicketDetails(new List<Guid>() { objectId });
|
||||
if (tickets.Count > 0)
|
||||
if (tickets?.Count > 0)
|
||||
return tickets[0];
|
||||
else
|
||||
return null;
|
||||
|
||||
return new cF4SDTicket { TicketObjectId = objectId };
|
||||
}
|
||||
|
||||
[Route("getTicketHistory"), HttpGet]
|
||||
public async Task<List<cTicketJournalItem>> getTicketHistory(Guid objectId)
|
||||
{
|
||||
return await _f4stHelperService.GetJournalEntries(objectId);
|
||||
return await _f4stHelperService.GetJournalEntries(objectId) ?? new List<cTicketJournalItem>();
|
||||
}
|
||||
|
||||
[Route("getTicketOverviewCounts"), HttpGet]
|
||||
@@ -149,7 +159,8 @@ namespace C4IT.F4SD
|
||||
.ToList();
|
||||
|
||||
var decodedQueues = ParseQueues(queues);
|
||||
return await _f4stHelperService.getTicketOverviewCounts(sid, scope, parsedKeys, queueoption, decodedQueues);
|
||||
return await _f4stHelperService.getTicketOverviewCounts(sid, scope, parsedKeys, queueoption, decodedQueues)
|
||||
?? new F4SDHelperService.TicketOverviewCountsResult();
|
||||
}
|
||||
|
||||
[Route("getTicketOverviewCountsByRoles"), HttpPost]
|
||||
@@ -173,7 +184,7 @@ namespace C4IT.F4SD
|
||||
parsedKeys,
|
||||
request?.QueueOption ?? 0,
|
||||
decodedQueues
|
||||
);
|
||||
) ?? new F4SDHelperService.TicketOverviewCountsByRoleResult();
|
||||
}
|
||||
|
||||
[Route("getTicketOverviewRelations"), HttpGet]
|
||||
@@ -187,7 +198,8 @@ namespace C4IT.F4SD
|
||||
)
|
||||
{
|
||||
var decodedQueues = ParseQueues(queues);
|
||||
return await _f4stHelperService.getTicketOverviewRelations(sid, scope, key, count, queueoption, decodedQueues);
|
||||
return await _f4stHelperService.getTicketOverviewRelations(sid, scope, key, count, queueoption, decodedQueues)
|
||||
?? new List<F4SDHelperService.TicketOverviewRelationDto>();
|
||||
}
|
||||
/*
|
||||
[Route("updateActivitySolution/{objectId}"), HttpPost]
|
||||
@@ -201,10 +213,10 @@ namespace C4IT.F4SD
|
||||
*/
|
||||
[Route("getPickup/{name}"), HttpGet]
|
||||
//[CacheOutput(UseETAG = true)]
|
||||
public async Task<HttpResponseMessage> getPickup(string name, [FromUri] EntityEnumerationVisibilityMode mode = EntityEnumerationVisibilityMode.None, [FromUri] Int32 group = -1)
|
||||
public async Task<EntityEnumeration> getPickup(string name, EntityEnumerationVisibilityMode mode = EntityEnumerationVisibilityMode.None, Int32 group = -1)
|
||||
{
|
||||
await Task.Delay(0);
|
||||
EntityEnumeration enumerationTemp = _entityDataService.GetEnumeration(name, mode);
|
||||
EntityEnumeration enumerationTemp = GetEnumeration(name, mode);
|
||||
var vals = enumerationTemp.Values;
|
||||
|
||||
if (group > -1)
|
||||
@@ -224,51 +236,44 @@ namespace C4IT.F4SD
|
||||
Values = vals.ToArray()
|
||||
};
|
||||
//CacheOutputAttribute.RegisterResponseEtag($"enum_{enumeration.Name}_{(int)mode}", $"{enumeration.Name}_{(int)mode}", cultureInvariant: false, userInvariant: true, val);
|
||||
return Request.CreateResponse(HttpStatusCode.OK, enumeration);
|
||||
return enumeration;
|
||||
}
|
||||
|
||||
[Route("getMyRoleMemberships", Order = 2), HttpGet]
|
||||
public async Task<HttpResponseMessage> getMyRoleMemberships()
|
||||
[Route("getMyRoleMemberships"), HttpGet]
|
||||
public async Task<object> getMyRoleMemberships()
|
||||
{
|
||||
var User = _userProfile.GetInteractiveUserInfo();
|
||||
var filter = AsqlHelper.BuildInCondition("ID", new Guid[] { User.Id });
|
||||
return Request.CreateResponse(HttpStatusCode.OK, await _f4stHelperService.UserPermissionsInfo(filter));
|
||||
var userId = GetCurrentUserId();
|
||||
if (userId == Guid.Empty)
|
||||
throw new UnauthorizedAccessException("Cannot determine the interactive Matrix42 user.");
|
||||
|
||||
var filter = AsqlHelper.BuildInCondition("ID", new Guid[] { userId });
|
||||
return await _f4stHelperService.UserPermissionsInfo(filter) ?? new UserPermissionsInfo();
|
||||
}
|
||||
[HttpGet]
|
||||
[Route("getRoleMemberships", Order = 1)]
|
||||
public async Task<HttpResponseMessage> getRoleMemberships([FromUri] GetRoleMembershipsRequest req)
|
||||
[Route("getRoleMemberships")]
|
||||
public async Task<object> getRoleMemberships(string sid = "", string upn = "", Guid? id = null)
|
||||
{
|
||||
var filter = "";
|
||||
|
||||
if (req.Id != null && req.Id.Value != Guid.Empty)
|
||||
if (id != null && id.Value != Guid.Empty)
|
||||
{
|
||||
filter = AsqlHelper.BuildInCondition("ID", new Guid[] { req.Id.Value });
|
||||
filter = AsqlHelper.BuildInCondition("ID", new Guid[] { id.Value });
|
||||
}
|
||||
else if (!string.IsNullOrEmpty(req.Sid))
|
||||
else if (!string.IsNullOrEmpty(sid))
|
||||
{
|
||||
filter = AsqlHelper.BuildInCondition("Accounts.T(SPSAccountClassAD).Sid", new string[] { req.Sid });
|
||||
filter = AsqlHelper.BuildInCondition("Accounts.T(SPSAccountClassAD).Sid", new string[] { sid });
|
||||
}
|
||||
else if (!string.IsNullOrEmpty(req.Upn))
|
||||
else if (!string.IsNullOrEmpty(upn))
|
||||
{
|
||||
filter = AsqlHelper.BuildInCondition("Accounts.T(SPSAccountClassAD).UserPrincipalName", new string[] { req.Upn });
|
||||
filter = AsqlHelper.BuildInCondition("Accounts.T(SPSAccountClassAD).UserPrincipalName", new string[] { upn });
|
||||
}
|
||||
|
||||
if (!string.IsNullOrEmpty(filter))
|
||||
{
|
||||
return Request.CreateResponse(HttpStatusCode.OK, await _f4stHelperService.UserPermissionsInfo(filter));
|
||||
return await _f4stHelperService.UserPermissionsInfo(filter) ?? new UserPermissionsInfo();
|
||||
}
|
||||
else
|
||||
{
|
||||
return null;
|
||||
}
|
||||
}
|
||||
|
||||
public class GetRoleMembershipsRequest
|
||||
{
|
||||
public Guid? Id { get; set; }
|
||||
public string Sid { get; set; }
|
||||
public string Upn { get; set; }
|
||||
public GetRoleMembershipsRequest() { }
|
||||
return new UserPermissionsInfo();
|
||||
}
|
||||
|
||||
public class TicketOverviewCountsByRolesRequest
|
||||
@@ -280,6 +285,95 @@ namespace C4IT.F4SD
|
||||
public string Queues { get; set; }
|
||||
}
|
||||
|
||||
private EntityEnumeration GetEnumeration(string name, EntityEnumerationVisibilityMode mode)
|
||||
{
|
||||
name = name?.Trim();
|
||||
var dataTable = _enumerationProvider.GetEnumeration(name, GetVisibilityFilter(mode));
|
||||
if (dataTable == null)
|
||||
throw new InvalidOperationException($"Enumeration '{name}' was not found.");
|
||||
|
||||
var valueColumn = FindColumn(dataTable, "Value") ?? FindNumericColumn(dataTable);
|
||||
if (string.IsNullOrEmpty(valueColumn))
|
||||
throw new InvalidOperationException($"Enumeration '{name}' does not contain a numeric value column.");
|
||||
|
||||
var displayColumn = FindColumn(dataTable, "DisplayString")
|
||||
?? FindColumn(dataTable, "DisplayExpression")
|
||||
?? FindColumn(dataTable, "Name")
|
||||
?? valueColumn;
|
||||
var hiddenColumn = FindColumn(dataTable, "Hidden");
|
||||
|
||||
var values = dataTable.Rows.Cast<DataRow>()
|
||||
.Select(row => new EntityEnumerationValue
|
||||
{
|
||||
Value = ConvertHelper.ParseInt(row[valueColumn], 0),
|
||||
DisplayString = Convert.ToString(row[displayColumn]),
|
||||
Hidden = hiddenColumn != null && ConvertHelper.ParseInt(row[hiddenColumn], 0) == 1,
|
||||
Extentions = dataTable.Columns.Cast<DataColumn>()
|
||||
.ToDictionary(column => column.ColumnName, column => row[column])
|
||||
})
|
||||
.ToArray();
|
||||
|
||||
return new EntityEnumeration
|
||||
{
|
||||
Name = name,
|
||||
Values = values
|
||||
};
|
||||
}
|
||||
|
||||
private static bool? GetVisibilityFilter(EntityEnumerationVisibilityMode mode)
|
||||
{
|
||||
switch (mode)
|
||||
{
|
||||
case EntityEnumerationVisibilityMode.Visible:
|
||||
return true;
|
||||
case EntityEnumerationVisibilityMode.Hidden:
|
||||
return false;
|
||||
default:
|
||||
return null;
|
||||
}
|
||||
}
|
||||
|
||||
private static string FindColumn(DataTable dataTable, string columnName)
|
||||
{
|
||||
return dataTable.Columns.Cast<DataColumn>()
|
||||
.FirstOrDefault(column => string.Equals(column.ColumnName, columnName, StringComparison.OrdinalIgnoreCase))
|
||||
?.ColumnName;
|
||||
}
|
||||
|
||||
private static string FindNumericColumn(DataTable dataTable)
|
||||
{
|
||||
var excludedNames = new HashSet<string>(StringComparer.OrdinalIgnoreCase)
|
||||
{
|
||||
"Hidden",
|
||||
"Position",
|
||||
"StateGroup"
|
||||
};
|
||||
|
||||
return dataTable.Columns.Cast<DataColumn>()
|
||||
.FirstOrDefault(column => !excludedNames.Contains(column.ColumnName) && IsNumericType(column.DataType))
|
||||
?.ColumnName;
|
||||
}
|
||||
|
||||
private static bool IsNumericType(Type type)
|
||||
{
|
||||
return type == typeof(byte)
|
||||
|| type == typeof(short)
|
||||
|| type == typeof(int)
|
||||
|| type == typeof(long)
|
||||
|| type == typeof(sbyte)
|
||||
|| type == typeof(ushort)
|
||||
|| type == typeof(uint)
|
||||
|| type == typeof(ulong);
|
||||
}
|
||||
|
||||
private static Guid GetCurrentUserId()
|
||||
{
|
||||
var principal = Thread.CurrentPrincipal as IM42Principal;
|
||||
return principal?.InteractivePrincipal?.M42Identity?.UserFragmentID
|
||||
?? principal?.M42Identity?.UserFragmentID
|
||||
?? Guid.Empty;
|
||||
}
|
||||
|
||||
private static List<cApiM42TicketQueueInfo> ParseQueues(string queues)
|
||||
{
|
||||
return (queues ?? string.Empty)
|
||||
@@ -290,8 +384,8 @@ namespace C4IT.F4SD
|
||||
if (segments.Length != 2)
|
||||
return null;
|
||||
|
||||
var name = HttpUtility.UrlDecode(segments[0]);
|
||||
var idStr = HttpUtility.UrlDecode(segments[1]);
|
||||
var name = WebUtility.UrlDecode(segments[0]);
|
||||
var idStr = WebUtility.UrlDecode(segments[1]);
|
||||
|
||||
return Guid.TryParse(idStr, out var guid)
|
||||
? new cApiM42TicketQueueInfo { QueueName = name, QueueID = guid }
|
||||
@@ -302,9 +396,9 @@ namespace C4IT.F4SD
|
||||
}
|
||||
|
||||
[Route("isAlive"), HttpGet]
|
||||
public HttpResponseMessage isAlive()
|
||||
public IHttpActionResult isAlive()
|
||||
{
|
||||
return new HttpResponseMessage(HttpStatusCode.NoContent);
|
||||
return new StatusCodeResult(HttpStatusCode.NoContent);
|
||||
}
|
||||
|
||||
[Route("loglevel"), HttpGet]
|
||||
@@ -321,7 +415,7 @@ namespace C4IT.F4SD
|
||||
catch (Exception E)
|
||||
{
|
||||
LogException(E);
|
||||
return null;
|
||||
return string.Empty;
|
||||
}
|
||||
finally
|
||||
{
|
||||
@@ -330,16 +424,20 @@ namespace C4IT.F4SD
|
||||
}
|
||||
|
||||
[Route("log"), HttpGet]
|
||||
public HttpResponseMessage getLog(string download = "0", int count = 50, string filter = "")
|
||||
public IHttpActionResult getLog(string download = "0", int count = 50, string filter = "")
|
||||
{
|
||||
try
|
||||
{
|
||||
return _f4stHelperService.privGetLog(download, count, Request, filter);
|
||||
var response = _f4stHelperService.privGetLog(download, count, Request, filter);
|
||||
if (response == null)
|
||||
return new StatusCodeResult(HttpStatusCode.NoContent);
|
||||
|
||||
return new ResponseMessageResult(response);
|
||||
}
|
||||
catch (Exception E)
|
||||
{
|
||||
LogException(E);
|
||||
return null;
|
||||
return new StatusCodeResult(HttpStatusCode.InternalServerError);
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -350,10 +448,9 @@ namespace C4IT.F4SD
|
||||
|
||||
public static bool IsInitialized { get; private set; } = false;
|
||||
|
||||
private static object initLock = new object();
|
||||
protected override void Initialize(HttpControllerContext controllerContext)
|
||||
private static readonly object initLock = new object();
|
||||
private static void EnsureInitialized()
|
||||
{
|
||||
base.Initialize(controllerContext);
|
||||
try
|
||||
{
|
||||
lock (initLock)
|
||||
@@ -377,25 +474,20 @@ namespace C4IT.F4SD
|
||||
public F4SDM42LogsWebApiController()
|
||||
{
|
||||
_f4stHelperService = new F4SDHelperService();
|
||||
EnsureInitialized();
|
||||
}
|
||||
|
||||
[Route(""), HttpGet]
|
||||
[EnableQuery]
|
||||
public IEnumerable<cM42LogEntry> getLog2(ODataQueryOptions<cM42LogEntry> queryOptions)
|
||||
{
|
||||
try
|
||||
{
|
||||
IQueryable<cM42LogEntry> queryable = _f4stHelperService.privGetLog2().AsQueryable();
|
||||
if (queryOptions.Filter != null)
|
||||
{
|
||||
queryable = queryOptions.Filter.ApplyTo(queryable, new ODataQuerySettings()).Cast<cM42LogEntry>();
|
||||
}
|
||||
return queryable;
|
||||
return ApplyLogFilter(_f4stHelperService.privGetLog2(), queryOptions);
|
||||
}
|
||||
catch (Exception E)
|
||||
{
|
||||
LogException(E);
|
||||
return null;
|
||||
return Enumerable.Empty<cM42LogEntry>();
|
||||
}
|
||||
}
|
||||
|
||||
@@ -403,19 +495,30 @@ namespace C4IT.F4SD
|
||||
[HttpGet]
|
||||
public int Log2Count(ODataQueryOptions<cM42LogEntry> queryOptions)
|
||||
{
|
||||
IQueryable<cM42LogEntry> queryable = _f4stHelperService.privGetLog2().AsQueryable();
|
||||
if (queryOptions.Filter != null)
|
||||
{
|
||||
queryable = queryOptions.Filter.ApplyTo(queryable, new ODataQuerySettings()).Cast<cM42LogEntry>();
|
||||
}
|
||||
return queryable.Count();
|
||||
return ApplyLogFilter(_f4stHelperService.privGetLog2(), queryOptions).Count();
|
||||
}
|
||||
|
||||
[Route("{id}")]
|
||||
[OperationType(OperationType.GetObject)]
|
||||
public cM42LogEntry GetClass(int id)
|
||||
{
|
||||
return _f4stHelperService.privGetLog2(id);
|
||||
return _f4stHelperService.privGetLog2(id) ?? new cM42LogEntry { LineNumber = id };
|
||||
}
|
||||
|
||||
private static IEnumerable<cM42LogEntry> ApplyLogFilter(IEnumerable<cM42LogEntry> entries, ODataQueryOptions<cM42LogEntry> queryOptions)
|
||||
{
|
||||
var result = entries ?? Enumerable.Empty<cM42LogEntry>();
|
||||
var filter = queryOptions?.Filter;
|
||||
|
||||
if (!string.IsNullOrWhiteSpace(filter))
|
||||
{
|
||||
result = result.Where(entry =>
|
||||
(entry.Message?.IndexOf(filter, StringComparison.OrdinalIgnoreCase) ?? -1) >= 0 ||
|
||||
(entry.logLvl?.IndexOf(filter, StringComparison.OrdinalIgnoreCase) ?? -1) >= 0 ||
|
||||
(entry.Theme?.IndexOf(filter, StringComparison.OrdinalIgnoreCase) ?? -1) >= 0);
|
||||
}
|
||||
|
||||
return result;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
28
F4SDM42WebApi/M42ExtensionScaffolder/.gitignore
vendored
Normal file
28
F4SDM42WebApi/M42ExtensionScaffolder/.gitignore
vendored
Normal file
@@ -0,0 +1,28 @@
|
||||
|
||||
.idea/
|
||||
.vs/
|
||||
.vscode/
|
||||
node_modules/
|
||||
dist/
|
||||
|
||||
package-lock.json
|
||||
workspace.json
|
||||
|
||||
.vs/
|
||||
.libs/
|
||||
.build/
|
||||
|
||||
bin/
|
||||
obj/
|
||||
|
||||
*.user
|
||||
|
||||
/**/AssemblyInfoProduct.cs
|
||||
/**/_Resharper.Caches
|
||||
/Solutions/*.sln.DotSettings.user
|
||||
/Solutions/**/*.csproj.user
|
||||
/Solutions/**/packages/*.*
|
||||
/Solutions/**/**/AssemblyInfoProduct.cs
|
||||
/Solutions/TestResult/*.*
|
||||
|
||||
BasePackage/Assemblies/
|
||||
14
F4SDM42WebApi/M42ExtensionScaffolder/README.md
Normal file
14
F4SDM42WebApi/M42ExtensionScaffolder/README.md
Normal file
@@ -0,0 +1,14 @@
|
||||
# M42ExtensionScaffolder
|
||||
|
||||
## Description
|
||||
Template project acting as an extension scaffolder. Automatically generate extension structure including provided projects and runtimes
|
||||
|
||||
## Owner
|
||||
Name: Titan
|
||||
Email: dmytro.romanii@matrix42.com
|
||||
|
||||
## Product
|
||||
M42 Enterprise
|
||||
|
||||
## Documentation
|
||||
- [Service Information](./service-info.yml)
|
||||
@@ -0,0 +1,25 @@
|
||||
<Project Sdk="Microsoft.NET.Sdk">
|
||||
|
||||
<PropertyGroup>
|
||||
<OutputType>Exe</OutputType>
|
||||
<TargetFramework>net8.0</TargetFramework>
|
||||
<ImplicitUsings>enable</ImplicitUsings>
|
||||
<Nullable>enable</Nullable>
|
||||
</PropertyGroup>
|
||||
|
||||
<ItemGroup>
|
||||
<PackageReference Include="Microsoft.Extensions.Configuration" Version="10.0.0" />
|
||||
<PackageReference Include="Microsoft.Extensions.Configuration.Json" Version="10.0.0" />
|
||||
</ItemGroup>
|
||||
|
||||
<ItemGroup>
|
||||
<ProjectReference Include="..\Matrix42.Extensions.Scaffolder.Core\Matrix42.Extensions.Scaffolder.Core.csproj" />
|
||||
</ItemGroup>
|
||||
|
||||
<ItemGroup>
|
||||
<None Update="appsettings.json">
|
||||
<CopyToOutputDirectory>PreserveNewest</CopyToOutputDirectory>
|
||||
</None>
|
||||
</ItemGroup>
|
||||
|
||||
</Project>
|
||||
@@ -0,0 +1,61 @@
|
||||
using Matrix42.Extensions.Scaffolder.Core;
|
||||
using Matrix42.Extensions.Scaffolder.Core.Project;
|
||||
using Microsoft.Extensions.Configuration;
|
||||
|
||||
namespace Matrix42.Extensions.Scaffolder.ConsoleApp
|
||||
{
|
||||
internal class Program
|
||||
{
|
||||
static void Main(string[] args)
|
||||
{
|
||||
var config = new ConfigurationBuilder()
|
||||
.SetBasePath(Directory.GetCurrentDirectory()) // required for appsettings.json
|
||||
.AddJsonFile("appsettings.json", optional: false, reloadOnChange: true)
|
||||
.Build();
|
||||
|
||||
var extensionPath = config["Scaffolder:ExtensionPath"];
|
||||
var extensionIdStr = config["Scaffolder:ExtensionId"];
|
||||
var extensionNamespace = config["Scaffolder:ExtensionNamespace"];
|
||||
|
||||
if (string.IsNullOrWhiteSpace(extensionPath))
|
||||
throw new Exception("Scaffolder:ExtensionPath is missing in appsettings.json");
|
||||
|
||||
var extensionId = Guid.TryParse(extensionIdStr, out var gid) ? gid : Guid.NewGuid();
|
||||
|
||||
var options = new ExtensionScaffoldingOptions
|
||||
{
|
||||
ExtensionPath = extensionPath,
|
||||
ExtensionId = extensionId,
|
||||
ExtensionNamespace = extensionNamespace,
|
||||
Projects = [
|
||||
new ProjectDefinition
|
||||
{
|
||||
Prefix = "Services",
|
||||
Runtimes = RuntimeTargets.WinCore | RuntimeTargets.LinuxCore,
|
||||
Functionality = ProjectFunctionality.WebApi
|
||||
},
|
||||
|
||||
new ProjectDefinition
|
||||
{
|
||||
Prefix = "Contracts",
|
||||
Runtimes = RuntimeTargets.All,
|
||||
Functionality = ProjectFunctionality.Custom
|
||||
},
|
||||
new ProjectDefinition
|
||||
{
|
||||
Prefix = "BizLogic",
|
||||
Runtimes = RuntimeTargets.All,
|
||||
Functionality = ProjectFunctionality.Custom
|
||||
}
|
||||
]
|
||||
};
|
||||
|
||||
var scaffolder = new ExtensionScaffolder();
|
||||
var projects = scaffolder.Generate(options);
|
||||
|
||||
Console.WriteLine("Generated projects:");
|
||||
foreach (var p in projects)
|
||||
Console.WriteLine(" - " + p);
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,7 @@
|
||||
{
|
||||
"Scaffolder": {
|
||||
"ExtensionPath": "C:\\Projects\\Matrix42\\Titan_Linux\\ESM-FieldServiceManagement-Extension_demo",
|
||||
"ExtensionId": "c55407f9-9b46-4483-8b65-1bc1c3827efc",
|
||||
"ExtensionNamespace": "Matrix42.FieldServiceManagement"
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,206 @@
|
||||
<Project xmlns="http://schemas.microsoft.com/developer/msbuild/2003">
|
||||
|
||||
<!--
|
||||
Layout assumptions
|
||||
|
||||
This .targets file lives in:
|
||||
{ExtensionPath}\Extension.Assemblies.targets
|
||||
|
||||
We want to copy to:
|
||||
BasePackage\Assemblies\
|
||||
→ {ExtensionPath}\BasePackage\Assemblies\
|
||||
|
||||
Root\InstalledPackages\Assemblies\{ExtensionId}\
|
||||
→ {ExtensionPath}\..\Root\InstalledPackages\Assemblies\{ExtensionId}\
|
||||
|
||||
Properties:
|
||||
- M42BasePackageAssembliesDir (can override in csproj)
|
||||
- M42RootAssembliesDir (needs M42ExtensionId)
|
||||
- M42AssemblyPattern (default: $(MSBuildProjectName)*.*)
|
||||
- M42DefaultRids (default: win-x64;linux-x64)
|
||||
- M42ExtensionId (set in csproj)
|
||||
- M42EnableRidBuild (true for net8.0 w/ RIDs, false for netstandard)
|
||||
-->
|
||||
<PropertyGroup>
|
||||
<!-- BasePackage under extension root -->
|
||||
<M42BasePackageAssembliesDir Condition="'$(M42BasePackageAssembliesDir)' == ''">$(MSBuildThisFileDirectory)BasePackage\Assemblies\</M42BasePackageAssembliesDir>
|
||||
|
||||
<!-- Root one level above extension root -->
|
||||
<M42RootAssembliesDir Condition="'$(M42RootAssembliesDir)' == '' AND '$(M42ExtensionId)' != ''">$(MSBuildThisFileDirectory)..\Root\InstalledPackages\Assemblies\$(M42ExtensionId)\</M42RootAssembliesDir>
|
||||
|
||||
<!-- Pattern & default RIDs -->
|
||||
<M42AssemblyPattern Condition="'$(M42AssemblyPattern)' == ''">$(MSBuildProjectName)*.*</M42AssemblyPattern>
|
||||
<M42DefaultRids Condition="'$(M42DefaultRids)' == ''">win-x64;linux-x64</M42DefaultRids>
|
||||
|
||||
<!-- Enable multi-RID builds per project; can be set to false in csproj -->
|
||||
<M42EnableRidBuild Condition="'$(M42EnableRidBuild)' == ''">true</M42EnableRidBuild>
|
||||
</PropertyGroup>
|
||||
|
||||
|
||||
<!--
|
||||
M42_BuildAllRids
|
||||
|
||||
Local only: if no RID was specified AND we're not in Azure DevOps,
|
||||
build all default RIDs (M42DefaultRids) by re-invoking MSBuild
|
||||
with RuntimeIdentifier and AppendRuntimeIdentifierToOutputPath=true.
|
||||
|
||||
This prevents the outer RID-less build by setting SkipBuild=true.
|
||||
|
||||
Skipped when M42EnableRidBuild=false (e.g. netstandard projects).
|
||||
-->
|
||||
<Target Name="M42_BuildAllRids"
|
||||
BeforeTargets="Build"
|
||||
Condition="'$(RuntimeIdentifier)' == ''
|
||||
AND ( '$(TF_BUILD)' != 'True' OR '$(M42BuildAllRidsOnCI)' == 'true' )
|
||||
AND '$(M42EnableRidBuild)' == 'true'">
|
||||
|
||||
<ItemGroup>
|
||||
<_M42RidList Include="$(M42DefaultRids)" />
|
||||
</ItemGroup>
|
||||
|
||||
<MSBuild Projects="$(MSBuildProjectFullPath)"
|
||||
Targets="Restore;Build"
|
||||
Properties="RuntimeIdentifier=%(_M42RidList.Identity);Configuration=$(Configuration);AppendRuntimeIdentifierToOutputPath=true"
|
||||
BuildInParallel="true" />
|
||||
|
||||
<PropertyGroup>
|
||||
<SkipBuild>true</SkipBuild>
|
||||
</PropertyGroup>
|
||||
</Target>
|
||||
|
||||
|
||||
<!--
|
||||
M42_PostBuild_CopyRidless
|
||||
|
||||
For RID-less builds (RuntimeIdentifier == ''), copy top-level output files
|
||||
that match M42AssemblyPattern directly from $(TargetDir) to:
|
||||
|
||||
1) BasePackage\Assemblies\
|
||||
2) Root\InstalledPackages\Assemblies\{ExtId}\ (if configured)
|
||||
|
||||
Useful for projects that don't support RID-specific builds (e.g. netstandard),
|
||||
or when M42EnableRidBuild=false.
|
||||
-->
|
||||
<Target Name="M42_PostBuild_CopyRidless"
|
||||
AfterTargets="Build"
|
||||
Condition="'$(RuntimeIdentifier)' == ''">
|
||||
|
||||
<Message Text="M42: RID-less copy from $(TargetDir) → $(M42BasePackageAssembliesDir)" Importance="high" />
|
||||
|
||||
<ItemGroup>
|
||||
<_M42FlatRootRidless Include="$(TargetDir)$(M42AssemblyPattern)" />
|
||||
</ItemGroup>
|
||||
|
||||
<!-- BasePackage flat copy -->
|
||||
<MakeDir Directories="$(M42BasePackageAssembliesDir)"
|
||||
Condition="!Exists('$(M42BasePackageAssembliesDir)')" />
|
||||
|
||||
<Copy
|
||||
SourceFiles="@(_M42FlatRootRidless)"
|
||||
DestinationFolder="$(M42BasePackageAssembliesDir)"
|
||||
SkipUnchangedFiles="true"
|
||||
Condition="Exists('$(TargetDir)')" />
|
||||
|
||||
<!-- Root flat copy (if configured) -->
|
||||
<Message Text="M42: RID-less copy to Root → $(M42RootAssembliesDir)" Importance="high"
|
||||
Condition="'$(M42RootAssembliesDir)' != ''" />
|
||||
|
||||
<MakeDir Directories="$(M42RootAssembliesDir)"
|
||||
Condition="'$(M42RootAssembliesDir)' != '' AND !Exists('$(M42RootAssembliesDir)')" />
|
||||
|
||||
<Copy
|
||||
SourceFiles="@(_M42FlatRootRidless)"
|
||||
DestinationFolder="$(M42RootAssembliesDir)"
|
||||
SkipUnchangedFiles="true"
|
||||
Condition="'$(M42RootAssembliesDir)' != '' AND Exists('$(TargetDir)')" />
|
||||
|
||||
</Target>
|
||||
|
||||
|
||||
<!--
|
||||
M42_PostBuild_CopyRID
|
||||
|
||||
After each RID-specific build, copy assemblies to:
|
||||
|
||||
1) BasePackage\Assemblies\ (FLAT, from RID-less bin\...\netX\)
|
||||
2) BasePackage\Assemblies\<RID>\... (RECURSIVE, from current RID build)
|
||||
|
||||
And, if M42RootAssembliesDir is set:
|
||||
|
||||
3) Root\InstalledPackages\Assemblies\{ExtId}\ (FLAT)
|
||||
4) Root\InstalledPackages\Assemblies\{ExtId}\<RID>\ (RECURSIVE)
|
||||
-->
|
||||
<Target Name="M42_PostBuild_CopyRID"
|
||||
AfterTargets="Build"
|
||||
Condition="'$(RuntimeIdentifier)' != ''">
|
||||
|
||||
<Message Text="M42: RID=$(RuntimeIdentifier) TargetDir=$(TargetDir)" Importance="high" />
|
||||
|
||||
<!-- Parent of ...\netX\<rid>\ -->
|
||||
<PropertyGroup>
|
||||
<M42_RidlessTargetDir>$([System.IO.Path]::GetFullPath('$(TargetDir)..\'))</M42_RidlessTargetDir>
|
||||
</PropertyGroup>
|
||||
|
||||
<!-- 1) FLAT copy from rid-less netX to BasePackage\Assemblies -->
|
||||
<Message Text="M42: flat copy from $(M42_RidlessTargetDir) → $(M42BasePackageAssembliesDir)" Importance="high" />
|
||||
|
||||
<ItemGroup>
|
||||
<_M42FlatRoot Include="$(M42_RidlessTargetDir)$(M42AssemblyPattern)" />
|
||||
</ItemGroup>
|
||||
|
||||
<MakeDir Directories="$(M42BasePackageAssembliesDir)"
|
||||
Condition="!Exists('$(M42BasePackageAssembliesDir)')" />
|
||||
|
||||
<Copy
|
||||
SourceFiles="@(_M42FlatRoot)"
|
||||
DestinationFolder="$(M42BasePackageAssembliesDir)"
|
||||
SkipUnchangedFiles="true"
|
||||
Condition="Exists('$(M42_RidlessTargetDir)')" />
|
||||
|
||||
|
||||
<!-- 1b) FLAT copy to Root if configured -->
|
||||
<Message Text="M42: flat copy to Root → $(M42RootAssembliesDir)" Importance="high"
|
||||
Condition="'$(M42RootAssembliesDir)' != ''" />
|
||||
|
||||
<MakeDir Directories="$(M42RootAssembliesDir)"
|
||||
Condition="'$(M42RootAssembliesDir)' != '' AND !Exists('$(M42RootAssembliesDir)')" />
|
||||
|
||||
<Copy
|
||||
SourceFiles="@(_M42FlatRoot)"
|
||||
DestinationFolder="$(M42RootAssembliesDir)"
|
||||
SkipUnchangedFiles="true"
|
||||
Condition="'$(M42RootAssembliesDir)' != '' AND Exists('$(M42_RidlessTargetDir)')" />
|
||||
|
||||
|
||||
<!-- 2) RID copy to BasePackage\Assemblies\<RID>\... -->
|
||||
<Message Text="M42: RID copy → $(M42BasePackageAssembliesDir)$(RuntimeIdentifier)\" Importance="high" />
|
||||
|
||||
<ItemGroup>
|
||||
<_M42Rid Include="$(TargetDir)**\$(M42AssemblyPattern)" />
|
||||
</ItemGroup>
|
||||
|
||||
<MakeDir Directories="$(M42BasePackageAssembliesDir)$(RuntimeIdentifier)"
|
||||
Condition="!Exists('$(M42BasePackageAssembliesDir)$(RuntimeIdentifier)')" />
|
||||
|
||||
<Copy
|
||||
SourceFiles="@(_M42Rid)"
|
||||
DestinationFolder="$(M42BasePackageAssembliesDir)$(RuntimeIdentifier)\%(RecursiveDir)"
|
||||
SkipUnchangedFiles="true" />
|
||||
|
||||
|
||||
<!-- 2b) RID copy to Root\...\<RID>\... -->
|
||||
<Message Text="M42: RID copy to Root → $(M42RootAssembliesDir)$(RuntimeIdentifier)\" Importance="high"
|
||||
Condition="'$(M42RootAssembliesDir)' != ''" />
|
||||
|
||||
<MakeDir Directories="$(M42RootAssembliesDir)$(RuntimeIdentifier)"
|
||||
Condition="'$(M42RootAssembliesDir)' != '' AND !Exists('$(M42RootAssembliesDir)$(RuntimeIdentifier)')" />
|
||||
|
||||
<Copy
|
||||
SourceFiles="@(_M42Rid)"
|
||||
DestinationFolder="$(M42RootAssembliesDir)$(RuntimeIdentifier)\%(RecursiveDir)"
|
||||
SkipUnchangedFiles="true"
|
||||
Condition="'$(M42RootAssembliesDir)' != ''" />
|
||||
|
||||
</Target>
|
||||
|
||||
</Project>
|
||||
@@ -0,0 +1,232 @@
|
||||
using Matrix42.Extensions.Scaffolder.Core.ProjectGenerators;
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.IO;
|
||||
|
||||
namespace Matrix42.Extensions.Scaffolder.Core;
|
||||
|
||||
public sealed class ExtensionScaffolder : IExtensionScaffolder
|
||||
{
|
||||
private readonly DefaultProjectGenerator _projectGenerator = new();
|
||||
|
||||
public IReadOnlyList<string> Generate(ExtensionScaffoldingOptions options)
|
||||
{
|
||||
if (options is null)
|
||||
throw new ArgumentNullException(nameof(options));
|
||||
|
||||
|
||||
if (string.IsNullOrWhiteSpace(options.ExtensionPath)) throw new ArgumentException("ExtensionPath must be set.", nameof(options));
|
||||
|
||||
if (string.IsNullOrWhiteSpace(options.ExtensionNamespace)) throw new ArgumentException("ExtensionNamespace must be set.", nameof(options));
|
||||
|
||||
if (options.Projects == null) throw new ArgumentException("Projects must be set.", nameof(options));
|
||||
|
||||
var result = new List<string>();
|
||||
|
||||
PrepareRootStructure(options);
|
||||
PrepareBasePackage(options);
|
||||
var solutionDir = PrepareSolutionFolder(options);
|
||||
PrepareRootArtifacts(options);
|
||||
PrepareSolutionFiles(options, solutionDir);
|
||||
|
||||
foreach (var def in options.Projects)
|
||||
{
|
||||
var csprojPath = _projectGenerator.GenerateProject(options, def);
|
||||
result.Add(csprojPath);
|
||||
}
|
||||
|
||||
GenerateSolutionFile(options, solutionDir, result);
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
private void PrepareRootStructure(ExtensionScaffoldingOptions options)
|
||||
{
|
||||
Directory.CreateDirectory(options.ExtensionPath);
|
||||
}
|
||||
|
||||
private void PrepareBasePackage(ExtensionScaffoldingOptions options)
|
||||
{
|
||||
var basePackageDir = Path.Combine(options.ExtensionPath, "BasePackage");
|
||||
Directory.CreateDirectory(basePackageDir);
|
||||
|
||||
var packageJsonPath = Path.Combine(basePackageDir, "package.json");
|
||||
if (!File.Exists(packageJsonPath))
|
||||
{
|
||||
var json = GetDefaultPackageJson(options);
|
||||
File.WriteAllText(packageJsonPath, json);
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Creates /Solutions/{ns} and returns that path (solution-level folder).
|
||||
/// </summary>
|
||||
private string PrepareSolutionFolder(ExtensionScaffoldingOptions options)
|
||||
{
|
||||
var solutionDir = Path.Combine(options.ExtensionPath, "Solutions", options.ExtensionNamespace);
|
||||
Directory.CreateDirectory(solutionDir);
|
||||
return solutionDir;
|
||||
}
|
||||
|
||||
private void PrepareRootArtifacts(ExtensionScaffoldingOptions options)
|
||||
{
|
||||
/*var azurePath = Path.Combine(options.ExtensionPath, "azure-pipelines-ci.yml");
|
||||
if (!File.Exists(azurePath))
|
||||
{
|
||||
File.WriteAllText(azurePath, Templates.AzurePipelinesYml);
|
||||
}*/
|
||||
|
||||
var azurePath = Path.Combine(options.ExtensionPath, "azure-pipelines-ci.yaml");
|
||||
if (!File.Exists(azurePath))
|
||||
{
|
||||
var repoName = new DirectoryInfo(options.ExtensionPath).Name;
|
||||
|
||||
var content = Templates.GetAzurePiplineCi();
|
||||
var replacedContent = content.Replace("{repoName}", repoName).Replace("{ns}", options.ExtensionNamespace);
|
||||
File.WriteAllText(azurePath, replacedContent);
|
||||
}
|
||||
|
||||
var gitignorePath = Path.Combine(options.ExtensionPath, ".gitignore");
|
||||
if (!File.Exists(gitignorePath))
|
||||
{
|
||||
File.WriteAllText(gitignorePath, Templates.Gitignore);
|
||||
}
|
||||
|
||||
/*var veracodePath = Path.Combine(options.ExtensionPath, "PrepareVeracodeScan.cmd");
|
||||
if (!File.Exists(veracodePath))
|
||||
{
|
||||
var content = Templates.PrepareVeracodeScanCmd.Replace("{ns}", options.ExtensionNamespace);
|
||||
File.WriteAllText(veracodePath, content);
|
||||
}*/
|
||||
|
||||
var targetsPath = Path.Combine(options.ExtensionPath, "Extension.Assemblies.targets");
|
||||
if (!File.Exists(targetsPath))
|
||||
{
|
||||
var content = Templates.GetMatrix42AssembliesTargets();
|
||||
File.WriteAllText(targetsPath, content);
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Solution-level files that should live next to the .sln (e.g. BuildEvent.cmd).
|
||||
/// </summary>
|
||||
private void PrepareSolutionFiles(ExtensionScaffoldingOptions options, string solutionDir)
|
||||
{
|
||||
var buildEventPath = Path.Combine(solutionDir, "BuildEvent.cmd");
|
||||
if (!File.Exists(buildEventPath))
|
||||
{
|
||||
var content = Templates.BuildEventCmdTemplate.Replace("{ns}", options.ExtensionNamespace);
|
||||
File.WriteAllText(buildEventPath, content);
|
||||
}
|
||||
|
||||
// If later you want to actually create the .sln here (for console scenario),
|
||||
// this is the right place as well.
|
||||
}
|
||||
|
||||
private static string GetDefaultPackageJson(ExtensionScaffoldingOptions options) =>
|
||||
$@"{{
|
||||
""Id"": ""{options.ExtensionId}"",
|
||||
""Vendor"": ""Not Specified"",
|
||||
""Name"": ""{options.ExtensionNamespace}"",
|
||||
""Version"": ""1.0"",
|
||||
""Prerequisites"": {{
|
||||
""MinimalRequiredProductVersion"": ""26.1.0"",
|
||||
""DependentPackages"": []
|
||||
}},
|
||||
""SetupDirectives"": {{
|
||||
""MaintenanceMode"": false,
|
||||
""RecycleWebApplication"": false,
|
||||
""RestartM42WindowsServices"": false
|
||||
}},
|
||||
""Sandboxed"": true
|
||||
}}";
|
||||
|
||||
/// <summary>
|
||||
/// Creates {ns}.sln under solutionDir and adds all csproj files to it.
|
||||
/// </summary>
|
||||
private void GenerateSolutionFile(
|
||||
ExtensionScaffoldingOptions options,
|
||||
string solutionDir,
|
||||
IReadOnlyList<string> projectPaths)
|
||||
{
|
||||
if (projectPaths == null || projectPaths.Count == 0)
|
||||
return;
|
||||
|
||||
var solutionName = options.ExtensionNamespace;
|
||||
var slnPath = Path.Combine(solutionDir, solutionName + ".sln");
|
||||
|
||||
// Basic VS solution header
|
||||
var lines = new List<string>();
|
||||
lines.Add("Microsoft Visual Studio Solution File, Format Version 12.00");
|
||||
lines.Add("# Visual Studio Version 17");
|
||||
lines.Add("VisualStudioVersion = 17.0.31912.275");
|
||||
lines.Add("MinimumVisualStudioVersion = 10.0.40219.1");
|
||||
|
||||
// C# project type GUID
|
||||
const string csProjTypeGuid = "{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}";
|
||||
|
||||
// Collect project GUIDs
|
||||
var projectEntries = new List<Tuple<string, string, string>>();
|
||||
// (projGuid, projName, relativePath)
|
||||
|
||||
foreach (var projPath in projectPaths)
|
||||
{
|
||||
var projName = Path.GetFileNameWithoutExtension(projPath);
|
||||
var relativePath = GetRelativePath(solutionDir, projPath);
|
||||
var projGuid = "{" + Guid.NewGuid().ToString().ToUpperInvariant() + "}";
|
||||
|
||||
projectEntries.Add(Tuple.Create(projGuid, projName, relativePath));
|
||||
|
||||
lines.Add(string.Format(
|
||||
"Project(\"{0}\") = \"{1}\", \"{2}\", \"{3}\"",
|
||||
csProjTypeGuid,
|
||||
projName,
|
||||
relativePath,
|
||||
projGuid));
|
||||
lines.Add("EndProject");
|
||||
}
|
||||
|
||||
// Global section (configs + project configs)
|
||||
lines.Add("Global");
|
||||
lines.Add("\tGlobalSection(SolutionConfigurationPlatforms) = preSolution");
|
||||
lines.Add("\t\tDebug|Any CPU = Debug|Any CPU");
|
||||
lines.Add("\t\tRelease|Any CPU = Release|Any CPU");
|
||||
lines.Add("\tEndGlobalSection");
|
||||
|
||||
lines.Add("\tGlobalSection(ProjectConfigurationPlatforms) = postSolution");
|
||||
foreach (var entry in projectEntries)
|
||||
{
|
||||
var guid = entry.Item1;
|
||||
lines.Add(string.Format("\t\t{0}.Debug|Any CPU.ActiveCfg = Debug|Any CPU", guid));
|
||||
lines.Add(string.Format("\t\t{0}.Debug|Any CPU.Build.0 = Debug|Any CPU", guid));
|
||||
lines.Add(string.Format("\t\t{0}.Release|Any CPU.ActiveCfg = Release|Any CPU", guid));
|
||||
lines.Add(string.Format("\t\t{0}.Release|Any CPU.Build.0 = Release|Any CPU", guid));
|
||||
}
|
||||
lines.Add("\tEndGlobalSection");
|
||||
|
||||
lines.Add("\tGlobalSection(SolutionProperties) = preSolution");
|
||||
lines.Add("\t\tHideSolutionNode = FALSE");
|
||||
lines.Add("\tEndGlobalSection");
|
||||
|
||||
lines.Add("EndGlobal");
|
||||
|
||||
File.WriteAllLines(slnPath, lines);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Simple helper to get relative path from one folder to a file.
|
||||
/// </summary>
|
||||
private static string GetRelativePath(string basePath, string fullPath)
|
||||
{
|
||||
var baseUri = new Uri(AppendDirectorySeparatorChar(basePath));
|
||||
var fullUri = new Uri(fullPath);
|
||||
var relative = baseUri.MakeRelativeUri(fullUri).ToString();
|
||||
|
||||
return relative.Replace('/', Path.DirectorySeparatorChar);
|
||||
}
|
||||
|
||||
private static string AppendDirectorySeparatorChar(string path)
|
||||
{
|
||||
return !path.EndsWith(Path.DirectorySeparatorChar.ToString()) ? path + Path.DirectorySeparatorChar : path;
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,30 @@
|
||||
using Matrix42.Extensions.Scaffolder.Core.Project;
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
|
||||
namespace Matrix42.Extensions.Scaffolder.Core
|
||||
{
|
||||
public sealed class ExtensionScaffoldingOptions
|
||||
{
|
||||
/// <summary>
|
||||
/// Absolute path where scaffolding should be created.
|
||||
/// Typically solution directory from VS or some folder from CLI.
|
||||
/// </summary>
|
||||
public string ExtensionPath { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// Extension id (Guid) – used in package.json or other metadata.
|
||||
/// </summary>
|
||||
public Guid ExtensionId { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// Root namespace, e.g. "Matrix42.MyAwesomeExtension".
|
||||
/// </summary>
|
||||
public string ExtensionNamespace { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// Projects to create.
|
||||
/// </summary>
|
||||
public IReadOnlyList<ProjectDefinition> Projects { get; set; } = Array.Empty<ProjectDefinition>();
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,20 @@
|
||||
using Matrix42.Extensions.Scaffolder.Core.Project;
|
||||
using System.Collections.Generic;
|
||||
|
||||
namespace Matrix42.Extensions.Scaffolder.Core.Functionality
|
||||
{
|
||||
public interface IProjectFunctionalityDefinition
|
||||
{
|
||||
ProjectFunctionality Kind { get; }
|
||||
|
||||
/// <summary>
|
||||
/// Files to create for this functionality (relative paths, template content).
|
||||
/// </summary>
|
||||
IEnumerable<TemplateFile> GetFiles(ExtensionScaffoldingOptions options, ProjectDefinition project);
|
||||
|
||||
/// <summary>
|
||||
/// References to add to the csproj.
|
||||
/// </summary>
|
||||
IEnumerable<ProjectReferenceDefinition> GetReferences(ExtensionScaffoldingOptions options, ProjectDefinition project);
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,65 @@
|
||||
using Matrix42.Extensions.Scaffolder.Core.Project;
|
||||
using System.Collections.Generic;
|
||||
|
||||
namespace Matrix42.Extensions.Scaffolder.Core.Functionality
|
||||
{
|
||||
public sealed class WebApiFunctionalityDefinition : IProjectFunctionalityDefinition
|
||||
{
|
||||
public ProjectFunctionality Kind => ProjectFunctionality.WebApi;
|
||||
|
||||
public IEnumerable<TemplateFile> GetFiles(
|
||||
ExtensionScaffoldingOptions options,
|
||||
ProjectDefinition project)
|
||||
{
|
||||
var ns = options.ExtensionNamespace;
|
||||
|
||||
yield return new TemplateFile
|
||||
{
|
||||
RelativePath = @"Controllers\TestController.cs",
|
||||
Content = WebApi_TestControllerTemplate.Replace("{ns}", ns),
|
||||
CreateIfMissingOnly = true
|
||||
};
|
||||
}
|
||||
|
||||
public IEnumerable<ProjectReferenceDefinition> GetReferences(ExtensionScaffoldingOptions options, ProjectDefinition project)
|
||||
{
|
||||
yield return new ProjectReferenceDefinition
|
||||
{
|
||||
Include = "Matrix42.WebApi.Contracts",
|
||||
HintPath = @"..\..\..\..\Root\bin\Matrix42.WebApi.Contracts.dll"
|
||||
};
|
||||
|
||||
yield return new ProjectReferenceDefinition
|
||||
{
|
||||
Include = "Matrix42.Hosting.Contracts",
|
||||
HintPath = @"..\..\..\..\Root\bin\Matrix42.Hosting.Contracts.dll"
|
||||
};
|
||||
}
|
||||
|
||||
private const string WebApi_TestControllerTemplate =
|
||||
@"
|
||||
using Matrix42.WebApi.Contracts;
|
||||
using Matrix42.Hosting.Contracts;
|
||||
|
||||
namespace {ns}.Services
|
||||
{
|
||||
[RoutePrefix(""api/test"")]
|
||||
public class TestController : ApiController
|
||||
{
|
||||
private readonly IDependencyResolver _resolver;
|
||||
|
||||
public TestController(IDependencyResolver resolver)
|
||||
{
|
||||
_resolver = resolver;
|
||||
}
|
||||
|
||||
[HttpPost, Route(""test"")]
|
||||
public string TestMethod()
|
||||
{
|
||||
// TODO: implement your test method logic
|
||||
return ""OK"";
|
||||
}
|
||||
}
|
||||
}";
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,11 @@
|
||||
using System.Collections.Generic;
|
||||
|
||||
namespace Matrix42.Extensions.Scaffolder.Core;
|
||||
|
||||
public interface IExtensionScaffolder
|
||||
{
|
||||
/// <summary>
|
||||
/// Generates all files/folders according to options and returns the list of generated csproj paths.
|
||||
/// </summary>
|
||||
IReadOnlyList<string> Generate(ExtensionScaffoldingOptions options);
|
||||
}
|
||||
@@ -0,0 +1,13 @@
|
||||
<Project Sdk="Microsoft.NET.Sdk">
|
||||
|
||||
<PropertyGroup>
|
||||
<TargetFramework>netstandard2.0</TargetFramework>
|
||||
<LangVersion>11.0</LangVersion>
|
||||
</PropertyGroup>
|
||||
|
||||
<ItemGroup>
|
||||
<EmbeddedResource Include="Extension.Assemblies.targets" />
|
||||
<EmbeddedResource Include="azure-pipelines-ci.yaml" />
|
||||
</ItemGroup>
|
||||
|
||||
</Project>
|
||||
@@ -0,0 +1,54 @@
|
||||
using System.Collections.Generic;
|
||||
|
||||
namespace Matrix42.Extensions.Scaffolder.Core.Project;
|
||||
|
||||
public class ProjectDefinition
|
||||
{
|
||||
/// <summary>
|
||||
/// E.g. "Services", "BizLogic", etc.
|
||||
/// If empty, project name will be equal to ExtensionNamespace.
|
||||
/// </summary>
|
||||
public string Prefix { get; set; } = string.Empty;
|
||||
|
||||
public RuntimeTargets Runtimes { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// Combination of functionality flags: WebApi, Engine, Behavior, Connector, Custom.
|
||||
/// </summary>
|
||||
public ProjectFunctionality Functionality { get; set; } = ProjectFunctionality.None;
|
||||
|
||||
public string Display => $"Prefix: {Prefix} - Runtimes: {Runtimes} - Functionality: {Functionality}";
|
||||
|
||||
public string GetProjectName(string extensionNamespace)
|
||||
{
|
||||
var pfx = Prefix?.Trim();
|
||||
return string.IsNullOrWhiteSpace(pfx)
|
||||
? extensionNamespace
|
||||
: $"{extensionNamespace}.{pfx}";
|
||||
}
|
||||
|
||||
public string GetNamespace(string extensionNamespace) => GetProjectName(extensionNamespace);
|
||||
|
||||
public bool DoesSupportAllRuntimes() => Runtimes.HasFlag(RuntimeTargets.All);
|
||||
|
||||
public string GetRuntimeIdentifiers()
|
||||
{
|
||||
if (DoesSupportAllRuntimes())
|
||||
{
|
||||
return "netstandard2.0";
|
||||
}
|
||||
|
||||
var list = new List<string>();
|
||||
if (Runtimes.HasFlag(RuntimeTargets.Win) || Runtimes.HasFlag(RuntimeTargets.WinCore))
|
||||
{
|
||||
list.Add("win-x64");
|
||||
}
|
||||
|
||||
if (Runtimes.HasFlag(RuntimeTargets.LinuxCore))
|
||||
{
|
||||
list.Add("linux-x64");
|
||||
}
|
||||
|
||||
return string.Join(";", list);
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,23 @@
|
||||
using System;
|
||||
|
||||
namespace Matrix42.Extensions.Scaffolder.Core.Project;
|
||||
|
||||
[Flags]
|
||||
public enum ProjectFunctionality
|
||||
{
|
||||
None = 0,
|
||||
WebApi = 1,
|
||||
Engine = 2,
|
||||
Behavior = 4,
|
||||
Connector = 8,
|
||||
Custom = 16
|
||||
}
|
||||
|
||||
[Flags]
|
||||
public enum RuntimeTargets
|
||||
{
|
||||
Win = 1,
|
||||
WinCore = 2,
|
||||
LinuxCore = 4,
|
||||
All = 8
|
||||
}
|
||||
@@ -0,0 +1,11 @@
|
||||
namespace Matrix42.Extensions.Scaffolder.Core.Project
|
||||
{
|
||||
/// <summary>
|
||||
/// Describes a single extra reference to put in the csproj.
|
||||
/// </summary>
|
||||
public sealed class ProjectReferenceDefinition
|
||||
{
|
||||
public string Include { get; set; }
|
||||
public string HintPath { get; set; }
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,200 @@
|
||||
using Matrix42.Extensions.Scaffolder.Core.Functionality;
|
||||
using Matrix42.Extensions.Scaffolder.Core.Project;
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.IO;
|
||||
using System.Linq;
|
||||
using System.Text;
|
||||
|
||||
namespace Matrix42.Extensions.Scaffolder.Core.ProjectGenerators
|
||||
{
|
||||
internal class DefaultProjectGenerator
|
||||
{
|
||||
private readonly IReadOnlyList<IProjectFunctionalityDefinition> _functionalityDefinitions;
|
||||
|
||||
public DefaultProjectGenerator()
|
||||
{
|
||||
_functionalityDefinitions = new IProjectFunctionalityDefinition[]
|
||||
{
|
||||
new WebApiFunctionalityDefinition(),
|
||||
// new EngineFunctionalityDefinition(),
|
||||
// new BehaviorFunctionalityDefinition(),
|
||||
// new ConnectorFunctionalityDefinition(),
|
||||
// new CustomFunctionalityDefinition(),
|
||||
};
|
||||
}
|
||||
|
||||
public string GenerateProject(ExtensionScaffoldingOptions options, ProjectDefinition def)
|
||||
{
|
||||
var ns = options.ExtensionNamespace;
|
||||
var projectName = def.GetProjectName(ns); // e.g. Matrix42.MyExt.Services
|
||||
|
||||
var solutionDir = Path.Combine(options.ExtensionPath, "Solutions", options.ExtensionNamespace);
|
||||
Directory.CreateDirectory(solutionDir);
|
||||
|
||||
var projectDir = Path.Combine(solutionDir, projectName);
|
||||
Directory.CreateDirectory(projectDir);
|
||||
|
||||
var csprojPath = Path.Combine(projectDir, $"{projectName}.csproj");
|
||||
|
||||
GenerateCsproj(csprojPath, def, options, projectName, ns, CollectFunctionalityReferences(options, def));
|
||||
GenerateHostFile(projectDir, projectName);
|
||||
GenerateFiles(projectDir, CollectFunctionalityFiles(options, def));
|
||||
|
||||
return csprojPath;
|
||||
}
|
||||
|
||||
#region Csproj / Host
|
||||
|
||||
protected virtual void GenerateCsproj(
|
||||
string csprojPath,
|
||||
ProjectDefinition def,
|
||||
ExtensionScaffoldingOptions options,
|
||||
string projectName,
|
||||
string rootNamespace,
|
||||
IReadOnlyList<ProjectReferenceDefinition> extraReferences)
|
||||
{
|
||||
var allRuntimes = def.DoesSupportAllRuntimes();
|
||||
|
||||
var tfm = allRuntimes ? def.GetRuntimeIdentifiers() : "net8.0"; // Todo: dynamic based on runtimes
|
||||
var runtimeIds = def.GetRuntimeIdentifiers();
|
||||
|
||||
var anyRids = !allRuntimes && !string.IsNullOrWhiteSpace(runtimeIds);
|
||||
var ridBlock = anyRids ? $"<RuntimeIdentifiers>{runtimeIds}</RuntimeIdentifiers>{Environment.NewLine}" : string.Empty;
|
||||
|
||||
var referencesXml = BuildReferencesXml(extraReferences);
|
||||
|
||||
var content =
|
||||
$@"<Project Sdk=""Microsoft.NET.Sdk"">
|
||||
<PropertyGroup>
|
||||
<TargetFramework>{tfm}</TargetFramework>
|
||||
<OutputType>Library</OutputType>
|
||||
<RootNamespace>{rootNamespace}</RootNamespace>
|
||||
{ridBlock}
|
||||
<AppendRuntimeIdentifierToOutputPath>true</AppendRuntimeIdentifierToOutputPath>
|
||||
<Nullable>enable</Nullable>
|
||||
<ImplicitUsings>enable</ImplicitUsings>
|
||||
<LangVersion>latestmajor</LangVersion>
|
||||
<BasePackageAssembliesDir>$(MSBuildProjectDirectory)\..\..\..\BasePackage\Assemblies\</BasePackageAssembliesDir>
|
||||
</PropertyGroup>
|
||||
|
||||
{referencesXml}
|
||||
|
||||
<PropertyGroup>
|
||||
<M42ExtensionId>{options.ExtensionId}</M42ExtensionId>
|
||||
<M42AssemblyPattern>$(MSBuildProjectName)*.*</M42AssemblyPattern>
|
||||
<M42EnableRidBuild>{anyRids.ToString().ToLowerInvariant()}</M42EnableRidBuild>
|
||||
</PropertyGroup>
|
||||
|
||||
<Import Project=""..\..\..\Extension.Assemblies.targets"" Condition=""Exists('..\..\..\Extension.Assemblies.targets')"" />
|
||||
</Project>
|
||||
";
|
||||
|
||||
File.WriteAllText(csprojPath, content);
|
||||
}
|
||||
|
||||
protected virtual void GenerateHostFile(string projectDir, string projectName)
|
||||
{
|
||||
var hostFileName = $"{projectName}.dll.host";
|
||||
var hostPath = Path.Combine(projectDir, hostFileName);
|
||||
|
||||
if (!File.Exists(hostPath))
|
||||
{
|
||||
File.WriteAllText(hostPath, Templates.DefaultHostFileContent);
|
||||
}
|
||||
}
|
||||
|
||||
private static string BuildReferencesXml(IEnumerable<ProjectReferenceDefinition> refs)
|
||||
{
|
||||
var list = refs?.ToList() ?? new List<ProjectReferenceDefinition>();
|
||||
if (list.Count == 0)
|
||||
return string.Empty;
|
||||
|
||||
var sb = new StringBuilder();
|
||||
sb.AppendLine(" <ItemGroup>");
|
||||
|
||||
foreach (var r in list)
|
||||
{
|
||||
sb.AppendLine($@" <Reference Include=""{r.Include}"">");
|
||||
if (!string.IsNullOrWhiteSpace(r.HintPath))
|
||||
{
|
||||
sb.AppendLine($@" <HintPath>{r.HintPath}</HintPath>");
|
||||
}
|
||||
sb.AppendLine(" </Reference>");
|
||||
}
|
||||
|
||||
sb.AppendLine(" </ItemGroup>");
|
||||
return sb.ToString();
|
||||
}
|
||||
|
||||
#endregion
|
||||
|
||||
#region Functionality integration (files + references)
|
||||
|
||||
/// <summary>
|
||||
/// Collects files to generate from all enabled functionalities.
|
||||
/// </summary>
|
||||
protected virtual IReadOnlyList<TemplateFile> CollectFunctionalityFiles(
|
||||
ExtensionScaffoldingOptions options, ProjectDefinition def)
|
||||
{
|
||||
var result = new List<TemplateFile>();
|
||||
var flags = def.Functionality;
|
||||
|
||||
foreach (var defn in _functionalityDefinitions)
|
||||
{
|
||||
if (!flags.HasFlag(defn.Kind))
|
||||
{
|
||||
continue;
|
||||
}
|
||||
|
||||
result.AddRange(defn.GetFiles(options, def));
|
||||
}
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Collects references to add to csproj from all enabled functionalities.
|
||||
/// </summary>
|
||||
protected virtual IReadOnlyList<ProjectReferenceDefinition> CollectFunctionalityReferences(
|
||||
ExtensionScaffoldingOptions options, ProjectDefinition def)
|
||||
{
|
||||
var result = new List<ProjectReferenceDefinition>();
|
||||
var flags = def.Functionality;
|
||||
|
||||
foreach (var defn in _functionalityDefinitions)
|
||||
{
|
||||
if (!flags.HasFlag(defn.Kind))
|
||||
{
|
||||
continue;
|
||||
}
|
||||
|
||||
result.AddRange(defn.GetReferences(options, def));
|
||||
}
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
protected virtual void GenerateFiles(string projectDir, IReadOnlyList<TemplateFile> files)
|
||||
{
|
||||
foreach (var file in files)
|
||||
{
|
||||
var targetPath = Path.Combine(projectDir, file.RelativePath);
|
||||
var targetDir = Path.GetDirectoryName(targetPath);
|
||||
if (!string.IsNullOrEmpty(targetDir))
|
||||
{
|
||||
Directory.CreateDirectory(targetDir);
|
||||
}
|
||||
|
||||
if (file.CreateIfMissingOnly && File.Exists(targetPath))
|
||||
{
|
||||
continue;
|
||||
}
|
||||
|
||||
File.WriteAllText(targetPath, file.Content);
|
||||
}
|
||||
}
|
||||
|
||||
#endregion
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,12 @@
|
||||
using Matrix42.Extensions.Scaffolder.Core.Project;
|
||||
using System.Collections.Generic;
|
||||
|
||||
namespace Matrix42.Extensions.Scaffolder.Core.ProjectGenerators;
|
||||
|
||||
internal interface IProjectGenerator
|
||||
{
|
||||
/// <summary>
|
||||
/// Generates the project and returns the path to the created .csproj file.
|
||||
/// </summary>
|
||||
string GenerateProject(ExtensionScaffoldingOptions options, ProjectDefinition def);
|
||||
}
|
||||
@@ -0,0 +1,26 @@
|
||||
namespace Matrix42.Extensions.Scaffolder.Core
|
||||
{
|
||||
/// <summary>
|
||||
/// Describes a single file to generate from a template.
|
||||
/// </summary>
|
||||
public sealed class TemplateFile
|
||||
{
|
||||
/// <summary>
|
||||
/// Path relative to project folder (for project files)
|
||||
/// or ExtensionPath (for root-level files).
|
||||
/// Example: "Controllers\\TestController.cs" or "BuildEvent.cmd".
|
||||
/// </summary>
|
||||
public string RelativePath { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// Template content (with tokens like {ns}, {projectName} etc.).
|
||||
/// </summary>
|
||||
public string Content { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// If true, file is only created if it doesn't exist.
|
||||
/// If false, it will be overwritten.
|
||||
/// </summary>
|
||||
public bool CreateIfMissingOnly { get; set; } = true;
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,91 @@
|
||||
using System.IO;
|
||||
|
||||
namespace Matrix42.Extensions.Scaffolder.Core
|
||||
{
|
||||
internal static class Templates
|
||||
{
|
||||
public const string Gitignore = @"
|
||||
.idea/
|
||||
.vs/
|
||||
.vscode/
|
||||
node_modules/
|
||||
dist/
|
||||
|
||||
package-lock.json
|
||||
workspace.json
|
||||
|
||||
.vs/
|
||||
.libs/
|
||||
.build/
|
||||
|
||||
bin/
|
||||
obj/
|
||||
|
||||
*.user
|
||||
|
||||
/**/AssemblyInfoProduct.cs
|
||||
/**/_Resharper.Caches
|
||||
/Solutions/*.sln.DotSettings.user
|
||||
/Solutions/**/*.csproj.user
|
||||
/Solutions/**/packages/*.*
|
||||
/Solutions/**/**/AssemblyInfoProduct.cs
|
||||
/Solutions/TestResult/*.*
|
||||
|
||||
BasePackage/Assemblies/
|
||||
";
|
||||
|
||||
public const string PrepareVeracodeScanCmd = @"set arch=""C:\Program Files\7-Zip\7z.exe""
|
||||
echo [*] Building backend archive...
|
||||
%arch% a -tzip -mx5 -x!*.config %Build_ArtifactStagingDirectory%\{ns}.zip %BaseDir%\Solutions\{ns}\.build\*.*
|
||||
";
|
||||
|
||||
public const string DefaultHostFileContent =
|
||||
@"<?xml version=""1.0"" encoding=""utf-8"" ?>
|
||||
<host xmlns=""urn:m42/host.config"">
|
||||
<modules></modules>
|
||||
<sections></sections>
|
||||
</host>
|
||||
";
|
||||
|
||||
public const string BuildEventCmdTemplate =
|
||||
@"call %~dps0..\..\TeamBuildEvent.cmd %1 %2 %3 ""/Solutions/{ns}""";
|
||||
|
||||
internal static string GetMatrix42AssembliesTargets()
|
||||
{
|
||||
var asm = typeof(Templates).Assembly;
|
||||
const string resourceName = "Matrix42.Extensions.Scaffolder.Core.Extension.Assemblies.targets";
|
||||
|
||||
using (var stream = asm.GetManifestResourceStream(resourceName))
|
||||
{
|
||||
if (stream == null)
|
||||
{
|
||||
throw new FileNotFoundException($"Embedded resource '{resourceName}' not found in assembly '{asm.FullName}'.");
|
||||
}
|
||||
|
||||
using (var reader = new StreamReader(stream))
|
||||
{
|
||||
return reader.ReadToEnd();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
internal static string GetAzurePiplineCi()
|
||||
{
|
||||
var asm = typeof(Templates).Assembly;
|
||||
const string resourceName = "Matrix42.Extensions.Scaffolder.Core.azure-pipelines-ci.yaml";
|
||||
|
||||
using (var stream = asm.GetManifestResourceStream(resourceName))
|
||||
{
|
||||
if (stream == null)
|
||||
{
|
||||
throw new FileNotFoundException($"Embedded resource '{resourceName}' not found in assembly '{asm.FullName}'.");
|
||||
}
|
||||
|
||||
using (var reader = new StreamReader(stream))
|
||||
{
|
||||
return reader.ReadToEnd();
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,123 @@
|
||||
# azure-pipelines.yml
|
||||
pr: none
|
||||
|
||||
trigger:
|
||||
branches:
|
||||
include:
|
||||
- release_26_1_0
|
||||
paths:
|
||||
include:
|
||||
- 'Solutions/**'
|
||||
|
||||
parameters:
|
||||
- name: BaseDir
|
||||
type: string
|
||||
default: $(Build.SourcesDirectory)
|
||||
|
||||
- name: SuiteRarShare
|
||||
type: string
|
||||
default: '\\m42-sto-ffm01.matrix42.de\ServiceStore\Builds\TitanLinux Continuous'
|
||||
|
||||
- name: RepoName
|
||||
type: string
|
||||
default: '{repoName}'
|
||||
|
||||
- name: SolutionName
|
||||
type: string
|
||||
default: '{ns}'
|
||||
|
||||
variables:
|
||||
- name: BaseDir
|
||||
value: ${{ parameters.BaseDir }}
|
||||
|
||||
- name: ExtensionTarget
|
||||
value: ${{ parameters.BaseDir }}/${{ parameters.RepoName }}
|
||||
|
||||
- name: SolutionDir
|
||||
value: $(ExtensionTarget)/Solutions/{ns}
|
||||
|
||||
- name: SolutionPath
|
||||
value: $(SolutionDir)/{ns}.sln
|
||||
|
||||
# Tests
|
||||
- name: TestsDir
|
||||
value: $(SolutionDir)
|
||||
- name: TestProject
|
||||
value: '{ns}.Tests/{ns}.Tests.csproj'
|
||||
|
||||
stages:
|
||||
- stage: Build
|
||||
displayName: 'Build ${{ parameters.RepoName }}'
|
||||
jobs:
|
||||
- job: Build_Backend
|
||||
displayName: 'Build, Test, Package'
|
||||
pool:
|
||||
name: M42BPM
|
||||
demands:
|
||||
- DotNetFramework
|
||||
- vstest
|
||||
|
||||
steps:
|
||||
- task: CopyFiles@2
|
||||
displayName: 'Copy extension $(ExtensionTarget) source files'
|
||||
inputs:
|
||||
SourceFolder: '${{ parameters.BaseDir }}'
|
||||
Contents: '**'
|
||||
TargetFolder: '$(ExtensionTarget)'
|
||||
|
||||
- task: CopyFiles@2
|
||||
displayName: 'Copy suite.rar'
|
||||
inputs:
|
||||
SourceFolder: '${{ parameters.SuiteRarShare }}'
|
||||
Contents: 'suite.rar'
|
||||
TargetFolder: '${{ parameters.BaseDir }}'
|
||||
OverWrite: true
|
||||
|
||||
- task: ExtractFiles@1
|
||||
displayName: 'Extract suite.rar'
|
||||
inputs:
|
||||
archiveFilePatterns: '${{ parameters.BaseDir }}/suite.rar'
|
||||
destinationFolder: '${{ parameters.BaseDir }}'
|
||||
cleanDestinationFolder: false
|
||||
overwriteExistingFiles: true
|
||||
|
||||
- task: DotNetCoreCLI@2
|
||||
displayName: 'Restore $(ExtensionTarget) solution'
|
||||
inputs:
|
||||
command: 'restore'
|
||||
projects: '$(SolutionPath)'
|
||||
|
||||
# Optional: override default RIDs globally if needed: -p:M42DefaultRids=win-x64;linux-x64
|
||||
- task: DotNetCoreCLI@2
|
||||
displayName: 'Build {ns} solution'
|
||||
inputs:
|
||||
command: 'build'
|
||||
projects: '$(SolutionPath)'
|
||||
arguments: >
|
||||
-c Release
|
||||
--no-restore
|
||||
-p:SolutionDir=$(SolutionDir)\
|
||||
-p:M42BuildAllRidsOnCI=true
|
||||
|
||||
- task: DotNetCoreCLI@2
|
||||
displayName: 'Test (net8.0)'
|
||||
inputs:
|
||||
command: 'test'
|
||||
projects: '$(TestsDir)/$(TestProject)'
|
||||
arguments: '-c Release -f net8.0 --no-build'
|
||||
|
||||
- task: ArchiveFiles@2
|
||||
displayName: 'Zip $(ExtensionTarget) BasePackage'
|
||||
inputs:
|
||||
rootFolderOrFile: '$(ExtensionTarget)/BasePackage'
|
||||
includeRootFolder: false
|
||||
archiveType: 'zip'
|
||||
sevenZipCompression: 'normal'
|
||||
archiveFile: '$(Build.ArtifactStagingDirectory)/${{ parameters.RepoName }}_1.0.zip'
|
||||
replaceExistingArchive: true
|
||||
|
||||
- task: PublishPipelineArtifact@1
|
||||
displayName: 'Publish ${{ parameters.RepoName }}_1.0.zip'
|
||||
inputs:
|
||||
targetPath: '$(Build.ArtifactStagingDirectory)/${{ parameters.RepoName }}_1.0.zip'
|
||||
artifact: '${{ parameters.RepoName }}'
|
||||
@@ -0,0 +1,91 @@
|
||||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<Project ToolsVersion="15.0" DefaultTargets="Build" xmlns="http://schemas.microsoft.com/developer/msbuild/2003">
|
||||
<PropertyGroup>
|
||||
<MinimumVisualStudioVersion>17.0</MinimumVisualStudioVersion>
|
||||
<VSToolsPath Condition="'$(VSToolsPath)' == ''">$(MSBuildExtensionsPath32)\Microsoft\VisualStudio\v$(VisualStudioVersion)</VSToolsPath>
|
||||
</PropertyGroup>
|
||||
<Import Project="$(MSBuildExtensionsPath)\$(MSBuildToolsVersion)\Microsoft.Common.props" Condition="Exists('$(MSBuildExtensionsPath)\$(MSBuildToolsVersion)\Microsoft.Common.props')" />
|
||||
<PropertyGroup>
|
||||
<Configuration Condition=" '$(Configuration)' == '' ">Debug</Configuration>
|
||||
<Platform Condition=" '$(Platform)' == '' ">AnyCPU</Platform>
|
||||
<SchemaVersion>2.0</SchemaVersion>
|
||||
<ProjectTypeGuids>{82b43b9b-a64c-4715-b499-d71e9ca2bd60};{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}</ProjectTypeGuids>
|
||||
<ProjectGuid>{50F8DCAA-48B9-47D5-ABB8-F8D33BEF1BD1}</ProjectGuid>
|
||||
<OutputType>Library</OutputType>
|
||||
<AppDesignerFolder>Properties</AppDesignerFolder>
|
||||
<RootNamespace>Matrix42.Extensions.Scaffolder.Vsix</RootNamespace>
|
||||
<AssemblyName>Matrix42.Extensions.Scaffolder.Vsix</AssemblyName>
|
||||
<TargetFrameworkVersion>v4.7.2</TargetFrameworkVersion>
|
||||
<GeneratePkgDefFile>true</GeneratePkgDefFile>
|
||||
<UseCodebase>true</UseCodebase>
|
||||
<IncludeAssemblyInVSIXContainer>true</IncludeAssemblyInVSIXContainer>
|
||||
<IncludeDebugSymbolsInVSIXContainer>false</IncludeDebugSymbolsInVSIXContainer>
|
||||
<IncludeDebugSymbolsInLocalVSIXDeployment>false</IncludeDebugSymbolsInLocalVSIXDeployment>
|
||||
<CopyBuildOutputToOutputDirectory>true</CopyBuildOutputToOutputDirectory>
|
||||
<CopyOutputSymbolsToOutputDirectory>true</CopyOutputSymbolsToOutputDirectory>
|
||||
<StartAction>Program</StartAction>
|
||||
<StartProgram Condition="'$(DevEnvDir)' != ''">$(DevEnvDir)devenv.exe</StartProgram>
|
||||
<StartArguments>/rootsuffix Exp</StartArguments>
|
||||
<GeneratePkgDefFile>false</GeneratePkgDefFile>
|
||||
</PropertyGroup>
|
||||
<PropertyGroup Condition=" '$(Configuration)|$(Platform)' == 'Debug|AnyCPU' ">
|
||||
<DebugSymbols>true</DebugSymbols>
|
||||
<DebugType>full</DebugType>
|
||||
<Optimize>false</Optimize>
|
||||
<OutputPath>bin\Debug\</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\Release\</OutputPath>
|
||||
<DefineConstants>TRACE</DefineConstants>
|
||||
<ErrorReport>prompt</ErrorReport>
|
||||
<WarningLevel>4</WarningLevel>
|
||||
</PropertyGroup>
|
||||
<ItemGroup>
|
||||
<Compile Include="Properties\AssemblyInfo.cs" />
|
||||
<Compile Include="Wizard\ExtensionProjectsWizard.cs" />
|
||||
<Compile Include="Wizard\ProjectDefinition.cs" />
|
||||
<Compile Include="Wizard\RuntimeTargets.cs" />
|
||||
<Compile Include="Wizard\WizardForm.cs">
|
||||
<SubType>Form</SubType>
|
||||
</Compile>
|
||||
<Compile Include="Wizard\WizardForm.Designer.cs">
|
||||
<DependentUpon>WizardForm.cs</DependentUpon>
|
||||
</Compile>
|
||||
</ItemGroup>
|
||||
<ItemGroup>
|
||||
<None Include="ProjectTemplates\Directory.Build.props.template" />
|
||||
<None Include="ProjectTemplates\Placeholder.csproj" />
|
||||
<None Include="source.extension.vsixmanifest">
|
||||
<SubType>Designer</SubType>
|
||||
</None>
|
||||
</ItemGroup>
|
||||
<ItemGroup>
|
||||
<Reference Include="System" />
|
||||
<Reference Include="System.Drawing" />
|
||||
<Reference Include="System.Windows.Forms" />
|
||||
</ItemGroup>
|
||||
<ItemGroup>
|
||||
<PackageReference Include="Microsoft.VisualStudio.SDK" Version="17.0.32112.339" ExcludeAssets="runtime" NoWarn="NU1604" />
|
||||
<PackageReference Include="Microsoft.VisualStudio.TemplateWizardInterface">
|
||||
<Version>17.10.40170</Version>
|
||||
</PackageReference>
|
||||
<PackageReference Include="Microsoft.VSSDK.BuildTools" Version="17.14.2096" NoWarn="NU1604" />
|
||||
</ItemGroup>
|
||||
<ItemGroup>
|
||||
<Content Include="ProjectTemplates\ExtensionSolution.vstemplate" />
|
||||
</ItemGroup>
|
||||
<Import Project="$(MSBuildToolsPath)\Microsoft.CSharp.targets" />
|
||||
<Import Project="$(VSToolsPath)\VSSDK\Microsoft.VsSDK.targets" Condition="'$(VSToolsPath)' != ''" />
|
||||
<!-- 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>
|
||||
-->
|
||||
</Project>
|
||||
@@ -0,0 +1,37 @@
|
||||
|
||||
Microsoft Visual Studio Solution File, Format Version 12.00
|
||||
# Visual Studio Version 17
|
||||
VisualStudioVersion = 17.14.36310.24 d17.14
|
||||
MinimumVisualStudioVersion = 10.0.40219.1
|
||||
Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "Matrix42.Extensions.Scaffolder.Vsix", "Matrix42.Extensions.Scaffolder.Vsix.csproj", "{50F8DCAA-48B9-47D5-ABB8-F8D33BEF1BD1}"
|
||||
EndProject
|
||||
Global
|
||||
GlobalSection(SolutionConfigurationPlatforms) = preSolution
|
||||
Debug|Any CPU = Debug|Any CPU
|
||||
Debug|arm64 = Debug|arm64
|
||||
Debug|x86 = Debug|x86
|
||||
Release|Any CPU = Release|Any CPU
|
||||
Release|arm64 = Release|arm64
|
||||
Release|x86 = Release|x86
|
||||
EndGlobalSection
|
||||
GlobalSection(ProjectConfigurationPlatforms) = postSolution
|
||||
{50F8DCAA-48B9-47D5-ABB8-F8D33BEF1BD1}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
|
||||
{50F8DCAA-48B9-47D5-ABB8-F8D33BEF1BD1}.Debug|Any CPU.Build.0 = Debug|Any CPU
|
||||
{50F8DCAA-48B9-47D5-ABB8-F8D33BEF1BD1}.Debug|arm64.ActiveCfg = Debug|arm64
|
||||
{50F8DCAA-48B9-47D5-ABB8-F8D33BEF1BD1}.Debug|arm64.Build.0 = Debug|arm64
|
||||
{50F8DCAA-48B9-47D5-ABB8-F8D33BEF1BD1}.Debug|x86.ActiveCfg = Debug|x86
|
||||
{50F8DCAA-48B9-47D5-ABB8-F8D33BEF1BD1}.Debug|x86.Build.0 = Debug|x86
|
||||
{50F8DCAA-48B9-47D5-ABB8-F8D33BEF1BD1}.Release|Any CPU.ActiveCfg = Release|Any CPU
|
||||
{50F8DCAA-48B9-47D5-ABB8-F8D33BEF1BD1}.Release|Any CPU.Build.0 = Release|Any CPU
|
||||
{50F8DCAA-48B9-47D5-ABB8-F8D33BEF1BD1}.Release|arm64.ActiveCfg = Release|arm64
|
||||
{50F8DCAA-48B9-47D5-ABB8-F8D33BEF1BD1}.Release|arm64.Build.0 = Release|arm64
|
||||
{50F8DCAA-48B9-47D5-ABB8-F8D33BEF1BD1}.Release|x86.ActiveCfg = Release|x86
|
||||
{50F8DCAA-48B9-47D5-ABB8-F8D33BEF1BD1}.Release|x86.Build.0 = Release|x86
|
||||
EndGlobalSection
|
||||
GlobalSection(SolutionProperties) = preSolution
|
||||
HideSolutionNode = FALSE
|
||||
EndGlobalSection
|
||||
GlobalSection(ExtensibilityGlobals) = postSolution
|
||||
SolutionGuid = {ECBF8D8B-3FBE-4CDA-BE52-C37D76054B09}
|
||||
EndGlobalSection
|
||||
EndGlobal
|
||||
@@ -0,0 +1,7 @@
|
||||
<Project>
|
||||
<PropertyGroup>
|
||||
<LangVersion>latest</LangVersion>
|
||||
<Nullable>enable</Nullable>
|
||||
<ImplicitUsings>enable</ImplicitUsings>
|
||||
</PropertyGroup>
|
||||
</Project>
|
||||
@@ -0,0 +1,21 @@
|
||||
<VSTemplate Version="3.0.0" Type="Project">
|
||||
<TemplateData>
|
||||
<Name>Matrix42 Extension Solution</Name>
|
||||
<Description>Create a new Matrix42 extension solution (WebApi / Contracts / BizLogic / Custom) using Matrix42.Extensions.SDK.</Description>
|
||||
<ProjectType>CSharp</ProjectType>
|
||||
<SortOrder>1000</SortOrder>
|
||||
<DefaultName>Matrix42.Extension</DefaultName>
|
||||
<CreateNewFolder>true</CreateNewFolder>
|
||||
<ProvideDefaultName>true</ProvideDefaultName>
|
||||
<LocationField>Enabled</LocationField>
|
||||
</TemplateData>
|
||||
|
||||
<TemplateContent>
|
||||
<Project File="Placeholder.csproj" ReplaceParameters="true" TargetFileName="$safeprojectname$.csproj" />
|
||||
</TemplateContent>
|
||||
|
||||
<WizardExtension>
|
||||
<Assembly>Matrix42.Extensions.Scaffolder.Vsix, Version=1.0.0.0, Culture=neutral, PublicKeyToken=null</Assembly>
|
||||
<FullClassName>Matrix42.Extensions.Scaffolder.Wizard.ExtensionProjectsWizard</FullClassName>
|
||||
</WizardExtension>
|
||||
</VSTemplate>
|
||||
@@ -0,0 +1,6 @@
|
||||
<Project Sdk="Microsoft.NET.Sdk">
|
||||
<PropertyGroup>
|
||||
<TargetFramework>net8.0</TargetFramework>
|
||||
<OutputType>Library</OutputType>
|
||||
</PropertyGroup>
|
||||
</Project>
|
||||
@@ -0,0 +1,33 @@
|
||||
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("Matrix42.Extensions.Scaffolder.Vsix")]
|
||||
[assembly: AssemblyDescription("")]
|
||||
[assembly: AssemblyConfiguration("")]
|
||||
[assembly: AssemblyCompany("")]
|
||||
[assembly: AssemblyProduct("Matrix42.Extensions.Scaffolder.Vsix")]
|
||||
[assembly: AssemblyCopyright("")]
|
||||
[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)]
|
||||
|
||||
// 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 Build and Revision Numbers
|
||||
// by using the '*' as shown below:
|
||||
// [assembly: AssemblyVersion("1.0.*")]
|
||||
[assembly: AssemblyVersion("1.0.0.0")]
|
||||
[assembly: AssemblyFileVersion("1.0.0.0")]
|
||||
@@ -0,0 +1,231 @@
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.IO;
|
||||
using EnvDTE;
|
||||
using EnvDTE80;
|
||||
using Microsoft.VisualStudio.TemplateWizard;
|
||||
|
||||
namespace Matrix42.Extensions.Scaffolder.Wizard
|
||||
{
|
||||
public class ExtensionProjectsWizard : IWizard
|
||||
{
|
||||
private DTE2 _dte;
|
||||
private Project _placeholderProject;
|
||||
private string _extensionNamespace = string.Empty;
|
||||
private List<ProjectDefinition> _projects = new List<ProjectDefinition>();
|
||||
private string _solutionDirectory = string.Empty;
|
||||
|
||||
public void RunStarted(
|
||||
object automationObject,
|
||||
Dictionary<string, string> replacementsDictionary,
|
||||
WizardRunKind runKind,
|
||||
object[] customParams)
|
||||
{
|
||||
_dte = automationObject as DTE2
|
||||
?? throw new InvalidOperationException("DTE2 not available.");
|
||||
|
||||
using (var form = new WizardForm())
|
||||
{
|
||||
var result = form.ShowDialog();
|
||||
if (result != System.Windows.Forms.DialogResult.OK)
|
||||
throw new WizardBackoutException();
|
||||
|
||||
_extensionNamespace = form.ExtensionNamespace;
|
||||
_projects = new List<ProjectDefinition>(form.Projects);
|
||||
}
|
||||
}
|
||||
|
||||
// 🔹 This is the method that was missing
|
||||
public void BeforeOpeningFile(ProjectItem projectItem)
|
||||
{
|
||||
// We don't need to do anything before a file is opened.
|
||||
// Leave empty on purpose.
|
||||
}
|
||||
|
||||
public void ProjectFinishedGenerating(Project project)
|
||||
{
|
||||
_placeholderProject = project;
|
||||
}
|
||||
|
||||
public void ProjectItemFinishedGenerating(ProjectItem projectItem)
|
||||
{
|
||||
}
|
||||
|
||||
public void RunFinished()
|
||||
{
|
||||
var solution = _dte.Solution;
|
||||
_solutionDirectory = Path.GetDirectoryName(solution.FullName);
|
||||
|
||||
if (string.IsNullOrEmpty(_solutionDirectory))
|
||||
return;
|
||||
|
||||
// Remove placeholder project from solution and disk
|
||||
if (_placeholderProject != null)
|
||||
{
|
||||
var placeholderPath = _placeholderProject.FullName;
|
||||
solution.Remove(_placeholderProject);
|
||||
TryDeleteDirectorySafe(Path.GetDirectoryName(placeholderPath));
|
||||
}
|
||||
|
||||
// Drop Directory.Build.props
|
||||
var propsTemplatePath = Path.Combine(
|
||||
GetExtensionInstallPath(),
|
||||
"ProjectTemplates",
|
||||
"Directory.Build.props.template");
|
||||
|
||||
if (File.Exists(propsTemplatePath))
|
||||
{
|
||||
var destProps = Path.Combine(_solutionDirectory, "Directory.Build.props");
|
||||
if (!File.Exists(destProps))
|
||||
File.Copy(propsTemplatePath, destProps, overwrite: false);
|
||||
}
|
||||
|
||||
foreach (var proj in _projects)
|
||||
{
|
||||
CreateProjectFromDefinition(solution, proj);
|
||||
}
|
||||
}
|
||||
|
||||
public bool ShouldAddProjectItem(string filePath) => true;
|
||||
|
||||
private void CreateProjectFromDefinition(Solution solution, ProjectDefinition def)
|
||||
{
|
||||
var projectName = def.GetProjectName(_extensionNamespace);
|
||||
var projectNamespace = def.GetNamespace(_extensionNamespace);
|
||||
var projectDir = Path.Combine(_solutionDirectory, projectName);
|
||||
|
||||
Directory.CreateDirectory(projectDir);
|
||||
|
||||
var csprojPath = Path.Combine(projectDir, projectName + ".csproj");
|
||||
var runtimeIds = def.GetRuntimeIdentifiers();
|
||||
var tfm = "net8.0"; // default target framework
|
||||
|
||||
var csprojContent = GenerateCsproj(def.Type, tfm, runtimeIds, projectNamespace);
|
||||
File.WriteAllText(csprojPath, csprojContent);
|
||||
|
||||
var codeFilePath = Path.Combine(
|
||||
projectDir,
|
||||
def.Type == ProjectType.WebApi ? "Program.cs" : "Class1.cs");
|
||||
|
||||
var codeContent = GenerateCodeFile(def.Type, projectNamespace);
|
||||
File.WriteAllText(codeFilePath, codeContent);
|
||||
|
||||
solution.AddFromFile(csprojPath);
|
||||
}
|
||||
|
||||
private string GenerateCsproj(
|
||||
ProjectType type,
|
||||
string tfm,
|
||||
string runtimeIds,
|
||||
string rootNamespace)
|
||||
{
|
||||
var outputType = type == ProjectType.WebApi ? "Exe" : "Library";
|
||||
var sdk = type == ProjectType.WebApi ? "Microsoft.NET.Sdk.Web" : "Microsoft.NET.Sdk";
|
||||
|
||||
var ridBlock = string.IsNullOrWhiteSpace(runtimeIds)
|
||||
? string.Empty
|
||||
: $" <RuntimeIdentifiers>{runtimeIds}</RuntimeIdentifiers>{Environment.NewLine}";
|
||||
|
||||
return
|
||||
$@"<Project Sdk=""{sdk}"">
|
||||
<PropertyGroup>
|
||||
<TargetFramework>{tfm}</TargetFramework>
|
||||
<OutputType>{outputType}</OutputType>
|
||||
<RootNamespace>{rootNamespace}</RootNamespace>
|
||||
</PropertyGroup>
|
||||
|
||||
<PropertyGroup>
|
||||
{ridBlock} </PropertyGroup>
|
||||
|
||||
<ItemGroup>
|
||||
<PackageReference Include=""Matrix42.Extensions.SDK"" Version=""1.0.0"" />
|
||||
</ItemGroup>
|
||||
</Project>
|
||||
";
|
||||
}
|
||||
|
||||
private string GenerateCodeFile(ProjectType type, string ns)
|
||||
{
|
||||
switch (type)
|
||||
{
|
||||
case ProjectType.WebApi:
|
||||
return
|
||||
$@"using Microsoft.AspNetCore.Builder;
|
||||
using Microsoft.Extensions.DependencyInjection;
|
||||
using Microsoft.Extensions.Hosting;
|
||||
using Matrix42.Extensions.SDK;
|
||||
|
||||
namespace {ns}
|
||||
{{
|
||||
public class Program
|
||||
{{
|
||||
public static void Main(string[] args)
|
||||
{{
|
||||
var builder = WebApplication.CreateBuilder(args);
|
||||
|
||||
builder.Services.AddControllers();
|
||||
// TODO: configure Matrix42.Extensions.SDK services
|
||||
|
||||
var app = builder.Build();
|
||||
app.MapControllers();
|
||||
|
||||
app.Run();
|
||||
}}
|
||||
}}
|
||||
}}";
|
||||
case ProjectType.Contracts:
|
||||
return
|
||||
$@"namespace {ns}
|
||||
{{
|
||||
// Place your contracts (DTOs, interfaces) here
|
||||
public class SampleContract
|
||||
{{
|
||||
public string Id {{ get; set; }} = string.Empty;
|
||||
}}
|
||||
}}";
|
||||
case ProjectType.BizLogic:
|
||||
return
|
||||
$@"using Matrix42.Extensions.SDK;
|
||||
|
||||
namespace {ns}
|
||||
{{
|
||||
// Place your business logic services here
|
||||
public class SampleService
|
||||
{{
|
||||
public string SayHello() => ""Hello from {ns}"";
|
||||
}}
|
||||
}}";
|
||||
case ProjectType.Custom:
|
||||
default:
|
||||
return
|
||||
$@"namespace {ns}
|
||||
{{
|
||||
// Custom project for your extension
|
||||
public class CustomEntry
|
||||
{{
|
||||
public string Name {{ get; set; }} = ""Custom"";
|
||||
}}
|
||||
}}";
|
||||
}
|
||||
}
|
||||
|
||||
private string GetExtensionInstallPath()
|
||||
{
|
||||
var asmPath = typeof(ExtensionProjectsWizard).Assembly.Location;
|
||||
return Path.GetDirectoryName(asmPath);
|
||||
}
|
||||
|
||||
private void TryDeleteDirectorySafe(string path)
|
||||
{
|
||||
try
|
||||
{
|
||||
if (!string.IsNullOrWhiteSpace(path) && Directory.Exists(path))
|
||||
Directory.Delete(path, recursive: true);
|
||||
}
|
||||
catch
|
||||
{
|
||||
// ignore
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,66 @@
|
||||
using System.Collections.Generic;
|
||||
|
||||
namespace Matrix42.Extensions.Scaffolder.Wizard
|
||||
{
|
||||
public enum ProjectType
|
||||
{
|
||||
WebApi,
|
||||
Contracts,
|
||||
BizLogic,
|
||||
Custom
|
||||
}
|
||||
|
||||
public class ProjectDefinition
|
||||
{
|
||||
public ProjectType Type { get; set; }
|
||||
public string Prefix { get; set; } = string.Empty; // custom for Custom type, otherwise derived
|
||||
public RuntimeTargets Runtimes { get; set; }
|
||||
|
||||
public string EffectivePrefix
|
||||
{
|
||||
get
|
||||
{
|
||||
if (Type == ProjectType.Custom)
|
||||
return Prefix;
|
||||
|
||||
switch (Type)
|
||||
{
|
||||
case ProjectType.WebApi:
|
||||
return string.IsNullOrWhiteSpace(Prefix) ? "Services" : Prefix;
|
||||
case ProjectType.Contracts:
|
||||
return string.IsNullOrWhiteSpace(Prefix) ? "Contracts" : Prefix;
|
||||
case ProjectType.BizLogic:
|
||||
return string.IsNullOrWhiteSpace(Prefix) ? "BizLogic" : Prefix;
|
||||
default:
|
||||
return Prefix;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
public string Display => $"{Type} - Prefix: {EffectivePrefix} - Runtimes: {Runtimes}";
|
||||
|
||||
public string GetProjectName(string extensionNamespace)
|
||||
{
|
||||
var pfx = EffectivePrefix?.Trim();
|
||||
return string.IsNullOrWhiteSpace(pfx)
|
||||
? extensionNamespace
|
||||
: $"{extensionNamespace}.{pfx}";
|
||||
}
|
||||
|
||||
public string GetNamespace(string extensionNamespace) => GetProjectName(extensionNamespace);
|
||||
|
||||
public string GetRuntimeIdentifiers()
|
||||
{
|
||||
if (Runtimes.HasFlag(RuntimeTargets.All))
|
||||
return "win-x64;linux-x64";
|
||||
|
||||
var list = new List<string>();
|
||||
if (Runtimes.HasFlag(RuntimeTargets.Win) || Runtimes.HasFlag(RuntimeTargets.WinCore))
|
||||
list.Add("win-x64");
|
||||
if (Runtimes.HasFlag(RuntimeTargets.LinuxCore))
|
||||
list.Add("linux-x64");
|
||||
|
||||
return string.Join(";", list);
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,12 @@
|
||||
namespace Matrix42.Extensions.Scaffolder.Wizard
|
||||
{
|
||||
[System.Flags]
|
||||
public enum RuntimeTargets
|
||||
{
|
||||
None = 0,
|
||||
Win = 1,
|
||||
WinCore = 2,
|
||||
LinuxCore = 4,
|
||||
All = 8
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,236 @@
|
||||
namespace Matrix42.Extensions.Scaffolder.Wizard
|
||||
{
|
||||
partial class WizardForm
|
||||
{
|
||||
private System.ComponentModel.IContainer components = null;
|
||||
|
||||
private System.Windows.Forms.Label lblTitle;
|
||||
private System.Windows.Forms.Label lblExtensionNamespace;
|
||||
private System.Windows.Forms.TextBox txtExtensionNamespace;
|
||||
private System.Windows.Forms.Label lblHint;
|
||||
private System.Windows.Forms.Label lblAddProjects;
|
||||
private System.Windows.Forms.Label lblProjectType;
|
||||
private System.Windows.Forms.ComboBox cboProjectType;
|
||||
private System.Windows.Forms.Label lblProjectPrefix;
|
||||
private System.Windows.Forms.TextBox txtProjectPrefix;
|
||||
private System.Windows.Forms.Label lblRuntimes;
|
||||
private System.Windows.Forms.CheckedListBox clbRuntimes;
|
||||
private System.Windows.Forms.Button btnAddProject;
|
||||
private System.Windows.Forms.ListBox lstProjects;
|
||||
private System.Windows.Forms.Button btnRemoveSelected;
|
||||
private System.Windows.Forms.Button btnOK;
|
||||
private System.Windows.Forms.Button btnCancel;
|
||||
|
||||
protected override void Dispose(bool disposing)
|
||||
{
|
||||
if (disposing && (components != null))
|
||||
components.Dispose();
|
||||
base.Dispose(disposing);
|
||||
}
|
||||
|
||||
private void InitializeComponent()
|
||||
{
|
||||
this.lblTitle = new System.Windows.Forms.Label();
|
||||
this.lblExtensionNamespace = new System.Windows.Forms.Label();
|
||||
this.txtExtensionNamespace = new System.Windows.Forms.TextBox();
|
||||
this.lblHint = new System.Windows.Forms.Label();
|
||||
this.lblAddProjects = new System.Windows.Forms.Label();
|
||||
this.lblProjectType = new System.Windows.Forms.Label();
|
||||
this.cboProjectType = new System.Windows.Forms.ComboBox();
|
||||
this.lblProjectPrefix = new System.Windows.Forms.Label();
|
||||
this.txtProjectPrefix = new System.Windows.Forms.TextBox();
|
||||
this.lblRuntimes = new System.Windows.Forms.Label();
|
||||
this.clbRuntimes = new System.Windows.Forms.CheckedListBox();
|
||||
this.btnAddProject = new System.Windows.Forms.Button();
|
||||
this.lstProjects = new System.Windows.Forms.ListBox();
|
||||
this.btnRemoveSelected = new System.Windows.Forms.Button();
|
||||
this.btnOK = new System.Windows.Forms.Button();
|
||||
this.btnCancel = new System.Windows.Forms.Button();
|
||||
this.SuspendLayout();
|
||||
//
|
||||
// lblTitle
|
||||
//
|
||||
this.lblTitle.AutoSize = true;
|
||||
this.lblTitle.Font = new System.Drawing.Font("Segoe UI", 11F, System.Drawing.FontStyle.Bold);
|
||||
this.lblTitle.Location = new System.Drawing.Point(12, 9);
|
||||
this.lblTitle.Name = "lblTitle";
|
||||
this.lblTitle.Size = new System.Drawing.Size(120, 20);
|
||||
this.lblTitle.TabIndex = 0;
|
||||
this.lblTitle.Text = "Projects Wizard";
|
||||
//
|
||||
// lblExtensionNamespace
|
||||
//
|
||||
this.lblExtensionNamespace.AutoSize = true;
|
||||
this.lblExtensionNamespace.Location = new System.Drawing.Point(13, 44);
|
||||
this.lblExtensionNamespace.Name = "lblExtensionNamespace";
|
||||
this.lblExtensionNamespace.Size = new System.Drawing.Size(113, 15);
|
||||
this.lblExtensionNamespace.TabIndex = 1;
|
||||
this.lblExtensionNamespace.Text = "Extension Namespace";
|
||||
//
|
||||
// txtExtensionNamespace
|
||||
//
|
||||
this.txtExtensionNamespace.Anchor = ((System.Windows.Forms.AnchorStyles)(((System.Windows.Forms.AnchorStyles.Top | System.Windows.Forms.AnchorStyles.Left)
|
||||
| System.Windows.Forms.AnchorStyles.Right)));
|
||||
this.txtExtensionNamespace.Location = new System.Drawing.Point(16, 62);
|
||||
this.txtExtensionNamespace.Name = "txtExtensionNamespace";
|
||||
this.txtExtensionNamespace.Size = new System.Drawing.Size(444, 23);
|
||||
this.txtExtensionNamespace.TabIndex = 2;
|
||||
//
|
||||
// lblHint
|
||||
//
|
||||
this.lblHint.AutoSize = true;
|
||||
this.lblHint.Location = new System.Drawing.Point(466, 65);
|
||||
this.lblHint.Name = "lblHint";
|
||||
this.lblHint.Size = new System.Drawing.Size(121, 15);
|
||||
this.lblHint.TabIndex = 3;
|
||||
this.lblHint.Text = "aka Matrix42.MyExtension";
|
||||
//
|
||||
// lblAddProjects
|
||||
//
|
||||
this.lblAddProjects.AutoSize = true;
|
||||
this.lblAddProjects.Location = new System.Drawing.Point(13, 103);
|
||||
this.lblAddProjects.Name = "lblAddProjects";
|
||||
this.lblAddProjects.Size = new System.Drawing.Size(71, 15);
|
||||
this.lblAddProjects.TabIndex = 4;
|
||||
this.lblAddProjects.Text = "Add Projects";
|
||||
//
|
||||
// lblProjectType
|
||||
//
|
||||
this.lblProjectType.AutoSize = true;
|
||||
this.lblProjectType.Location = new System.Drawing.Point(13, 129);
|
||||
this.lblProjectType.Name = "lblProjectType";
|
||||
this.lblProjectType.Size = new System.Drawing.Size(70, 15);
|
||||
this.lblProjectType.TabIndex = 5;
|
||||
this.lblProjectType.Text = "Project Type";
|
||||
//
|
||||
// cboProjectType
|
||||
//
|
||||
this.cboProjectType.DropDownStyle = System.Windows.Forms.ComboBoxStyle.DropDownList;
|
||||
this.cboProjectType.FormattingEnabled = true;
|
||||
this.cboProjectType.Location = new System.Drawing.Point(16, 147);
|
||||
this.cboProjectType.Name = "cboProjectType";
|
||||
this.cboProjectType.Size = new System.Drawing.Size(150, 23);
|
||||
this.cboProjectType.TabIndex = 6;
|
||||
//
|
||||
// lblProjectPrefix
|
||||
//
|
||||
this.lblProjectPrefix.AutoSize = true;
|
||||
this.lblProjectPrefix.Location = new System.Drawing.Point(179, 129);
|
||||
this.lblProjectPrefix.Name = "lblProjectPrefix";
|
||||
this.lblProjectPrefix.Size = new System.Drawing.Size(75, 15);
|
||||
this.lblProjectPrefix.TabIndex = 7;
|
||||
this.lblProjectPrefix.Text = "Project Prefix";
|
||||
//
|
||||
// txtProjectPrefix
|
||||
//
|
||||
this.txtProjectPrefix.Location = new System.Drawing.Point(182, 147);
|
||||
this.txtProjectPrefix.Name = "txtProjectPrefix";
|
||||
this.txtProjectPrefix.Size = new System.Drawing.Size(150, 23);
|
||||
this.txtProjectPrefix.TabIndex = 8;
|
||||
//
|
||||
// lblRuntimes
|
||||
//
|
||||
this.lblRuntimes.AutoSize = true;
|
||||
this.lblRuntimes.Location = new System.Drawing.Point(345, 129);
|
||||
this.lblRuntimes.Name = "lblRuntimes";
|
||||
this.lblRuntimes.Size = new System.Drawing.Size(121, 15);
|
||||
this.lblRuntimes.TabIndex = 9;
|
||||
this.lblRuntimes.Text = "Runtimes (multiselect)";
|
||||
//
|
||||
// clbRuntimes
|
||||
//
|
||||
this.clbRuntimes.CheckOnClick = true;
|
||||
this.clbRuntimes.FormattingEnabled = true;
|
||||
this.clbRuntimes.Location = new System.Drawing.Point(348, 147);
|
||||
this.clbRuntimes.Name = "clbRuntimes";
|
||||
this.clbRuntimes.Size = new System.Drawing.Size(150, 76);
|
||||
this.clbRuntimes.TabIndex = 10;
|
||||
//
|
||||
// btnAddProject
|
||||
//
|
||||
this.btnAddProject.Location = new System.Drawing.Point(504, 147);
|
||||
this.btnAddProject.Name = "btnAddProject";
|
||||
this.btnAddProject.Size = new System.Drawing.Size(75, 23);
|
||||
this.btnAddProject.TabIndex = 11;
|
||||
this.btnAddProject.Text = "Add";
|
||||
this.btnAddProject.UseVisualStyleBackColor = true;
|
||||
this.btnAddProject.Click += new System.EventHandler(this.btnAddProject_Click);
|
||||
//
|
||||
// lstProjects
|
||||
//
|
||||
this.lstProjects.Anchor = ((System.Windows.Forms.AnchorStyles)((((System.Windows.Forms.AnchorStyles.Top | System.Windows.Forms.AnchorStyles.Bottom)
|
||||
| System.Windows.Forms.AnchorStyles.Left)
|
||||
| System.Windows.Forms.AnchorStyles.Right)));
|
||||
this.lstProjects.FormattingEnabled = true;
|
||||
this.lstProjects.ItemHeight = 15;
|
||||
this.lstProjects.Location = new System.Drawing.Point(16, 236);
|
||||
this.lstProjects.Name = "lstProjects";
|
||||
this.lstProjects.Size = new System.Drawing.Size(563, 139);
|
||||
this.lstProjects.TabIndex = 12;
|
||||
//
|
||||
// btnRemoveSelected
|
||||
//
|
||||
this.btnRemoveSelected.Anchor = ((System.Windows.Forms.AnchorStyles)((System.Windows.Forms.AnchorStyles.Bottom | System.Windows.Forms.AnchorStyles.Left)));
|
||||
this.btnRemoveSelected.Location = new System.Drawing.Point(16, 385);
|
||||
this.btnRemoveSelected.Name = "btnRemoveSelected";
|
||||
this.btnRemoveSelected.Size = new System.Drawing.Size(120, 23);
|
||||
this.btnRemoveSelected.TabIndex = 13;
|
||||
this.btnRemoveSelected.Text = "Remove selected";
|
||||
this.btnRemoveSelected.UseVisualStyleBackColor = true;
|
||||
this.btnRemoveSelected.Click += new System.EventHandler(this.btnRemoveSelected_Click);
|
||||
//
|
||||
// btnOK
|
||||
//
|
||||
this.btnOK.Anchor = ((System.Windows.Forms.AnchorStyles)((System.Windows.Forms.AnchorStyles.Bottom | System.Windows.Forms.AnchorStyles.Right)));
|
||||
this.btnOK.Location = new System.Drawing.Point(423, 385);
|
||||
this.btnOK.Name = "btnOK";
|
||||
this.btnOK.Size = new System.Drawing.Size(75, 23);
|
||||
this.btnOK.TabIndex = 14;
|
||||
this.btnOK.Text = "Create";
|
||||
this.btnOK.UseVisualStyleBackColor = true;
|
||||
this.btnOK.Click += new System.EventHandler(this.btnOK_Click);
|
||||
//
|
||||
// btnCancel
|
||||
//
|
||||
this.btnCancel.Anchor = ((System.Windows.Forms.AnchorStyles)((System.Windows.Forms.AnchorStyles.Bottom | System.Windows.Forms.AnchorStyles.Right)));
|
||||
this.btnCancel.Location = new System.Drawing.Point(504, 385);
|
||||
this.btnCancel.Name = "btnCancel";
|
||||
this.btnCancel.Size = new System.Drawing.Size(75, 23);
|
||||
this.btnCancel.TabIndex = 15;
|
||||
this.btnCancel.Text = "Cancel";
|
||||
this.btnCancel.UseVisualStyleBackColor = true;
|
||||
this.btnCancel.Click += new System.EventHandler(this.btnCancel_Click);
|
||||
//
|
||||
// WizardForm
|
||||
//
|
||||
this.AutoScaleDimensions = new System.Drawing.SizeF(7F, 15F);
|
||||
this.AutoScaleMode = System.Windows.Forms.AutoScaleMode.Font;
|
||||
this.ClientSize = new System.Drawing.Size(592, 420);
|
||||
this.Controls.Add(this.btnCancel);
|
||||
this.Controls.Add(this.btnOK);
|
||||
this.Controls.Add(this.btnRemoveSelected);
|
||||
this.Controls.Add(this.lstProjects);
|
||||
this.Controls.Add(this.btnAddProject);
|
||||
this.Controls.Add(this.clbRuntimes);
|
||||
this.Controls.Add(this.lblRuntimes);
|
||||
this.Controls.Add(this.txtProjectPrefix);
|
||||
this.Controls.Add(this.lblProjectPrefix);
|
||||
this.Controls.Add(this.cboProjectType);
|
||||
this.Controls.Add(this.lblProjectType);
|
||||
this.Controls.Add(this.lblAddProjects);
|
||||
this.Controls.Add(this.lblHint);
|
||||
this.Controls.Add(this.txtExtensionNamespace);
|
||||
this.Controls.Add(this.lblExtensionNamespace);
|
||||
this.Controls.Add(this.lblTitle);
|
||||
this.FormBorderStyle = System.Windows.Forms.FormBorderStyle.FixedDialog;
|
||||
this.MaximizeBox = false;
|
||||
this.MinimizeBox = false;
|
||||
this.Name = "WizardForm";
|
||||
this.StartPosition = System.Windows.Forms.FormStartPosition.CenterParent;
|
||||
this.Text = "Matrix42 Extension Solution Wizard";
|
||||
this.Load += new System.EventHandler(this.WizardForm_Load);
|
||||
this.ResumeLayout(false);
|
||||
this.PerformLayout();
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,164 @@
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Windows.Forms;
|
||||
|
||||
namespace Matrix42.Extensions.Scaffolder.Wizard
|
||||
{
|
||||
public partial class WizardForm : Form
|
||||
{
|
||||
private readonly List<ProjectDefinition> _projects = new List<ProjectDefinition>();
|
||||
|
||||
public string ExtensionNamespace => txtExtensionNamespace.Text.Trim();
|
||||
public IReadOnlyList<ProjectDefinition> Projects => _projects;
|
||||
|
||||
public WizardForm()
|
||||
{
|
||||
InitializeComponent();
|
||||
|
||||
cboProjectType.DataSource = Enum.GetValues(typeof(ProjectType));
|
||||
|
||||
clbRuntimes.Items.Add("Win");
|
||||
clbRuntimes.Items.Add("WinCore");
|
||||
clbRuntimes.Items.Add("LinuxCore");
|
||||
clbRuntimes.Items.Add("ALL");
|
||||
|
||||
cboProjectType.SelectedIndexChanged += CboProjectType_SelectedIndexChanged;
|
||||
}
|
||||
|
||||
private void WizardForm_Load(object sender, EventArgs e)
|
||||
{
|
||||
lblHint.Text = "aka Matrix42.MyExtension";
|
||||
}
|
||||
|
||||
private void CboProjectType_SelectedIndexChanged(object sender, EventArgs e)
|
||||
{
|
||||
var type = (ProjectType)cboProjectType.SelectedItem;
|
||||
switch (type)
|
||||
{
|
||||
case ProjectType.WebApi:
|
||||
txtProjectPrefix.Text = "Services";
|
||||
txtProjectPrefix.ReadOnly = false;
|
||||
break;
|
||||
case ProjectType.Contracts:
|
||||
txtProjectPrefix.Text = "Contracts";
|
||||
txtProjectPrefix.ReadOnly = false;
|
||||
break;
|
||||
case ProjectType.BizLogic:
|
||||
txtProjectPrefix.Text = "BizLogic";
|
||||
txtProjectPrefix.ReadOnly = false;
|
||||
break;
|
||||
case ProjectType.Custom:
|
||||
txtProjectPrefix.Text = string.Empty;
|
||||
txtProjectPrefix.ReadOnly = false;
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
private void btnAddProject_Click(object sender, EventArgs e)
|
||||
{
|
||||
if (!ValidateProjectInputs())
|
||||
return;
|
||||
|
||||
var def = new ProjectDefinition
|
||||
{
|
||||
Type = (ProjectType)cboProjectType.SelectedItem,
|
||||
Prefix = txtProjectPrefix.Text.Trim(),
|
||||
Runtimes = GetSelectedRuntimes()
|
||||
};
|
||||
|
||||
_projects.Add(def);
|
||||
lstProjects.Items.Add(def.Display);
|
||||
|
||||
txtProjectPrefix.Clear();
|
||||
for (int i = 0; i < clbRuntimes.Items.Count; i++)
|
||||
clbRuntimes.SetItemChecked(i, false);
|
||||
}
|
||||
|
||||
private RuntimeTargets GetSelectedRuntimes()
|
||||
{
|
||||
RuntimeTargets result = RuntimeTargets.None;
|
||||
|
||||
foreach (var item in clbRuntimes.CheckedItems)
|
||||
{
|
||||
switch (item.ToString())
|
||||
{
|
||||
case "Win":
|
||||
result |= RuntimeTargets.Win;
|
||||
break;
|
||||
case "WinCore":
|
||||
result |= RuntimeTargets.WinCore;
|
||||
break;
|
||||
case "LinuxCore":
|
||||
result |= RuntimeTargets.LinuxCore;
|
||||
break;
|
||||
case "ALL":
|
||||
result |= RuntimeTargets.All;
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
private bool ValidateProjectInputs()
|
||||
{
|
||||
if (cboProjectType.SelectedItem == null)
|
||||
{
|
||||
MessageBox.Show("Please select project type.");
|
||||
return false;
|
||||
}
|
||||
|
||||
var type = (ProjectType)cboProjectType.SelectedItem;
|
||||
if (string.IsNullOrWhiteSpace(txtProjectPrefix.Text))
|
||||
{
|
||||
if (type == ProjectType.Custom)
|
||||
{
|
||||
MessageBox.Show("Project prefix is required for Custom project type.");
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
if (clbRuntimes.CheckedItems.Count == 0)
|
||||
{
|
||||
MessageBox.Show("Please select at least one runtime.");
|
||||
return false;
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
private void btnRemoveSelected_Click(object sender, EventArgs e)
|
||||
{
|
||||
int idx = lstProjects.SelectedIndex;
|
||||
if (idx < 0 || idx >= _projects.Count)
|
||||
return;
|
||||
|
||||
_projects.RemoveAt(idx);
|
||||
lstProjects.Items.RemoveAt(idx);
|
||||
}
|
||||
|
||||
private void btnOK_Click(object sender, EventArgs e)
|
||||
{
|
||||
if (string.IsNullOrWhiteSpace(ExtensionNamespace))
|
||||
{
|
||||
MessageBox.Show("Extension Namespace is required.");
|
||||
return;
|
||||
}
|
||||
|
||||
if (_projects.Count == 0)
|
||||
{
|
||||
MessageBox.Show("Please add at least one project.");
|
||||
return;
|
||||
}
|
||||
|
||||
DialogResult = DialogResult.OK;
|
||||
Close();
|
||||
}
|
||||
|
||||
private void btnCancel_Click(object sender, EventArgs e)
|
||||
{
|
||||
DialogResult = DialogResult.Cancel;
|
||||
Close();
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,22 @@
|
||||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<PackageManifest Version="2.0.0" xmlns="http://schemas.microsoft.com/developer/vsx-schema/2011" xmlns:d="http://schemas.microsoft.com/developer/vsx-schema-design/2011">
|
||||
<Metadata>
|
||||
<Identity Id="Matrix42.Extensions.Scaffolder.Vsix.7c0f30ed-547f-4e1d-a046-8120ae21fc8b" Version="1.0" Language="en-US" Publisher="Matrix42" />
|
||||
<DisplayName>Matrix42.Extensions.Scaffolder.Vsix</DisplayName>
|
||||
<Description xml:space="preserve">Creates a new Matrix42 extension solution with multiple projects based on Matrix42.Extensions.SDK.</Description>
|
||||
</Metadata>
|
||||
<Installation>
|
||||
<InstallationTarget Id="Microsoft.VisualStudio.Community" Version="[17.0, 18.0)">
|
||||
<ProductArchitecture>amd64</ProductArchitecture>
|
||||
</InstallationTarget>
|
||||
</Installation>
|
||||
<Dependencies>
|
||||
<Dependency Id="Microsoft.Framework.NDP" DisplayName="Microsoft .NET Framework" d:Source="Manual" Version="[4.7,)" />
|
||||
</Dependencies>
|
||||
<Prerequisites>
|
||||
<Prerequisite Id="Microsoft.VisualStudio.Component.CoreEditor" Version="[17.0,18.0)" DisplayName="Visual Studio core editor" />
|
||||
</Prerequisites>
|
||||
<Assets>
|
||||
<Asset Type="Microsoft.VisualStudio.ProjectTemplate" Path="ProjectTemplates\ExtensionSolution.vstemplate" />
|
||||
</Assets>
|
||||
</PackageManifest>
|
||||
@@ -0,0 +1,37 @@
|
||||
|
||||
Microsoft Visual Studio Solution File, Format Version 12.00
|
||||
# Visual Studio Version 17
|
||||
VisualStudioVersion = 17.14.36310.24
|
||||
MinimumVisualStudioVersion = 10.0.40219.1
|
||||
Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "Matrix42.Extensions.Scaffolder.Core", "Matrix42.Extensions.Scaffolder.Core\Matrix42.Extensions.Scaffolder.Core.csproj", "{43E82070-2941-4589-8BF5-1FD1D427BDAE}"
|
||||
EndProject
|
||||
Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "Matrix42.Extensions.Scaffolder.Console", "Matrix42.Extensions.Scaffolder.Console\Matrix42.Extensions.Scaffolder.Console.csproj", "{F7979A70-0D89-46B7-814C-1E7D0B0DF441}"
|
||||
EndProject
|
||||
Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "Matrix42.Extensions.Scaffolder.Vsix", "Matrix42.Extensions.Scaffolder.Vsix\Matrix42.Extensions.Scaffolder.Vsix.csproj", "{50F8DCAA-48B9-47D5-ABB8-F8D33BEF1BD1}"
|
||||
EndProject
|
||||
Global
|
||||
GlobalSection(SolutionConfigurationPlatforms) = preSolution
|
||||
Debug|Any CPU = Debug|Any CPU
|
||||
Release|Any CPU = Release|Any CPU
|
||||
EndGlobalSection
|
||||
GlobalSection(ProjectConfigurationPlatforms) = postSolution
|
||||
{43E82070-2941-4589-8BF5-1FD1D427BDAE}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
|
||||
{43E82070-2941-4589-8BF5-1FD1D427BDAE}.Debug|Any CPU.Build.0 = Debug|Any CPU
|
||||
{43E82070-2941-4589-8BF5-1FD1D427BDAE}.Release|Any CPU.ActiveCfg = Release|Any CPU
|
||||
{43E82070-2941-4589-8BF5-1FD1D427BDAE}.Release|Any CPU.Build.0 = Release|Any CPU
|
||||
{F7979A70-0D89-46B7-814C-1E7D0B0DF441}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
|
||||
{F7979A70-0D89-46B7-814C-1E7D0B0DF441}.Debug|Any CPU.Build.0 = Debug|Any CPU
|
||||
{F7979A70-0D89-46B7-814C-1E7D0B0DF441}.Release|Any CPU.ActiveCfg = Release|Any CPU
|
||||
{F7979A70-0D89-46B7-814C-1E7D0B0DF441}.Release|Any CPU.Build.0 = Release|Any CPU
|
||||
{50F8DCAA-48B9-47D5-ABB8-F8D33BEF1BD1}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
|
||||
{50F8DCAA-48B9-47D5-ABB8-F8D33BEF1BD1}.Debug|Any CPU.Build.0 = Debug|Any CPU
|
||||
{50F8DCAA-48B9-47D5-ABB8-F8D33BEF1BD1}.Release|Any CPU.ActiveCfg = Release|Any CPU
|
||||
{50F8DCAA-48B9-47D5-ABB8-F8D33BEF1BD1}.Release|Any CPU.Build.0 = Release|Any CPU
|
||||
EndGlobalSection
|
||||
GlobalSection(SolutionProperties) = preSolution
|
||||
HideSolutionNode = FALSE
|
||||
EndGlobalSection
|
||||
GlobalSection(ExtensibilityGlobals) = postSolution
|
||||
SolutionGuid = {3329054A-94A3-4953-8650-68C9B450515A}
|
||||
EndGlobalSection
|
||||
EndGlobal
|
||||
17
F4SDM42WebApi/M42ExtensionScaffolder/service-info.yml
Normal file
17
F4SDM42WebApi/M42ExtensionScaffolder/service-info.yml
Normal file
@@ -0,0 +1,17 @@
|
||||
product: "M42 Enterprise" # The project or platform this service belongs to
|
||||
service_name: "Extensions Scaffolder" # Name of the service
|
||||
description: "Template project acting as an extension scaffolder. Automatically generate extension structure including provided projects and runtimes" # A brief description of the service
|
||||
|
||||
owner:
|
||||
name: "Titan" # Owner of the service (could be an individual or team)
|
||||
email: "dmytro.romanii@matrix42.com" # Contact email for the owner
|
||||
|
||||
pipelines:
|
||||
pull_request_pipeline: "N/A" # URL to the pipeline that runs for pull requests
|
||||
ci_pipeline: "N/A" # URL to the continuous integration (CI) pipeline
|
||||
cd_pipeline: "N/A" # URL to the continuous delivery (CD) pipeline
|
||||
|
||||
links:
|
||||
repository: "https://dev.azure.com/matrix42/DWP/_git/M42ExtensionScaffolder"
|
||||
documentation: "https://dev.azure.com/matrix42/DWP/_git/M42ExtensionScaffolder?path=/README.md"
|
||||
backlog: "https://dev.azure.com/matrix42/BPM/_backlogs/backlog/Titan"
|
||||
BIN
F4SDM42WebApi/M42Libraries/26.1/AdminUI.AppManFoundation.dll
Normal file
BIN
F4SDM42WebApi/M42Libraries/26.1/AdminUI.AppManFoundation.dll
Normal file
Binary file not shown.
BIN
F4SDM42WebApi/M42Libraries/26.1/AdminUI.DcmObjectWrapper.dll
Normal file
BIN
F4SDM42WebApi/M42Libraries/26.1/AdminUI.DcmObjectWrapper.dll
Normal file
Binary file not shown.
BIN
F4SDM42WebApi/M42Libraries/26.1/AdminUI.WqlQueryEngine.dll
Normal file
BIN
F4SDM42WebApi/M42Libraries/26.1/AdminUI.WqlQueryEngine.dll
Normal file
Binary file not shown.
BIN
F4SDM42WebApi/M42Libraries/26.1/Ajax.dll
Normal file
BIN
F4SDM42WebApi/M42Libraries/26.1/Ajax.dll
Normal file
Binary file not shown.
BIN
F4SDM42WebApi/M42Libraries/26.1/AjaxControlToolkit.dll
Normal file
BIN
F4SDM42WebApi/M42Libraries/26.1/AjaxControlToolkit.dll
Normal file
Binary file not shown.
BIN
F4SDM42WebApi/M42Libraries/26.1/AngleSharp.dll
Normal file
BIN
F4SDM42WebApi/M42Libraries/26.1/AngleSharp.dll
Normal file
Binary file not shown.
BIN
F4SDM42WebApi/M42Libraries/26.1/AntiXSSLibrary.dll
Normal file
BIN
F4SDM42WebApi/M42Libraries/26.1/AntiXSSLibrary.dll
Normal file
Binary file not shown.
BIN
F4SDM42WebApi/M42Libraries/26.1/AutoMapper.dll
Normal file
BIN
F4SDM42WebApi/M42Libraries/26.1/AutoMapper.dll
Normal file
Binary file not shown.
BIN
F4SDM42WebApi/M42Libraries/26.1/Azure.Core.dll
Normal file
BIN
F4SDM42WebApi/M42Libraries/26.1/Azure.Core.dll
Normal file
Binary file not shown.
BIN
F4SDM42WebApi/M42Libraries/26.1/Azure.Identity.dll
Normal file
BIN
F4SDM42WebApi/M42Libraries/26.1/Azure.Identity.dll
Normal file
Binary file not shown.
BIN
F4SDM42WebApi/M42Libraries/26.1/BouncyCastle.Crypto.dll
Normal file
BIN
F4SDM42WebApi/M42Libraries/26.1/BouncyCastle.Crypto.dll
Normal file
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
BIN
F4SDM42WebApi/M42Libraries/26.1/CsvHelper.dll
Normal file
BIN
F4SDM42WebApi/M42Libraries/26.1/CsvHelper.dll
Normal file
Binary file not shown.
BIN
F4SDM42WebApi/M42Libraries/26.1/DcmObjectModel.dll
Normal file
BIN
F4SDM42WebApi/M42Libraries/26.1/DcmObjectModel.dll
Normal file
Binary file not shown.
BIN
F4SDM42WebApi/M42Libraries/26.1/EPPlus.dll
Normal file
BIN
F4SDM42WebApi/M42Libraries/26.1/EPPlus.dll
Normal file
Binary file not shown.
BIN
F4SDM42WebApi/M42Libraries/26.1/EntityFramework.SqlServer.dll
Normal file
BIN
F4SDM42WebApi/M42Libraries/26.1/EntityFramework.SqlServer.dll
Normal file
Binary file not shown.
BIN
F4SDM42WebApi/M42Libraries/26.1/EntityFramework.dll
Normal file
BIN
F4SDM42WebApi/M42Libraries/26.1/EntityFramework.dll
Normal file
Binary file not shown.
Binary file not shown.
BIN
F4SDM42WebApi/M42Libraries/26.1/Google.Apis.Auth.dll
Normal file
BIN
F4SDM42WebApi/M42Libraries/26.1/Google.Apis.Auth.dll
Normal file
Binary file not shown.
BIN
F4SDM42WebApi/M42Libraries/26.1/Google.Apis.Core.dll
Normal file
BIN
F4SDM42WebApi/M42Libraries/26.1/Google.Apis.Core.dll
Normal file
Binary file not shown.
BIN
F4SDM42WebApi/M42Libraries/26.1/Google.Apis.Gmail.v1.dll
Normal file
BIN
F4SDM42WebApi/M42Libraries/26.1/Google.Apis.Gmail.v1.dll
Normal file
Binary file not shown.
BIN
F4SDM42WebApi/M42Libraries/26.1/Google.Apis.PlatformServices.dll
Normal file
BIN
F4SDM42WebApi/M42Libraries/26.1/Google.Apis.PlatformServices.dll
Normal file
Binary file not shown.
BIN
F4SDM42WebApi/M42Libraries/26.1/Google.Apis.dll
Normal file
BIN
F4SDM42WebApi/M42Libraries/26.1/Google.Apis.dll
Normal file
Binary file not shown.
BIN
F4SDM42WebApi/M42Libraries/26.1/HtmlAgilityPack.dll
Normal file
BIN
F4SDM42WebApi/M42Libraries/26.1/HtmlAgilityPack.dll
Normal file
Binary file not shown.
BIN
F4SDM42WebApi/M42Libraries/26.1/ICSharpCode.SharpZipLib.dll
Normal file
BIN
F4SDM42WebApi/M42Libraries/26.1/ICSharpCode.SharpZipLib.dll
Normal file
Binary file not shown.
BIN
F4SDM42WebApi/M42Libraries/26.1/Interop.ActiveDs.dll
Normal file
BIN
F4SDM42WebApi/M42Libraries/26.1/Interop.ActiveDs.dll
Normal file
Binary file not shown.
BIN
F4SDM42WebApi/M42Libraries/26.1/Interop.DTS.dll
Normal file
BIN
F4SDM42WebApi/M42Libraries/26.1/Interop.DTS.dll
Normal file
Binary file not shown.
BIN
F4SDM42WebApi/M42Libraries/26.1/Interop.WindowsInstaller.dll
Normal file
BIN
F4SDM42WebApi/M42Libraries/26.1/Interop.WindowsInstaller.dll
Normal file
Binary file not shown.
BIN
F4SDM42WebApi/M42Libraries/26.1/Ionic.Zip.dll
Normal file
BIN
F4SDM42WebApi/M42Libraries/26.1/Ionic.Zip.dll
Normal file
Binary file not shown.
BIN
F4SDM42WebApi/M42Libraries/26.1/MailBee.NET.dll
Normal file
BIN
F4SDM42WebApi/M42Libraries/26.1/MailBee.NET.dll
Normal file
Binary file not shown.
BIN
F4SDM42WebApi/M42Libraries/26.1/MailKit.dll
Normal file
BIN
F4SDM42WebApi/M42Libraries/26.1/MailKit.dll
Normal file
Binary file not shown.
BIN
F4SDM42WebApi/M42Libraries/26.1/Matrix42.AI.Contracts.dll
Normal file
BIN
F4SDM42WebApi/M42Libraries/26.1/Matrix42.AI.Contracts.dll
Normal file
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
BIN
F4SDM42WebApi/M42Libraries/26.1/Matrix42.Api.Contracts.dll
Normal file
BIN
F4SDM42WebApi/M42Libraries/26.1/Matrix42.Api.Contracts.dll
Normal file
Binary file not shown.
BIN
F4SDM42WebApi/M42Libraries/26.1/Matrix42.Api.DbClient.dll
Normal file
BIN
F4SDM42WebApi/M42Libraries/26.1/Matrix42.Api.DbClient.dll
Normal file
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
BIN
F4SDM42WebApi/M42Libraries/26.1/Matrix42.Auth.BizLogic.dll
Normal file
BIN
F4SDM42WebApi/M42Libraries/26.1/Matrix42.Auth.BizLogic.dll
Normal file
Binary file not shown.
BIN
F4SDM42WebApi/M42Libraries/26.1/Matrix42.Auth.Contracts.dll
Normal file
BIN
F4SDM42WebApi/M42Libraries/26.1/Matrix42.Auth.Contracts.dll
Normal file
Binary file not shown.
BIN
F4SDM42WebApi/M42Libraries/26.1/Matrix42.Auth.Engines.dll
Normal file
BIN
F4SDM42WebApi/M42Libraries/26.1/Matrix42.Auth.Engines.dll
Normal file
Binary file not shown.
BIN
F4SDM42WebApi/M42Libraries/26.1/Matrix42.Auth.STS.dll
Normal file
BIN
F4SDM42WebApi/M42Libraries/26.1/Matrix42.Auth.STS.dll
Normal file
Binary file not shown.
BIN
F4SDM42WebApi/M42Libraries/26.1/Matrix42.Auth.Services.dll
Normal file
BIN
F4SDM42WebApi/M42Libraries/26.1/Matrix42.Auth.Services.dll
Normal file
Binary file not shown.
Binary file not shown.
BIN
F4SDM42WebApi/M42Libraries/26.1/Matrix42.Behaviors.Contracts.dll
Normal file
BIN
F4SDM42WebApi/M42Libraries/26.1/Matrix42.Behaviors.Contracts.dll
Normal file
Binary file not shown.
BIN
F4SDM42WebApi/M42Libraries/26.1/Matrix42.BizLogic.Client.dll
Normal file
BIN
F4SDM42WebApi/M42Libraries/26.1/Matrix42.BizLogic.Client.dll
Normal file
Binary file not shown.
BIN
F4SDM42WebApi/M42Libraries/26.1/Matrix42.BizLogic.Common.dll
Normal file
BIN
F4SDM42WebApi/M42Libraries/26.1/Matrix42.BizLogic.Common.dll
Normal file
Binary file not shown.
BIN
F4SDM42WebApi/M42Libraries/26.1/Matrix42.BizLogic.Journal.dll
Normal file
BIN
F4SDM42WebApi/M42Libraries/26.1/Matrix42.BizLogic.Journal.dll
Normal file
Binary file not shown.
BIN
F4SDM42WebApi/M42Libraries/26.1/Matrix42.Blob.BizLogic.dll
Normal file
BIN
F4SDM42WebApi/M42Libraries/26.1/Matrix42.Blob.BizLogic.dll
Normal file
Binary file not shown.
BIN
F4SDM42WebApi/M42Libraries/26.1/Matrix42.Blob.Contracts.dll
Normal file
BIN
F4SDM42WebApi/M42Libraries/26.1/Matrix42.Blob.Contracts.dll
Normal file
Binary file not shown.
Binary file not shown.
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user