C# targeting multiple frameworks - c#-7.3

I've tried doing some searching on this but as I am unsure of "what" this is I didn't get very far so it's most likely a duplicate of another question I couldn't find.
I'm looking at a piece of code for a little test application and noticed the "Target Framework" drop down in properties was disabled. Editing the .csproj file shows me this:
<TargetFrameworks>net451;netcoreapp1.0;netcoreapp2.0</TargetFrameworks>
Looking a little lower down in the file, I see this:
<ItemGroup Condition="'$(TargetFramework)' != 'netstandard2.0'">
<PackageReference Include="Microsoft.AspNetCore.Server.IISIntegration" Version="1.0.2" />
<PackageReference Include="Microsoft.AspNetCore.Server.Kestrel" Version="1.0.3" />
</ItemGroup>
<ItemGroup Condition="'$(TargetFramework)' == 'netstandard2.0'">
<PackageReference Include="Microsoft.AspNetCore.All" Version="2.0.0" />
</ItemGroup>
<ItemGroup Condition="'$(TargetFramework)' == 'net451' ">
<Reference Include="System" />
<Reference Include="Microsoft.CSharp" />
</ItemGroup>
Would someone please just point me in the right direction to understand what this is, how this works and what it's use case is?
Further to that then, looking at this directive for a Task
#if NET451
return Task.FromResult(true);
#else
return Task.CompletedTask;
#endif
I note that the NET451 is enabled and I'm trying to find out why this is the one it selected instead of netstandard2.0? Normally I could just select the targeted framework but as I mentioned, the drop down is disabled, so I'm trying to understand how it's selecting the one it is.

You can look at TargetFramework as the current target from TargetFrameworks. MSBuild will build each target at a time.
Sadly, there's still no UI for TargetFrameworks.
The way you choose which one is active in Visual Studio is in the top left combo box at the top of the editor window.

Related

Slow Cheetah not working in when building

I have added Cheeatah to simplify managing my configuration.
I can see the changes in the Preview. But when I look at the config when I build I dont see it transforming my config file. I have selected the configuration and click build. Am I missing something
Make sure the configuration file reference in the project file as the TransformOnBuild node with a value of True, below is an example:
<None Include="App.config">
<TransformOnBuild>True</TransformOnBuild>
</None>
Unlike Kieron's answer, in my situation, <TransformOnBuild> was only set for Designer. Just had to delete that condition:
<None Include="App.config">
<SubType>Designer</SubType>
<TransformOnBuild>true</TransformOnBuild>
</None>
An other situation in which the same error occurs:
<Content Include="Castle.Config.Xml">
<TransformOnBuild>true</TransformOnBuild>
<CopyToOutputDirectory>Always</CopyToOutputDirectory>
</Content>
Problem: TransformOnBuild vs CopyToOutputDirectory!
"TransformOnBuild" is a implicit "CopyToOutputDirectory". If you define both, first the transformation is done, then "copy" overrides you transformed file.
This situation in our project happend cause a developer has set the copy tag accidentially. It seems, that the order was not in all situations the same. Removing the CopyToOutputDirectory solves this problem.
This version works as expected:
<Content Include="Castle.Config.Xml">
<TransformOnBuild>true</TransformOnBuild>
</Content>

Using $(PlatformTarget) for content items in csproj files

I'd like to use the selected platform target -- $(PlatformTarget) for certain content items in my .csproj file.
For example:
<Content Include="Plugins\$(PlatformTarget)\Plugins.dll">
<CopyToOutputDirectory>PreserveNewest</CopyToOutputDirectory>
</Content>
When opening this project in VS, it seems that the platform target property is not yet resolved (the file appears to be non-existing).
Is there any way to overcome this?
Do you mean $(Platform)?
<Content Include="Plugins\$(Platform)\Plugins.dll">
<CopyToOutputDirectory>PreserveNewest</CopyToOutputDirectory>
</Content>

BuildingInsideVisualStudio Property Value Not Working With File Reference and Project Reference Conditional

