@ -0,0 +1,50 @@ |
|||
param( |
|||
[string]$branch, |
|||
[string]$newVersion |
|||
) |
|||
|
|||
. ..\nupkg\common.ps1 |
|||
|
|||
if (!$branch) |
|||
{ |
|||
$branch = Read-Host "Enter the branch name" |
|||
} |
|||
|
|||
#----------- Read the current version from common.props ----------- |
|||
$commonPropsFilePath = resolve-path "../common.props" |
|||
$commonPropsXmlCurrent = [xml](Get-Content $commonPropsFilePath ) |
|||
$currentVersion = $commonPropsXmlCurrent.Project.PropertyGroup.Version.Trim() |
|||
|
|||
if (!$newVersion) |
|||
{ |
|||
$newVersion = Read-Host "Current version is '$currentVersion'. Enter the new version (empty for no change) " |
|||
if($newVersion -eq "") |
|||
{ |
|||
$newVersion = $currentVersion |
|||
} |
|||
} |
|||
|
|||
if ($newVersion -ne $currentVersion){ |
|||
# Update common.props for version attribute |
|||
$commonPropsXmlCurrent.Project.PropertyGroup.Version = $newVersion |
|||
$commonPropsXmlCurrent.Save( $commonPropsFilePath ) |
|||
#check if it's updated... |
|||
$commonPropsXmlNew = [xml](Get-Content $commonPropsFilePath ) |
|||
$newVersionAfterUpdate = $commonPropsXmlNew.Project.PropertyGroup.Version |
|||
echo "`n`nNew version updated as '$newVersionAfterUpdate' in $commonPropsFilePath`n" |
|||
} |
|||
|
|||
|
|||
################################################################ |
|||
Write-Info "Pulling ABP $branch branch from GitHub" |
|||
cd .. |
|||
git switch $branch |
|||
git pull origin |
|||
|
|||
################################################################ |
|||
Write-Info "Building ABP repository" |
|||
cd build |
|||
.\build-all-release.ps1 |
|||
|
|||
Write-Info "Completed: Building ABP repository" |
|||
cd ..\deploy #always return to the deploy directory |
|||
@ -0,0 +1,10 @@ |
|||
. ..\nupkg\common.ps1 |
|||
Write-Info "Creating NuGet packages" |
|||
|
|||
echo "`n-----=====[ CREATING NUGET PACKAGES ]=====-----`n" |
|||
cd ..\nupkg |
|||
powershell -File pack.ps1 |
|||
echo "`n-----=====[ CREATING NUGET PACKAGES COMPLETED ]=====-----`n" |
|||
|
|||
Write-Info "Completed: Creating NuGet packages" |
|||
cd ..\deploy #always return to the deploy directory |
|||
@ -0,0 +1,31 @@ |
|||
param( |
|||
[string]$nugetApiKey |
|||
) |
|||
|
|||
. ..\nupkg\common.ps1 |
|||
|
|||
if (!$nugetApiKey) |
|||
{ |
|||
#reading password from file content |
|||
$passwordFileName = "nuget-api-key.txt" |
|||
$pathExists = Test-Path -Path $passwordFileName -PathType Leaf |
|||
if ($pathExists) |
|||
{ |
|||
$nugetApiKey = Get-Content $passwordFileName |
|||
echo "Using NuGet API Key from $passwordFileName ..." |
|||
} |
|||
} |
|||
|
|||
if (!$nugetApiKey) |
|||
{ |
|||
$nugetApiKey = Read-Host "Enter the NuGet API KEY" |
|||
} |
|||
|
|||
Write-Info "Pushing packages to NuGet" |
|||
echo "`n-----=====[ PUSHING PACKAGES TO NUGET ]=====-----`n" |
|||
cd ..\nupkg |
|||
powershell -File push_packages.ps1 $nugetApiKey |
|||
echo "`n-----=====[ PUSHING PACKAGES TO NUGET COMPLETED ]=====-----`n" |
|||
Write-Info "Completed: Pushing packages to NuGet" |
|||
|
|||
cd ..\deploy #always return to the deploy directory |
|||
@ -0,0 +1,39 @@ |
|||
param( |
|||
[string]$npmAuthToken |
|||
) |
|||
|
|||
. ..\nupkg\common.ps1 |
|||
|
|||
if (!$npmAuthToken) |
|||
{ |
|||
#reading password from file content |
|||
$passwordFileName = "npm-auth-token.txt" |
|||
$pathExists = Test-Path -Path $passwordFileName -PathType Leaf |
|||
if ($pathExists) |
|||
{ |
|||
$npmAuthToken = Get-Content $passwordFileName |
|||
echo "Using NPM Auth Token from $passwordFileName ..." |
|||
} |
|||
} |
|||
|
|||
if (!$npmAuthToken) |
|||
{ |
|||
$npmAuthToken = Read-Host "Enter the NPM Auth Token" |
|||
} |
|||
|
|||
cd ..\npm |
|||
|
|||
#---------------------------------------------------------------------------- |
|||
|
|||
echo "`nSetting npmjs.org auth-token token`n" |
|||
npm set //registry.npmjs.org/:_authToken $npmAuthToken |
|||
|
|||
#---------------------------------------------------------------------------- |
|||
|
|||
Write-Info "Pushing MVC packages to NPM" |
|||
echo "`n-----=====[ PUSHING MVC PACKS TO NPM ]=====-----`n" |
|||
powershell -File publish-mvc.ps1 |
|||
echo "`n-----=====[ PUSHING MVC PACKS TO NPM COMPLETED ]=====-----`n" |
|||
Write-Info "Completed: Pushing MVC packages to NPM" |
|||
|
|||
cd ..\deploy #always return to the deploy directory |
|||
@ -0,0 +1,39 @@ |
|||
param( |
|||
[string]$npmAuthToken |
|||
) |
|||
|
|||
. ..\nupkg\common.ps1 |
|||
|
|||
if (!$npmAuthToken) |
|||
{ |
|||
#reading password from file content |
|||
$passwordFileName = "npm-auth-token.txt" |
|||
$pathExists = Test-Path -Path $passwordFileName -PathType Leaf |
|||
if ($pathExists) |
|||
{ |
|||
$npmAuthToken = Get-Content $passwordFileName |
|||
echo "Using NPM Auth Token from $passwordFileName ..." |
|||
} |
|||
} |
|||
|
|||
if (!$npmAuthToken) |
|||
{ |
|||
$npmAuthToken = Read-Host "Enter the NPM Auth Token" |
|||
} |
|||
|
|||
cd ..\npm |
|||
|
|||
#---------------------------------------------------------------------------- |
|||
|
|||
echo "`nSetting npmjs.org auth-token token`n" |
|||
npm set //registry.npmjs.org/:_authToken $npmAuthToken |
|||
|
|||
#---------------------------------------------------------------------------- |
|||
|
|||
Write-Info "Pushing MVC packages to NPM" |
|||
echo "`n-----=====[ PUSHING MVC PACKS TO NPM ]=====-----`n" |
|||
powershell -File publish-ng.ps1 |
|||
echo "`n-----=====[ PUSHING MVC PACKS TO NPM COMPLETED ]=====-----`n" |
|||
Write-Info "Completed: Pushing MVC packages to NPM" |
|||
|
|||
cd ..\deploy #always return to the deploy directory |
|||
@ -0,0 +1,14 @@ |
|||
. ..\nupkg\common.ps1 |
|||
|
|||
cd .. |
|||
|
|||
Write-Info "Committing changes to GitHub" |
|||
echo "`n-----=====[ COMMITTING CHANGES ]=====-----`n" |
|||
git add . |
|||
git commit -m Update_NPM_Package_Versions |
|||
git push |
|||
|
|||
echo "`n-----=====[ COMMITTING CHANGES COMPLETED ]=====-----`n" |
|||
Write-Info "Completed: Committing changes to GitHub" |
|||
|
|||
cd deploy #always return to the deploy directory |
|||
@ -0,0 +1,35 @@ |
|||
#THIS IS NOT BEING USED CURRENTLY. RELEASE GITHUB MANUALLY |
|||
|
|||
# Import the module dynamically from the PowerShell Gallery. Use CurrentUser scope to avoid having to run as admin. |
|||
Import-Module -Name new-github-release-function.psm1 |
|||
|
|||
# Specify the parameters required to create the release. Do it as a hash table for easier readability. |
|||
$newGitHubReleaseParameters = |
|||
@{ |
|||
GitHubUsername = 'abpframework' |
|||
GitHubRepositoryName = 'abp' |
|||
GitHubAccessToken = '*******************' |
|||
ReleaseName = "5.0.0-rc.2" |
|||
TagName = "5.0.0-rc.2" |
|||
ReleaseNotes = "N/A" |
|||
#AssetFilePaths = @('C:\MyProject\Installer.exe','C:\MyProject\Documentation.md') |
|||
IsPreRelease = $true |
|||
IsDraft = $true # Set to true when testing so we don't publish a real release (visible to everyone) by accident. |
|||
} |
|||
|
|||
# Try to create the Release on GitHub and save the results. |
|||
$result = New-GitHubRelease @newGitHubReleaseParameters |
|||
|
|||
# Provide some feedback to the user based on the results. |
|||
if ($result.Succeeded -eq $true) |
|||
{ |
|||
Write-Output "Release published successfully! View it at $($result.ReleaseUrl)" |
|||
} |
|||
elseif ($result.ReleaseCreationSucceeded -eq $false) |
|||
{ |
|||
Write-Error "The release was not created. Error message is: $($result.ErrorMessage)" |
|||
} |
|||
elseif ($result.AllAssetUploadsSucceeded -eq $false) |
|||
{ |
|||
Write-Error "The release was created, but not all of the assets were uploaded to it. View it at $($result.ReleaseUrl). Error message is: $($result.ErrorMessage)" |
|||
} |
|||
@ -0,0 +1,33 @@ |
|||
param( |
|||
[string]$password |
|||
) |
|||
|
|||
. ..\nupkg\common.ps1 |
|||
|
|||
if (!$password) |
|||
{ |
|||
#reading password from file content |
|||
$sshPasswordFileName = "ssh-password.txt" |
|||
$password = Get-Content $sshPasswordFileName |
|||
echo "Using SSH password from $sshPasswordFileName ..." |
|||
} |
|||
|
|||
if (!$password) |
|||
{ |
|||
$password = Read-Host "Enter the Natro jenkins user password" |
|||
} |
|||
|
|||
# Get the current version |
|||
[xml]$commonPropsXml = Get-Content "../common.props" |
|||
$version = $commonPropsXml.Project.PropertyGroup.Version |
|||
echo "`n---===[ Current version: $version ]===---" |
|||
|
|||
#--------------------------------------------------------------------- |
|||
Write-Info "Downloading release zip into Natro" |
|||
echo "`n---===[ Running SSH commands on NATRO ]===---" |
|||
echo "`nDownloading release file into Natro..." |
|||
|
|||
plink.exe -ssh jenkins@94.73.164.234 -pw $password -P 22 -batch "powershell -File c:\ci\scripts\download-latest-abp-release.ps1 ${version}" |
|||
|
|||
Write-Info "Completed: Downloading release zip into Natro completed" |
|||
#--------------------------------------------------------------------- |
|||
@ -0,0 +1,347 @@ |
|||
#Requires -Version 3.0 |
|||
|
|||
function New-GitHubRelease |
|||
{ |
|||
<# |
|||
.SYNOPSIS |
|||
Creates a new Release for the given GitHub repository. |
|||
|
|||
.DESCRIPTION |
|||
Uses the GitHub API to create a new Release for a given repository. |
|||
Allows you to specify all of the Release properties, such as the Tag, Name, Assets, and if it's a Draft or Prerelease or not. |
|||
|
|||
.PARAMETER GitHubUsername |
|||
The username that the GitHub repository exists under. |
|||
e.g. For the repository https://github.com/deadlydog/New-GitHubRelease, the username is 'deadlydog'. |
|||
|
|||
.PARAMETER GitHubRepositoryName |
|||
The name of the repository to create the Release for. |
|||
e.g. For the repository https://github.com/deadlydog/New-GitHubRelease, the repository name is 'New-GitHubRelease'. |
|||
|
|||
.PARAMETER GitHubAccessToken |
|||
The Access Token to use as credentials for GitHub. |
|||
Access tokens can be generated at https://github.com/settings/tokens. |
|||
The access token will need to have the repo/public_repo permission on it for it to be allowed to create a new Release. |
|||
|
|||
.PARAMETER TagName |
|||
The name of the tag to create at the Commitish. |
|||
|
|||
.PARAMETER ReleaseName |
|||
The name to use for the new release. |
|||
If blank, the TagName will be used. |
|||
|
|||
.PARAMETER ReleaseNotes |
|||
The text describing the contents of the release. |
|||
|
|||
.PARAMETER AssetFilePaths |
|||
The full paths of the files to include in the release. |
|||
|
|||
.PARAMETER Commitish |
|||
Specifies the commitish value that determines where the Git tag is created from. |
|||
Can be any branch or commit SHA. Unused if the Git tag already exists. |
|||
Default: the repository's default branch (usually master). |
|||
|
|||
.PARAMETER IsDraft |
|||
True to create a draft (unpublished) release, false to create a published one. |
|||
Default: false |
|||
|
|||
.PARAMETER IsPreRelease |
|||
True to identify the release as a prerelease. false to identify the release as a full release. |
|||
Default: false |
|||
|
|||
.OUTPUTS |
|||
A hash table with the following properties is returned: |
|||
|
|||
Succeeded = $true if the Release was created successfully and all assets were uploaded to it, $false if some part of the process failed. |
|||
ReleaseCreationSucceeded = $true if the Release was created successfully (does not include asset uploads), $false if the Release was not created. |
|||
AllAssetUploadsSucceeded = $true if all assets were uploaded to the Release successfully, $false if one of them failed, $null if there were no assets to upload. |
|||
ReleaseUrl = The URL of the new Release that was created. |
|||
ErrorMessage = A message describing what went wrong in the case that Succeeded is $false. |
|||
|
|||
.EXAMPLE |
|||
# Import the module dynamically from the PowerShell Gallery. Use CurrentUser scope to avoid having to run as admin. |
|||
Import-Module -Name New-GitHubRelease -Scope CurrentUser |
|||
|
|||
# Specify the parameters required to create the release. Do it as a hash table for easier readability. |
|||
$newGitHubReleaseParameters = |
|||
@{ |
|||
GitHubUsername = 'deadlydog' |
|||
GitHubRepositoryName = 'New-GitHubRelease' |
|||
GitHubAccessToken = 'SomeLongHexidecimalString' |
|||
ReleaseName = "New-GitHubRelease v1.0.0" |
|||
TagName = "v1.0.0" |
|||
ReleaseNotes = "This release contains the following changes: ..." |
|||
AssetFilePaths = @('C:\MyProject\Installer.exe','C:\MyProject\Documentation.md') |
|||
IsPreRelease = $false |
|||
IsDraft = $true # Set to true when testing so we don't publish a real release (visible to everyone) by accident. |
|||
} |
|||
|
|||
# Try to create the Release on GitHub and save the results. |
|||
$result = New-GitHubRelease @newGitHubReleaseParameters |
|||
|
|||
# Provide some feedback to the user based on the results. |
|||
if ($result.Succeeded -eq $true) |
|||
{ |
|||
Write-Output "Release published successfully! View it at $($result.ReleaseUrl)" |
|||
} |
|||
elseif ($result.ReleaseCreationSucceeded -eq $false) |
|||
{ |
|||
Write-Error "The release was not created. Error message is: $($result.ErrorMessage)" |
|||
} |
|||
elseif ($result.AllAssetUploadsSucceeded -eq $false) |
|||
{ |
|||
Write-Error "The release was created, but not all of the assets were uploaded to it. View it at $($result.ReleaseUrl). Error message is: $($result.ErrorMessage)" |
|||
} |
|||
|
|||
Attempt to create a new Release on GitHub, and provide feedback to the user indicating if it succeeded or not. |
|||
|
|||
.LINK |
|||
Project home: https://github.com/deadlydog/New-GitHubRelease |
|||
|
|||
.NOTES |
|||
Name: New-GitHubRelease |
|||
Author: Daniel Schroeder (originally based on the script at https://github.com/majkinetor/au/blob/master/scripts/Github-CreateRelease.ps1) |
|||
GitHub Release API Documentation: https://developer.github.com/v3/repos/releases/#create-a-release |
|||
Version: 1.0.2 |
|||
#> |
|||
[CmdletBinding()] |
|||
param |
|||
( |
|||
[Parameter(Mandatory=$true,HelpMessage="The username the repository is under (e.g. deadlydog).")] |
|||
[string] $GitHubUsername, |
|||
|
|||
[Parameter(Mandatory=$true,HelpMessage="The repository name to create the release in (e.g. Invoke-MsBuild).")] |
|||
[string] $GitHubRepositoryName, |
|||
|
|||
[Parameter(Mandatory=$true,HelpMessage="The Acess Token to use as credentials for GitHub.")] |
|||
[string] $GitHubAccessToken, |
|||
|
|||
[Parameter(Mandatory=$true,HelpMessage="The name of the tag to create at the the Commitish.")] |
|||
[string] $TagName, |
|||
|
|||
[Parameter(Mandatory=$false,HelpMessage="The name of the release. If blank, the TagName will be used.")] |
|||
[string] $ReleaseName, |
|||
|
|||
[Parameter(Mandatory=$false,HelpMessage="Text describing the contents of the tag.")] |
|||
[string] $ReleaseNotes, |
|||
|
|||
[Parameter(Mandatory=$false,HelpMessage="The full paths of the files to include in the release.")] |
|||
[string[]] $AssetFilePaths, |
|||
|
|||
[Parameter(Mandatory=$false, HelpMessage="Specifies the commitish value that determines where the Git tag is created from. Can be any branch or commit SHA. Unused if the Git tag already exists. Default: the repository's default branch (usually master).")] |
|||
[string] $Commitish, |
|||
|
|||
[Parameter(Mandatory=$false,HelpMessage="True to create a draft (unpublished) release, false to create a published one. Default: false")] |
|||
[bool] $IsDraft = $false, |
|||
|
|||
[Parameter(Mandatory=$false,HelpMessage="True to identify the release as a prerelease. false to identify the release as a full release. Default: false")] |
|||
[bool] $IsPreRelease = $false |
|||
) |
|||
|
|||
BEGIN |
|||
{ |
|||
# Turn on Strict Mode to help catch syntax-related errors. |
|||
# This must come after a script's/function's param section. |
|||
# Forces a function to be the first non-comment code to appear in a PowerShell Script/Module. |
|||
Set-StrictMode -Version Latest |
|||
|
|||
Set-SecurityProtocolForThread |
|||
|
|||
[string] $NewLine = [Environment]::NewLine |
|||
|
|||
if ([string]::IsNullOrEmpty($ReleaseName)) |
|||
{ |
|||
$ReleaseName = $TagName |
|||
} |
|||
|
|||
# Ensure that all of the given asset file paths to upload are valid. |
|||
Test-AllFilePathsAndThrowErrorIfOneIsNotValid $AssetFilePaths |
|||
} |
|||
|
|||
END { } |
|||
|
|||
PROCESS |
|||
{ |
|||
# Create the hash table to return, with default values. |
|||
$result = @{} |
|||
$result.Succeeded = $false |
|||
$result.ReleaseCreationSucceeded = $false |
|||
$result.AllAssetUploadsSucceeded = $false |
|||
$result.ReleaseUrl = $null |
|||
$result.ErrorMessage = $null |
|||
|
|||
[bool] $thereAreNoAssetsToIncludeInTheRelease = ($AssetFilePaths -eq $null) -or ($AssetFilePaths.Count -le 0) |
|||
if ($thereAreNoAssetsToIncludeInTheRelease) |
|||
{ |
|||
$result.AllAssetUploadsSucceeded = $null |
|||
} |
|||
|
|||
$authHeader = |
|||
@{ |
|||
Authorization = 'Basic ' + [Convert]::ToBase64String([Text.Encoding]::ASCII.GetBytes($GitHubAccessToken + ":x-oauth-basic")) |
|||
} |
|||
|
|||
$releaseData = |
|||
@{ |
|||
tag_name = $TagName |
|||
target_commitish = $Commitish |
|||
name = $ReleaseName |
|||
body = $ReleaseNotes |
|||
draft = $IsDraft |
|||
prerelease = $IsPreRelease |
|||
} |
|||
|
|||
$createReleaseWebRequestParameters = |
|||
@{ |
|||
Uri = "https://api.github.com/repos/$GitHubUsername/$GitHubRepositoryName/releases" |
|||
Method = 'POST' |
|||
Headers = $authHeader |
|||
ContentType = 'application/json' |
|||
Body = (ConvertTo-Json $releaseData -Compress) |
|||
} |
|||
|
|||
try |
|||
{ |
|||
Write-Verbose "Sending web request to create the new Release..." |
|||
$createReleaseWebRequestResults = Invoke-RestMethodAndThrowDescriptiveErrorOnFailure $createReleaseWebRequestParameters |
|||
} |
|||
catch |
|||
{ |
|||
$result.ReleaseCreationSucceeded = $false |
|||
$result.ErrorMessage = $_.Exception.Message |
|||
return $result |
|||
} |
|||
|
|||
$result.ReleaseCreationSucceeded = $true |
|||
$result.ReleaseUrl = $createReleaseWebRequestResults.html_url |
|||
|
|||
if ($thereAreNoAssetsToIncludeInTheRelease) |
|||
{ |
|||
$result.Succeeded = $true |
|||
return $result |
|||
} |
|||
|
|||
# Upload Url has template parameters on the end (e.g. ".../assets{?name,label}"), so remove them. |
|||
[string] $urlToUploadFilesTo = $createReleaseWebRequestResults.upload_url -replace '{.+}' |
|||
|
|||
try |
|||
{ |
|||
Write-Verbose "Uploading asset files to the new release..." |
|||
Send-FilesToGitHubRelease -filePathsToUpload $AssetFilePaths -urlToUploadFilesTo $urlToUploadFilesTo -authHeader $authHeader |
|||
} |
|||
catch |
|||
{ |
|||
$result.AllAssetUploadsSucceeded = $false |
|||
$result.ErrorMessage = $_.Exception.Message |
|||
return $result |
|||
} |
|||
|
|||
$result.AllAssetUploadsSucceeded = $true |
|||
$result.Succeeded = $true |
|||
return $result |
|||
} |
|||
} |
|||
|
|||
function Send-FilesToGitHubRelease([string[]] $filePathsToUpload, [string] $urlToUploadFilesTo, $authHeader) |
|||
{ |
|||
[int] $numberOfFilesToUpload = $filePathsToUpload.Count |
|||
[int] $numberOfFilesUploaded = 0 |
|||
$filePathsToUpload | ForEach-Object ` |
|||
{ |
|||
$filePath = $_ |
|||
$fileName = Get-Item $filePath | Select-Object -ExpandProperty Name |
|||
|
|||
$uploadAssetWebRequestParameters = |
|||
@{ |
|||
# Append the name of the file to the upload url. |
|||
Uri = $urlToUploadFilesTo + "?name=$fileName" |
|||
Method = 'POST' |
|||
Headers = $authHeader |
|||
ContentType = 'application/zip' |
|||
InFile = $filePath |
|||
} |
|||
|
|||
$numberOfFilesUploaded = $numberOfFilesUploaded + 1 |
|||
Write-Verbose "Uploading asset $numberOfFilesUploaded of $numberOfFilesToUpload, '$filePath'." |
|||
Invoke-RestMethodAndThrowDescriptiveErrorOnFailure $uploadAssetWebRequestParameters > $null |
|||
} |
|||
} |
|||
|
|||
function Test-AllFilePathsAndThrowErrorIfOneIsNotValid([string[]] $filePaths) |
|||
{ |
|||
foreach ($filePath in $filePaths) |
|||
{ |
|||
[bool] $fileWasNotFoundAtPath = [string]::IsNullOrEmpty($filePath) -or !(Test-Path -Path $filePath -PathType Leaf) |
|||
if ($fileWasNotFoundAtPath) |
|||
{ |
|||
throw "There is no file at the specified path, '$filePath'." |
|||
} |
|||
} |
|||
} |
|||
|
|||
function Invoke-RestMethodAndThrowDescriptiveErrorOnFailure($requestParametersHashTable) |
|||
{ |
|||
$requestDetailsAsNicelyFormattedString = Convert-HashTableToNicelyFormattedString $requestParametersHashTable |
|||
Write-Verbose "Making web request with the following parameters:$NewLine$requestDetailsAsNicelyFormattedString" |
|||
|
|||
try |
|||
{ |
|||
$webRequestResult = Invoke-RestMethod @requestParametersHashTable |
|||
} |
|||
catch |
|||
{ |
|||
[Exception] $exception = $_.Exception |
|||
|
|||
[string] $errorMessage = Get-RestMethodExceptionDetailsOrNull -restMethodException $exception |
|||
if ([string]::IsNullOrWhiteSpace($errorMessage)) |
|||
{ |
|||
$errorMessage = $exception.ToString() |
|||
} |
|||
|
|||
throw "An unexpected error occurred while making web request:$NewLine$errorMessage" |
|||
} |
|||
|
|||
Write-Verbose "Web request returned the following result:$NewLine$webRequestResult" |
|||
return $webRequestResult |
|||
} |
|||
|
|||
function Get-RestMethodExceptionDetailsOrNull([Exception] $restMethodException) |
|||
{ |
|||
try |
|||
{ |
|||
$responseDetails = @{ |
|||
ResponseUri = $exception.Response.ResponseUri |
|||
StatusCode = $exception.Response.StatusCode |
|||
StatusDescription = $exception.Response.StatusDescription |
|||
ErrorMessage = $exception.Message |
|||
} |
|||
[string] $responseDetailsAsNicelyFormattedString = Convert-HashTableToNicelyFormattedString $responseDetails |
|||
|
|||
[string] $errorInfo = "Request Details:" + $NewLine + $requestDetailsAsNicelyFormattedString |
|||
$errorInfo += $NewLine |
|||
$errorInfo += "Response Details:" + $NewLine + $responseDetailsAsNicelyFormattedString |
|||
return $errorInfo |
|||
} |
|||
catch |
|||
{ |
|||
return $null |
|||
} |
|||
} |
|||
|
|||
function Convert-HashTableToNicelyFormattedString($hashTable) |
|||
{ |
|||
[string] $nicelyFormattedString = $hashTable.Keys | ForEach-Object ` |
|||
{ |
|||
$key = $_ |
|||
$value = $hashTable.$key |
|||
" $key = $value$NewLine" |
|||
} |
|||
return $nicelyFormattedString |
|||
} |
|||
|
|||
function Set-SecurityProtocolForThread |
|||
{ |
|||
[System.Net.ServicePointManager]::SecurityProtocol = [System.Net.SecurityProtocolType]::Tls12 -bor [System.Net.SecurityProtocolType]::Tls11 -bor [System.Net.SecurityProtocolType]::Tls |
|||
} |
|||
|
|||
Export-ModuleMember -Function New-GitHubRelease |
|||
@ -0,0 +1,31 @@ |
|||
# ABP Framework Release Steps |
|||
|
|||
## 1-) Set your secret keys |
|||
|
|||
The following files are ignored from GitHub, therefore you need to create these files in your local environment. |
|||
|
|||
* create `npm-auth-token.txt` file in this folder and write the npmjs.org auth token. it's a GUID type. |
|||
* create `nuget-api-key.txt` file this folder and write your nuget.org API key. |
|||
* create `ssh-password.txt` file and write `jenkins` user SSH password. |
|||
|
|||
## 2-) Run the commands |
|||
|
|||
The commands are the followings: |
|||
|
|||
- **1-fetch-and-build.ps1** |
|||
- You need to enter the branch name. eg: `rel-5.0` |
|||
- You need to enter the new version for this release. eg: `5.0.0-rc.2` |
|||
- **2-nuget-pack.ps1** |
|||
- **3-nuget-push.ps1** |
|||
- **4-npm-publish.ps1** |
|||
- **5-git-commit.ps1** |
|||
- **6-new-github-release.ps1** |
|||
- Note: The step 6 is not active. You need to manually make GitHub release from https://github.com/abpframework/abp/releases/new |
|||
* create tag. eg: `5.0.0-rc.1` |
|||
* create the release from the related branch eg: `rel-5.0` |
|||
* enter the release title. eg: `5.0.0-rc.1` |
|||
* auto generate release notes and delete merge lines |
|||
* check `This is a pre-release` if it's a RC version. |
|||
* click `Publish release` button. |
|||
- **7-download-release-zip.ps1** |
|||
|
|||
@ -0,0 +1,47 @@ |
|||
# ABP.IO Platform 5.0 Final Has Been Released! |
|||
|
|||
[ABP Framework](https://abp.io/) and [ABP Commercial](https://commercial.abp.io/) 5.0 versions have been released today. |
|||
|
|||
## What's new with 5.0? |
|||
|
|||
Since all the new features are already explained in details with the [5.0 RC.1 Announcement Post](https://blog.abp.io/abp/ABP-IO-Platform-5.0-RC-1-Has-Been-Released), I will not repeat all the details again. See the [RC Blog Post](https://blog.abp.io/abp/ABP-IO-Platform-5.0-RC-1-Has-Been-Released) for all the features and enhancements. |
|||
|
|||
## Getting started with 5.0 |
|||
|
|||
### Creating new solutions |
|||
|
|||
You can create a new solution with the ABP Framework version 5.0 by either using the `abp new` command or using the **direct download** tab on the [get started page](https://abp.io/get-started). |
|||
|
|||
Type the following command in a command-line terminal to install the ABP CLI version 5.0: |
|||
|
|||
````bash |
|||
dotnet tool install -g Volo.Abp.Cli --version 5.0.0 |
|||
```` |
|||
|
|||
To upgrade your existing ABP CLI installation: |
|||
|
|||
````bash |
|||
dotnet tool update -g Volo.Abp.Cli --version 5.0.0 |
|||
```` |
|||
|
|||
Then you can create a new solution using the `abp new` command: |
|||
|
|||
````bash |
|||
abp new Acme.BookStore |
|||
```` |
|||
|
|||
> See the [getting started document](https://docs.abp.io/en/abp/latest/Getting-Started) for details. |
|||
|
|||
### Upgrading existing solutions |
|||
|
|||
Check [the migration guide](https://docs.abp.io/en/abp/latest/Migration-Guides/Abp-5_0) for the applications with the version 4.x upgrading to the version 5.0. Also see [the upgrading guide](https://docs.abp.io/en/abp/latest/Upgrading) to understand how to update existing solutions. |
|||
|
|||
## ABP Community Talks 2021.12 |
|||
|
|||
 |
|||
|
|||
As the core ABP development team, we've decided to organize monthly live meetings with the ABP community. The first live meeting will be at **December 16, 2021, 17:00 (UTC)** on YouTube. ABP core team members will present some of the new features coming with ABP 5.0. |
|||
|
|||
**Join this event on the Kommunity platform: https://kommunity.com/volosoft/events/abp-community-talks-4afca9c9** |
|||
|
|||
See you in the event! |
|||
|
After Width: | Height: | Size: 907 KiB |
@ -0,0 +1,717 @@ |
|||
# Integrating DevExpress ASP.NET Core Reporting to ABP MVC Application |
|||
|
|||
In this step by step article, I will demonstrate how to integrate DevExpress Reporting [DocumentViewer](https://docs.devexpress.com/XtraReports/400248/web-reporting/asp-net-core-reporting/document-viewer-in-asp-net-core-applications) and [End-User Report Designer](https://docs.devexpress.com/XtraReports/400249/web-reporting/asp-net-core-reporting/end-user-report-designer-in-asp-net-core-applications) components to an existing ABP application. We will also create core bundling packages for styling, DevExpress javascript components and also DocumentViewer specific bundling packages. |
|||
|
|||
## Create the Project (Optional) |
|||
|
|||
ABP Framework offers startup templates to get to business faster. We can download a new startup template using [ABP CLI](https://docs.abp.io/en/abp/latest/CLI): |
|||
|
|||
````bash |
|||
abp new Acme.BookStore |
|||
```` |
|||
|
|||
After the download is finished, open the solution in Visual Studio (or your favorite IDE): |
|||
|
|||
 |
|||
|
|||
Run the `Acme.BookStore.DbMigrator` application to create the database and seed the initial data (which creates the admin user, admin role, related permissions, etc). Then we can run the `Acme.BookStore.Web` project to see our application working. |
|||
|
|||
> _Default admin username is **admin** and password is **1q2w3E\***_ |
|||
|
|||
## Installing Packages |
|||
|
|||
You can also follow [this documentation](https://js.devexpress.com/Documentation/17_1/Guide/ASP.NET_MVC_Controls/Prerequisites_and_Installation/) to install DevExpress packages into your computer. We will be installing both nuget references and npm references. |
|||
|
|||
> Don't forget to add _"DevExpress NuGet Feed"_ to your **Nuget Package Sources**. |
|||
|
|||
### Adding NuGet Packages |
|||
|
|||
- Add the `<PackageReference Include="DevExtreme.AspNet.Core" Version="21.2.3" />` NuGet package reference to the **Acme.BookStore.Application.Contracts.csproj**. Or run |
|||
|
|||
```csharp |
|||
Install-Package DevExtreme.AspNet.Core |
|||
``` |
|||
|
|||
command under **Acme.BookStore.Application.Contracts** project. |
|||
|
|||
- Add the `<PackageReference Include="DevExpress.AspNetCore.Reporting" Version="21.2.3" />` NuGet package reference to the **Acme.BookStore.Web.csproj**. Or run |
|||
|
|||
```csharp |
|||
Install-Package DevExpress.AspNetCore.Reporting |
|||
``` |
|||
|
|||
command under the **Acme.BookStore.Web** project. **Note:** You need a commercial license to use this package. |
|||
|
|||
### Adding NPM Packages |
|||
|
|||
Open your `Acme.BookStore.Web` project folder with a command line. Add **devextreme** and [other required third party NPM packages](https://docs.devexpress.com/XtraReports/401763/web-reporting/asp-net-core-reporting/end-user-report-designer-in-asp-net-applications/quick-start/add-an-end-user-report-designer-to-an-aspnet-core-application): |
|||
|
|||
- `npm install devexpress-reporting @devexpress/analytics-core devextreme` |
|||
- `npm install globalize jquery-ui-dist cldrjs` |
|||
|
|||
At the end, your `package.json` should look as shown below: |
|||
|
|||
```json |
|||
{ |
|||
"version": "1.0.0", |
|||
"name": "my-app", |
|||
"private": true, |
|||
"dependencies": { |
|||
"@abp/aspnetcore.mvc.ui.theme.basic": "^5.0.0-rc.1", |
|||
"@devexpress/analytics-core": "^21.2.3", |
|||
"cldrjs": "^0.5.5", |
|||
"devexpress-reporting": "^21.2.3", |
|||
"devextreme": "^21.2.3", |
|||
"globalize": "^1.7.0", |
|||
"jquery-ui-dist": "^1.12.1" |
|||
} |
|||
} |
|||
``` |
|||
|
|||
### Adding Resource Mappings |
|||
|
|||
The `devextreme` and third party NPM packages will be saved under the `node_modules` folder. We need to move the needed files in our `wwwroot/libs` folder to use them in the web project. We can do it using the ABP [client side resource mapping](https://docs.abp.io/en/abp/latest/UI/AspNetCore/Client-Side-Package-Management) system. |
|||
|
|||
Open the `abp.resourcemapping.js` file in your `Acme.BookStore.Web` project and add definitions inside the `mappings` object so the final `abp.resourcemapping.js` file can look as shown below: |
|||
|
|||
```javascript |
|||
module.exports = { |
|||
aliases: { |
|||
|
|||
}, |
|||
mappings: { |
|||
"@node_modules/devextreme/dist/**/*": "@libs/devextreme/", |
|||
"@node_modules/jquery-ui-dist/jquery-ui.min.js": "@libs/devextreme/js/", |
|||
"@node_modules/@devexpress/analytics-core/dist/**/*": "@libs/devexpress-analytics-core/", |
|||
"@node_modules/devexpress-reporting/dist/**/*": "@libs/devexpress-reporting/", |
|||
"@node_modules/knockout/build/output/knockout-latest.js":"@libs/devexpress-reporting/js/", |
|||
"@node_modules/cldrjs/dist/cldr.js":"@libs/devexpress-reporting/cldrjs/", |
|||
"@node_modules/cldrjs/dist/cldr/event.js":"@libs/devexpress-reporting/cldrjs/", |
|||
"@node_modules/cldrjs/dist/cldr/supplemental.js":"@libs/devexpress-reporting/cldrjs/", |
|||
"@node_modules/cldrjs/dist/cldr/unresolved.js":"@libs/devexpress-reporting/cldrjs/", |
|||
"@node_modules/globalize/dist/globalize.js":"@libs/devexpress-reporting/globalize/", |
|||
"@node_modules/globalize/dist/globalize/message.js":"@libs/devexpress-reporting/globalize/", |
|||
"@node_modules/globalize/dist/globalize/number.js":"@libs/devexpress-reporting/globalize/", |
|||
"@node_modules/globalize/dist/globalize/currency.js":"@libs/devexpress-reporting/globalize/", |
|||
"@node_modules/globalize/dist/globalize/date.js":"@libs/devexpress-reporting/globalize/", |
|||
"@node_modules/ace-builds/src-min-noconflict/ace.js":"@libs/devexpress-reporting/ace-builds/", |
|||
"@node_modules/ace-builds/src-min-noconflict/ext-language_tools.js":"@libs/devexpress-reporting/ace-builds/", |
|||
"@node_modules/ace-builds/src-min-noconflict/theme-dreamweaver.js":"@libs/devexpress-reporting/ace-builds/", |
|||
"@node_modules/ace-builds/src-min-noconflict/theme-ambiance.js":"@libs/devexpress-reporting/ace-builds/", |
|||
"@node_modules/ace-builds/src-min-noconflict/snippets/text.js":"@libs/devexpress-reporting/ace-builds/" |
|||
} |
|||
}; |
|||
``` |
|||
|
|||
Open your `Acme.BookStore.Web` project folder with a command line and run the `abp install-libs` command. This command will copy the needed library files into the `/wwwroot/libs/devextreme/` folder. |
|||
|
|||
````bash |
|||
abp install-libs |
|||
```` |
|||
|
|||
You can see `devextreme`, `devexpress-reporting` and `devexpress-analytics-core` folders inside the `wwwroot/libs`: |
|||
|
|||
 |
|||
|
|||
|
|||
|
|||
## Bundling |
|||
|
|||
We will create [bundle contributors](https://docs.abp.io/en/abp/latest/UI/AspNetCore/Bundling-Minification) to add the devextreme css and javascript files for DevExpress [DocumentViewer](https://docs.devexpress.com/XtraReports/400248/web-reporting/asp-net-core-reporting/document-viewer-in-asp-net-core-applications) and [End-User Report Designer](https://docs.devexpress.com/XtraReports/400249/web-reporting/asp-net-core-reporting/end-user-report-designer-in-asp-net-core-applications) components. |
|||
|
|||
To utilize bundling better, we will create hierarchical contributors for both styles and scripts as seen below: |
|||
|
|||
 |
|||
|
|||
It is recommended to follow this hierarchy because some of the scripts and styles need to be added before one another. Once you grab the relations between the dependent scripts and styles, you are free to modify the `Bundling hierarchy` as you desire and re-use the contributors for other DevExpress components. |
|||
|
|||
We'll start with creating folders in the `Acme.BookStore.Web` project starting with a folder named **Bundling**. Create the following folders for future usage: |
|||
|
|||
- Create a `Common` folder under `Bundling` folder |
|||
- Create a `Reporting` folder under `Bundling` folder |
|||
- Create a `ThirdParty` folder under `Reporting ` folder |
|||
- Create a `DocumentViewer` folder under `Reporting ` folder |
|||
- Create a `DocumentDesigner` folder under `Reporting ` folder |
|||
|
|||
At the end, you should have a folder structure as shown below: |
|||
|
|||
 |
|||
|
|||
With this structured foldering, you can easily add other devexpress components in an isolated and maintained way. |
|||
|
|||
### Adding the Common Style Contributor |
|||
|
|||
Create a `DevExtremeCommonStyleContributor.cs` file under the `Bundling/Common` folder with the following content: |
|||
|
|||
```csharp |
|||
using System.Collections.Generic; |
|||
using Volo.Abp.AspNetCore.Mvc.UI.Bundling; |
|||
|
|||
namespace Acme.BookStore.Web.Bundling.Common; |
|||
|
|||
public class DevExtremeCommonStyleContributor : BundleContributor |
|||
{ |
|||
public override void ConfigureBundle(BundleConfigurationContext context) |
|||
{ |
|||
context.Files.AddIfNotContains("/libs/devextreme/css/dx.common.css"); |
|||
context.Files.AddIfNotContains("/libs/devextreme/css/dx.light.css"); |
|||
} |
|||
} |
|||
``` |
|||
|
|||
> You can choose other themes than the light theme. Check the `/libs/devextreme/css/` folder and the DevExtreme documentation for other themes. |
|||
|
|||
Now we will add the common bundle to the global style bundles. Open your `Acme.BookStoreWebModule.cs` file in your `Acme.BookStore.Web` project and add the following code into the `ConfigureServices` method: |
|||
|
|||
```csharp |
|||
Configure<AbpBundlingOptions>(options => |
|||
{ |
|||
options |
|||
.StyleBundles |
|||
.Get(StandardBundles.Styles.Global) |
|||
.AddContributors(typeof(DevExtremeCommonStyleContributor)); |
|||
}); |
|||
``` |
|||
|
|||
### Adding the Document Viewer Style Contributor |
|||
|
|||
Create a `DevExpressDocumentViewerStyleContributor.cs` file under the `Bundling/Reporting/DocumentViewer` folder with the following content: |
|||
|
|||
```csharp |
|||
using System.Collections.Generic; |
|||
using Acme.BookStore.Web.Bundling.Common; |
|||
using Volo.Abp.AspNetCore.Mvc.UI.Bundling; |
|||
using Volo.Abp.Modularity; |
|||
|
|||
namespace Acme.BookStore.Web.Bundling.Reporting.DocumentViewer; |
|||
|
|||
[DependsOn( |
|||
typeof(DevExtremeCommonStyleContributor) |
|||
)] |
|||
public class DevExpressDocumentViewerStyleContributor : BundleContributor |
|||
{ |
|||
public override void ConfigureBundle(BundleConfigurationContext context) |
|||
{ |
|||
context.Files.AddIfNotContains("/libs/devexpress-reporting/css/dx-reporting-skeleton-screen.css"); |
|||
context.Files.AddIfNotContains("/libs/devexpress-analytics-core/css/dx-analytics.common.css"); |
|||
context.Files.AddIfNotContains("/libs/devexpress-analytics-core/css/dx-analytics.light.css"); |
|||
context.Files.AddIfNotContains("/libs/devexpress-reporting/css/dx-webdocumentviewer.css"); |
|||
} |
|||
} |
|||
``` |
|||
|
|||
### Adding the Document Designer Style Contributor |
|||
|
|||
Create a `DevExtremeDocumentDesignerStyleContributor.cs` file under the `Bundling/Reporting/DocumentDesigner` folder with the following content: |
|||
|
|||
```csharp |
|||
using System.Collections.Generic; |
|||
using Acme.BookStore.Web.Bundling.Reporting.DocumentViewer; |
|||
using Volo.Abp.AspNetCore.Mvc.UI.Bundling; |
|||
using Volo.Abp.Modularity; |
|||
|
|||
namespace Acme.BookStore.Web.Bundling.Reporting.DocumentDesigner; |
|||
|
|||
[DependsOn( |
|||
typeof(DevExtremeDocumentViewerStyleContributor) |
|||
)] |
|||
public class DevExtremeDocumentDesignerStyleContributor : BundleContributor |
|||
{ |
|||
public override void ConfigureBundle(BundleConfigurationContext context) |
|||
{ |
|||
context.Files.AddIfNotContains("/libs/devexpress-analytics-core/css/dx-querybuilder.css"); |
|||
context.Files.AddIfNotContains("/libs/devexpress-reporting/css/dx-reportdesigner.css"); |
|||
} |
|||
} |
|||
``` |
|||
|
|||
### Adding the Reporting Common Script Contributor |
|||
|
|||
Create a `DevExtremeReportingCommonScriptContributor.cs` file under the `Bundling/Common` folder with the following content: |
|||
|
|||
```csharp |
|||
using System.Collections.Generic; |
|||
using Volo.Abp.AspNetCore.Mvc.UI.Bundling; |
|||
using Volo.Abp.AspNetCore.Mvc.UI.Packages.JQuery; |
|||
using Volo.Abp.Modularity; |
|||
|
|||
namespace Acme.BookStore.Web.Bundling.Common; |
|||
|
|||
[DependsOn( |
|||
typeof(JQueryScriptContributor) |
|||
)] |
|||
public class DevExtremeReportingCommonScriptContributor : BundleContributor |
|||
{ |
|||
public override void ConfigureBundle(BundleConfigurationContext context) |
|||
{ |
|||
context.Files.AddIfNotContains("/libs/devextreme/js/jquery-ui.min.js"); |
|||
context.Files.AddIfNotContains("/libs/devexpress-reporting/js/knockout-latest.js"); |
|||
context.Files.AddIfNotContains("/libs/devextreme/js/dx.all.js"); // Has to be added after jquery and knockout |
|||
} |
|||
} |
|||
``` |
|||
|
|||
The `DevExtremeReportingCommonScriptContributor` depends on the `JQueryScriptContributor` which adds JQuery related files before the DevExpress packages (see the [bundling system](https://docs.abp.io/en/abp/latest/UI/AspNetCore/Bundling-Minification) for details). |
|||
|
|||
> Since not all of the components of DevExtreme use scripts like `knockout.js` and `jquery-ui.js`, we used *ReportingCommon* naming. You can choose another name or a *Common* contributor by only adding `dx.all.js`. |
|||
|
|||
### Adding the Third Party Script Contributor |
|||
|
|||
Create a `DevExpressReportingThirdPartyScriptContributor.cs` file under the `Bundling/Reporting/ThirdParty` folder with the following content: |
|||
|
|||
```csharp |
|||
using System.Collections.Generic; |
|||
using Acme.BookStore.Web.Bundling.Common; |
|||
using Volo.Abp.AspNetCore.Mvc.UI.Bundling; |
|||
using Volo.Abp.Modularity; |
|||
|
|||
namespace Acme.BookStore.Web.Bundling.Reporting.ThirdParty; |
|||
|
|||
[DependsOn( |
|||
typeof(DevExtremeReportingCommonScriptContributor) |
|||
)] |
|||
public class DevExpressReportingThirdPartyScriptContributor : BundleContributor |
|||
{ |
|||
public override void ConfigureBundle(BundleConfigurationContext context) |
|||
{ |
|||
// cldrj related scripts |
|||
context.Files.AddIfNotContains("/libs/devexpress-reporting/cldrjs/cldr.js"); |
|||
context.Files.AddIfNotContains("/libs/devexpress-reporting/cldrjs/event.js"); |
|||
context.Files.AddIfNotContains("/libs/devexpress-reporting/cldrjs/supplemental.js"); |
|||
context.Files.AddIfNotContains("/libs/devexpress-reporting/cldrjs/unresolved.js"); |
|||
// globalize related scripts |
|||
context.Files.AddIfNotContains("/libs/devexpress-reporting/globalize/globalize.js"); |
|||
context.Files.AddIfNotContains("/libs/devexpress-reporting/globalize/currency.js"); |
|||
context.Files.AddIfNotContains("/libs/devexpress-reporting/globalize/date.js"); |
|||
context.Files.AddIfNotContains("/libs/devexpress-reporting/globalize/message.js"); |
|||
context.Files.AddIfNotContains("/libs/devexpress-reporting/globalize/number.js"); |
|||
// ace-builds related scripts |
|||
context.Files.AddIfNotContains("/libs/devexpress-reporting/ace-builds/ace.js"); |
|||
context.Files.AddIfNotContains("/libs/devexpress-reporting/ace-builds/ext-language_tools.js"); |
|||
context.Files.AddIfNotContains("/libs/devexpress-reporting/ace-builds/theme-ambiance.js"); |
|||
context.Files.AddIfNotContains("/libs/devexpress-reporting/ace-builds/theme-dreamweaver.js"); |
|||
context.Files.AddIfNotContains("/libs/devexpress-reporting/ace-builds/text.js"); |
|||
} |
|||
} |
|||
``` |
|||
|
|||
The `DevExpressReportingThirdPartyScriptContributor` depends on the newly created `DevExtremeReportingCommonScriptContributor` which adds the specified scripts before third party scripts. |
|||
|
|||
### Adding the Document Viewer Script Contributor |
|||
|
|||
Create a `DevExpressDocumentViewerScriptContributor.cs` file under the `Bundling/Reporting/DocumentViewer` folder with the following content: |
|||
|
|||
```csharp |
|||
using System.Collections.Generic; |
|||
using Acme.BookStore.Web.Bundling.Reporting.ThirdParty; |
|||
using Volo.Abp.AspNetCore.Mvc.UI.Bundling; |
|||
using Volo.Abp.Modularity; |
|||
|
|||
namespace Acme.BookStore.Web.Bundling.Reporting.DocumentViewer; |
|||
|
|||
[DependsOn(typeof(DevExpressReportingThirdPartyScriptContributor))] |
|||
public class DevExpressDocumentViewerScriptContributor : BundleContributor |
|||
{ |
|||
public override void ConfigureBundle(BundleConfigurationContext context) |
|||
{ |
|||
context.Files.AddIfNotContains("/libs/devexpress-analytics-core/js/dx-analytics-core.min.js"); |
|||
context.Files.AddIfNotContains("/libs/devexpress-reporting/js/dx-webdocumentviewer.min.js"); |
|||
} |
|||
} |
|||
``` |
|||
|
|||
Note that the `DevExpressDocumentViewerScriptContributor` depends on the newly created `DevExpressReportingThirdPartyScriptContributor`. |
|||
|
|||
### Adding the Document Designer Script Contributor |
|||
|
|||
```csharp |
|||
using System.Collections.Generic; |
|||
using Acme.BookStore.Web.Bundling.Reporting.DocumentViewer; |
|||
using Volo.Abp.AspNetCore.Mvc.UI.Bundling; |
|||
using Volo.Abp.Modularity; |
|||
|
|||
namespace Acme.BookStore.Web.Bundling.Reporting.DocumentDesigner; |
|||
|
|||
[DependsOn( |
|||
typeof(DevExpressDocumentViewerScriptContributor) |
|||
)] |
|||
public class DevExpressDocumentDesignerScriptContributor : BundleContributor |
|||
{ |
|||
public override void ConfigureBundle(BundleConfigurationContext context) |
|||
{ |
|||
context.Files.AddIfNotContains("/libs/devexpress-analytics-core/js/dx-querybuilder.min.js"); |
|||
context.Files.AddIfNotContains("/libs/devexpress-reporting/js/dx-reportdesigner.min.js"); |
|||
} |
|||
} |
|||
``` |
|||
|
|||
## End User Report Designer Integration |
|||
|
|||
> You are free to create your desired pages and rooting. This sample will be creating a **Designer** page to demonstrate the layout for the DevExpress reporting components individually. |
|||
|
|||
Create a `Reporting` folder under `Pages` in the `Acme.BookStore.Web` project . |
|||
|
|||
### Adding a Document Designer Page |
|||
|
|||
Create a `Designer.cshtml` Razor page under the `Pages/Reporting` folder and add the following: |
|||
|
|||
```csharp |
|||
@page |
|||
@using Acme.BookStore.Web.Bundling.Reporting.DocumentDesigner |
|||
@using DevExpress.AspNetCore |
|||
@model Acme.BookStore.Web.Pages.Reporting.Designer |
|||
|
|||
@{ |
|||
var designerRender = Html.DevExpress().ReportDesigner("reportDesigner") |
|||
.Height("1000px"); |
|||
@designerRender.RenderHtml() |
|||
} |
|||
|
|||
@section Scripts { |
|||
<abp-style type="typeof(DevExpressDocumentDesignerStyleContributor)"/> |
|||
|
|||
<abp-script type="typeof(DevExpressDocumentDesignerScriptContributor)"/> |
|||
@designerRender.RenderScripts() |
|||
} |
|||
``` |
|||
|
|||
### Adding Controllers |
|||
|
|||
Create a `Controllers` folder and add a `ReportingController.cs` file to contain customized controllers for reporting endpoints: |
|||
|
|||
```csharp |
|||
using DevExpress.AspNetCore.Reporting.QueryBuilder; |
|||
using DevExpress.AspNetCore.Reporting.QueryBuilder.Native.Services; |
|||
using DevExpress.AspNetCore.Reporting.ReportDesigner; |
|||
using DevExpress.AspNetCore.Reporting.ReportDesigner.Native.Services; |
|||
using DevExpress.AspNetCore.Reporting.WebDocumentViewer; |
|||
using DevExpress.AspNetCore.Reporting.WebDocumentViewer.Native.Services; |
|||
|
|||
namespace Acme.BookStore.Web.Controllers; |
|||
|
|||
public class CustomWebDocumentViewerController : WebDocumentViewerController |
|||
{ |
|||
public CustomWebDocumentViewerController(IWebDocumentViewerMvcControllerService controllerService) |
|||
: base(controllerService) |
|||
{ |
|||
} |
|||
} |
|||
|
|||
public class CustomReportDesignerController : ReportDesignerController |
|||
{ |
|||
public CustomReportDesignerController(IReportDesignerMvcControllerService controllerService) |
|||
: base(controllerService) |
|||
{ |
|||
} |
|||
} |
|||
|
|||
public class CustomQueryBuilderController : QueryBuilderController |
|||
{ |
|||
public CustomQueryBuilderController(IQueryBuilderMvcControllerService controllerService) |
|||
: base(controllerService) |
|||
{ |
|||
} |
|||
} |
|||
``` |
|||
|
|||
### Service Configuration and Midware Update |
|||
|
|||
Update the `ConfigureServices` method of the `BookStoreWebModule.cs` file in **Acme.BookStore.Web** project with the following: |
|||
|
|||
```csharp |
|||
context.Services.AddDevExpressControls(); |
|||
context.Services.AddTransient<CustomReportDesignerController>(); |
|||
context.Services.AddTransient<CustomQueryBuilderController>(); |
|||
context.Services.AddTransient<CustomWebDocumentViewerController>(); |
|||
// UnComment this line if you want to use report storage which is used for menus like "Save as" etc. |
|||
//context.Services.AddScoped<ReportStorageWebExtension, CustomReportStorageWebExtension>(); |
|||
``` |
|||
|
|||
Add `UseDevExpressControls` before `UseConfiguredEndpoints` in `OnApplicationInitialization` as the following: |
|||
|
|||
```csharp |
|||
... |
|||
app.UseDevExpressControls(); |
|||
|
|||
app.UseCorrelationId(); |
|||
... |
|||
``` |
|||
|
|||
### Adding Custom Report Storage (Optional) |
|||
|
|||
Create `CustomReportStorageWebExtension.cs` under the **Acme.BookStore.Web** project as below: |
|||
|
|||
```csharp |
|||
using System; |
|||
using System.Collections.Generic; |
|||
using System.IO; |
|||
using System.Linq; |
|||
using DevExpress.XtraReports.UI; |
|||
using Microsoft.AspNetCore.Hosting; |
|||
|
|||
namespace Acme.BookStore.Web; |
|||
|
|||
public class CustomReportStorageWebExtension : DevExpress.XtraReports.Web.Extensions.ReportStorageWebExtension |
|||
{ |
|||
readonly string ReportDirectory; |
|||
const string FileExtension = ".repx"; |
|||
|
|||
public CustomReportStorageWebExtension(IWebHostEnvironment env) |
|||
{ |
|||
ReportDirectory = Path.Combine(env.ContentRootPath, "Reports"); |
|||
if (!Directory.Exists(ReportDirectory)) |
|||
{ |
|||
Directory.CreateDirectory(ReportDirectory); |
|||
} |
|||
} |
|||
|
|||
public override bool CanSetData(string url) |
|||
{ |
|||
return true; |
|||
} |
|||
|
|||
public override bool IsValidUrl(string url) |
|||
{ |
|||
return true; |
|||
} |
|||
|
|||
public override byte[] GetData(string url) |
|||
{ |
|||
try |
|||
{ |
|||
if (Directory.EnumerateFiles(ReportDirectory).Select(Path.GetFileNameWithoutExtension).Contains(url)) |
|||
{ |
|||
return File.ReadAllBytes(Path.Combine(ReportDirectory, url + FileExtension)); |
|||
} |
|||
|
|||
if (ReportsFactory.Reports.ContainsKey(url)) |
|||
{ |
|||
using (MemoryStream ms = new MemoryStream()) |
|||
{ |
|||
ReportsFactory.Reports[url]().SaveLayoutToXml(ms); |
|||
return ms.ToArray(); |
|||
} |
|||
} |
|||
|
|||
throw new DevExpress.XtraReports.Web.ClientControls.FaultException( |
|||
string.Format("Could not find report '{0}'.", url)); |
|||
} |
|||
catch (Exception) |
|||
{ |
|||
throw new DevExpress.XtraReports.Web.ClientControls.FaultException( |
|||
string.Format("Could not find report '{0}'.", url)); |
|||
} |
|||
} |
|||
|
|||
public override Dictionary<string, string> GetUrls() |
|||
{ |
|||
return Directory.GetFiles(ReportDirectory, "*" + FileExtension) |
|||
.Select(Path.GetFileNameWithoutExtension) |
|||
.Concat(ReportsFactory.Reports.Select(x => x.Key)) |
|||
.ToDictionary<string, string>(x => x); |
|||
} |
|||
|
|||
public override void SetData(XtraReport report, string url) |
|||
{ |
|||
report.SaveLayoutToXml(Path.Combine(ReportDirectory, url + FileExtension)); |
|||
} |
|||
|
|||
public override string SetNewData(XtraReport report, string defaultUrl) |
|||
{ |
|||
SetData(report, defaultUrl); |
|||
return defaultUrl; |
|||
} |
|||
} |
|||
|
|||
public class ReportsFactory |
|||
{ |
|||
public static Dictionary<string, Func<XtraReport>> Reports { get; set; } |
|||
} |
|||
``` |
|||
|
|||
> You can check more about it at [DevExpress Report Storage documentation](https://docs.devexpress.com/XtraReports/400211/web-reporting/asp-net-core-reporting/end-user-report-designer-in-asp-net-applications/add-a-report-storage). |
|||
|
|||
### Adding a DataSource To Designer |
|||
|
|||
Update `Designer.cshtml.cs` under `Pages/Reporting` in the **Acme.BookStore.Web** project with the following: |
|||
|
|||
```csharp |
|||
using System; |
|||
using System.Collections.Generic; |
|||
using DevExpress.DataAccess.ConnectionParameters; |
|||
using DevExpress.DataAccess.Json; |
|||
using DevExpress.DataAccess.Sql; |
|||
using DevExpress.XtraReports.UI; |
|||
using Microsoft.AspNetCore.Mvc.RazorPages; |
|||
|
|||
namespace Acme.BookStore.Web.Pages.Reporting; |
|||
|
|||
public class Designer : PageModel |
|||
{ |
|||
public ReportDesignerModel DesignerModel { get; set; } |
|||
|
|||
public void OnGet() |
|||
{ |
|||
// Create a SQL data source. |
|||
// MsSqlConnectionParameters parameters = new MsSqlConnectionParameters("localhost", |
|||
// "dbName", "userName", "password", MsSqlAuthorizationType.SqlServer); |
|||
// SqlDataSource dataSource = new SqlDataSource(parameters); |
|||
// SelectQuery query = SelectQueryFluentBuilder.AddTable("Products").SelectAllColumnsFromTable().Build("Products"); |
|||
// dataSource.Queries.Add(query); |
|||
// dataSource.RebuildResultSchema(); |
|||
|
|||
// Create a JSON data source. |
|||
JsonDataSource jsonDataSource = new JsonDataSource(); |
|||
jsonDataSource.JsonSource = new UriJsonSource(new Uri("https://raw.githubusercontent.com/DevExpress-Examples/DataSources/master/JSON/customers.json")); |
|||
jsonDataSource.Fill(); |
|||
|
|||
|
|||
DesignerModel = new ReportDesignerModel |
|||
{ |
|||
Report = new XtraReport(), |
|||
DataSources = new Dictionary<string, object>() |
|||
}; |
|||
// DesignerModel.DataSources.Add("BookStoreDb", dataSource); |
|||
DesignerModel.DataSources.Add("JsonDataSource", jsonDataSource); |
|||
} |
|||
|
|||
public class ReportDesignerModel |
|||
{ |
|||
public XtraReport Report { get; set; } |
|||
public Dictionary<string, object> DataSources { get; set; } |
|||
} |
|||
} |
|||
``` |
|||
|
|||
This will allow binding the `data-source` for your report designer. Also update `Designer.cshtml` to use these data sources: |
|||
|
|||
```csharp |
|||
@{ |
|||
var designerRender = Html.DevExpress().ReportDesigner("reportDesigner") |
|||
.Height("1000px") |
|||
.Bind(Model.DesignerModel.Report) |
|||
.DataSources(configureDS => |
|||
{ |
|||
foreach (var ds in Model.DesignerModel.DataSources) |
|||
{ |
|||
configureDS.Add(ds.Key, ds.Value); |
|||
} |
|||
}); |
|||
@designerRender.RenderHtml() |
|||
} |
|||
``` |
|||
|
|||
You can now see the **Add New DataSource** icon in the Field List: |
|||
 |
|||
|
|||
> You can check [DevExpress Reporting Use Data Sources and Connections documentations](https://docs.devexpress.com/XtraReports/401896/web-reporting/asp-net-core-reporting/end-user-report-designer-in-asp-net-applications/use-data-sources-and-connections) for more information. |
|||
|
|||
## Document Viewer Integration |
|||
|
|||
> You are free to create your desired pages and rooting. This sample will be creating a **Viewer** page to demonstrate the layout for the DevExpress reporting components individually. |
|||
|
|||
Since End User Report Designer already implements the required controllers for features, you should only add a new page for document viewing. |
|||
|
|||
### Adding a Document Viewer Page |
|||
|
|||
Create a `Viewer.cshtml` Razor page under the `Pages/Reporting` folder and add the following: |
|||
|
|||
```csharp |
|||
@page |
|||
@using Acme.BookStore.Web.Bundling.Reporting.DocumentViewer |
|||
@using DevExpress.AspNetCore |
|||
@model Acme.BookStore.Web.Pages.Reporting.Viewer |
|||
|
|||
@{ |
|||
var viewerRender = Html.DevExpress().WebDocumentViewer("DocumentViewer") |
|||
.Height("1000px") |
|||
.Bind("TestReport"); |
|||
@viewerRender.RenderHtml() |
|||
} |
|||
|
|||
@section Scripts { |
|||
<abp-style type="typeof(DevExpressDocumentViewerStyleContributor)"/> |
|||
|
|||
<abp-script type="typeof(DevExpressDocumentViewerScriptContributor)"/> |
|||
@viewerRender.RenderScripts() |
|||
} |
|||
``` |
|||
|
|||
> Note: `TestReport.repx` file must be found under `Reports` folder in **Acme.BookStore.Web** project. |
|||
|
|||
### Adding the Antiforgery Token or Passing Bearer Token |
|||
|
|||
While exporting data, you may come across **HTTP 400** error which logs as `[ERR] The required antiforgery request token was not provided in either form field "__RequestVerificationToken" or header value "RequestVerificationToken".` Or you may want to pass **Bearer Token**. |
|||
|
|||
To add these functionalities, update the `Viewer.cshtml` file under the `Pages/Reporting` folder in the **Acme.BookStore.Web** project as shown below: |
|||
|
|||
```csharp |
|||
@page |
|||
@using Acme.BookStore.Web.Bundling.Reporting.DocumentViewer |
|||
@using DevExpress.AspNetCore |
|||
@model Acme.BookStore.Web.Pages.Reporting.Viewer |
|||
@inject Microsoft.AspNetCore.Antiforgery.IAntiforgery Xsrf |
|||
|
|||
@functions{ |
|||
public string GetAntiXsrfRequestToken() |
|||
{ |
|||
return Xsrf.GetAndStoreTokens(HttpContext).RequestToken; |
|||
} |
|||
} |
|||
|
|||
<script type="text/javascript"> |
|||
function SetupJwt(bearerToken, xsrf) { |
|||
DevExpress.Analytics.Utils.ajaxSetup.ajaxSettings = { |
|||
headers: { |
|||
//'Authorization': 'Bearer ' + bearerToken, |
|||
'RequestVerificationToken': xsrf |
|||
} |
|||
}; |
|||
} |
|||
|
|||
function AttachXSRFToken_OnExport(args, xsrf) { |
|||
args.FormData["__RequestVerificationToken"] = xsrf; |
|||
} |
|||
|
|||
function WebDocumentViewer_BeforeRender(s, e) { |
|||
SetupJwt('bearer token can be passed here', "@GetAntiXsrfRequestToken()"); |
|||
$(window).on('beforeunload', function(e) { |
|||
s.Close(); |
|||
}); |
|||
} |
|||
function OnViewerExport(_s, e) { |
|||
AttachXSRFToken_OnExport(e, "@GetAntiXsrfRequestToken()"); |
|||
} |
|||
</script> |
|||
|
|||
<input type="hidden" id="RequestVerificationToken" name="RequestVerificationToken" value="@GetAntiXsrfRequestToken()"> |
|||
|
|||
@{ |
|||
var viewerRender = Html.DevExpress().WebDocumentViewer("DocumentViewer") |
|||
.ClientSideEvents(x => |
|||
{ |
|||
x.BeforeRender("WebDocumentViewer_BeforeRender"); |
|||
x.OnExport("OnViewerExport"); |
|||
}) |
|||
.Height("1000px") |
|||
.Bind("CustomerReport"); |
|||
@viewerRender.RenderHtml() |
|||
} |
|||
|
|||
@section Scripts { |
|||
<abp-style type="typeof(DevExpressDocumentViewerStyleContributor)"/> |
|||
|
|||
<abp-script type="typeof(DevExpressDocumentViewerScriptContributor)"/> |
|||
@viewerRender.RenderScripts() |
|||
} |
|||
``` |
|||
|
|||
> You can also add similar configuration to Report Designer for exporting in Preview Mode. |
|||
|
|||
## Result |
|||
|
|||
 |
|||
|
|||
## Source Code |
|||
|
|||
- You can download the source code from [here](https://github.com/abpframework/abp-samples/tree/master/DevExtreme-Reports-Mvc). |
|||
|
After Width: | Height: | Size: 53 KiB |
|
After Width: | Height: | Size: 5.0 KiB |
|
After Width: | Height: | Size: 40 KiB |
|
After Width: | Height: | Size: 8.9 KiB |
|
After Width: | Height: | Size: 116 KiB |
|
After Width: | Height: | Size: 8.8 KiB |
@ -0,0 +1,321 @@ |
|||
# Integrating the Syncfusion MVC Components to the ABP MVC UI |
|||
|
|||
## Introduction |
|||
|
|||
In this article we will see how we can integrate the Syncfusion MVC Components into our ABP application. |
|||
|
|||
## Source Code |
|||
|
|||
You can find the source code of the application at https://github.com/EngincanV/ABP-Syncfusion-Components-Demo. |
|||
|
|||
## Prerequisites |
|||
|
|||
* [.NET 6](https://dotnet.microsoft.com/en-us/download/dotnet/6.0) |
|||
|
|||
* In this article, we will create a new startup template in v5.0.0-rc.2 and if you follow this article from top to bottom and create a new startup template with me, you need to install the [.NET 6 SDK](https://dotnet.microsoft.com/en-us/download/dotnet/6.0) before starting. |
|||
|
|||
**NOTE:** ABP v5.X stable version has been released. You can replace v5.0.0-rc.2 with the latest stable version in your steps. |
|||
|
|||
Also, you need to update your ABP CLI to the v5.0.0-rc.2, you can use the command below to update your CLI version: |
|||
|
|||
```bash |
|||
dotnet tool update Volo.Abp.Cli -g --version 5.0.0-rc.2 |
|||
``` |
|||
|
|||
or install it if you haven't installed it before: |
|||
|
|||
```bash |
|||
dotnet tool install Volo.Abp.Cli -g --version 5.0.0-rc.2 |
|||
``` |
|||
|
|||
## Creating the Solution |
|||
|
|||
In this article, we will create a new startup template with EF Core as a database provider and MVC for the UI framework. But if you already have a project with MVC UI, you don't need to create a new startup template, you can directly implement the following steps to your existing project. |
|||
|
|||
> If you already have a project with MVC/Razor Pages UI, you can skip this section. |
|||
|
|||
We can create a new startup template by using the [ABP CLI](https://docs.abp.io/en/abp/latest/CLI): |
|||
|
|||
```bash |
|||
abp new SyncfusionComponentsDemo -t app --preview |
|||
``` |
|||
|
|||
Our project boilerplate will be ready after the download is finished. Then, we can open the solution and start developing. |
|||
|
|||
## Starting the Development |
|||
|
|||
### Pre-requisite |
|||
|
|||
> If you've already had a license from Syncfusion, you can skip this section. |
|||
|
|||
* The first thing we need to do is create an account to be able to get a license from Syncfusion. |
|||
|
|||
* So, let's navigate to https://www.syncfusion.com/aspnet-core-ui-controls and click the "Download Free Trial" button. |
|||
|
|||
* Then fill the form and start your 30-day free trial. |
|||
|
|||
* After that, navigate to https://www.syncfusion.com/account/manage-trials/downloads to get our license key that will be used in our application. |
|||
|
|||
 |
|||
|
|||
Click the "Get License Key" link for "ASP.NET Core (Essential JS 2)". |
|||
|
|||
 |
|||
|
|||
Then a modal will be opened like in the above image, select a version and click the "Get License Key" button. |
|||
|
|||
 |
|||
|
|||
Lastly, copy the generated license key value. |
|||
|
|||
In order to use the relevant components, Syncfusion needs to check this license key to know that our license is valid. |
|||
|
|||
### Configurations |
|||
|
|||
After providing a license key from Syncfusion, we can start with the configuration that needs to be done in our application. |
|||
|
|||
#### 1-) Install the Syncfusion.EJ2.AspNet.Core package |
|||
|
|||
We need to install the `Syncfusion.EJ2.AspNet.Core` Nuget package to our Web project (*.Web). |
|||
|
|||
We can install it via **Visual Studio's Nuget Package Manager**: |
|||
|
|||
 |
|||
|
|||
or via dotnet cli: |
|||
|
|||
```bash |
|||
dotnet add package Syncfusion.EJ2.AspNet.Core --version 19.3.0.57 |
|||
``` |
|||
|
|||
> In this article, I've used the package in version 19.3.0.57. |
|||
|
|||
#### 2-) Register the License Key |
|||
|
|||
* After installing the package, we need to register our license key to be able to use the Syncfusion Components. |
|||
|
|||
* To register the license key, open your web module class and update the `ConfigureServices` method as follows: |
|||
|
|||
```csharp |
|||
public override void ConfigureServices(ServiceConfigurationContext context) |
|||
{ |
|||
var hostingEnvironment = context.Services.GetHostingEnvironment(); |
|||
var configuration = context.Services.GetConfiguration(); |
|||
|
|||
//Register Syncfusion license |
|||
Syncfusion.Licensing.SyncfusionLicenseProvider.RegisterLicense(licenseKey: configuration["Syncfusion:LicenseKey"].ToString()); |
|||
|
|||
ConfigureUrls(configuration); |
|||
ConfigureBundles(); |
|||
ConfigureAuthentication(context, configuration); |
|||
ConfigureAutoMapper(); |
|||
ConfigureVirtualFileSystem(hostingEnvironment); |
|||
ConfigureLocalizationServices(); |
|||
ConfigureNavigationServices(); |
|||
ConfigureAutoApiControllers(); |
|||
ConfigureSwaggerServices(context.Services); |
|||
} |
|||
``` |
|||
|
|||
Instead of writing the license key directly in here we can define it in the **appsettings.json** file and use it here by using the Configuration system of .NET. |
|||
|
|||
|
|||
* Open your **appsettings.json** file and add a new section named "Syncfusion" as below: |
|||
|
|||
```json |
|||
{ |
|||
//... |
|||
|
|||
"Syncfusion": { |
|||
"LicenseKey": "<your-license-key>" |
|||
} |
|||
} |
|||
``` |
|||
|
|||
> Replace the `<your-license-key> part with your license key that we've obtained in the previous section.` |
|||
|
|||
* To be able to use the Syncfusion Components we need to define them in our **_ViewImports.cshtml** file. By doing that we can use the Syncfusion components everywhere in our application. |
|||
|
|||
* Open your **/Pages/_ViewImports.cshtml** file and add a new tag helper: |
|||
|
|||
```cshtml |
|||
@addTagHelper *, Microsoft.AspNetCore.Mvc.TagHelpers |
|||
@addTagHelper *, Volo.Abp.AspNetCore.Mvc.UI |
|||
@addTagHelper *, Volo.Abp.AspNetCore.Mvc.UI.Bootstrap |
|||
@addTagHelper *, Volo.Abp.AspNetCore.Mvc.UI.Bundling |
|||
@addTagHelper *, Syncfusion.EJ2 //use Syncfusion components |
|||
``` |
|||
|
|||
#### 3-) Adding Syncfusion styles and scripts to our application |
|||
|
|||
Firstly, let's install the `@syncfusion/ej2` package from **npm**. |
|||
|
|||
* Open your **package.json** file and add the `@syncfusion/ej2` package with version **19.3.57**: |
|||
|
|||
```json |
|||
{ |
|||
"version": "1.0.0", |
|||
"name": "my-app", |
|||
"private": true, |
|||
"dependencies": { |
|||
"@abp/aspnetcore.mvc.ui.theme.basic": "^5.0.0-rc.2", |
|||
"@syncfusion/ej2": "^19.3.57" |
|||
} |
|||
} |
|||
``` |
|||
|
|||
* Then, open the **abp.resourcemapping.js** file and update the **mappings** section: |
|||
|
|||
```js |
|||
module.exports = { |
|||
aliases: { |
|||
|
|||
}, |
|||
mappings: { |
|||
"@node_modules/@syncfusion/ej2/dist/ej2.min.js": "@libs/syncfusion/", |
|||
"@node_modules/@syncfusion/ej2/material.css": "@libs/syncfusion/" |
|||
} |
|||
}; |
|||
``` |
|||
|
|||
> ABP copies related packages from **node_modules** folder to the **libs** folder by examining this file. You can read this [document](docs.abp.io/en/abp/latest/UI/AspNetCore/Client-Side-Package-Management#mapping-the-library-resources) for more info. |
|||
|
|||
* Then run the `abp install-libs` to install the dependencies and copy them into the libs folder by your mappings configuration. After running this command, in your **libs** folder it should be a folder named **syncfusion** folder. |
|||
|
|||
 |
|||
|
|||
The last thing we need to do is, add some style and script files provided by Syncfusion, between our head-body tags. |
|||
|
|||
* We can do this by creating two view components (one for Styles and the other for Scripts). Let's do that. |
|||
|
|||
First, create a folder structure as shown below under the **Components** folder. |
|||
|
|||
 |
|||
|
|||
Then open the related files and add the following codes to each of these files. |
|||
|
|||
* **Default.cshtml** (/Components/Syncfusion/Script/Default.cshtml) |
|||
|
|||
```cshtml |
|||
@addTagHelper *, Syncfusion.EJ2 //add this line |
|||
|
|||
<!-- Syncfusion Essential JS 2 Scripts --> |
|||
<script src="/libs/syncfusion/ej2.min.js"></script> |
|||
|
|||
<!-- Syncfusion Essential JS 2 ScriptManager --> |
|||
<ejs-scripts></ejs-scripts> |
|||
``` |
|||
|
|||
* **SyncfusionScriptComponent.cs** |
|||
|
|||
```csharp |
|||
using Microsoft.AspNetCore.Mvc; |
|||
using Volo.Abp.AspNetCore.Mvc; |
|||
|
|||
namespace SyncfusionComponentsDemo.Web.Components.Syncfusion.Script |
|||
{ |
|||
public class SyncfusionScriptComponent : AbpViewComponent |
|||
{ |
|||
public IViewComponentResult Invoke() |
|||
{ |
|||
return View("~/Components/Syncfusion/Script/Default.cshtml"); |
|||
} |
|||
} |
|||
} |
|||
``` |
|||
|
|||
* **Default.cshtml** (/Components/Syncfusion/Style/Default.cshtml) |
|||
|
|||
```cshtml |
|||
<!-- Syncfusion Essential JS 2 Styles --> |
|||
<link rel="stylesheet" href="/libs/syncfusion/material.css"> |
|||
``` |
|||
|
|||
* SyncfusionStyleComponent.cs |
|||
|
|||
```csharp |
|||
using Microsoft.AspNetCore.Mvc; |
|||
using Volo.Abp.AspNetCore.Mvc; |
|||
|
|||
namespace SyncfusionComponentsDemo.Web.Components.Syncfusion.Style |
|||
{ |
|||
public class SyncfusionStyleComponent : AbpViewComponent |
|||
{ |
|||
public IViewComponentResult Invoke() |
|||
{ |
|||
return View("~/Components/Syncfusion/Style/Default.cshtml"); |
|||
} |
|||
} |
|||
} |
|||
``` |
|||
|
|||
After creating these two components, we can use the [**Layout Hooks**](https://docs.abp.io/en/abp/latest/UI/AspNetCore/Layout-Hooks) system of ABP to inject these two components between head and script tags. |
|||
|
|||
To do this, open your web module class and update the `ConfigureServices` method as below: |
|||
|
|||
|
|||
```csharp |
|||
public override void ConfigureServices(ServiceConfigurationContext context) |
|||
{ |
|||
var hostingEnvironment = context.Services.GetHostingEnvironment(); |
|||
var configuration = context.Services.GetConfiguration(); |
|||
|
|||
//Register Syncfusion license |
|||
var licenseKey = configuration["Syncfusion:LicenseKey"].ToString(); |
|||
Syncfusion.Licensing.SyncfusionLicenseProvider.RegisterLicense(licenseKey: licenseKey); |
|||
|
|||
Configure<AbpLayoutHookOptions>(options => |
|||
{ |
|||
//Now, the SyncfusionStyleComponent code will be inserted in the head of the page as the last item. |
|||
options.Add(LayoutHooks.Head.Last, typeof(SyncfusionStyleComponent)); |
|||
|
|||
//the SyncfusionScriptComponent will be inserted in the body of the page as the last item. |
|||
options.Add(LayoutHooks.Body.Last, typeof(SyncfusionScriptComponent)); |
|||
}); |
|||
|
|||
ConfigureUrls(configuration); |
|||
ConfigureBundles(); |
|||
ConfigureAuthentication(context, configuration); |
|||
ConfigureAutoMapper(); |
|||
ConfigureVirtualFileSystem(hostingEnvironment); |
|||
ConfigureLocalizationServices(); |
|||
ConfigureNavigationServices(); |
|||
ConfigureAutoApiControllers(); |
|||
ConfigureSwaggerServices(context.Services); |
|||
} |
|||
``` |
|||
|
|||
After injecting the Syncfusion style and script into our application, our configurations have been completed. We can try with a simple component to see if it works as we expected. |
|||
|
|||
* Let's try with the [Calendar](https://www.syncfusion.com/aspnet-core-ui-controls/calendar) component. Open your **Index.cshtml** file and update with the below content: |
|||
|
|||
```cshtml |
|||
@page |
|||
@using Microsoft.AspNetCore.Mvc.Localization |
|||
@using SyncfusionComponentsDemo.Localization |
|||
@using Volo.Abp.Users |
|||
@model SyncfusionComponentsDemo.Web.Pages.IndexModel |
|||
|
|||
@section styles { |
|||
<abp-style src="/Pages/Index.css" /> |
|||
} |
|||
|
|||
@section scripts { |
|||
<abp-script src="/Pages/Index.js" /> |
|||
} |
|||
|
|||
<div class="container"> |
|||
<h2>Syncfusion - Calendar Component</h2> |
|||
<ejs-calendar id="calendar"></ejs-calendar> |
|||
</div> |
|||
``` |
|||
|
|||
* Then when we run the application, we need to see the relevant calendar component as below. |
|||
|
|||
 |
|||
|
|||
### Conclusion |
|||
|
|||
In this article, we've explained how to integrate the **Syncfusion Components** into our applications. After following this article, you can use the Syncfusion components in your application. |
|||
|
|||
Thanks for reading the article, I hope you've found it useful :) |
|||
|
After Width: | Height: | Size: 26 KiB |
|
After Width: | Height: | Size: 15 KiB |
|
After Width: | Height: | Size: 30 KiB |
|
After Width: | Height: | Size: 45 KiB |
|
After Width: | Height: | Size: 25 KiB |
|
After Width: | Height: | Size: 15 KiB |
|
After Width: | Height: | Size: 53 KiB |
@ -0,0 +1,3 @@ |
|||
# eShopOnAbp |
|||
|
|||
This document is in progress. Please see the source code for now: https://github.com/abpframework/eShopOnAbp |
|||
@ -0,0 +1,71 @@ |
|||
# HTTP Error Reporter Service |
|||
|
|||
`HttpErrorReporterService` is a service which is exposed by `@abp/ng.core` package. HTTP errors can be reported by using this service. The service emits an event when an error is reported and keeps the errors as an array. The [`RestService`](./HTTP-Requests#restservice) uses the `HttpErrorReporterService` for reporting errors. |
|||
|
|||
See the example below to learn how to report an error: |
|||
|
|||
```ts |
|||
import { HttpErrorReporterService } from '@abp/ng.core'; |
|||
import { HttpClient } from '@angular/common/http'; |
|||
import { Injectable } from '@angular/core'; |
|||
import { of } from 'rxjs'; |
|||
import { catchError } from 'rxjs/operators'; |
|||
|
|||
@Injectable() |
|||
export class SomeService { |
|||
constructor(private http: HttpClient, private httpErrorReporter: HttpErrorReporterService) {} |
|||
|
|||
getData() { |
|||
return this.http.get('http://example.com/get-data').pipe( |
|||
catchError(err => { |
|||
this.httpErrorReporter.reportError(err); |
|||
return of(null); |
|||
}), |
|||
); |
|||
} |
|||
} |
|||
``` |
|||
|
|||
See the following example to learn listening the reported errors: |
|||
|
|||
```ts |
|||
import { HttpErrorReporterService } from '@abp/ng.core'; |
|||
import { HttpErrorResponse } from '@angular/common/http'; |
|||
import { Injectable } from '@angular/core'; |
|||
|
|||
@Injectable() |
|||
export class MyErrorHandler { |
|||
constructor(private httpErrorReporter: HttpErrorReporterService) { |
|||
this.handleErrors(); |
|||
} |
|||
|
|||
handleErrors() { |
|||
this.httpErrorReporter.reporter$.subscribe((err: HttpErrorResponse) => { |
|||
// handle the errors here |
|||
}); |
|||
} |
|||
} |
|||
``` |
|||
|
|||
|
|||
## API |
|||
|
|||
|
|||
### `reporter$: Observable<HttpErrorResponse>` |
|||
|
|||
`reporter$` is a getter, returns an observable. It emits an event when a new error is reported. The event value type is `HttpErrorResponse`. |
|||
|
|||
|
|||
### `errors$: Observable<HttpErrorResponse[]>` |
|||
|
|||
`errors$` is a getter, returns an observable. It emits an event when a new error is reported. The event value is all errors reported at runtime. |
|||
|
|||
### `errors: HttpErrorResponse` |
|||
|
|||
`errors` is a getter that returns all errors reported. |
|||
|
|||
|
|||
### `reportError(error: HttpErrorResponse): void` |
|||
|
|||
`reportError` is a method. The errors can be reported via this. |
|||
When an error is reported, the method triggers the `reports$` and `errors$` observables to emit an event. |
|||
|
After Width: | Height: | Size: 76 KiB |
|
Before Width: | Height: | Size: 80 KiB After Width: | Height: | Size: 41 KiB |