Tıklama partisi yerine PowerShell betiklerini kullanarak .NET Framework’ten .NET Core’a geçiş

Womanne

Member


  1. Tıklama partisi yerine PowerShell betiklerini kullanarak .NET Framework’ten .NET Core’a geçiş

Ne yazık ki, Microsoft’un henüz WPF ve Windows Forms projelerini .NET Core’a geçirmek için bir geçiş aracı yoktur. Bu gönderide, taşıma işleminin manuel olarak yaptığı işlerin bir kısmını ortadan kaldıran bir PowerShell betiği tanıtılmaktadır.


.NET Core 3.0, 23 Eylül 2019’da piyasaya sürülecek ve bununla birlikte Windows masaüstü uygulamalarını Windows Forms ve Windows Presentation Foundation (WPF) ile ilk kez .NET Core’da çalıştırabilecek (her ne kadar platformdan bağımsız olmasa da, yalnızca Windows’ta) ) . Mevcut .NET Framework tabanlı masaüstü uygulamalarını geçirmenin faydaları şunları içerir:

  • a) C# 8.0’da yalnızca .NET Core’da kullanılabilen bazı yeni kitaplık işlevleri ve dil özellikleri,
  • b) .NET Core’da CLR ve bazı kitaplık işlevlerinin daha iyi performansı,
  • c) en iyi dağıtım seçenekleri (önceden kurulum olmadan bağımsız dağıtım dahil) e
  • d) bir sistem üzerinde herhangi bir sayıda .NET Core sürümünün yan yana çalışması.
Orgy tıklama geçişi


Ne yazık ki, Microsoft’un henüz .NET Framework projelerini .NET Core’a dönüştürmek için bir geçiş aracı yoktur. “Projeyi .NET Core’a Dönüştür” Pazar Aracı, geçerli .NET Core 3.0 Önizleme veya Sürüm Adayı ile çalışmaz.

Program kodu ve kaynak dosyaları birçok durumda (ancak hepsinde değil) bire bir yeniden kullanılabilirken, proje formatı (.csproj/packages.config) önemli ölçüde değişti. Sonuç olarak, geliştiricilerin birçok küçük manuel adımda .NET Core’a geçmesi gerekir:

  • Kodu ve kaynak dosyasını kopyalayın
  • Yeni bir proje dosyası oluştur
  • Proje referanslarını geri yükle
  • NuGet referanslarını sıfırla
  • Bireysel derlemelere yapılan başvuruları geri yükler
  • Grafikler, metin dosyaları ve diğer kaynaklar için “Kaynak” veya “Gömülü Kaynak” oluşturma eylemini yeniden ayarlayın
  • Muhtemelen diğer dosya türleri için (örn. Entity Framework model dosyaları .edmx veya DatatSet yazıldı .xsd) inşa eylemini ayarlayın
Her bir proje için tüm bunları gözden geçirmelisiniz. Gerçek bir tıklama cümbüşü!


Alternatif: PowerShell betiği aracılığıyla geçiş yapın


Bu gibi durumlarda her zaman olduğu gibi, işimi kolaylaştıran PowerShell betikleri yazıyorum. Örnek olarak bu girişin altında yazdırılan PowerShell betiğini sağlıyorum. İki kitaplıklı (DAL ve BO) bir WPF projesini ve bir birim test projesini (Windows Uygulama Sürücüsü tabanlı UI testleri ile) .NET Framework 4.8’den .NET Core 3.0’a geçirin.

Betik, eski proje dosyasından bazı bilgileri okur (.csproj) (ör. kök ad alanı, proje referansları). Ancak NuGet paketleri söz konusu olduğunda, bu kasıtlı olarak gerçekleşmez çünkü eskileri paketler.configdosyalar yalnızca doğrudan başvuruları değil, aynı zamanda .NET Core proje dosyasındaki yeni dünyada artık açıkça ihtiyaç duyulmayan geçişli başvuruları da içerir. Yeni proje dosyası, .NET Core SDK’da sağlanan araç kullanılarak oluşturulmadı dotnet.exe oluşturuldu, ancak kodda saklanan şablonlarla, çünkü proje dosyasında bazı ayarlar gerekli, örneğin AssemblyInfo.cs.

Bu durumda kullanılan tüm program kodları hala .NET Core 3.0 altında çalıştığı için durum basittir. Bu şekilde, yeni .NET Core programı herhangi bir başka değişiklik yapılmadan başarıyla derlenebilir, başlatılabilir ve sonunda test edilebilir.

Aşağıdaki videoda, klasik .NET Framework uygulaması önce msbuild.exe kullanılarak derleniyor ve ardından başlatılıyor. .NET Framework 4.8 üzerinde çalıştığını uygulamanın başlık çubuğundan anlayabilirsiniz. Bunu, artık başlık çubuğunda .NET Core 3.0’ı görebileceğiniz betikli geçiş ve UI testi takip eder.