I am trying to add a project and file reference to the same dll in the csproj with the BuildingInVsideisualStudio property. But when they are in the csproj together, only the file reference is picked up. If I remove the file reference, it picks up the csproj. I have tried swapping the order, but no luck. Any ideas why this doesn't work?
Here is the basic idea:
<ItemGroup Condition="'$(BuildingInsideVisualStudio)' == false">
<Reference Include="MyNamespace.Mine">
<HintPath>..\$(OutDir)\MyNamespace.Mine.dll</HintPath>
</Reference>
</ItemGroup>
<ItemGroup Condition="'$(BuildingInsideVisualStudio)' == '' Or '$(BuildingInsideVisualStudio)' == true">
<ProjectReference Include="..\MyNamespace.Mine.csproj">
<Project>{GUID}</Project>
<Name>MyNamespace.Mine</Name>
</ProjectReference>
</ItemGroup>
Someone else has gone down this path, too, but it appears there are some caveats. I need to do this conditional because of my build process, which cannot change. Using the file reference forces me to lose the Go to Definition and Find All References (sorry, but I cannot install ReSharper to solve this either).
Two problems I see:
You didn't take into account that $(BuildingInsideVisualStudio) can be empty (''). For the first condition use:
<ItemGroup Condition="'$(BuildingInsideVisualStudio)' != 'true'">
Always surround both operands with single quotes:
<ItemGroup Condition="'$(BuildingInsideVisualStudio)' == 'true'">
MSDN reference:
Single quotes are not required for simple alphanumeric strings or
boolean values. However, single quotes are required for empty values.
UPDATE:
May be a long shot, but you can try using conditions on the property defintions:
<PropertyGroup Condition="'$(BuildingInsideVisualStudio)' != 'true'"><!-- In CMD -->
<ReferenceInclude>MyNamespace.Mine"</ReferenceInclude>
<ReferenceIncludePath>..\$(OutDir)\MyNamespace.Mine.dll</ReferenceIncludePath>
</PropertyGroup>
<PropertyGroup Condition="'$(BuildingInsideVisualStudio)' == 'true'"><!-- In VS -->
<ProjectReferenceInclude>..\MyNamespace.Mine.csproj</ProjectReferenceInclude>
<ProjectReferenceIncludeId>{GUID}</ProjectReferenceIncludeId>
</PropertyGroup>
So the references will get resolved conditionally:
<ItemGroup>
<Reference Include="$(ReferenceInclude)">
<HintPath>$(ReferenceIncludePath)</HintPath>
</Reference>
</ItemGroup>
<ItemGroup>
<ProjectReference Include="$(ProjectReferenceInclude)">
<Project>$(ProjectReferenceIncludeId)</Project>
<Name>%(ProjectReferenceInclude.MSBuildProjectName)</Name>
</ProjectReference>
</ItemGroup>
In Visual Studio 2010 and 2012 you can also use a Choose statement instead of adding a reference with a condition. This seems to work a lot better:
<Choose>
<When Condition="('$(VisualStudioVersion)' == '10.0' or '$(VisualStudioVersion)' == '') and '$(TargetFrameworkVersion)' == 'v3.5'">
<ItemGroup>
<Reference Include="Microsoft.VisualStudio.QualityTools.UnitTestFramework, Version=10.1.0.0, Culture=neutral, PublicKeyToken=b03f5f7f11d50a3a, processorArchitecture=MSIL" />
</ItemGroup>
</When>
<Otherwise>
<ItemGroup>
<Reference Include="Microsoft.VisualStudio.QualityTools.UnitTestFramework" />
</ItemGroup>
</Otherwise>
</Choose>
Assuming I understood the question correctly after bit of experimentation it seems that naming them differently would solve most of the problems; msbuild would respect the condition and use assembly reference, VS would display them both in solution explorer but would prebuilt the reference as if it is project kind and would keep goto-definition without R# working. Conditional import is something else worth looking into but I haven't tried it.
<ItemGroup>
<ProjectReference Include="..\ClassLibrary1\ClassLibrary1.csproj" Condition="'$(Foo)'=='Bar1'">
<Project>{FD0E01BC-7777-4620-9EF2-5F60804B3173}</Project>
<Name>ClassLibrary1-ProjRef</Name>
</ProjectReference>
<Reference Include="ClassLibrary1" Condition="'$(Foo)'=='Bar2'">
<Name>ClassLibrary1-AssRef</Name>
<HintPath>..\ClassLibrary1\bin\Debug\ClassLibrary1.dll</HintPath>
</Reference>
</ItemGroup>
The response Microsoft posted to this question on Connect indicates that Visual Studio deliberately ignores conditions on assembly references, project or not. This is understandable; however, the resolution process seems to always prefer file-based references when the project file contains more than one reference to the same assembly, which is moot.
In short, you're out of luck, unless there is a way to tell VS to consider a project reference even with a file reference is present to the same assembly. I do not know of a way to do this, and I'd also be interested to learn if it's still possible somehow.

