Edit #1 Start
To Replicate this:
Create a new "vanilla" WPF application addressing .Net Core 3.1
Add an Windows Application Packaging Project to the solution (follow the steps mentioned in Set up your desktop application for MSIX packaging in Visual Studio)
Try to "deploy" to a UNC path...
Edit #1 End
I am in the process of converting a WPF .net framework application to .net core 3.1. This application is an "internal" tool that we've always deployed by using ClickOnce to place create the setup on a shared UNC path. So simple....
I've now re-written it in .Net Core and need to deploy it. Finding that "ClickOnce" is no longer available, I understand that I have to go down the "MSIX" route. The documentation looks like it should be simple, but I guess I'm missing a few things....
1 - I've had to change my Developer Settings from "Side Bar" to "Developer Mode"
2 - It builds fine on my machine, but on Azure DevOps fails
3 - and how do I actually deploy it...?
Let's look at each in turn.
1 - Side Bar => Developer Mode issue
I add a new Windows Application Packaging Project to my solution, pick Windows version 1909 for both target and minimum versions, and set my WPF application to be the Entry Point. I try to run this and it forces me to change from "Side Bar" to "Developer Mode".
Is this only affecting me as the developer....if so, that's fine. I doubt the final end users will want to do this.
2 - Azure DevOps build pipeline fails
Locally, it compiles just fine, even under Release Mode where I have all warnings set to Error, and have FxCop running. Push it to Azure and it says:
[error]C:\Program Files\dotnet\sdk\3.1.201\Sdks\Microsoft.NET.Sdk\targets\Microsoft.PackageDependencyResolution.targets(234,5):
Error NETSDK1047: Assets file
'd:\a\1\s\MyApp\MyApp\obj\project.assets.json' doesn't have a target for '.NETCoreApp,Version=v3.1/win-x86'.
Ensure that restore has run
and that you have included 'netcoreapp3.1' in the TargetFrameworks for
your project.
You may also need to include 'win-x86' in your
project's RuntimeIdentifiers.
Okay
my YAML file has a "Restore NuGet Packages" step preceding the build
that succeeded.
I look in my SKD project file for my application and
I see <TargetFramework>netcoreapp3.1</TargetFramework>
Regarding "RuntimeIdentifiers", I found the link Additions to the csproj format for .NET Core so added <RuntimeIdentifiers>win-x64;win-x86</RuntimeIdentifiers> immediately under <TargetFramework>netcoreapp3.1</TargetFramework> (should I be more specific an use win10-x64;win10-x86?)
Either way, this failed with a slightly different message:
There was a mismatch between the processor architecture of the project
being built "MSIL" and the processor architecture of the reference
"path to my dll", "x86". This mismatch may cause runtime failures.
Please consider changing the targeted processor architecture of your
project through the Configuration Manager so as to align the processor
architectures between your project and references, or take a
dependency on references with a processor architecture that matches
the targeted processor architecture of your project.
3 - how do I actually deploy it?
From MSIX: The Modern Way to Deploy Desktop Apps on Windows it states:
To generate the actual MSIX package, there’s a wizard available under
Project | Store | Create App Packages in Visual Studio.
There isn't on my machine....I even went as far as installing the Visual Studio workload "Universal Windows Platform Development". I can see a "Deploy" under the Build menu...but is this it....where do I put the UNC path?
I think I'm missing something fairly fundamental....
The relevant part of my CSPROJ is
<PropertyGroup>
<OutputType>WinExe</OutputType>
<TargetFramework>netcoreapp3.1</TargetFramework>
<RuntimeIdentifiers>win-x64;win-x86</RuntimeIdentifiers>
<UseWPF>true</UseWPF>
</PropertyGroup>
The package project is:
<?xml version="1.0" encoding="utf-8"?>
<Project ToolsVersion="15.0" DefaultTargets="Build" xmlns="http://schemas.microsoft.com/developer/msbuild/2003">
<PropertyGroup Condition="'$(VisualStudioVersion)' == '' or '$(VisualStudioVersion)' < '15.0'">
<VisualStudioVersion>15.0</VisualStudioVersion>
</PropertyGroup>
<ItemGroup Label="ProjectConfigurations">
<ProjectConfiguration Include="Debug|x86">
<Configuration>Debug</Configuration>
<Platform>x86</Platform>
</ProjectConfiguration>
<ProjectConfiguration Include="Release|x86">
<Configuration>Release</Configuration>
<Platform>x86</Platform>
</ProjectConfiguration>
<ProjectConfiguration Include="Debug|x64">
<Configuration>Debug</Configuration>
<Platform>x64</Platform>
</ProjectConfiguration>
<ProjectConfiguration Include="Release|x64">
<Configuration>Release</Configuration>
<Platform>x64</Platform>
</ProjectConfiguration>
<ProjectConfiguration Include="Debug|ARM">
<Configuration>Debug</Configuration>
<Platform>ARM</Platform>
</ProjectConfiguration>
<ProjectConfiguration Include="Release|ARM">
<Configuration>Release</Configuration>
<Platform>ARM</Platform>
</ProjectConfiguration>
<ProjectConfiguration Include="Debug|ARM64">
<Configuration>Debug</Configuration>
<Platform>ARM64</Platform>
</ProjectConfiguration>
<ProjectConfiguration Include="Release|ARM64">
<Configuration>Release</Configuration>
<Platform>ARM64</Platform>
</ProjectConfiguration>
<ProjectConfiguration Include="Debug|AnyCPU">
<Configuration>Debug</Configuration>
<Platform>AnyCPU</Platform>
</ProjectConfiguration>
<ProjectConfiguration Include="Release|AnyCPU">
<Configuration>Release</Configuration>
<Platform>AnyCPU</Platform>
</ProjectConfiguration>
</ItemGroup>
<PropertyGroup>
<WapProjPath Condition="'$(WapProjPath)'==''">$(MSBuildExtensionsPath)\Microsoft\DesktopBridge\</WapProjPath>
</PropertyGroup>
<Import Project="$(WapProjPath)\Microsoft.DesktopBridge.props" />
<PropertyGroup>
<ProjectGuid>08b169a2-6461-440b-afa1-ca35c7d98aa7</ProjectGuid>
<TargetPlatformVersion>10.0.18362.0</TargetPlatformVersion>
<TargetPlatformMinVersion>10.0.18362.0</TargetPlatformMinVersion>
<DefaultLanguage>en-US</DefaultLanguage>
<AppxPackageSigningEnabled>True</AppxPackageSigningEnabled>
<EntryPointProjectUniqueName>..\MyApp\MyApp.csproj</EntryPointProjectUniqueName>
<PackageCertificateThumbprint>01C08F1E21D5624A484DB362BE4F056504B825CC</PackageCertificateThumbprint>
</PropertyGroup>
<ItemGroup>
<AppxManifest Include="Package.appxmanifest">
<SubType>Designer</SubType>
</AppxManifest>
</ItemGroup>
<ItemGroup>
<Content Include="Images\SplashScreen.scale-200.png" />
<Content Include="Images\LockScreenLogo.scale-200.png" />
<Content Include="Images\Square150x150Logo.scale-200.png" />
<Content Include="Images\Square44x44Logo.scale-200.png" />
<Content Include="Images\Square44x44Logo.targetsize-24_altform-unplated.png" />
<Content Include="Images\StoreLogo.png" />
<Content Include="Images\Wide310x150Logo.scale-200.png" />
</ItemGroup>
<ItemGroup>
<ProjectReference Include="..\MyApp\MyApp.csproj">
<SkipGetTargetFrameworkProperties>True</SkipGetTargetFrameworkProperties>
</ProjectReference>
</ItemGroup>
<Import Project="$(WapProjPath)\Microsoft.DesktopBridge.targets" />
</Project>
(can/should I remove references to the "DEBUG" and to "ARM" which I don't think will be relevant??)
And the manifest is
<?xml version="1.0" encoding="utf-8"?>
<Package
xmlns="http://schemas.microsoft.com/appx/manifest/foundation/windows10"
xmlns:uap="http://schemas.microsoft.com/appx/manifest/uap/windows10"
xmlns:rescap="http://schemas.microsoft.com/appx/manifest/foundation/windows10/restrictedcapabilities"
IgnorableNamespaces="uap rescap">
<Identity
Name="46aebba6-d403-4412-89c0-05279b36e54e"
Publisher="CN=MyCompany"
Version="2020.5.0.0" />
<Properties>
<DisplayName>MyApp</DisplayName>
<PublisherDisplayName>MyCompany</PublisherDisplayName>
<Logo>Images\StoreLogo.png</Logo>
</Properties>
<Dependencies>
<TargetDeviceFamily Name="Windows.Desktop" MinVersion="10.0.14393.0" MaxVersionTested="10.0.14393.0" />
</Dependencies>
<Resources>
<Resource Language="x-generate"/>
</Resources>
<Applications>
<Application Id="App"
Executable="$targetnametoken$.exe"
EntryPoint="$targetentrypoint$">
<uap:VisualElements
DisplayName="MyApp.Package"
Description="MyApp.Package"
BackgroundColor="transparent"
Square150x150Logo="Images\Square150x150Logo.png"
Square44x44Logo="Images\Square44x44Logo.png">
<uap:DefaultTile Wide310x150Logo="Images\Wide310x150Logo.png" />
<uap:SplashScreen Image="Images\SplashScreen.png" />
</uap:VisualElements>
</Application>
</Applications>
<Capabilities>
<Capability Name="internetClient" />
<rescap:Capability Name="runFullTrust" />
</Capabilities>
</Package>
Thanks!
In .wapproj project file please add,
<PropertyGroup>
<ResolveAssemblyWarnOrErrorOnTargetArchitectureMismatch>
None
</ResolveAssemblyWarnOrErrorOnTargetArchitectureMismatch>
</PropertyGroup>
Related
I have a Winforms .NET Core 3 app that I want to publish as a Self-Contained Single-File Deployment
Here is the relevant .csproj file
<Project Sdk="Microsoft.NET.Sdk.WindowsDesktop">
<PropertyGroup>
<OutputType>WinExe</OutputType>
<TargetFramework>netcoreapp3.0</TargetFramework>
<UseWindowsForms>true</UseWindowsForms>
<RuntimeIdentifier>win-x64</RuntimeIdentifier>
<PublishSingleFile>true</PublishSingleFile>
</PropertyGroup>
<ItemGroup>
<!--PackageReferences-->
</ItemGroup>
<ItemGroup>
<!--ProjectReferences-->
</ItemGroup>
</Project>
I am using <RuntimeIdentifier>win-x64</RuntimeIdentifier> so it generates a Self Contained Deployment for Windows x64 and <PublishSingleFile>true</PublishSingleFile> so everything gets embedded in the .exe file.
When publishing by running:
dotnet publish -c Release
I get the .exe and the .pdb files at bin\Release\netcoreapp3.0\win-x64\publish
- MyApp.exe
- MyApp.pdb
What do I need to change in the .csproj file so I get the MyApp.dll.config or MyApp.exe.config whichever is correct next to the .exe so the app actually reads config from it instead of its embedded App.Config?
I have tried adding this
<ItemGroup>
<Content Update="*.config">
<CopyToPublishDirectory>PreserveNewest</CopyToPublishDirectory>
<ExcludeFromSingleFile>true</ExcludeFromSingleFile>
</Content>
</ItemGroup>
as hinted by this link Single-file Publish - Build System Interface but it still produces only the two files.
Your question helped me figure out this for me, so thanks.
hopefully this works for you too.
my .csproj looks like
<PropertyGroup>
<OutputType>Exe</OutputType>
<TargetFramework>netcoreapp3.0</TargetFramework>
<PublishReadyToRun>true</PublishReadyToRun>
<PublishSingleFile>true</PublishSingleFile>
<PublishTrimmed>true</PublishTrimmed>
<RuntimeIdentifier>win-x64</RuntimeIdentifier>
</PropertyGroup>
<ItemGroup>
<Content Include="*.json">
<CopyToOutputDirectory>PreserveNewest</CopyToOutputDirectory>
<ExcludeFromSingleFile>true</ExcludeFromSingleFile>
</Content>
</ItemGroup>
just done some further testing with a .config file
<ItemGroup>
<None Update="*.config">
<CopyToOutputDirectory>PreserveNewest</CopyToOutputDirectory>
<ExcludeFromSingleFile>true</ExcludeFromSingleFile>
</None>
</ItemGroup>
that worked for me, with the other config from above.
I am trying to manually update a new csproj file to configure building for .NET Framework 4.0 Client Profile.
This works correctly
<Project Sdk="Microsoft.NET.Sdk">
<PropertyGroup>
<TargetFrameworks>NET40</TargetFrameworks>
</PropertyGroup>
</Project>
but this generates an error
<Project Sdk="Microsoft.NET.Sdk">
<PropertyGroup>
<TargetFrameworks>NET40</TargetFrameworks>
<TargetFrameworkProfile>Client</TargetFrameworkProfile>
</PropertyGroup>
</Project>
'project.assets.json' doesn't have a target for
'.NETFramework,Version=v4.0,Profile=Client'.
Ensure that restore has run and that you have included
'net40-client' in the TargetFrameworks for your project.
Is it possible to use new csproj format e.g. <Project Sdk="Microsoft.NET.Sdk"> to build for .NET Framework Client Profile?
This worked for me:
<TargetFramework>net40-client</TargetFramework>
<TargetFrameworkIdentifier>.NETFramework</TargetFrameworkIdentifier>
<TargetFrameworkVersion>v4.0</TargetFrameworkVersion>
<TargetFrameworkProfile>Client</TargetFrameworkProfile>
There is a package for this, all you have to do is to replace the first line of your csproj with:
<Project Sdk="MSBuild.Sdk.Extras/2.0.54">
Then you have some new target frameworks available such as net40-client, so
<TargetFrameworks>net40-client</TargetFrameworks>
will now work.
See the project page (https://github.com/novotnyllc/MSBuildSdkExtras) if you want more information.
Trying to trigger a build of a .net standard/core csproj when an external file changes. The file is in the the $(USERPROFILE)\Documents directory.
Have tried Targets with BeforeTargets equal to PrepareForBuild, PreBuildEvent but none work.
<Project Sdk="Microsoft.NET.Sdk" Project="Sdk.props">
<PropertyGroup>
<TargetFrameworks>netstandard2.0;net471</TargetFrameworks>
</PropertyGroup>
<Target Name="PrepareForBuild2" BeforeTargets="PrepareForBuild">
<Exec Command="echo PrepareForBuild2" />
</Target>
</Project>
Found solution - use UpToDateCheckInput
<ItemGroup>
<UpToDateCheckInput Include="$(USERPROFILE)\Documents\MyFile.txt" />
</ItemGroup>
I am just starting out with .NET standard. In a proof-of-concept project I'm trying to use Dapper as my ORM. In the .NET Standard 2.0 class library project, I added Dapper 1.50.5 Nuget package. However, the assembly isn't getting loaded at runtime.
I get this error:
System.IO.FileNotFoundException HResult=0x80070002
Message=Could not load file or assembly 'Dapper, Version=1.50.5.0, Culture=neutral, PublicKeyToken=null' or one of its dependencies.
The system cannot find the file specified.
Complete contents of my .csproj:
<Project Sdk="Microsoft.NET.Sdk">
<PropertyGroup>
<TargetFramework>netstandard2.0</TargetFramework>
</PropertyGroup>
<ItemGroup>
<PackageReference Include="Dapper" Version="1.50.5" />
<PackageReference Include="Npgsql" Version="4.0.4" />
<PackageReference Include="System.Data.SqlClient" Version="4.6.0" />
<PackageReference Include="System.Reflection.Emit.Lightweight" Version="4.3.0" />
<PackageReference Include="System.Reflection.TypeExtensions" Version="4.5.1" />
<PackageReference Include="System.Runtime.CompilerServices.Unsafe" Version="4.5.2" />
<PackageReference Include="System.Threading.Tasks.Extensions" Version="4.5.1" />
</ItemGroup>
</Project>
So, you see I've installed the dependencies and dependencies of the dependencies.
What else should I do?
The .NETStandard assembly was added as a reference to my WPF project. I needed to make changes in the .csproj of the WPF project.
The solution mentioned in https://github.com/dotnet/sdk/issues/901 fixes it.
Steps:
Edit your core .csproj file in notepad.
Add the below two lines in each that you find in it.
<RestoreProjectStyle>PackageReference</RestoreProjectStyle>
<AutoGenerateBindingRedirects>true</AutoGenerateBindingRedirects>
Clean and rebuild your solution.
For the gurus out there in batch file writing and Visual Studio (most significantly Visual Studio 2013), I would like to know if it is possible to do the following:
I have a series of projects part of a solution, many of which are dependent on the dll's generated by other projects (in a waterfall fashion really). I would like to know if it is possible to write a batch file to build all projects to generate the corresponding dll's, and then update their references to the newly assembled dll's (also with the batch file).
Is this even possible? I would like avoid using extensions like NuGet or any other software.
You pick the right language/tool to do builds. msbuild is the tool (and kind of the language) that you write this kind of stuff. they are called build-scripts. they are NOT bat scripts. do not use .bat scripts. that's what people did 20 years ago.
Below is a basic msbuild script file. It will
Build the .sln
copy the files of one of the csproj's (usually the GUI csproj) to a folder
zip the files into a zip file
You would put this in a file called "MyBuildScript.proj" (or MyBuildScript.msbuild)
After you do that, you will execute the file with msbuild.exe
"%WINDIR%\Microsoft.NET\Framework\v4.0.30319\msbuild.exe" /target:AllTargetsWrapped "MyBuildScript.proj" /p:Configuration=Debug;FavoriteFood=Popeyes /l:FileLogger,Microsoft.Build.Engine;logfile=MyBuildScript.proj.Release.log
(MyBuildScript.proj)
<?xml version="1.0" encoding="utf-8"?>
<Project xmlns="http://schemas.microsoft.com/developer/msbuild/2003" DefaultTargets="AllTargetsWrapped">
<PropertyGroup>
<!-- Get this project from http://msbuildextensionpack.codeplex.com/releases/view/105659 -->
<MSBuildExtensionPackFoundPath Condition="Exists('$(MSBuildExtensionsPath64)\ExtensionPack\4.0\MSBuild.ExtensionPack.tasks')">$(MSBuildExtensionsPath64)\ExtensionPack\4.0\MSBuild.ExtensionPack.tasks</MSBuildExtensionPackFoundPath>
<MSBuildExtensionPackFoundPath Condition="Exists('$(MSBuildExtensionsPath32)\ExtensionPack\4.0\MSBuild.ExtensionPack.tasks')">$(MSBuildExtensionsPath32)\ExtensionPack\4.0\MSBuild.ExtensionPack.tasks</MSBuildExtensionPackFoundPath>
<MSBuildExtensionPackFoundPath Condition="Exists('$(MSBuildExtensionsPath)\ExtensionPack\4.0\MSBuild.ExtensionPack.tasks')">$(MSBuildExtensionsPath)\ExtensionPack\4.0\MSBuild.ExtensionPack.tasks</MSBuildExtensionPackFoundPath>
<MSBuildExtensionPackFoundPath Condition="$(MSBuildExtensionPackFoundPath)==''">CouldNotFindBaseDirectoryCheckForInstalledProduct\MSBuild.ExtensionPack.tasks</MSBuildExtensionPackFoundPath>
</PropertyGroup>
<Import Project="$(MSBuildExtensionPackFoundPath)"/>
<PropertyGroup>
<!-- Always declare some kind of "base directory" and then work off of that in the majority of cases -->
<WorkingCheckout>.</WorkingCheckout>
<WorkingDir>.</WorkingDir>
<ArtifactDestinationFolder>$(WorkingCheckout)\ZZZArtifacts</ArtifactDestinationFolder>
<ZipArtifactDestinationFolder>$(WorkingDir)\ZZZZipArtifacts</ZipArtifactDestinationFolder>
</PropertyGroup>
<Target Name="AllTargetsWrapped">
<CallTarget Targets="CleanArtifactFolder" />
<CallTarget Targets="BuildItUp" />
<CallTarget Targets="CopyFilesToArtifactFolder" />
<CallTarget Targets="ZipItUp" />
</Target>
<Target Name="BuildItUp" >
<MSBuild Projects="$(WorkingCheckout)\Solution1.sln" Targets="Build" Properties="Configuration=$(Configuration)">
<Output TaskParameter="TargetOutputs" ItemName="TargetOutputsItemName"/>
</MSBuild>
<Message Text="BuildItUp completed" />
</Target>
<Target Name="CleanArtifactFolder">
<RemoveDir Directories="$(ArtifactDestinationFolder)" Condition="Exists($(ArtifactDestinationFolder))"/>
<MakeDir Directories="$(ArtifactDestinationFolder)" Condition="!Exists($(ArtifactDestinationFolder))"/>
<RemoveDir Directories="$(ZipArtifactDestinationFolder)" Condition="Exists($(ZipArtifactDestinationFolder))"/>
<MakeDir Directories="$(ZipArtifactDestinationFolder)" Condition="!Exists($(ZipArtifactDestinationFolder))"/>
<Message Text="Cleaning done" />
</Target>
<Target Name="CopyFilesToArtifactFolder">
<ItemGroup>
<MyExcludeFiles Include="$(WorkingDir)\**\*.doesnotexist" />
</ItemGroup>
<ItemGroup>
<MyIncludeFiles Include="$(WorkingDir)\CsProjectOne\bin\$(Configuration)\**\*.*" Exclude="#(MyExcludeFiles)"/>
</ItemGroup>
<Copy
SourceFiles="#(MyIncludeFiles)"
DestinationFiles="#(MyIncludeFiles->'$(ArtifactDestinationFolder)\%(Filename)%(Extension)')"
/> <!-- %(RecursiveDir) -->
</Target>
<Target Name="ZipItUp">
<ItemGroup>
<NonConfigFilesExcludeFiles Include="$(ArtifactDestinationFolder)\**\*.doesnotexist" />
</ItemGroup>
<ItemGroup>
<NonConfigFilesIncludeFiles Include="$(ArtifactDestinationFolder)\**\*" Exclude="#(NonConfigFilesExcludeFiles)"/>
</ItemGroup>
<!-- Create a zip file based on the FilesToZip collection -->
<MSBuild.ExtensionPack.Compression.Zip TaskAction="Create" CompressFiles="#(NonConfigFilesIncludeFiles)" RemoveRoot="$(ArtifactDestinationFolder)" ZipFileName="$(ZipArtifactDestinationFolder)\MyOutputFile.zip"/>
<!-- -->
</Target>
</Project>
That is how you write build-logic. There are other build tools out there, but this is the default dotNet one.
Do NOT write crappy, hard to maintain .bat files.
Use the correct tool for the job.
PS "msbuildextensionpack" is an example of extensions for msbuild. there are MANY MANY helpful extensions for msbuild. 99% of the time, somebody has written a msbuild extension to help do what you need to do.
Need to send a file to an ftp client destination? Somebody already wrote a task.
Need to manipulate some .xml file? Somebody already wrote a task.
Need to zip a file (like in this example). Somebody already wrote a task.
Need to do........anything mainstream........ Somebody already wrote a task.