Çözüm


Elbette komut dosyası, tüm projeler için herkese uyan tek bir çözüm değildir, ancak bu tür geçiş projeleri için bir şablon olarak tasarlanmıştır. Bu tür betikler şirketimizde, bazen çözümde birkaç düzine bireysel projeyle birlikte, .NET Core 3.0’a birkaç gerçek WPF ve Windows Forms proje geçişi için kullanılmıştır. Bu, birçok manuel ve sıkıcı işi kurtardı.

komut dosyası kodu


Videoda gösterilen PowerShell geçiş betiği için betik kodu aşağıdadır:

. H:TFSINTITV.util.ps1 # PowerShell Utilities, e.g. Head, H1, H2, Info, Error
CLS
Head "Script-based Migration of a classic WPF Project (.NET Framework) to .NET Core 3.0"
Head "(C) Dr. Holger Schwichtenberg 2019"
Head "Version: 2.0 (24.09.2019)"
# ******************************************************

cd $psscriptroot
$ErrorActionPreference = "stop"
$oldPath = "T:MLLWPFMLLWPFClassic"

if ($args[0] -ne $null)
{
$newPath = $args[0]
}
else {
$newPath = "t:MLLWPFMLLWPFCore3"
}

#region -------------------------- Templates
$projWPFTemplate =
@"
<!-- generated by $($MyInvocation.MyCommand.Name) [DATE] -->
<Project Sdk="Microsoft.NET.Sdk.WindowsDesktop">

<PropertyGroup>
<OutputType>[OutputType]</OutputType>
<TargetFramework>netcoreapp3.0</TargetFramework>
<UseWPF>true</UseWPF>
<GenerateAssemblyInfo>false</GenerateAssemblyInfo>
<Deterministic>false</Deterministic>
<RootNamespace>[rootnamespace]</RootNamespace>
<ApplicationIcon>[icon]</ApplicationIcon>
<RuntimeIdentifier>win-x64</RuntimeIdentifier>
<PublishSingleFile>true</PublishSingleFile>
<UseAppHost>true</UseAppHost>
</PropertyGroup>

<!-- Assets -->
<ItemGroup>
[AssetsRef]
</ItemGroup>

<!-- Nuget Packages -->
<ItemGroup>
[NugetReference]
</ItemGroup>

<!-- Projects -->
<ItemGroup>
[ProjectReference]
</ItemGroup>

<!-- DLLs -->
<ItemGroup>
[LibReference]
</ItemGroup>
</Project>

"@

$projLibTemplate =
@"
<!-- generated by $($MyInvocation.MyCommand.Name) [DATE] -->
<Project Sdk="Microsoft.NET.Sdk">

<PropertyGroup>
<OutputType>[OutputType]</OutputType>
<TargetFramework>netcoreapp3.0</TargetFramework>
<GenerateAssemblyInfo>false</GenerateAssemblyInfo>
<Deterministic>false</Deterministic>
<RootNamespace>[rootnamespace]</RootNamespace>

</PropertyGroup>

<!-- Assets -->
<ItemGroup>
[AssetsRef]
</ItemGroup>

<!-- Nuget Packages -->
<ItemGroup>
[NugetReference]
</ItemGroup>

<!-- Projects -->
<ItemGroup>
[ProjectReference]
</ItemGroup>

<!-- DLLs -->
<ItemGroup>
[LibReference]
</ItemGroup>
</Project>

"@

$NugetRefTemplate=
@"
<PackageReference Include="NAME" Version="VERSION" />
"@

$ProjRefTemplate=
@"
<ProjectReference Include="TODO" />
"@

$LibRefTemplate=
@"
<Reference Include="TODO">
<HintPath>.._LibsTODO.dll</HintPath>
</Reference>
"@

$AssetTemplate=
@"
<Resource Include="FILE" />
"@
#endregion

