Is it possible to create platform specific views? - maui

In UWP, device specific views can be created by placing those views into their respective folders or appending the relevant device name to the file name.
I don't see any information on doing the equivalent with MAUI as regards platform specific views only platform specific code.
Is this a thing ?
The closest I can get is using preprocessor directives and giving the files unique names. This means there are still multiple code behind files unfortunately.
So -
#if ANDROID
await Navigation.PushAsync(new Page1Windows());
#elif WINDOWS
await Navigation.PushAsync(new Page1Android());
#endif

It's a thing.
The default MAUI projects provide a platform specific folder you can put platform specific code in.
If you want something more complicated, like your platform-named folders or files, you can edit your csproj to include or exclude files by name & platform.
There are examples of both file and folder-based targeting in the Configure multi-targeting docs:
Here's the combined view from Combine filename and folder multi-targeting that excludes files and folders that include platform names that don't match the current target.
<ItemGroup Condition="$(TargetFramework.StartsWith('net6.0-android')) != true">
<Compile Remove="**\**\*.Android.cs" /> <None Include="**\**\*.Android.cs" Exclude="$(DefaultItemExcludes);$(DefaultExcludesInProjectFolder)" />
<Compile Remove="**\Android\**\*.cs" /> <None Include="**\Android\**\*.cs" Exclude="$(DefaultItemExcludes);$(DefaultExcludesInProjectFolder)" />
</ItemGroup>
<ItemGroup Condition="$(TargetFramework.StartsWith('net6.0-ios')) != true AND $(TargetFramework.StartsWith('net6.0-maccatalyst')) != true">
<Compile Remove="**\**\*.iOS.cs" /> <None Include="**\**\*.iOS.cs" Exclude="$(DefaultItemExcludes);$(DefaultExcludesInProjectFolder)" />
<Compile Remove="**\iOS\**\*.cs" /> <None Include="**\iOS\**\*.cs" Exclude="$(DefaultItemExcludes);$(DefaultExcludesInProjectFolder)" />
</ItemGroup>
<ItemGroup Condition="$(TargetFramework.Contains('-windows')) != true ">
<Compile Remove="**\*.Windows.cs" /> <None Include="**\*.Windows.cs" Exclude="$(DefaultItemExcludes);$(DefaultExcludesInProjectFolder)" />
<Compile Remove="**\Windows\**\*.cs" /> <None Include="**\Windows\**\*.cs" Exclude="$(DefaultItemExcludes);$(DefaultExcludesInProjectFolder)" />
</ItemGroup>

Related

Select to which ItemGroup to add Content entries using .csproj extension in VS Code

How could I select to which ItemGroup the Content entries get added. I am using the .csproj extension in VS Code.
E.g. if I have the following:
<ItemGroup>
</ItemGroup>
<ItemGroup>
</ItemGroup>
Then there are two options:
<ItemGroup>
<Content Include="folder\foo.extension" />
</ItemGroup>
<ItemGroup>
</ItemGroup>
and
<ItemGroup>
</ItemGroup>
<ItemGroup>
<Content Include="folder\foo.extension" />
</ItemGroup>
I would like to control which option is used. My ultimate goal is to have the same behavior in VS Code as it is in VS 2022.
It doesn't matter which ItemGroup you select, neither does the order.
Usage of Item, ItemGroup elemtens
https://learn.microsoft.com/en-us/visualstudio/msbuild/item-element-msbuild?view=vs-2022#attributes-and-elements
Posible values for Content
https://learn.microsoft.com/en-us/visualstudio/msbuild/common-msbuild-project-items?view=vs-2022#content
Works fine with dotnet cli (VS Code)
<ItemGroup>
<Content Include="folder/foo.extension">
<CopyToOutputDirectory>PreserveNewest</CopyToOutputDirectory>
</Content>
</ItemGroup>

Some assembly binding redirects are not generated automatically even if AutoGenerateBindingRedirects is set to true