VS Setup Project target app.config in ..obj\x86\Release

I created an app.config transform for my WinForms project using Dan Abramov's solution here. Works great and the config file is transformed and present in the correct obj folder.
When I look at the outputs for the Primary Output of my application, it gets the app.config from the project directory instead of the corresponding obj folder like everything else...a big oversight, in my opinion, by MSFT. Obviously, they didn't have transforms in mind for all config file types.
So now, how do I get the Primary Output of my main project to output the config file from the obj folder based on the build configuration?
Have you tried using SlowCheetah (a VS extension) which enables you to transform app.config in the same way that web.config works. Also your scenario for transforming app.config for a setup project is supported.
I found the work around I was looking for here. Scroll to the bottom and see kakoskin's answer. In conjunction with Dan Abramov's solution, I was able to get the results I was looking for. Here's the MSBuild code I used:
<Target Name="AfterBuild" Condition="exists('app.$(Configuration).config')">
<TransformXml Source="app.config" Destination="$(IntermediateOutputPath)$(TargetFileName).config" Transform="app.$(Configuration).config" />
<!-- Force build process to use the transformed configuration file from now on. -->
<ItemGroup>
<AppConfigWithTargetPath Remove="app.config" />
<AppConfigWithTargetPath Include="$(IntermediateOutputPath)$(TargetFileName).config">
<TargetPath>$(TargetFileName).config</TargetPath>
</AppConfigWithTargetPath>
</ItemGroup>
<TransformXml Source="App.config" Transform="app.$(Configuration).config" Destination="App.Transformed.config" />
The <ItemGroup> section will remove the app.config file from the corresponding obj\ folder and replace it with the transformed config file, which is not needed but I left it in there anyways.
Hope this helps others out as well!

WinForm partial classes

I have a WinForm project that contains a form called MainUI. You can see that the automatically generated partial class shows up as a node under MainUI.cs. Is there a way to "move" my self created partial class MainUI.Other.cs under MainUI.cs so that it'll show as another node?
Close the solution in Visual Studio, and open your .csproj file in a text editor. Find MainUI.Other.cs, and add the following XML element:
<Compile Include="MainUI.Other.cs">
<SubType>Form</SubType>
<DependentUpon>MainUI.cs</DependentUpon> <!-- this is the magic incantation -->
</Compile>
Reopen the solution in Visual Studio and enjoy subnodular goodness.
That said, you may want to reconsider whether this is a good idea. The reason the .designer.cs file is displayed as a subnode is because you won't normally need or want to open it, because it contains generated code which you'd normally view or edit through the designer. Whereas a partial class file will contain your code, that you'll want to edit and view; it may be confusing to maintenance programmers if the file is not easily visible in Solution Explorer. However, only you can know what's right for your project -- just something to bear in mind!
Yes, this is possible, but you will have to hand edit the project file.
In the project file (open it with the XML Editor) locate the file listing item group. In my example, I left the form as "Form1.cs". Add the child element "<DependentUpon>" to your extended class as per the example below:
<Compile Include="Form1.cs">
<SubType>Form</SubType>
</Compile>
<Compile Include="Form1.Designer.cs">
<DependentUpon>Form1.cs</DependentUpon>
</Compile>
<Compile Include="Form1.Designer.Other.cs">
<DependentUpon>Form1.cs</DependentUpon>
<SubType>Form</SubType>
</Compile>
Typically though you wouldn't want any non-generated code to be hidden as a child node though. My normal practice is to create a folder in the project called "Partial Classes" and add them all in the same location.
You can modify the project source file to group the related files.
In the project source file, find ItemGroup element which contains MainUI.cs and add an entry for MainUI.Others.cs
Here a blog post showing how to do it in details.
Group/nest source code files
Just to add to #itowlson's answer: if you're getting an error such as "Duplicate 'Compile' items were included." when compiling, that's probably because the files you're telling it to include are already included using a wild card.
The solution is to remove then add them to the compile config like so:
</Project>
<ItemGroup>
<Compile Remove="MainUI.Other1.cs" />
<Compile Remove="MainUI.Other2.cs" />
</ItemGroup>
<ItemGroup>
<Compile Include="MainUI.Other1.cs">
<DependentUpon>MainUI.cs</DependentUpon>
</Compile>
<Compile Include="MainUI.Other2.cs">
<DependentUpon>MainUI.cs</DependentUpon>
</Compile>
</ItemGroup>
</Project>

Resources