Can share global namespaces across .net 6 projects? - c#

In .Net 6, we gained Global Usings. I have several projects that are similar and I'd like to share the same GlobalNamespaces.cs file I've created across the projects.
I tried to add the file as a link in Visual Studio, but after removing the usings of that file, I'm getting build errors.
Is there a way to share it across projects?
An example:
c:\myproject\src\GlobalUsings.cs
c:\myproject\src\Project1\ (*.csproj, cs files)
c:\myproject\src\Project2\ (*.csproj, cs files)
I want to use GlobalUsings in both.

Thanks to #gsferreira's article and a link to an example from his tweet
I was able to add a Directory.Build.props file next to my .sln and it works!
<Project>
<PropertyGroup>
<LangVersion>latest</LangVersion>
</PropertyGroup>
<ItemGroup Condition="'$(MSBuildProjectExtension)' == '.csproj' AND '$(MSBuildProjectName)' != 'My.Other.Project'">
<Using Include="Newtonsoft.Json" />
</ItemGroup>
</Project>
This works now!
// using Newtonsoft.Json;
namespace Project2;
public class Class1
{
JToken token = new JObject();
}
This works well for global using, but I found it was more complicated than I expected since there are some project that don't have nuget packages or other projects referenced. So the Global usings isn't really global, but more specific to what the project has referenced. If the similar projects were in a same sub folder, maybe that would work better. I haven't tried nesting Directory.Build.props files

Related

How to make visual studio project use <ReferencePackage> or DLL reference And <ProjectReference> together to switch between Debug and DLL Release?