I have a simple net48 project with some nuget package references. However, some assembly binding redirects are not generated, even if AutoGenerateBindingRedirects and GenerateBindingRedirectsOutputType is set to true!
<Project Sdk="Microsoft.NET.Sdk">
<PropertyGroup>
<TargetFramework>net48</TargetFramework>
<TreatWarningsAsErrors>true</TreatWarningsAsErrors>
<AutoGenerateBindingRedirects>true</AutoGenerateBindingRedirects>
<GenerateBindingRedirectsOutputType>true</GenerateBindingRedirectsOutputType>
</PropertyGroup>
...
<ItemGroup>
<PackageReference Include="Microsoft.WindowsAPICodePack.Core" Version="1.1.0" />
<PackageReference Include="Microsoft.WindowsAPICodePack.Shell" Version="1.1.0" />
<PackageReference Include="ZetaLongPaths" Version="1.0.10.41" />
<PackageReference Include="OxyPlot.Core" Version="2.0.0" />
<PackageReference Include="OxyPlot.WindowsForms" Version="2.0.0" />
...
</ItemGroup>
</Project>
For some of our package references the bindings are generated automatically, however for the 5 I have mentioned above no redirect is added!
Since we are using renovate-bot to update our nuget packages, this will break the automation since we need to add these 5 bindings manually which requires adaption once the version has been changed!
Does anybody know how to get those bindings generated automatically?

Not able see test cases in Text Explorer for the .net core 2 based Test project

I have created a test project based on .Net Core 2 and wrote some NUnit test cases. After installing necessary NuGet packages i.e. NUnit3TestAdapter, I was able to see all test cases in "Test Explorer" and able to execute those. Now, when I looked into the project directory, I found that it's creating "obj" folder and some json files in it. So I tried to change the path of "obj" folder by modifying ".csproj" file. I provided some different path in the parameter "BaseIntermediateOutputPath" and that way, I was able to get rid of "obj" folder. The reason for providing different path was, I wanted to keep json files separate from source code.
However, after modifying that I am not able to see or execute any test cases from Test Explorer.
Is this a Microsoft bug?
Is any packages having dependency on "obj" folder?
P.S.
I am using "NUnit" and "NSubstitute" packages for my test project.
<Project Sdk="Microsoft.NET.Sdk">
<PropertyGroup>
<Configuration Condition=" '$(Configuration)' == '' ">Debug</Configuration>
<Platform Condition=" '$(Platform)' == '' ">AnyCPU</Platform>
<TargetFramework>netcoreapp2.0</TargetFramework>
<OutputPath>..\..\build\$(Configuration)\UnitTests\</OutputPath>
<BaseIntermediateOutputPath>..\..\work\$(MSBuildProjectName)\</BaseIntermediateOutputPath>
</PropertyGroup>
<Import Project="Sdk.props" Sdk="Microsoft.NET.Sdk" />
<ItemGroup>
<PackageReference Include="Castle.Core" Version="4.1.1" />
<PackageReference Include="Microsoft.NET.Test.Sdk" Version="15.3.0" />
<PackageReference Include="NSubstitute" Version="2.0.3" />
<PackageReference Include="NUnit" Version="3.8.1" />
<PackageReference Include="NUnit3TestAdapter" Version="3.8.0" />
</ItemGroup>
<Import Project="Sdk.targets" Sdk="Microsoft.NET.Sdk" />
<ItemGroup>
<ProjectReference Include="..\UtilityLibrary\UtilityLibrary.csproj" />
</ItemGroup>
</Project>
When .NET Core projects build, they do not copy all referenced files into the bin folder. When you add Microsoft.NET.Test.Sdk to your test project, one of the things it does is add an AssemblyResolve event handler which loads other dependent assemblies from a list of searchDirectories.
BaseIntermediateOutputPath not working was reported against the VSTest project and is an issue with MSBuild. The workaround is noted in the dotnet sdk repository. From that, you need to use Sdk imports in your csproj instead of the Sdk attribute on the Project element.
<Project>
<PropertyGroup>
<BaseIntermediateOutputPath>obj\XXX\</BaseIntermediateOutputPath>
</PropertyGroup>
<Import Project="Sdk.props" Sdk="Microsoft.NET.Sdk" />
<!-- Body of project -->
<Import Project="Sdk.targets" Sdk="Microsoft.NET.Sdk" />
</Project>

netcoreapp1.0 not compatible with net45

