fix: resolve WPF event handler variable scope null exception and dialog itemsource casting
This commit is contained in:
@@ -2,6 +2,10 @@
|
|||||||
|
|
||||||
## [v1.7.0] - 2026-10-21
|
## [v1.7.0] - 2026-10-21
|
||||||
### Fixed & Improved
|
### Fixed & Improved
|
||||||
|
- **WPF UI 이벤트 핸들러 스코프(`& $null`) 및 ShowDialog 런타임 예외 해결**:
|
||||||
|
- `Start-App.ps1`: `BtnLaunchResolver`, `BtnDetectActiveDc`, `CmbSqlAuthType`, `BtnReloadConfig`, `BtnResolveUsers` 등 WPF UI 컴포넌트 이벤트 발생 시, 함수 로컬 스코프 종료로 인해 변수가 `$null`로 평가되어 `& $variable` 호출 시 `"파이프라인 요소의 '&' 뒤에 있는 식이 잘못된 개체를 생성했습니다"` 예외를 발생시키던 스코프 바인딩 결함 수정
|
||||||
|
- 모든 UI 이벤트 핸들러 스크립트블록(`$script:handleOpenResolver`, `$script:detectActiveDcAction`, `$script:updateSqlAuthUi`, `$script:runResolutionDialog`, `$script:appendShareLog`)을 `$script:` 스코프로 격상하여 이벤트 디스패처 스레드에서 안전하게 호출되도록 보장
|
||||||
|
- `Show-UserResolverDialog`: 단일 사용자 검증 시 `DataGrid.ItemsSource`에 단일 객체가 전달되어 `IEnumerable` 형 변환 예외가 발생하던 문제를 배열 강제 래핑(`@($results)`)으로 원천 차단
|
||||||
- **NetApp ONTAP REST API Active DC 감지 및 단독 스크립트 실행(Standalone) 지원 강화**:
|
- **NetApp ONTAP REST API Active DC 감지 및 단독 스크립트 실행(Standalone) 지원 강화**:
|
||||||
- **REST API JSON 필드 매핑 수정 (`Modules/NetAppService.ps1`)**:
|
- **REST API JSON 필드 매핑 수정 (`Modules/NetAppService.ps1`)**:
|
||||||
- ONTAP REST API `/api/protocols/cifs/domains`의 `discovered_servers` 하위 개체에서 도메인 컨트롤러 호스트명 키(`server_name`)가 `name`으로 잘못 매핑되어 실서버 연결 시에도 항상 가상 데모 DC(`dc04.corp.local`)로 폴백되던 버그 수정
|
- ONTAP REST API `/api/protocols/cifs/domains`의 `discovered_servers` 하위 개체에서 도메인 컨트롤러 호스트명 키(`server_name`)가 `name`으로 잘못 매핑되어 실서버 연결 시에도 항상 가상 데모 DC(`dc04.corp.local`)로 폴백되던 버그 수정
|
||||||
|
|||||||
+17
-17
@@ -296,11 +296,11 @@ function Show-UserResolverDialog {
|
|||||||
$txtInput.Text = $InitialText
|
$txtInput.Text = $InitialText
|
||||||
}
|
}
|
||||||
|
|
||||||
$runResolution = {
|
$script:runResolutionDialog = {
|
||||||
$raw = if ($txtInput) { $txtInput.Text } else { "" }
|
$raw = if ($txtInput) { $txtInput.Text } else { "" }
|
||||||
$tokens = Parse-MultiUserInput -RawInput $raw
|
$tokens = Parse-MultiUserInput -RawInput $raw
|
||||||
$results = Resolve-UsersWithAmbiguityCheck -Tokens $tokens -Config $global:AppConfig
|
$results = Resolve-UsersWithAmbiguityCheck -Tokens $tokens -Config $global:AppConfig
|
||||||
if ($grid) { $grid.ItemsSource = $results }
|
if ($grid) { $grid.ItemsSource = @($results) }
|
||||||
|
|
||||||
$ambCount = @($results | Where-Object { $_.IsAmbiguous }).Count
|
$ambCount = @($results | Where-Object { $_.IsAmbiguous }).Count
|
||||||
$normCount = @($results | Where-Object { $_.IsResolved -and (-not $_.IsAmbiguous) }).Count
|
$normCount = @($results | Where-Object { $_.IsResolved -and (-not $_.IsAmbiguous) }).Count
|
||||||
@@ -320,14 +320,14 @@ function Show-UserResolverDialog {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
if ($btnResolve) { $btnResolve.add_Click({ & $runResolution }) }
|
if ($btnResolve) { $btnResolve.add_Click({ & $script:runResolutionDialog }) }
|
||||||
if ($btnPaste) {
|
if ($btnPaste) {
|
||||||
$btnPaste.add_Click({
|
$btnPaste.add_Click({
|
||||||
try {
|
try {
|
||||||
$clip = [System.Windows.Clipboard]::GetText()
|
$clip = [System.Windows.Clipboard]::GetText()
|
||||||
if (-not [string]::IsNullOrWhiteSpace($clip)) {
|
if (-not [string]::IsNullOrWhiteSpace($clip)) {
|
||||||
$txtInput.Text = $clip
|
$txtInput.Text = $clip
|
||||||
& $runResolution
|
& $script:runResolutionDialog
|
||||||
}
|
}
|
||||||
} catch {}
|
} catch {}
|
||||||
})
|
})
|
||||||
@@ -390,7 +390,7 @@ function Show-UserResolverDialog {
|
|||||||
}
|
}
|
||||||
|
|
||||||
# Initial Run
|
# Initial Run
|
||||||
& $runResolution
|
& $script:runResolutionDialog
|
||||||
|
|
||||||
$ret = $dialog.ShowDialog()
|
$ret = $dialog.ShowDialog()
|
||||||
if ($ret -eq $true) {
|
if ($ret -eq $true) {
|
||||||
@@ -592,7 +592,7 @@ function Navigate-ToPage {
|
|||||||
$btnClearLog = $view.FindName("BtnClearLog")
|
$btnClearLog = $view.FindName("BtnClearLog")
|
||||||
|
|
||||||
# Helper to append logs
|
# Helper to append logs
|
||||||
$appendShareLog = {
|
$script:appendShareLog = {
|
||||||
param([string]$msg)
|
param([string]$msg)
|
||||||
$v = $ViewCache["ShareAccess"]
|
$v = $ViewCache["ShareAccess"]
|
||||||
if ($v) {
|
if ($v) {
|
||||||
@@ -663,7 +663,7 @@ function Navigate-ToPage {
|
|||||||
$sams = @($checkedUsers | ForEach-Object { $_.SamAccountName })
|
$sams = @($checkedUsers | ForEach-Object { $_.SamAccountName })
|
||||||
$res = Add-UsersToShareAndGroup -ShareName $shareName -SamAccountNames $sams -Config $global:AppConfig
|
$res = Add-UsersToShareAndGroup -ShareName $shareName -SamAccountNames $sams -Config $global:AppConfig
|
||||||
|
|
||||||
foreach ($l in $res.Logs) { & $appendShareLog $l }
|
foreach ($l in $res.Logs) { & $script:appendShareLog $l }
|
||||||
[System.Windows.MessageBox]::Show($res.Message, "그룹 추가 완료", [System.Windows.MessageBoxButton]::OK, [System.Windows.MessageBoxImage]::Information)
|
[System.Windows.MessageBox]::Show($res.Message, "그룹 추가 완료", [System.Windows.MessageBoxButton]::OK, [System.Windows.MessageBoxImage]::Information)
|
||||||
|
|
||||||
& $script:reloadShareData
|
& $script:reloadShareData
|
||||||
@@ -689,7 +689,7 @@ function Navigate-ToPage {
|
|||||||
$sams = @($checkedUsers | ForEach-Object { $_.SamAccountName })
|
$sams = @($checkedUsers | ForEach-Object { $_.SamAccountName })
|
||||||
$res = Remove-UsersFromShareAndGroup -ShareName $shareName -SamAccountNames $sams -Config $global:AppConfig
|
$res = Remove-UsersFromShareAndGroup -ShareName $shareName -SamAccountNames $sams -Config $global:AppConfig
|
||||||
|
|
||||||
foreach ($l in $res.Logs) { & $appendShareLog $l }
|
foreach ($l in $res.Logs) { & $script:appendShareLog $l }
|
||||||
[System.Windows.MessageBox]::Show($res.Message, "그룹 해제 완료", [System.Windows.MessageBoxButton]::OK, [System.Windows.MessageBoxImage]::Information)
|
[System.Windows.MessageBox]::Show($res.Message, "그룹 해제 완료", [System.Windows.MessageBoxButton]::OK, [System.Windows.MessageBoxImage]::Information)
|
||||||
|
|
||||||
& $script:reloadShareData
|
& $script:reloadShareData
|
||||||
@@ -759,7 +759,7 @@ function Navigate-ToPage {
|
|||||||
$txtStatus = $view.FindName("TxtWsExecutionStatus")
|
$txtStatus = $view.FindName("TxtWsExecutionStatus")
|
||||||
|
|
||||||
# Launch Resolver Handler
|
# Launch Resolver Handler
|
||||||
$handleOpenResolver = {
|
$script:handleOpenResolver = {
|
||||||
$curr = if ($txtTokens) { $txtTokens.Text } else { "" }
|
$curr = if ($txtTokens) { $txtTokens.Text } else { "" }
|
||||||
$resolved = Show-UserResolverDialog -InitialText $curr -Owner $mainWindow
|
$resolved = Show-UserResolverDialog -InitialText $curr -Owner $mainWindow
|
||||||
if ($resolved -and $resolved.Count -gt 0) {
|
if ($resolved -and $resolved.Count -gt 0) {
|
||||||
@@ -771,8 +771,8 @@ function Navigate-ToPage {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
if ($btnLaunchResolver) { $btnLaunchResolver.add_Click({ & $handleOpenResolver }) }
|
if ($btnLaunchResolver) { $btnLaunchResolver.add_Click({ & $script:handleOpenResolver }) }
|
||||||
if ($btnOpenStandalone) { $btnOpenStandalone.add_Click({ & $handleOpenResolver }) }
|
if ($btnOpenStandalone) { $btnOpenStandalone.add_Click({ & $script:handleOpenResolver }) }
|
||||||
|
|
||||||
if ($btnQuickCheck) {
|
if ($btnQuickCheck) {
|
||||||
$btnQuickCheck.add_Click({
|
$btnQuickCheck.add_Click({
|
||||||
@@ -792,14 +792,14 @@ function Navigate-ToPage {
|
|||||||
}
|
}
|
||||||
|
|
||||||
# Multi-DC Active DC Detection Handler
|
# Multi-DC Active DC Detection Handler
|
||||||
$detectActiveDcAction = {
|
$script:detectActiveDcAction = {
|
||||||
if ($txtActiveDcInfo) { $txtActiveDcInfo.Text = "NetApp 도메인 컨트롤러 바인딩 탐색 중..." }
|
if ($txtActiveDcInfo) { $txtActiveDcInfo.Text = "NetApp 도메인 컨트롤러 바인딩 탐색 중..." }
|
||||||
$dcInfo = Get-NetAppActiveDc -Config $global:AppConfig
|
$dcInfo = Get-NetAppActiveDc -Config $global:AppConfig
|
||||||
if ($txtActiveDcInfo) {
|
if ($txtActiveDcInfo) {
|
||||||
$txtActiveDcInfo.Text = "Active DC: [$($dcInfo.ActiveDC)] (Node: $($dcInfo.Node), 상태: $($dcInfo.Status))"
|
$txtActiveDcInfo.Text = "Active DC: [$($dcInfo.ActiveDC)] (Node: $($dcInfo.Node), 상태: $($dcInfo.Status))"
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
if ($btnDetectActiveDc) { $btnDetectActiveDc.add_Click({ & $detectActiveDcAction }) }
|
if ($btnDetectActiveDc) { $btnDetectActiveDc.add_Click({ & $script:detectActiveDcAction }) }
|
||||||
|
|
||||||
# Dry-Run Simulation
|
# Dry-Run Simulation
|
||||||
if ($btnDryRun) {
|
if ($btnDryRun) {
|
||||||
@@ -1235,7 +1235,7 @@ function Navigate-ToPage {
|
|||||||
|
|
||||||
& $script:loadSettingsToUI
|
& $script:loadSettingsToUI
|
||||||
|
|
||||||
$updateSqlAuthUi = {
|
$script:updateSqlAuthUi = {
|
||||||
$v = $ViewCache["Settings"]
|
$v = $ViewCache["Settings"]
|
||||||
if (-not $v) { return }
|
if (-not $v) { return }
|
||||||
$cmb = $v.FindName("CmbSqlAuthType")
|
$cmb = $v.FindName("CmbSqlAuthType")
|
||||||
@@ -1283,9 +1283,9 @@ function Navigate-ToPage {
|
|||||||
|
|
||||||
$cmbSqlAuth = $view.FindName("CmbSqlAuthType")
|
$cmbSqlAuth = $view.FindName("CmbSqlAuthType")
|
||||||
if ($cmbSqlAuth) {
|
if ($cmbSqlAuth) {
|
||||||
$cmbSqlAuth.add_SelectionChanged({ & $updateSqlAuthUi })
|
$cmbSqlAuth.add_SelectionChanged({ & $script:updateSqlAuthUi })
|
||||||
}
|
}
|
||||||
& $updateSqlAuthUi
|
& $script:updateSqlAuthUi
|
||||||
|
|
||||||
# Test AD
|
# Test AD
|
||||||
if ($btnTestAd) {
|
if ($btnTestAd) {
|
||||||
@@ -1458,7 +1458,7 @@ function Navigate-ToPage {
|
|||||||
$btnReload.add_Click({
|
$btnReload.add_Click({
|
||||||
$global:AppConfig = Get-AppConfig
|
$global:AppConfig = Get-AppConfig
|
||||||
& $script:loadSettingsToUI
|
& $script:loadSettingsToUI
|
||||||
& $updateSqlAuthUi
|
if ($script:updateSqlAuthUi) { & $script:updateSqlAuthUi }
|
||||||
Update-ModeBadgeUI
|
Update-ModeBadgeUI
|
||||||
[System.Windows.MessageBox]::Show("config.json 설정을 다시 불러왔습니다.", "알림", [System.Windows.MessageBoxButton]::OK, [System.Windows.MessageBoxImage]::Information)
|
[System.Windows.MessageBox]::Show("config.json 설정을 다시 불러왔습니다.", "알림", [System.Windows.MessageBoxButton]::OK, [System.Windows.MessageBoxImage]::Information)
|
||||||
})
|
})
|
||||||
|
|||||||
Reference in New Issue
Block a user