import: merge .wiki/concepts/ from temp prefix into existing dir (history preserved via merge+rename)
This commit is contained in:
125
.wiki/concepts/cms-config-rewrite-pattern.md
Normal file
125
.wiki/concepts/cms-config-rewrite-pattern.md
Normal file
@@ -0,0 +1,125 @@
|
||||
---
|
||||
title: Web.config rewrite — кодировка и connection-string patterns
|
||||
type: concept
|
||||
tags: [iis, webconfig, encoding, powershell, traceback]
|
||||
sources: [../sources/nas-recovery-session-2026-05-18.md]
|
||||
updated: 2026-05-19
|
||||
---
|
||||
|
||||
# Web.config rewrite на Windows: encoding pitfall
|
||||
|
||||
## Сценарий
|
||||
|
||||
После cross-host миграции CMS в VM, нужно переписать connection strings (`192.168.1.10` → `10.0.2.2` или другой host). Делается через SSH/PowerShell `Get-Content`+`-replace`+`Set-Content`.
|
||||
|
||||
## Pitfall: Set-Content без -Encoding
|
||||
|
||||
```powershell
|
||||
# WRONG — на PowerShell 5.1 пишет UTF-16 LE
|
||||
(Get-Content $f -Raw) -replace 'old', 'new' | Set-Content $f -NoNewline
|
||||
```
|
||||
|
||||
**Симптом** после этого:
|
||||
- IIS возвращает `HTTP 500.19 - Internal Server Error`, "Файл конфигурации создан в неправильном формате XML", error code `0x8007000d`.
|
||||
- В детале: первые строки файла показывают артефакты `????????` (UTF-16 в окне UTF-8 ожидаемой проверки).
|
||||
|
||||
**Корень:** PowerShell 5.1 (Windows встроенный) `Set-Content` без `-Encoding` использует **default = UTF-16 LE** (Unicode). IIS ожидает UTF-8 (BOM или без BOM).
|
||||
|
||||
## Правильный способ
|
||||
|
||||
```powershell
|
||||
$utf8WithBom = New-Object System.Text.UTF8Encoding($true)
|
||||
$content = Get-Content $file -Raw
|
||||
$new = $content -replace 'old', 'new'
|
||||
[System.IO.File]::WriteAllText($file, $new, $utf8WithBom)
|
||||
```
|
||||
|
||||
Или, если хочется без BOM:
|
||||
```powershell
|
||||
$utf8NoBom = New-Object System.Text.UTF8Encoding($false)
|
||||
[System.IO.File]::WriteAllText($file, $new, $utf8NoBom)
|
||||
```
|
||||
|
||||
ASP.NET / IIS работают и с BOM, и без — но для дефолтного XML конфига Microsoft предпочитает с BOM.
|
||||
|
||||
### PowerShell 7+ workaround
|
||||
|
||||
В Core: `Set-Content -Encoding utf8` пишет UTF-8 БЕЗ BOM (отличается от PS 5!). `-Encoding utf8BOM` — с BOM.
|
||||
|
||||
## Connection string patterns в CMS
|
||||
|
||||
Нашли в `MoreThenCms.WebUI/Web.config` source (development):
|
||||
|
||||
```xml
|
||||
<add name="MoreThenCmsEntities"
|
||||
connectionString="Data Source=DESKTOP-XYZ\SQLEXPRESS;Initial Catalog=MoreThenCms;
|
||||
Integrated Security=True;MultipleActiveResultSets=True"
|
||||
providerName="System.Data.SqlClient" />
|
||||
```
|
||||
|
||||
В production (внутри OVA, после восстановления):
|
||||
|
||||
```xml
|
||||
<add name="MoreThenCmsEntities"
|
||||
connectionString="Data Source=192.168.1.10;Initial Catalog=MoreThenCms;
|
||||
Integrated Security=False;User Id=snolla;
|
||||
Password=fXkH4@8O%3pc;MultipleActiveResultSets=True"
|
||||
providerName="System.Data.SqlClient" />
|
||||
```
|
||||
|
||||
То есть в prod CMS использует **SQL login `snolla`**, не Integrated Security. Сам логин остался в `master.mdf` после восстановления — никаких дополнительных шагов не понадобилось.
|
||||
|
||||
## Mass-edit нескольких сайтов
|
||||
|
||||
Под Windows VM было 4 Web.config с одинаковым паттерном:
|
||||
|
||||
- `C:\inetpub\wwwroot\MoreThenCms.Web\Web.config`
|
||||
- `C:\inetpub\wwwroot\Snolla.IdentityManager\Web.config`
|
||||
- `C:\stayer\stostayer.old\web.config`
|
||||
- (плюс `C:\stayer\MoreThenCms.Web\` — main stostayer без 192.168.1.10 reference)
|
||||
|
||||
Скрипт через SSH в VM:
|
||||
|
||||
```powershell
|
||||
$files = @(
|
||||
'C:\inetpub\wwwroot\MoreThenCms.Web\Web.config',
|
||||
'C:\inetpub\wwwroot\Snolla.IdentityManager\Web.config',
|
||||
'C:\stayer\stostayer.old\web.config'
|
||||
)
|
||||
$utf8WithBom = New-Object System.Text.UTF8Encoding($true)
|
||||
foreach ($f in $files) {
|
||||
$content = Get-Content $f -Raw
|
||||
$new = $content -replace [regex]::Escape('192.168.1.10'), '10.0.2.2'
|
||||
[System.IO.File]::WriteAllText($f, $new, $utf8WithBom)
|
||||
}
|
||||
# затем
|
||||
iisreset
|
||||
```
|
||||
|
||||
## Storage providers (Azure / MinIO)
|
||||
|
||||
В `appSettings` нашли:
|
||||
|
||||
```xml
|
||||
<add name="azureGalleries" storageType="MoreThenCms.FileStorage.Azure.AzureCloudStorage, ...">
|
||||
<settings>
|
||||
<add name="connectionString"
|
||||
value="DefaultEndpointsProtocol=http;AccountName=snolla;
|
||||
AccountKey=<base64>" />
|
||||
<add name="container" value="galleries" />
|
||||
</settings>
|
||||
</add>
|
||||
```
|
||||
|
||||
Используется **Azure Storage SDK с custom endpoint**. В production endpoint указывает на **MinIO** (S3-compat но **не** Azure-compat — пользователь упомянул "не так всё" и обещал пояснить). Точная схема подключения — TBD, надо изучать `MoreThenCms.FileStorage.Azure.AzureCloudStorage` класс.
|
||||
|
||||
## `[regex]::Escape` для безопасной замены IP
|
||||
|
||||
`192.168.1.10` без escape — точки в regex matchят любой char. Лучше escape:
|
||||
|
||||
```powershell
|
||||
$pattern = [regex]::Escape('192.168.1.10')
|
||||
$new = $content -replace $pattern, '10.0.2.2'
|
||||
```
|
||||
|
||||
Связано: [[snolla-recovery-vm]], [[traefik-on-windows-docker-desktop]].
|
||||
Reference in New Issue
Block a user