3 hours of googling and I still can't find an answer
I tried this also: Package [some package] is not compatible with netcoreapp1.0
Still doesn't work, I even added net45 and net40 reference on the imports. Another is problem is my mvc core project doesnt have a package.json
Because you are probably using VS2017, you won't have a project.json since it doesn't exist any longer. So, doing the following will get you to hopefully a working project.
<PropertyGroup>
<TargetFramework>net452</TargetFramework>
<RuntimeIdentifier>win7-x86</RuntimeIdentifier>
</PropertyGroup>
<ItemGroup>
<PackageReference Include="Microsoft.ApplicationInsights.AspNetCore" Version="2.0.0" />
<PackageReference Include="Microsoft.AspNet.SignalR.Core" Version="2.2.1" />
<PackageReference Include="Microsoft.AspNetCore" Version="1.1.1" />
<PackageReference Include="Microsoft.AspNetCore.Mvc" Version="1.1.2" />
<PackageReference Include="Microsoft.AspNetCore.Owin" Version="1.1.1" />
<PackageReference Include="Microsoft.AspNetCore.StaticFiles" Version="1.1.1" />
<PackageReference Include="Microsoft.Extensions.Logging.Debug" Version="1.1.1" />
<PackageReference Include="Microsoft.VisualStudio.Web.BrowserLink" Version="1.1.0" />
</ItemGroup>
<ItemGroup>
<DotNetCliToolReference Include="Microsoft.VisualStudio.Web.CodeGeneration.Tools" Version="1.0.0" />
</ItemGroup>
right click your project file edit .csproj, then remove and replace the <propertygroup> </propertygroup> and it's contents. Should work now to reference signalr packages. The unfortunate fun is you have to create your own middleware to tie it into the core framework..
https://www.codeproject.com/Articles/1115941/ASP-NET-Core-Building-a-Real-Time-Online-Poll-Syst
I did create the middleware really quick and it does compile. Whether it works I hadn't gotten that far. Keep in mind that link references the really old stuff before VS2017 and .csproj files for the projects.
hope that helps.

How to avoid xml document generation when using nuget pack

