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>
Related
Following every guide everywhere:
Step 1:
Step 2: it works! Huzzah! Except that it doesn't. Instead I get yellow triangles:
This project is tiny for now because I only just started. The guides about yellow triangles talk about conflicts which can't be the case here. I have next to nothing imported or used yet:
Apparently this is due to using .Net Core and Microsoft couldn't anticipate that people would want to use forms in the new normal...
I found this:
How to use System.Windows.Forms in .NET Core class library
This is what worked:
Removed reference/dependancy entirely
Right-click project, Unload
Right-click project, Edit project file
Add the following:
<PropertyGroup>
<TargetFramework>net6.0-windows</TargetFramework>
<UseWPF>true</UseWPF>
<UseWindowsForms>true</UseWindowsForms>
</PropertyGroup>
Reload project file
Add "using system.windows.forms" to the top.
I'm trying out WPF .NET Core for the first time, and one of the things I always do in a new WPF .NET Framework project is turn on the console, but I receive an error when I try to do this in .NET Core.
In traditional WPF, targeting .NET Framework, this was fairly simple;
Set the Build Action for App.xaml to Page
Define a Main method somewhere, and tag it with the STAThreadAttribute
In the project settings, set the output type to Console Application, and set the Startup object to wherever you put the Main method
I replicated these steps in the WPF .NET Core, but I get an error when I try to change the Build Action for App.xaml
The error (it occurs immediately after selecting Page in the dropdown in the Properties window):
An error has occurred while saving the edited properties listed below:
Build Action
One or more values are invalid.
Cannot add 'App.xaml' to the project, because the path is explicitly excluded from the project
(C:\Program Files\dotnet\sdk\3.0.100\Sdks\Microsoft.NET.Sdk.WindowsDesktop\targets\Microsoft.NET.Sdk.WindowsDesktop.targets (45,5)).
Does anyone know a way around this, or another way to enable the console in WPF .NET Core?
Setting the following properties will make your WPF application a "Console Application"
<PropertyGroup>
<OutputType>Exe</OutputType>
<DisableWinExeOutputInference>true</DisableWinExeOutputInference>
</PropertyGroup>
The SDK automatically change OutputType from Exe to WinExe for WPF and WinForms apps. See https://learn.microsoft.com/en-us/dotnet/core/compatibility/windows-forms/5.0/automatically-infer-winexe-output-type
After some trial and error, I figured out that the .csproj file got messed up. I don't know how exactly it went wrong, I suspect it had to do with editing the project through its Properties window in that version of VS2019.
I edited the .csproj by hand, and it works if it looks as follows:
<Project Sdk="Microsoft.NET.Sdk.WindowsDesktop">
<PropertyGroup>
<OutputType>Exe</OutputType>
<TargetFramework>netcoreapp3.0</TargetFramework>
<UseWPF>true</UseWPF>
<ApplicationIcon />
<StartupObject>ProjectName.App</StartupObject>
</PropertyGroup>
<ItemGroup>
<Page Include="App.xaml"></Page>
</ItemGroup>
<ItemGroup>
<ApplicationDefinition Remove="App.xaml"></ApplicationDefinition> <--- key part
</ItemGroup>
</Project>
I checked the .csproj file for a working .NET Framework project, and the key seems to be removing App.xaml as ApplicationDefinition by hand, as the .NET Framework .csproj did not have that section in it.
I have an .NET Standard project where I implemented a module for an ASP.NET Core CMS framework. Currently, it uses the CMS framework libraries coming from NuGet packages. If I grab the source code of the CMS framework from GitHub and add my module to its solution and replace the package references to the actual project references it will work fine.
My goal is to make it work without updating the references in the csproj file so if the project is added to the full source code solution then use the project references, otherwise use the NuGet package references.
So let's say the .NET Standard project is called 'ModuleA'. It has a package reference to 'ModuleB':
<ItemGroup>
<PackageReference Include="ModuleB" Version="1.0.0" />
</ItemGroup>
When I want to use ModuleA in a solution where ModuleB is accessible then I use project reference to it:
<ItemGroup>
<ProjectReference Include="..\..\ModuleB\ModuleB.csproj" />
</ItemGroup>
I'd like to include both of them in the .csproj file somehow and make it to use the proper references on build (e.g. based on some conditions like project exists?).
If both are added to the csproj then the build will fail (e.g. 'Unable to find project ...ModuleB.csproj. Check that the project reference is valid and that project file exists.').
You could do that probably dynamically, but I think it's not really transparant how that would work.
I would recommend to add a configuration, e.g. in my example "Local-Debug" and use conditions in your csproj.
Example
Creating the configuration:
And in your csproj you could do this:
<ItemGroup>
<ProjectReference Condition="'$(Configuration)' == 'Local-Debug'" Include="otherProject.csproj" />
<PackageReference Condition="'$(Configuration)' != 'Local-Debug'" Include="otherProjectPackage" Version="2.4.1" />
</ItemGroup>
Your dependencies must be statically known and resolve-able at build-time. See #Julian's answer for a good config-driven build-time solution.
As a run-time solution: You can dynamically load your references at run-time. This way, you can search for the DLL you need in the working directory of your app and if you don't find it there, then download it (from Nuget or elsewhere), either as a binary that you can directly load, or as a source that you can build; and then load that library dynamically.
Here's how you can load an assembly dynamically (at run-time): https://learn.microsoft.com/en-us/dotnet/api/system.reflection.assembly.loadfrom?view=netframework-4.8
And this question: Loading library dynamically
Coding against a dynamically loaded assembly has its own quirks; you will need clear interface definitions for the referenced library, or else, you'll find yourself dealing with a lot of reflection and dynamics.
I'm following along with a talk by Immo Landwerth, in a .NET standard project, I saw him switching between projects (which are not typically projects under the solution) from the top left drop-down menu, here is a gif: https://image.ibb.co/mmjoHU/pre.gif
To reproduce the same thing I created a class library in .NET Framework to see the goings, but the project failed to load (with a modified csproj file to be the same as the demo's csproj), then I created a .NET standard library and modified the .csproj file to this (the same as the demo's csproj):
<Project Sdk="MSBuild.Sdk.Extras">
<PropertyGroup>
<TargetFrameworks>netstandard1.4;net461;uap10.0</TargetFrameworks>
</PropertyGroup>
<ItemGroup>
<PackageReference Include="System.ValueTuple" Version="4.3.0" />
</ItemGroup>
<ItemGroup Condition=" '$(TargetFramework)' == 'net461' ">
<Reference Include="System.Device" />
</ItemGroup>
</Project>
I could see the three target frameworks:netstandard1.4;net461;uap10.0. but really couldn't understand how they got mapped to the preprocessors: NET461, WINDOWS_UWP. which work on the Immo's project, but didn't work with my modified .NET standard library and the three targets didn't appear.
Looks like conditional compilation symbols with linked .cs files to me.
In the Properties > Build tab, you should see a textbox labelled "Conditional compilation symbols". Any strings you put in this textbox can be used to conditionally execute code with #if and #elif. There are also symbols that the build system is already aware of (some are listed here).
I'm assuming these projects also share the same .cs files, which explains the #if/#elif/#else conditions "flipping" within the same file (when you add a file to a project, choose add it as a link to an existing file, then a copy is not made).
I have done this exact thing on multiple projects for different configurations and the behavior matches the .gif you posted.
Currently I have this in multiple projects:
<PropertyGroup>
<InstallerMajorVersion>1</InstallerMajorVersion>
<InstallerMinorVersion>09</InstallerMinorVersion>
<InstallerBuildVersion>08</InstallerBuildVersion>
</PropertyGroup>
...
<PropertyGroup>
<OutputName>Project-$(InstallerMajorVersion).$(InstallerMinorVersion).$(InstallerBuildVersion)</OutputName>
</PropertyGroup>
I'd like to have this information (the first PropertyGroup) in only one file, so I don't have to edit it in multiple places. However I need to import or somehow get to this information from every project file so I can set OutputName correctly.
How do you share properties/variables between multiple projects?
I didn't have much luck with my <Import /> approach: VS2010 - Using <Import /> to share properties between setup projects?
How about creating an altogether separate project just for loading this configuration stuff, and compiling it as a separate library / DLL? You could then use that DLL in each of the other projects where you need to import these settings.
It works using Import. I just had problems with VS2010 caching. See the linked issue for more details.