function Migrate-Project($projectfile, $template, $newPath, $outputtype, $projects, $libs, $nugets)
{ <#
.SYNOPSIS
convert a .NET Framework project to .NET Core
#>
h1 "Converting .NET Framework project to .NET Core"

#region -------------------------- Getting data from existing project file
h2 "Getting data from existing project file..."
$projectfile = [System.IO.Path]::Combine($oldPath, $projectfile)
print "Project file: $projectfile"
$sourcefolder = (get-item $projectfile).DirectoryName
$newProjectName = [System.IO.Path]::GetFileNameWithoutExtension((get-item $projectfile).Name)
$newProjectFolder = [System.IO.Path]::Combine($newpath,$newProjectName)
$newProjectFilePath = [System.IO.Path]::Combine($newProjectFolder,"$($newProjectName).csproj")
print "Source path: $sourcefolder"
print "Target path: $newProjectFolder"

if (-not (test-path $projectfile)) { throw "Project file not found!" }
$rootnamespace = Get-RegExFromFile $projectfile '<RootNamespace>(.*)</RootNamespace>'
if ($rootnamespace -eq $null) { $rootnamespace = $newProjectName }
print "Rootnamespace: $rootnamespace"
if ($projects -eq $null) {
$projects = Get-RegExFromFile $projectfile '<ProjectReference Include="(.*)"'
if ($project -ne $null) { $projects | foreach { print "Projektreference: $_" } }
}

$applicationicon = Get-RegExFromFile $projectfile '<ApplicationIcon>(.*)</ApplicationIcon>'
print "applicationicon: $applicationicon"

#endregion

#region -------------------------- Remove Destination Folder"
h2 "Clean Destination Folder $newProjectFolder"
if (test-path $newProjectFolder) {
warning "Removing existing files in $newProjectFolder..."
rd $newProjectFolder -Force -Recurse
}
#endregion

#region -------------------------- Copy Code
h2 "Copy Code $newProjectName to $newProjectFolder"
Copy-Item $sourcefolder $newProjectFolder -Recurse -Force
dir $newProjectFolder | out-default

h2 "Remove unused files in $newProjectName..."
rd $newProjectFolderbin -Recurse
rd $newProjectFolderobj -Recurse
remove-item $newProjectFolder*.vspscc
remove-item $newProjectFolder*.sln
remove-item $newProjectFolder*.csproj
dir $newProjectFolder -Recurse | Set-ItemProperty -Name IsReadOnly -Value $false -ErrorAction SilentlyContinue | out-default
dir $newProjectFolder | out-default
#endregion

#region -------------------------- Creating new project file
h2 "Creating new project file ($newProjectFilePath )..."
$csproj = $template
$csproj = $csproj.Replace("[DATE]",(get-Date))
$csproj = $csproj.Replace("[OutputType]",$outputtype)
$csproj = $csproj.Replace("[rootnamespace]",$rootnamespace)
$csproj = $csproj.Replace("[icon]",$applicationicon)

$projRef = ""
foreach($r in $projects)
{
print "Project: $r"
$projRef += " " + $ProjRefTemplate.Replace("TODO",$r) + "`n"
}
$csproj = $csproj.Replace("[ProjectReference]",$projRef.TrimEnd())

$assetRef = ""
if (test-path $newProjectFolderassets)
{
$assets = dir $newProjectFolderassets
foreach($a in $assets)
{
print "Asset: $a"
$assetRef += " " + $AssetTemplate.Replace("FILE","assets$($a.name)") + "`n"
}
}
$csproj = $csproj.Replace("[AssetsRef]",$assetRef.TrimEnd())

$nugetref = ""
foreach($n in $nugets.keys)
{
print "Nuget: $n $($nugets[$n])"
$nugetref += " " + $NugetRefTemplate.Replace("NAME",$n).Replace("VERSION",$nugets[$n]) + "`n"
}
$csproj = $csproj.Replace("[NugetReference]",$nugetref.TrimEnd())

$libref = ""
foreach($l in $libs)
{
print "DLL: $l"
$libref += " " + $LibRefTemplate.Replace("TODO",$l)
}
$csproj = $csproj.Replace("[LibReference]",$libref.TrimEnd())

print $csproj
$csproj | Set-Content $newProjectFilePath -Force

#endregion

#region -------------------------- Build
h2 "Build $newProjectName..."
cd $newProjectFolder
#dotnet restore | out-default
dotnet build | out-default
#endregion
return $newProjectFolder
}

#region ############################ Main