I'm creating the package for my assembly but I dont' want to include the docs/*.xml files in my nuget package. I have tried the -Exclude switch of the pack command and the exclude property for the files section in the nuspec file to explictly excluding these files. None of these worked. So every time I generate my nuget package and then test it by installing it in the target project it always adds a docs folder with all the xml files. How can I avoid that the xml files are included into the nuget package? Any help would be highly appreciated.
To exclude all .xml files you should use the **\*.xml wildcard. I am guessing that you are using *.xml which will not work.
To exclude all .xml files you could use a nuget command line similar to the following:
nuget.exe pack MyPackage.nuspec -Exclude **\*.xml
If you only need to exclude .xml files in the docs directory then you can use a nuget command line similar to the following:
nuget.exe package MyPackage.nuspec -Exclude **\docs\*.xml
The wildcards seem to work relative to the folder that your .nuspec file is in.So if you have an .xml file in a docs subfolder relative to the .nuspec file then a wildcard if docs*.xml should work too.
Thank you Matt, I'm already doing what you mentioned but seems to me that Nuget does some other things by convention. Even if I use the exclude just like you said the docs folder is included. I resolved the issue by generating the nuspec file with the -a switch (I was using my .csproj file). I also had to copy the .dll file to a folder outside of my solution's folder. This way everything worked fine and as expected.
Anyway your answer is accurate but in my scenario it wasn't working. Not sure if this is by design.
Here's my final msbuild file which I'm currently using to generate the package. Hopefully Nuget soon will add more switches to the spec command so we won't have to modify so much the nuspec file afterwards.
<Project DefaultTargets="NugetPackage" xmlns="http://schemas.microsoft.com/developer/msbuild/2003">
<PropertyGroup>
<Configuration Condition=" '$(Configuration)' == '' ">Debug</Configuration>
<OutputPathCore>NugetPkgs\$(Configuration)\My.Assembly</OutputPathCore>
<NuGetExePath>assets\nuget.exe</NuGetExePath>
<Import Project="$(MSBuildExtensionsPath)\MSBuildCommunityTasks\MSBuild.Community.Tasks.Targets"/>
<Import Project="$(MSBuildExtensionsPath)\ExtensionPack\4.0\MSBuild.ExtensionPack.tasks"/>
<Target Name="NugetPackage" DependsOnTargets="PackageClean;BuildNugetPackageMyAssembly">
<Target Name="PackageClean">
<RemoveDir Directories ="NugetPkgs\$(Configuration)" ContinueOnError ="true"/>
<Target Name="BuildNugetPackageMyAssembly">
<MakeDir Directories="$(OutputPathCore)" />
<MakeDir Directories="$(OutputPathCore)\Package" />
<MakeDir Directories="$(OutputPathCore)\lib\net40" />
<MakeDir Directories="$(OutputPathCore)\lib\net20" />
<MakeDir Directories="$(OutputPathCore)\lib\net20-cf" />
<Copy
DestinationFolder="$(OutputPathCore)\lib\net40"
SourceFiles="Source\My.Assembly\bin\$(Configuration)\My.Assembly.dll" />
<Copy
DestinationFolder="$(OutputPathCore)\lib\net20"
SourceFiles="VS2008\Source\My.Assembly\bin\$(Configuration)\My.Assembly.dll" />
<Copy
DestinationFolder="$(OutputPathCore)\lib\net20-cf"
SourceFiles="VS2008\Source\My.Assembly.CF\bin\$(Configuration)\My.Assembly.CF.dll" />
<Copy DestinationFolder="$(OutputPathCore)\content" SourceFiles="CHANGES" />
<Copy SourceFiles="Release Notes.txt" DestinationFiles="$(OutputPathCore)\Readme.txt" />
<Exec Command=""$(NuGetExePath)" spec -a "$(OutputPathCore)\lib\net40\My.Assembly.dll"" />
<XmlUpdate Namespace="http://schemas.microsoft.com/packaging/2010/07/nuspec.xsd" XmlFileName="My.Assembly.nuspec" XPath="//package/metadata/licenseUrl" Value="http://someurl" />
<XmlUpdate Namespace="http://schemas.microsoft.com/packaging/2010/07/nuspec.xsd" XmlFileName="My.Assembly.nuspec" XPath="//package/metadata/projectUrl" Value="http://someurl" />
<XmlUpdate Namespace="http://schemas.microsoft.com/packaging/2010/07/nuspec.xsd" XmlFileName="My.Assembly.nuspec" XPath="//package/metadata/iconUrl" Value="http://somenice.png" />
<XmlUpdate Namespace="http://schemas.microsoft.com/packaging/2010/07/nuspec.xsd" XmlFileName="My.Assembly.nuspec" XPath="//package/metadata/tags" Value="My.Assembly" />
<XmlUpdate Namespace="http://schemas.microsoft.com/packaging/2010/07/nuspec.xsd" XmlFileName="My.Assembly.nuspec" XPath="//package/metadata/releaseNotes" Value="Review readme.txt for details." />
<ItemGroup>
<file Include="Source\My.Assembly\bin\$(Configuration)\My.Assembly.dll"/>
<file Include="VS2008\Source\My.Assembly\bin\$(Configuration)\My.Assembly.dll"/>
<file Include="$(OutputPathCore)\Readme.txt"/>
</ItemGroup>
<MSBuild.ExtensionPack.Xml.XmlFile TaskAction="RemoveElement" File="My.Assembly.nuspec" Element="dependencies" XPath="//package/metadata/dependencies" />
<MSBuild.ExtensionPack.Xml.XmlFile TaskAction="AddElement" File="My.Assembly.nuspec" Key="" Value="" Element="files" XPath="//package" InsertAfterXPath="//package" />
<MSBuild.ExtensionPack.Xml.XmlFile TaskAction="AddElement" File="My.Assembly.nuspec" Key="src" Value="%(file.Identity)" Element="file" XPath="//package/files" />
<MSBuild.ExtensionPack.Xml.XmlFile TaskAction="AddAttribute" File="My.Assembly.nuspec" XPath="//package/files/*[1]" Key="target" Value="lib\net40" />
<MSBuild.ExtensionPack.Xml.XmlFile TaskAction="AddAttribute" File="My.Assembly.nuspec" XPath="//package/files/*[2]" Key="target" Value="lib\net20" />
<MSBuild.ExtensionPack.Xml.XmlFile TaskAction="AddAttribute" File="My.Assembly.nuspec" XPath="//package/files/*[3]" Key="target" Value=""/>
<Exec Command=""$(NuGetExePath)" pack My.Assembly.nuspec -OutputDirectory "$(OutputPathCore)\Package" -NoPackageAnalysis" />
<Delete Files ="My.Assembly.nuspec" />
Another thing I can think of is
Create a nuspec file and edit it. this needs to be done only once (could be checked in as well). Any reasons you are editing the nuspec file while doing build?
use files element in nuspec file to copy files to destination folders
<files>
<file src="bin\Debug\*.dll" target="lib" />
<file src="bin\Debug\*.pdb" target="lib" />
<file src="tools\*\.*" exclude="*\.log" />
</files>
3. pack command can remain to be done at build time.
more details for files can be found here http://docs.nuget.org/docs/reference/nuspec-reference