Public/Middleware/Enable-KrExceptionHandling.ps1
<# .SYNOPSIS Enables exception handling middleware for a Kestrun server instance. .DESCRIPTION This cmdlet configures the exception handling middleware for a Kestrun server instance, allowing for customizable error handling and response generation. .PARAMETER Server The Kestrun server instance (resolved if omitted via Resolve-KestrunServer). .PARAMETER ExceptionHandlingPath The path to re-execute when an exception occurs (e.g., '/error'). .PARAMETER CreateScopeForErrors If specified, creates a new scope for handling errors. .PARAMETER AllowStatusCode404Response If specified, allows handling of 404 status code responses. .PARAMETER IncludeDetailsInDevelopment If specified, includes detailed error information when the environment is set to Development. .PARAMETER UseProblemDetails If specified, formats error responses using the Problem Details standard (RFC 7807). .PARAMETER Compress If specified, compress the json response for error handling. .PARAMETER DeveloperExceptionPage If specified, enables the Developer Exception Page middleware with default options. .PARAMETER SourceCodeLineCount The number of source code lines to display around the error line in the Developer Exception Page. .PARAMETER SourceCodePath The base path to use for locating source code files in the Developer Exception Page. .PARAMETER LanguageOptions A LanguageOptions object defining the scripting language, code, references, imports, and arguments for custom error handling logic. .PARAMETER ScriptBlock A PowerShell script block to execute for custom error handling logic. .PARAMETER Code A string containing the code to execute for custom error handling logic. .PARAMETER Language The scripting language of the provided code (e.g., PowerShell, CSharp, VisualBasic). .PARAMETER CodeFilePath The file path to a script file containing the code to execute for custom error handling logic. .PARAMETER ExtraRefs An array of additional assemblies to reference when executing the custom error handling code. .PARAMETER Arguments A hashtable of arguments to pass to the custom error handling code. .PARAMETER ExtraImports An array of additional namespaces to import when executing the custom error handling code. .PARAMETER PassThru If specified, returns the modified Kestrun server instance. .OUTPUTS The modified Kestrun server instance if the PassThru parameter is specified; otherwise, no output. .EXAMPLE Enable-KrExceptionHandling -ExceptionHandlingPath '/error' -CreateScopeForErrors -AllowStatusCode404Response -PassThru Enables exception handling middleware on the default Kestrun server instance, re-executing requests to '/error' when exceptions occur, creating a scope for error handling, and allowing handling of 404 status code responses. The modified server instance is returned. .EXAMPLE Enable-KrExceptionHandling -Server $myServer -DeveloperExceptionPage -SourceCodeLineCount 10 -SourceCodePath 'C:\MyApp' Enables the Developer Exception Page middleware on the specified Kestrun server instance, displaying 10 lines of source code around the error line and using 'C:\MyApp' as the base path for source files. .EXAMPLE $langOptions = [Kestrun.Hosting.Options.LanguageOptions]::new() $langOptions.Language = [Kestrun.Scripting.ScriptLanguage]::PowerShell $langOptions.Code = { param($exception) "An error occurred: $($exception.Message)" } Enable-KrExceptionHandling -Server $myServer -LanguageOptions $langOptions Enables custom exception handling on the specified Kestrun server instance, executing the provided PowerShell code block when an exception occurs. The code block receives the exception object as a parameter. The custom error handling logic can be defined using the LanguageOptions, ScriptBlock, Code, or CodeFilePath parameters. .NOTES This function is part of the Kestrun PowerShell module and is used to manage Kestrun servers and their middleware components. #> function Enable-KrExceptionHandling { [KestrunRuntimeApi('Definition')] [CmdletBinding(DefaultParameterSetName = 'Default')] [OutputType([Kestrun.Hosting.KestrunHost])] param( [Parameter(ValueFromPipeline = $true)] [Kestrun.Hosting.KestrunHost] $Server, # Redirect [Parameter(Mandatory = $true, ParameterSetName = 'ExceptionHandlingPath')] [string] $ExceptionHandlingPath, [Parameter(ParameterSetName = 'LanguageOptions')] [Parameter(ParameterSetName = 'ScriptBlock')] [Parameter(ParameterSetName = 'Code')] [Parameter(ParameterSetName = 'CodeFilePath')] [Parameter(ParameterSetName = 'ExceptionHandlingPath')] [switch] $CreateScopeForErrors, [Parameter(ParameterSetName = 'LanguageOptions')] [Parameter(ParameterSetName = 'ScriptBlock')] [Parameter(ParameterSetName = 'Code')] [Parameter(ParameterSetName = 'CodeFilePath')] [Parameter(ParameterSetName = 'ExceptionHandlingPath')] [switch] $AllowStatusCode404Response, [Parameter(ParameterSetName = 'Json')] [switch] $IncludeDetailsInDevelopment, [Parameter(ParameterSetName = 'Json')] [switch] $UseProblemDetails, [Parameter(ParameterSetName = 'Json')] [switch] $Compress, [Parameter(Mandatory = $true, ParameterSetName = 'DeveloperExceptionPage')] [switch] $DeveloperExceptionPage, [Parameter(ParameterSetName = 'DeveloperExceptionPage')] [int] $SourceCodeLineCount, [Parameter(ParameterSetName = 'DeveloperExceptionPage')] [string] $SourceCodePath, # Custom via LanguageOptions or ScriptBlock [Parameter(ParameterSetName = 'LanguageOptions')] [Kestrun.Hosting.Options.LanguageOptions] $LanguageOptions, [Parameter(ParameterSetName = 'ScriptBlock')] [scriptblock] $ScriptBlock, [Parameter(Mandatory = $true, ParameterSetName = 'Code')] [Alias('CodeBlock')] [string]$Code, [Parameter(Mandatory = $true, ParameterSetName = 'Code')] [Kestrun.Scripting.ScriptLanguage]$Language, [Parameter(Mandatory = $true, ParameterSetName = 'CodeFilePath')] [string]$CodeFilePath, [Parameter(ParameterSetName = 'ScriptBlock')] [Parameter(ParameterSetName = 'Code')] [Parameter(ParameterSetName = 'CodeFilePath')] [System.Reflection.Assembly[]]$ExtraRefs = $null, [Parameter(ParameterSetName = 'ScriptBlock')] [Parameter(ParameterSetName = 'Code')] [Parameter(ParameterSetName = 'CodeFilePath')] [hashtable]$Arguments, [Parameter(ParameterSetName = 'ScriptBlock')] [Parameter(ParameterSetName = 'Code')] [Parameter(ParameterSetName = 'CodeFilePath')] [string[]]$ExtraImports = $null, [switch] $PassThru ) begin { $Server = Resolve-KestrunServer -Server $Server } process { $exceptionOptions = [Kestrun.Hosting.Options.ExceptionOptions]::new($Server) # Map direct ExceptionOptions properties from parameters if ($PSBoundParameters.ContainsKey('CreateScopeForErrors')) { $exceptionOptions.CreateScopeForErrors = $CreateScopeForErrors.IsPresent } if ($PSBoundParameters.ContainsKey('AllowStatusCode404Response')) { $exceptionOptions.AllowStatusCode404Response = $AllowStatusCode404Response.IsPresent } if ($PSCmdlet.ParameterSetName -eq 'ExceptionHandlingPath') { $exceptionOptions.ExceptionHandlingPath = [Microsoft.AspNetCore.Http.PathString]::new($ExceptionHandlingPath) } elseif ($PSCmdlet.ParameterSetName -eq 'Json') { # If using JSON fallback, set the options accordingly # If using the JSON fallback, set up the built-in JSON handler $exceptionOptions.UseJsonExceptionHandler($UseProblemDetails.IsPresent, $IncludeDetailsInDevelopment.IsPresent, $Compress.IsPresent) } elseif ($PSCmdlet.ParameterSetName -eq 'LanguageOptions') { # If using LanguageOptions, assign it directly $exceptionOptions.LanguageOptions = $LanguageOptions } elseif ($PSCmdlet.ParameterSetName -eq 'DeveloperExceptionPage') { # Warn if not in Development environment if (-not (Test-KrDebugContext)) { if (Test-KrLogger) { Write-KrLog -Level Warning -Message 'DeveloperExceptionPage is typically used in Development environment. Current environment does not appear to be Development.' } else { Write-Warning -Message 'DeveloperExceptionPage is typically used in Development environment. Current environment does not appear to be Development.' } } # If using Developer Exception Page, set up the options accordingly $exceptionOptions.DeveloperExceptionPageOptions = [Microsoft.AspNetCore.Builder.DeveloperExceptionPageOptions]::new() # Configure Developer Exception Page options if specified if ($PSBoundParameters.ContainsKey('SourceCodeLineCount')) { $exceptionOptions.DeveloperExceptionPageOptions.SourceCodeLineCount = $SourceCodeLineCount } if ($PSBoundParameters.ContainsKey('SourceCodePath')) { $exceptionOptions.DeveloperExceptionPageOptions.FileProvider = [Microsoft.Extensions.FileProviders.PhysicalFileProvider]::new($SourceCodePath) } } elseif ($PSCmdlet.ParameterSetName -ne 'Default') { $lo = [Kestrun.Hosting.Options.LanguageOptions]::new() $lo.ExtraImports = $ExtraImports $lo.ExtraRefs = $ExtraRefs if ($null -ne $Arguments) { $dict = [System.Collections.Generic.Dictionary[string, object]]::new() foreach ($key in $Arguments.Keys) { $dict[$key] = $Arguments[$key] } $lo.Arguments = $dict } switch ($PSCmdlet.ParameterSetName) { 'ScriptBlock' { $lo.Language = [Kestrun.Scripting.ScriptLanguage]::PowerShell $lo.Code = $ScriptBlock.ToString() } 'Code' { $lo.Language = $Language $lo.Code = $Code } 'CodeFilePath' { if (-not (Test-Path -Path $CodeFilePath)) { throw "The specified code file path does not exist: $CodeFilePath" } $extension = Split-Path -Path $CodeFilePath -Extension switch ($extension) { '.ps1' { $lo.Language = [Kestrun.Scripting.ScriptLanguage]::PowerShell } '.cs' { $lo.Language = [Kestrun.Scripting.ScriptLanguage]::CSharp } '.vb' { $lo.Language = [Kestrun.Scripting.ScriptLanguage]::VisualBasic } default { throw "Unsupported '$extension' code file extension." } } $lo.Code = Get-Content -Path $CodeFilePath -Raw } default { throw "Unrecognized ParameterSetName: $($PSCmdlet.ParameterSetName)" } } $exceptionOptions.LanguageOptions = $lo } # Assign the configured options to the server instance $Server.ExceptionOptions = $exceptionOptions if ($PassThru.IsPresent) { # if the PassThru switch is specified, return the modified server instance return $Server } } } |