Remove-Item $newPath/* -Recurse -Force -ea SilentlyContinue

md $newPath -ea SilentlyContinue
explorer $newPath
$nugets = @{
"System.ComponentModel.Annotations"="4.5.0"
}

Migrate-Project MiracleListLight_BOMiracleListLight_BO.csproj $projLibTemplate $newPath "Library" $null $null $nugets

$nugets = @{
"ITV.AppUtil.NETStandard.Core"="3.0.1";
"Microsoft.EntityFrameworkCore.SqlServer"="2.2.6";
"Microsoft.EntityFrameworkCore.Sqlite"="2.2.6";
}

Migrate-Project MiracleListLight_DALMiracleListLight_DAL.csproj $projLibTemplate $newPath "Library" $null $null $nugets

$nugets = @{
"Appium.WebDriver"="4.0.0.6-beta";
"Microsoft.NET.Test.Sdk"="16.2.0";
"MSTest.TestAdapter"="1.4.0";
"MSTest.Testframework"="1.4.0";
}

Migrate-Project MiracleListLight_UITestsMiracleListLight_UITests.csproj $projWPFTemplate $newPath "Library" $null $null $nugets

$nugets = @{
"ITV.AppUtil.NETStandard.Core"="3.0.1";
"Microsoft.EntityFrameworkCore"="2.2.6";
"Microsoft.Windows.Compatibility"="3.0.0-rc1.19456.4"
}

$newProjectFolder = Migrate-Project MiracleListLight_WPFUIMiracleListLight_WPFUI.csproj $projWPFTemplate $newPath "WinEXE" $null $null $nugets

h1 "Copy .sln file..."
copy $oldPath/MiracleListLight_WPF.sln $newPath/MiracleListLight_WPF.sln

h1 "Testing if EXE exists.."
$exe1 = [System.Io.Path]::Combine($newProjectFolder,"binDebugnetcoreapp3.0win-x64MiracleListLight_WPFUI.exe")

if (-not (test-path $exe1)) { error "EXE not found: $exe" ; return }
success "EXE found: $exe1"

h1 "Publish App..."
$singpleFilePubPath = "t:MLLWPFMLLWPFCore-SingleFilePublish"
$wpf = [System.Io.Path]::Combine($newPath,"MiracleListLight_WPFUI")
cd $wpf
dotnet publish -o $singpleFilePubPath
explorer $singpleFilePubPath
$exe = [System.Io.Path]::Combine($singpleFilePubPath, "MiracleListLight_WPFUI.exe")
if (-not (test-path $exe)) { error "EXE not found: $exe" ; return }
success "EXE found: $exe"

h1 "UI Testing..."
$uitests = [System.Io.Path]::Combine($newPath,"MiracleListLight_UITests")
cd $uitests
Replace-TextInFile "app.config" "H:MLMiracleListLightMiracleListLight_WPFUIbinDebugMiracleListLight_WPFUI.exe" $exe1
dotnet test
#endregion

success "Migration completed"

Es folgt noch ein Ausschnitt aus der im Skript verwendeten Hilfsbibliothek für die farbigen Ausgaben und die Dateiänderungen.
# PowerShell Utilities / Colorful output and other
# (C) Dr. Holger Schwichtenberg, www.IT-Visions.de, 2007-2019
function Get-RegExFromFile($path, $pattern)
<#
.SYNOPSIS
Get a tag oder value from a project file
#>
{
$content = get-content $path
$matches = ($content | select-string -pattern $pattern).Matches
if ( $matches -eq $null) { return $null }
$matches | foreach { $_.Groups[1].Value }
}

function Replace-TextInFile($path, $oldtext, $newtext)
{
<#
.SYNOPSIS
Replace a text in a file
#>
((Get-Content -path $path -Raw).Replace($oldtext, $newtext)) | Set-Content -Path $path
}

function Replace-RegExInFile($path, $reg, $newtext)
{
<#
.SYNOPSIS
Replace a text in a file
#>
(Get-Content -path $path -Raw) -replace $reg,$newtext | Set-Content -Path $path -Encoding UTF8
}

function head()
{
[CmdletBinding()]
Param( [Parameter(ValueFromPipeline)]$s)
Write-Host $s -ForegroundColor Blue -BackgroundColor White
}

function print()
{
[CmdletBinding()]
Param( [Parameter(ValueFromPipeline)]$s)
Write-Host $s
}

function h1()
{
[CmdletBinding()]
Param( [Parameter(ValueFromPipeline)]$s)
Write-Host $s -ForegroundColor black -BackgroundColor Yellow
}

function h2()
{
[CmdletBinding()]
Param( [Parameter(ValueFromPipeline)]$s)
Write-Host $s -ForegroundColor White -BackgroundColor Green
}

function h3()
{
[CmdletBinding()]
Param( [Parameter(ValueFromPipeline)]$s)
Write-Host $s -ForegroundColor White -BackgroundColor DarkBlue
}

function error()
{
[CmdletBinding()]
Param( [Parameter(ValueFromPipeline)]$s)
Write-Host $s -ForegroundColor white -BackgroundColor red
}

function warning()
{
[CmdletBinding()]
Param( [Parameter(ValueFromPipeline)]$s)
Write-Host $s -ForegroundColor yellow
}

function info()
{
[CmdletBinding()]
Param( [Parameter(ValueFromPipeline)]$s)
Write-Host $s -ForegroundColor cyan
}

function success()
{
[CmdletBinding()]
Param( [Parameter(ValueFromPipeline)]$s)
Write-Host $s -ForegroundColor green
}


()






Haberin Sonu
 
Üst