Please I have a problem. sorry if question title are not recognized well, I can't upload full-image during my reputations.
Edit:
I need something like that maybe
https://github.com/RicoSuter/NuGetReferenceSwitcher
or
https://github.com/0UserName/NuGetSwitcher
but above repos are not updated to VS 2022? please any help?
Edit: Looks like other people asks about that issue: https://github.com/dotnet/sdk/issues/1151
Shortly, I need to make a Class Library project can modify/edit in my side only. Other people only use DLL reference or Nuget package.
What I need to do?
I need to create a main project that used across me as public source and other people as DLL only not debuggable.
In my side the class library project must seen if I choose MSBuild configuration (Debug mode) not Nuget DLL. but I need to modify whole core source. Then republish it again as Nuget to allow other people to use it privately.
I guess the whole gape in main project .csproj file. I need to modify it to allow Configuration to switch between Nuget build that visible to other developers and Debug that only visible at me. When choose it the <ProjectReference> should load and should become visible at my solution.
You can ignore Github things I mentioned. A repo can be private/public wihtout problem.
Problem Short Description:
I have main project in solution A. (Must be GIT public for other people)
I have class library in solution B (Which maybe used in 2 main projects) (Must be GIT private repo for me only)
I need the class library source only visible for me not other people. they just see Package or DLL.
The main project are public Git repo, while class library are private Git repo.
In my case I need to setup a 2 types of MSBuild configuration. (Debug/) and (Nuget/ )
the other people only allowed to use which are private nuget package and they must not debug the class library.
I need only me to use (Debug/<ProjectReference>) -> So I can change class library directly and build Nuget package for other people without PDB file,etc included.
What I try to do? What topics I read?
I Following topics I follow: Use local source code of NuGet package to debug and edit code (#Mr Qian comment)
and https://sitecore.stackexchange.com/questions/15293/what-are-packagereferences-and-how-will-they-help-optimise-the-way-i-deal-with-n/15294
I create two solutions. First (FooProject Executable), Second(FooClassLibrary)
I modify the FooProject.csproj and add following lines
<ItemGroup Condition="'$(Configuration)' == 'Debug'">
<ProjectReference
Include="..\..\FooClassLibrary\FooClassLibrary\FooClassLibrary.csproj">
<Project>{a2329af5-316e-4339-8b56-d78aba72e919}</Project>
<Name>FooClassLibrary</Name>
</ProjectReference>
</ItemGroup>
<ItemGroup Condition="'$(Configuration)' == 'Release'">
<Reference Include="FooClassLibrary">
<HintPath>..\..\FooClassLibrary\FooClassLibrary\bin\Release\FooClassLibrary.dll>
</HintPath>
</Reference>
</ItemGroup>
Edit:
I fix issues in above .csproj code. Now class library referenced with two MSBuild configuration (Debug and Release). But I don't add Class Libray in FooProject solution in Debug MSBuild.
Should now I create two solutions *.sln files? one for FooProject and reference with FooClassLibrary as DLL for non-modifying debugging?
And second FooProject solution (FooClassDebuggingAndEdit.sln) that reference project to FooProject?
Here's a two solutions *.rar link
https://anonfiles.com/rdm8A4I2x9/TwoSolutions_rar
I don't know why a solution should also reference the ClassLibrary project or it can't modified when do <ReferenceProject> in FooProject. I got following error message when debug:
Do I need change something?
Currently there's no official solution for that.
So if anyone need what approach I collected and I modify some tags to prevent conflict PackageName with ProjectName, Here's final solution, Which original copied from https://github.com/dotnet/sdk/issues/1151#issuecomment-459275750
Many thanks to script author:
Here's enhancement version of it:
<PropertyGroup>
<ReplacePackageReferences Condition="'$(ReplacePackageReferences)' == ''">true</ReplacePackageReferences>
<ReplaceProjectReferences Condition="'$(ReplaceProjectReferences)' == ''">true</ReplaceProjectReferences>
</PropertyGroup>
<Choose>
<When Condition="'$(SolutionPath)' != '' AND '$(SolutionPath)' != '*undefined*' AND Exists('$(SolutionPath)')">
<PropertyGroup>
<SolutionFileContent>$([System.IO.File]::ReadAllText($(SolutionPath)))</SolutionFileContent>
<SmartSolutionDir>$([System.IO.Path]::GetDirectoryName( $(SolutionPath) ))</SmartSolutionDir>
<RegexPattern>(?<="[PackageName]", ")(.*)(?=", ")</RegexPattern>
<HasSolution>true</HasSolution>
</PropertyGroup>
</When>
<Otherwise>
<PropertyGroup>
<HasSolution>false</HasSolution>
</PropertyGroup>
</Otherwise>
</Choose>
<Choose>
<When Condition="$(ReplacePackageReferences) AND $(HasSolution)">
<ItemGroup>
<!-- Keep the identity of the packagereference -->
<SmartPackageReference Include="#(PackageReference)">
<InProject>false</InProject>
<PackageName>%(Identity)</PackageName>
<InSolution>$(SolutionFileContent.Contains('\%(Identity).csproj'))</InSolution>
</SmartPackageReference>
<!-- Filter them by mapping them to another itemGroup using the WithMetadataValue item function -->
<PackageInSolution Include="#(SmartPackageReference -> WithMetadataValue('InSolution', True) )">
<Pattern>$(RegexPattern.Replace('[PackageName]','%(PackageName)') )</Pattern>
<SmartPath>$([System.Text.RegularExpressions.Regex]::Match( '$(SolutionFileContent)', '%(Pattern)' ))</SmartPath>
<ProjName>'%(PackageName)'</ProjName>
</PackageInSolution>
<ProjectReference Include="#(PackageInSolution -> '$(SmartSolutionDir)\%(SmartPath)' )">
<Name>#(PackageInSolution -> %(ProjName))</Name>
</ProjectReference>
<!-- Remove the package references that are now referenced as projects -->
<PackageReference Remove="#(PackageInSolution -> '%(PackageName)' )" />
</ItemGroup>
</When>
<When Condition="$(ReplaceProjectReferences) AND '$(_RestoreSolutionFileUsed)' == ''">
<ItemGroup>
<!-- Keep the identity of the project reference (relative path), determine the project name and whether the project is contained in the current solution -->
<SmartProjectReference Include="#(ProjectReference)">
<OriginalIdentity>%(Identity)</OriginalIdentity>
<ProjectName>$([System.IO.Path]::GetFileNameWithoutExtension( $([System.IO.Path]::GetFullPath( '%(OriginalIdentity)' )) ))</ProjectName>
<InSolution>$(SolutionFileContent.Contains('\%(ProjectName).csproj'))</InSolution>
</SmartProjectReference>
<!-- Filter them by mapping them to another itemGroup using the WithMetadataValue item function -->
<ProjectNotInSolution Include="#(SmartProjectReference -> WithMetadataValue('InSolution', False) )">
</ProjectNotInSolution>
<!--Reference the latest version of the package (why not * ? > see https://github.com/NuGet/Home/issues/7328-->
<PackageReference Include="#(ProjectNotInSolution -> '%(ProjectName)' )" Version="*" />
<!-- Remove the project references that are now referenced as packages -->
<ProjectReference Remove="#(ProjectNotInSolution -> '%(OriginalIdentity)' )" />
</ItemGroup>
</When>
</Choose>
Note if you need to auto update nuget package then you must specify the package above the script provided above:
<ItemGroup>
<PackageReferen``ce Include="FooClassLibrary" Version="*"/>
</ItemGroup>
Feel free to modify or edit above script or edit the answer. If you found better answer please post it (Ex You create new extension for that or something).

Adding reference to another executable with ReferenceOutputAssembly=false doesn't copy dependencies

I have a solution with several executables in it (say, MainApp.exe and Tool.exe).
The main goal is to ensure that the tool (Tool.exe) with its dependencies is copied to the main executable directory during build.
I used the advice from here, and it seemed to work with the older Visual Studio version (at least with some version prior to 16.8).
My project structure (simplified) looks like this:
Solution.sln
├ MainApp.csproj
├ Tool.csproj
| └ App.config
└ ToolLib.csproj
Tool project contains App.config file, and references ToolLib project.
My MainApp.csproj looks like this:
<Project Sdk="Microsoft.NET.Sdk">
<PropertyGroup>
<TargetFramework>netcoreapp3.1</TargetFramework>
<OutputType>Exe</OutputType>
</PropertyGroup>
<ItemGroup>
<ProjectReference Include="../Tool/Tool.csproj">
<ReferenceOutputAssembly>false</ReferenceOutputAssembly>
<OutputItemType>Content</OutputItemType>
<CopyToOutputDirectory>PreserveNewest</CopyToOutputDirectory>
<Targets>Build;DebugSymbolsProjectOutputGroup</Targets>
</ProjectReference>
</ItemGroup>
</Project>
After upgrading to 16.8 after the compilation the file Tool.exe was indeed copied to the output directory, but neither its dependency ToolLib.dll nor Tool.config was copied to the output directory any more.
Is this a bug or intended behaviour? What is the proper way to ensure that the whole Tool with all the needed dependencies is copied to the MainApp's output dir?
Added test project reproducing the problem here: https://github.com/vladd/ReferenceOutputAssembly
What you gave is too old and it is not suitable for VS2019. And all your projects target to net core 3.1. I have tested your project both in VS2019 16.8 , VS2019 16.7, even 16.6 which all act the same behavior as you described. Only contain the Tool.dll and Tool.exe.
So I wonder why you said before that the result of the build of ToolLib will be printed in the main project.
Actually, <ReferenceOutputAssembly>false</ReferenceOutputAssembly> will prevent the most main output files of the referenced project and its dependency project being copied into the main project.
Suggestion
You have to set it as true:
<ReferenceOutputAssembly>true</ReferenceOutputAssembly>
If you want to not copy ToolLib.pdb and Tool.pdb files into the main project, you could add these node on MainApp.csproj file:
<PropertyGroup>
<AllowedReferenceRelatedFileExtensions>*.pdb;.dll.config</AllowedReferenceRelatedFileExtensions>
</PropertyGroup>
If you also want to copy pdb files, you should add .pdb under AllowedReferenceRelatedFileExtensions.
<AllowedReferenceRelatedFileExtensions>.pdb;.dll.config</AllowedReferenceRelatedFileExtensions>
Update 1
I tried your suggestion but with it the files Tools.deps,json and
Tool.runtimeconfig.json are not copied, so running the tool fails.
Add this on MainApp.csproj file:
<PropertyGroup>
<AllowedReferenceRelatedFileExtensions>.pdb;.dll.config;.runtimeconfig.dev.json;.runtimeconfig.json</AllowedReferenceRelatedFileExtensions>
</PropertyGroup>

Xamarin Forms Solution based on existing standard solution

Im looking for a way to extend a working standard Xamarin Forms solution with its own git repository with another customer specific solution taht should have its own project as extra to the solution.
STANDARD SOLUTION
Projects
UWP
DROID
IOS
Application (.net standard )
CORE (.net standard )
The new Solution should use the existing solution.
CUSTOMER SOLUTION
ADD EXISTING (Project)
UWP
DROID
IOS
Application (.net standard )
CORE (.net standard )
When only the original projects are added, everythings works as expected.
SO how to add the custom project and logic to the new solution.
I was hoping to add project to the Customer solution using something like this.
Some inject or discover ICustomerProjectAdapter during startup.
I tried
[assembly: Xamarin.Forms.Dependency(typeof(CustomTemplateAdapter))]
namespace CustomTemplate
{
public class CustomTemplateAdapter : ICustomerProjectAdapter
{
public string Test { get { return "HELLO WORLD - Custom Template";} }
}
}
but this didnt work CustomerProjectAdapter was always null.
var CustomerProjectAdapter = DependencyService.Get<ICustomerProjectAdapter>();
How can we use a standard Xamarin forms Solution and extend it using a second repository/2nd solution and have some form of injection to use a extra Project.
Each customer solution would use this process.
I dont want to add customer specific code into the Main repository.
Using customer specific configurations or having customer specific sections
in csproj file would be ok. At code level also adding customer section would be ok if it is restricted a singe injection point.
I also tried adding references to MAIN cs.proj using a pre compile time script.
this resulted in Not found errors in Visual studio when switch between solutions. . But even with the csproj changed at compile time, the discovery/inject problem still wasnt solved.
How do i best solve this type of problem?
So in case someone is looking for such a solution I got conditions in project file working. It solves the problem nicely.
The only compromise and reference to customer code or projects is restricted to one project and is only inside the csproj file. We have a fascade project responsible for returning an instance of a custom-adpater that resides in another project. This project is referenced at build time.
Compile and syntax checks inside VS all work based on the solution currently open.
<Project Sdk="Microsoft.NET.Sdk">
<PropertyGroup>
<TargetFramework>netstandard2.0</TargetFramework>
</PropertyGroup>
<Choose>
<When Condition="'$(SolutionName)' == 'MyCustomSolution' ">
<ItemGroup>
<ProjectReference Include="..\..\XPC_CustomRepos\CUSTOMERn\Customern.csproj">
<Name>XYZ.CustomAdapter</Name>
</ProjectReference>
</ItemGroup>
</When>
<!-- Repeat for each custom solution -->
<Otherwise>
<ItemGroup>
<ProjectReference Include="..\STANDARD.Adapter\XYZ.Adapter.csproj">
<Name>XYZ.Standard</Name>
</ProjectReference>
</ItemGroup>
</Otherwise>
</Choose>
</Project>

exclude certain projects from using Directory.Build.props

i have a new visual studio solution that has around 350 projects. it takes visual studio a lot of time to compile the .sln file so i implemented Directory.Build.props to avoid copying of references that are not needed to copy to the local directory so the build can be made quicker. below is the code that im using inside the Directory.Build.props file under the root folder.
<Project xmlns="http://schemas.microsoft.com/developer/msbuild/2003">
<ItemDefinitionGroup>
<Reference>
<Private>False</Private>
</Reference>
<ProjectReference>
<Private>False</Private>
</ProjectReference>
</ItemDefinitionGroup>
</Project>
since i placed Directory.Build.props under root folder it is being applied for all projects.
Question::
how can i exclude few projects from applying Directory.Build.props so that the references can be copied to the local.
in short i want the Directory.Build.props to be applied to only 300 projects under the solution file remaining 50 projects need to be excluded from this
how/where can i write a condition in the above code that will exclude certain projects being affected by this code
For others dealing with the same problem, there is another trick that can be used to exclude certain project from using the Directory.Build.props file found at root level.
If you add a dummy Directory.Build.props file in the project you want to exclude, then the Directory.Build.props from the root will not be used. This is because MSBuild walks the directory structure upwards from the location of your project, until it locates the first Directory.Build.props. That will be used. This behavior is documented on the Customize your build page under Search scope at the Microsoft docs.
Sample of the dummy Directory.Build.props:
<Project>
<!-- Only here so that the default Directory.Build.props will not be used. -->
</Project>
I found this to be a convenient way to solve this issue. Especially when dealing with only a few projects that need to be excluded.
I had to work around this in a bit of a hacky way.
In my example, there was a custom analyzer project I wrote that I did not want included in another set of projects. I ended up writing something like this in my Directory.Build.props:
<Project>
...
<Choose>
<When Condition="$(MSBuildProjectName)!='Analyzer' AND ...">
<ItemGroup>
<ProjectReference Include="..\Analyzer\Analyzer.csproj">
<ReferenceOutputAssembly>false</ReferenceOutputAssembly>
<OutputItemType>Analyzer</OutputItemType>
</ProjectReference>
</ItemGroup>
</When>
<Otherwise>
...
</Otherwise>
</Choose>
...
</Project>
Where I filled in ... with the projects I wanted it to skip.
I understand this may not be the exact answer you were looking for, but I did a ton of research and was also unable to find any way to do it the way you described. The stuff I have posted was the only way I was able to achieve the ability to exclude certain things from being applied to specific projects by filtering via name. I know that this is hacky and sucks, but it's the only thing that was able to work for me.
Also note that <Otherwise></Otherwise> may be turned into <Otherwise /> possibly, and may even be optional altogether. I left it there so that you could place stuff inside of it if needed.

Using the same assembly references in csproj with different folder structures

I have a C# project, MyProject.csproj that sits in a solution with the following folder structure and references Dependency.dll:
Libs
Dependency.dll
Projects
MyProject
MyProject.csproj
Thus the reference to Dependency.dll in MyProject.csproj has a HintPath of something like this:
..\..\Libs\Dependency.dll
Now I'd like to use MyProject in a different solution in a different project structure, without modifications, as source. This is because MyProject sits in its own source control repository and I'm using it in different solutions as Mercurial subrepositories/Git submodules. (The problem might be solved on the source control level...) Such a diffreent solution would look like this:
Libs
Dependency.dll
MyProject
MyProject.csproj
Note that the MyProject folder is now on the same level as the Libs folder. Thus the original HintPath is now invalid (since it should be ..\Libs\Dependency.dll) and I get build errors.
Is there a way to fix this but keep the same csproj across the different solutions?
I found the following possible solutions which are great but require the modification of the csproj. This is mostly possible in my case but sometimes there are external components where I can't request such modifications, so I'd look for some solution-level override if possible.
Conditional HintPath based on file existence check: .csproj multiple hint paths for an assembly This might work as for the majority of cases the solution structure is well-known here.
Specifying multiple assembly search locations: https://stackoverflow.com/a/15816779/220230
Thank you.
For now, I solved the issue using the technique outlined in this blog post.
<ItemGroup>
<LibReferenceSearchPathFiles Include="..\..\Libs\**\*.dll">
<InProject>false</InProject>
</LibReferenceSearchPathFiles>
</ItemGroup>
<Target Name="BeforeResolveReferences">
<RemoveDuplicates Inputs="#(LibReferenceSearchPathFiles->'%(RootDir)%(Directory)')">
<Output TaskParameter="Filtered" ItemName="LibReferenceSearchPath" />
</RemoveDuplicates>
<CreateProperty Value="#(LibReferenceSearchPath);$(AssemblySearchPaths)">
<Output TaskParameter="Value" PropertyName="AssemblySearchPaths" />
</CreateProperty>
</Target>
This enables dlls from subfolders of Libs to be loaded. If all the dlls would be in the root of the Libs folder, then the first wildcard can be removed from the Include value.

Categories