Change project-properties with IWizard - c#

I created a template for a VS-project where I want to set some attributes provided by the user. So I implemented IWizard-interface:
public void RunStarted(object automationObject, Dictionary<string, string> replacementsDictionary, WizardRunKind runKind, object[] customParams)
{
string projectPath = replacementsDictionary["$destinationdirectory$"];
string projectName = replacementsDictionary["$projectname$"];
SchemaWizardForm frm = new SchemaWizardForm(projectPath, projectName);
frm.ShowDialog();
this.m_assemblyInfo = frm.AssemblyInfo;
replacementsDictionary["$assemblyTitle$"] = frm.AssemblyInfo.AssemblyName;
replacementsDictionary["$assemblyName$"] = frm.AssemblyInfo.AssemblyName;
replacementsDictionary["$copyrightYear$"] = DateTime.Now.Month + "/" + DateTime.Now.Year;
replacementsDictionary["$defaultNamespace$"] = frm.AssemblyInfo.RootNamespace;
}
Now within my template´s project-file I have something like this:
<Project ToolsVersion="4.0" DefaultTargets="Build" xmlns="http://schemas.microsoft.com/developer/msbuild/2003">
<PropertyGroup>
<Configuration Condition=" '$(Configuration)' == '' ">Debug</Configuration>
<Platform Condition=" '$(Platform)' == '' ">x86</Platform>
<ProductVersion>8.0.30703</ProductVersion>
<SchemaVersion>2.0</SchemaVersion>
<OutputType>Library</OutputType>
<AppDesignerFolder>Properties</AppDesignerFolder>
<RootNamespace>$defaultNamespace$</RootNamespace>
<AssemblyName>$assemblyName$</AssemblyName>
<TargetFrameworkVersion>v3.5</TargetFrameworkVersion>
<FileAlignment>512</FileAlignment>
</PropertyGroup>
</Project>
And in AssemblyInfo.cs:
[assembly: AssemblyTitle("$assemblyTitle$")]
[assembly: AssemblyCopyright("(C) $copyrightYear$ MyCompany")]
// ...
I can sucessfully create my project using the wizard. Its copyright-date from AssemblyInfo.cs after generation is [assembly: AssemblyCopyright("(C) 8/2016 MyCompany")] - which is fine. However the RootNamespace has a value similar to the projectsname. I already debugged the above code, where the replacementsDictionary dontains the correct entry for the namespace (see image below).
Here is the result-project
As you can see both the Assembly Name and the Default namespace contain the value from projectsname instead of what I entered in my user-form (asdas in my case). However the copyright-date accessable via the Assembly Information-button at Project-->Propertes-->Application is set correctly (not shown in the image).
Isn´t it possible to change the projects properties themeselfes using a replacementDictionary?

Obviously we can´t change the project´s properties via such a dictionary. What we can do instead is to modify the projectname-entry within this map which solved the issue for me. Now Assembly title, Assembly name and Default namespace all refer to that same variable. It is a bit annoying (in particular that we can´t change the name of the assembly and the namespace independently) but this works for me.
replacementsDictionary["$projectname$"] = frm.AssemblyInfo.ProjectName;
replacementsDictionary["$safeprojectname$"] = frm.AssemblyInfo.ProjectName;

Related

Roslyn fails to compile a trivial project

I am trying to use Roslyn to compile a trivial project but it fails.
Consider the following setup (assuming c:\temp exists and you have .NET 6 installed):
mkdir c:\temp\TestLib
notepad c:\temp\TestLib\TestLib.csproj
<Project Sdk="Microsoft.NET.Sdk">
<PropertyGroup>
<TargetFramework>net6.0</TargetFramework>
<ImplicitUsings>enable</ImplicitUsings>
<Nullable>enable</Nullable>
</PropertyGroup>
</Project>
notepad c:\temp\TestLib\SomeClass.cs
namespace TestLib
{
public class SomeClass
{
void DoThings()
{
Console.WriteLine("Things!");
}
}
}
cd c:\temp\TestLib
dotnet build
Result: Build succeeded
mkdir c:\temp\RoslynTrouble
notepad c:\temp\RoslynTrouble\RoslynTrouble.csproj
<Project Sdk="Microsoft.NET.Sdk">
<PropertyGroup>
<OutputType>Exe</OutputType>
<TargetFramework>net6.0</TargetFramework>
<ImplicitUsings>enable</ImplicitUsings>
<Nullable>enable</Nullable>
</PropertyGroup>
<ItemGroup>
<PackageReference Include="Microsoft.Build.Locator" Version="1.5.5" />
<PackageReference Include="Microsoft.CodeAnalysis.CSharp.Workspaces" Version="3.8.0" />
<PackageReference Include="Microsoft.CodeAnalysis.Workspaces.MSBuild" Version="3.8.0" />
</ItemGroup>
</Project>
notepad c:\temp\RoslynTrouble\Program.cs
using Microsoft.Build.Locator;
using Microsoft.CodeAnalysis.MSBuild;
class TestProgram
{
public static async Task Main(string[] args)
{
string csprojPath = args[0];
var instance = MSBuildLocator.RegisterDefaults();
Console.WriteLine(instance.Name + ": " + instance.Version);
var workspace = MSBuildWorkspace.Create();
var project = await workspace.OpenProjectAsync(csprojPath);
var compilation = await project.GetCompilationAsync();
if (compilation == null)
{
Console.WriteLine("Error: unexpected null compilation");
return;
}
foreach (var diagnostic in compilation.GetDiagnostics())
{
Console.WriteLine(diagnostic);
}
}
}
cd c:\temp\RoslynTrouble
dotnet run c:\temp\TestLib\TestLib.csproj
Expected result: no errors
Actual result: lots of compilation errors:
.NET Core SDK: 6.0.203
c:\open\prototypes\TestLib\obj\Debug\net6.0\TestLib.GlobalUsings.g.cs(2,1): error CS0116: A namespace cannot directly contain members such as fields or methods
c:\open\prototypes\TestLib\obj\Debug\net6.0\TestLib.GlobalUsings.g.cs(3,1): error CS0116: A namespace cannot directly contain members such as fields or methods
c:\open\prototypes\TestLib\obj\Debug\net6.0\TestLib.GlobalUsings.g.cs(4,1): error CS0116: A namespace cannot directly contain members such as fields or methods
c:\open\prototypes\TestLib\obj\Debug\net6.0\TestLib.GlobalUsings.g.cs(5,1): error CS0116: A namespace cannot directly contain members such as fields or methods
c:\open\prototypes\TestLib\obj\Debug\net6.0\TestLib.GlobalUsings.g.cs(6,1): error CS0116: A namespace cannot directly contain members such as fields or methods
c:\open\prototypes\TestLib\obj\Debug\net6.0\TestLib.GlobalUsings.g.cs(7,1): error CS0116: A namespace cannot directly contain members such as fields or methods
c:\open\prototypes\TestLib\obj\Debug\net6.0\TestLib.GlobalUsings.g.cs(8,1): error CS0116: A namespace cannot directly contain members such as fields or methods
c:\open\prototypes\TestLib\SomeClass.cs(7,13): error CS0103: The name 'Console' does not exist in the current context
c:\open\prototypes\TestLib\obj\Debug\net6.0\TestLib.GlobalUsings.g.cs(2,8): hidden CS8019: Unnecessary using directive.
c:\open\prototypes\TestLib\obj\Debug\net6.0\TestLib.GlobalUsings.g.cs(8,8): hidden CS8019: Unnecessary using directive.
c:\open\prototypes\TestLib\obj\Debug\net6.0\TestLib.AssemblyInfo.cs(11,1): hidden CS8019: Unnecessary using directive.
c:\open\prototypes\TestLib\obj\Debug\net6.0\TestLib.GlobalUsings.g.cs(7,8): hidden CS8019: Unnecessary using directive.
c:\open\prototypes\TestLib\obj\Debug\net6.0\TestLib.GlobalUsings.g.cs(6,8): hidden CS8019: Unnecessary using directive.
c:\open\prototypes\TestLib\obj\Debug\net6.0\.NETCoreApp,Version=v6.0.AssemblyAttributes.cs(2,1): hidden CS8019: Unnecessary using directive.
c:\open\prototypes\TestLib\obj\Debug\net6.0\TestLib.GlobalUsings.g.cs(3,8): hidden CS8019: Unnecessary using directive.
c:\open\prototypes\TestLib\obj\Debug\net6.0\TestLib.AssemblyInfo.cs(12,1): hidden CS8019: Unnecessary using directive.
c:\open\prototypes\TestLib\obj\Debug\net6.0\TestLib.GlobalUsings.g.cs(4,8): hidden CS8019: Unnecessary using directive.
c:\open\prototypes\TestLib\obj\Debug\net6.0\TestLib.GlobalUsings.g.cs(5,8): hidden CS8019: Unnecessary using directive.
c:\open\prototypes\TestLib\obj\Debug\net6.0\.NETCoreApp,Version=v6.0.AssemblyAttributes.cs(3,1): hidden CS8019: Unnecessary using directive.
What am I missing and how can I fix those errors?
Below you'll find the modifications described in a Note. Try the following:
mkdir c:\temp\TestLib
notepad c:\temp\TestLib\TestLib.csproj
Click Yes
TestLib.csproj:
<Project Sdk="Microsoft.NET.Sdk">
<PropertyGroup>
<TargetFramework>net6.0</TargetFramework>
<ImplicitUsings>enable</ImplicitUsings>
<Nullable>enable</Nullable>
</PropertyGroup>
</Project>
Save As (save with "UTF-8" encoding)
notepad c:\temp\TestLib\SomeClass.cs
Click Yes
SomeClass.cs:
Note: Made the method public - not much point in having a class with one method and making it private.
namespace TestLib
{
public class SomeClass
{
public void DoThings()
{
Console.WriteLine("Things!");
}
}
}
Save As (save with "UTF-8" encoding)
mkdir c:\temp\RoslynTrouble
notepad c:\temp\RoslynTrouble\RoslynTrouble.csproj
Click Yes
RoslynTrouble.csproj:
Note: Use version 4.4.0 for Microsoft.CodeAnalysis.CSharp.Workspaces and Microsoft.CodeAnalysis.Workspaces.MSBuild.
<Project Sdk="Microsoft.NET.Sdk">
<PropertyGroup>
<OutputType>Exe</OutputType>
<TargetFramework>net6.0</TargetFramework>
<ImplicitUsings>enable</ImplicitUsings>
<Nullable>enable</Nullable>
</PropertyGroup>
<ItemGroup>
<PackageReference Include="Microsoft.Build.Locator" Version="1.5.5" />
<PackageReference Include="Microsoft.CodeAnalysis.CSharp.Workspaces" Version="4.4.0" />
<PackageReference Include="Microsoft.CodeAnalysis.Workspaces.MSBuild" Version="4.4.0" />
</ItemGroup>
</Project>
Save As (save with "UTF-8" encoding)
notepad c:\temp\RoslynTrouble\Program.cs
Click Yes
Program.cs:
Note: Added namespace RoslynTrouble. Changed class name to Program to match the filename (Program.cs).
using Microsoft.Build.Locator;
using Microsoft.CodeAnalysis.MSBuild;
namespace RoslynTrouble
{
public class Program
{
public static async Task Main(string[] args)
{
string csprojPath = args[0];
var instance = MSBuildLocator.RegisterDefaults();
Console.WriteLine(instance.Name + ": " + instance.Version);
var workspace = MSBuildWorkspace.Create();
var project = await workspace.OpenProjectAsync(csprojPath);
var compilation = await project.GetCompilationAsync();
if (compilation == null)
{
Console.WriteLine("Error: unexpected null compilation");
return;
}
foreach (var diagnostic in compilation.GetDiagnostics())
{
Console.WriteLine(diagnostic);
}
}
}
}
Save As (save with "UTF-8" encoding)
cd c:\temp\RoslynTrouble
dotnet run "C:\temp\TestLib\TestLib.csproj"
Note: The double-quotes in the command above are optional since there aren't any spaces in the path.
Result:
Note: The result has warnings, but no errors.
.NET Core SDK: 6.0.301
C:\temp\TestLib\obj\Debug\net6.0\.NETCoreApp,Version=v6.0.AssemblyAttributes.cs(2,7): hidden CS8933: The using directive for 'System' appeared previously as global using
C:\temp\TestLib\obj\Debug\net6.0\TestLib.AssemblyInfo.cs(10,7): hidden CS8933: The using directive for 'System' appeared previously as global using
C:\temp\TestLib\obj\Debug\net6.0\TestLib.GlobalUsings.g.cs(5,1): hidden CS8019: Unnecessary using directive.
C:\temp\TestLib\obj\Debug\net6.0\TestLib.GlobalUsings.g.cs(3,1): hidden CS8019: Unnecessary using directive.
C:\temp\TestLib\obj\Debug\net6.0\TestLib.GlobalUsings.g.cs(4,1): hidden CS8019: Unnecessary using directive.
C:\temp\TestLib\obj\Debug\net6.0\TestLib.AssemblyInfo.cs(11,1): hidden CS8019: Unnecessary using directive.
C:\temp\TestLib\obj\Debug\net6.0\.NETCoreApp,Version=v6.0.AssemblyAttributes.cs(2,1): hidden CS8019: Unnecessary using directive.
C:\temp\TestLib\obj\Debug\net6.0\TestLib.GlobalUsings.g.cs(8,1): hidden CS8019: Unnecessary using directive.
C:\temp\TestLib\obj\Debug\net6.0\.NETCoreApp,Version=v6.0.AssemblyAttributes.cs(3,1): hidden CS8019: Unnecessary using directive.
C:\temp\TestLib\obj\Debug\net6.0\TestLib.AssemblyInfo.cs(10,1): hidden CS8019: Unnecessary using directive.
C:\temp\TestLib\obj\Debug\net6.0\TestLib.GlobalUsings.g.cs(7,1): hidden CS8019: Unnecessary using directive.
C:\temp\TestLib\obj\Debug\net6.0\TestLib.GlobalUsings.g.cs(6,1): hidden CS8019: Unnecessary using directive.
If one would like to avoid displaying warnings, one could use the following alternative code for Program.cs:
using Microsoft.Build.Locator;
using Microsoft.CodeAnalysis.MSBuild;
namespace RoslynTrouble
{
public class Program
{
public static async Task Main(string[] args)
{
bool errorsExist = false;
string csprojPath = args[0];
var instance = MSBuildLocator.RegisterDefaults();
Console.WriteLine(instance.Name + ": " + instance.Version);
var workspace = MSBuildWorkspace.Create();
var project = await workspace.OpenProjectAsync(csprojPath);
var compilation = await project.GetCompilationAsync();
if (compilation == null)
{
Console.WriteLine("Error: unexpected null compilation");
return;
}
foreach (Microsoft.CodeAnalysis.Diagnostic diagnostic in compilation.GetDiagnostics())
{
if (diagnostic.Severity != Microsoft.CodeAnalysis.DiagnosticSeverity.Hidden &&
diagnostic.Severity != Microsoft.CodeAnalysis.DiagnosticSeverity.Warning)
{
Console.WriteLine(diagnostic);
errorsExist = true;
}
}
if (!errorsExist)
Console.WriteLine($"Successfully compiled '{args[0]}'.");
}
}
}
Resources:
Roslyn Code Analysis returns false build errors from an error free solution

Incremental Source Generator generated code passed compilation with syntax error

I made a Incremental Source Generator:
<Project Sdk="Microsoft.NET.Sdk">
<PropertyGroup>
<TargetFramework>netstandard2.0</TargetFramework>
<IsRoslynComponent>true</IsRoslynComponent>
<LangVersion>latest</LangVersion>
</PropertyGroup>
<ItemGroup>
<PackageReference Include="Microsoft.CodeAnalysis" Version="4.2.0" />
<PackageReference Include="System.Text.Json" Version="6.0.0" />
</ItemGroup>
</Project>
It generates code that has an obvious syntax error
[Generator]
public class SourceGenerator : IIncrementalGenerator {
public void Initialize(IncrementalGeneratorInitializationContext context) {
context.RegisterSourceOutput(context.AdditionalTextsProvider, static (context, name) => {
string sourceCode = $#"
public class {"AAA"}{{
{{
}}
";
context.AddSource("AAA" + ".g.cs", sourceCode);
});
}
After building the solution for the first time and errors were expected. I restarted Visual Studio. I can see following code was generated:
public class AAA{
{
}
When viewing this AAA.g.cs, the text editor didn't highlight the fault of less closing braket.
Then I build the solution for the second time. It was succeeded. How can this be possible?

How to avoid using namespace prefixes in Xaml

I've started migrating company owned application from UWP 10 to WinUI (on NET5) using upgrade-assistant tool. Give or take, the most conflicts are gone, but the the nasty one remains in .xaml files. The underlying code can't be source-generated due to missing namespace prefixes:
<ResourceDictionary
xmlns:xaml="clr-namespace:Windows.UI.Xaml;assembly=Windows"
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
xmlns:local="using:Ifs.Uma.UI.Controls">
<Style TargetType="local:Dialog">
<Setter Property="Background" Value="#FFEDEDED" />
</Style>
</ResourceDictionary>
I'm not sure if I'm missing some package references. Or if it's possible to just define them somewhere (XmlnsDefinitionAttribute is not available)? Is it even possible without going through hundreds of .xaml files and fixing all them manually or via find-replace?
For example, one of .csproj files with referenced packages below:
<Project Sdk="Microsoft.NET.Sdk">
<PropertyGroup>
<TargetFramework>netstandard2.0</TargetFramework>
<OutputType>Library</OutputType>
<RootNamespace>SomeUI</RootNamespace>
<DefaultLanguage>en</DefaultLanguage>
<CodeAnalysisRuleSet>..\FrameworkRules.ruleset</CodeAnalysisRuleSet>
<AppxBundlePlatforms>x86|x64</AppxBundlePlatforms>
<GenerateAssemblyInfo>false</GenerateAssemblyInfo>
</PropertyGroup>
<PropertyGroup Condition=" '$(Configuration)|$(Platform)' == 'Debug|AnyCPU' ">
<DefineConstants>DEBUG;TRACE;NETFX_CORE;WINDOWS_UWP</DefineConstants>
<WarningLevel>4</WarningLevel>
</PropertyGroup>
<PropertyGroup Condition=" '$(Configuration)|$(Platform)' == 'Release|AnyCPU' ">
<DefineConstants>TRACE;NETFX_CORE;WINDOWS_UWP</DefineConstants>
<WarningLevel>4</WarningLevel>
<CodeAnalysisRuleSet>..\FrameworkRules.Release.ruleset</CodeAnalysisRuleSet>
<TreatWarningsAsErrors>true</TreatWarningsAsErrors>
</PropertyGroup>
<PropertyGroup>
<NetStandardImplicitPackageVersion>2.0.3</NetStandardImplicitPackageVersion>
</PropertyGroup>
</ItemGroup>
<ItemGroup>
<Compile Update="Properties\AssemblyInfo.cs">
<CopyToOutputDirectory>Always</CopyToOutputDirectory>
</Compile>
</ItemGroup>
<ItemGroup>
<PackageReference Include="Microsoft.DotNet.UpgradeAssistant.Extensions.Default.Analyzers" Version="0.3.330701">
<PrivateAssets>all</PrivateAssets>
</PackageReference>
</ItemGroup>
<!-- I had to add those manually to get the code working -->
<ItemGroup>
<PackageReference Include="System.Runtime.InteropServices.WindowsRuntime" Version="4.3.0" />
<PackageReference Include="System.Runtime.WindowsRuntime" Version="4.7.0" />
<PackageReference Include="System.Runtime.WindowsRuntime.UI.Xaml" Version="4.7.0" />
<Reference Include="Windows">
<HintPath Condition="Exists('C:\Program Files (x86)\Windows Kits\10\UnionMetadata\Facade\Windows.winMD')">C:\Program Files (x86)\Windows Kits\10\UnionMetadata\Facade\Windows.winMD</HintPath>
</Reference>
<Reference Include="Windows.Foundation.FoundationContract">
<HintPath Condition="Exists('C:\Program Files (x86)\Windows Kits\10\References\10.0.19041.0\Windows.Foundation.FoundationContract\4.0.0.0\Windows.Foundation.FoundationContract.winmd')">C:\Program Files (x86)\Windows Kits\10\References\10.0.19041.0\Windows.Foundation.FoundationContract\4.0.0.0\Windows.Foundation.FoundationContract.winmd</HintPath>
</Reference>
<Reference Include="Windows.Foundation.UniversalApiContract">
<HintPath Condition="Exists('C:\Program Files (x86)\Windows Kits\10\References\10.0.19041.0\Windows.Foundation.UniversalApiContract\10.0.0.0\Windows.Foundation.UniversalApiContract.winmd')">C:\Program Files (x86)\Windows Kits\10\References\10.0.19041.0\Windows.Foundation.UniversalApiContract\10.0.0.0\Windows.Foundation.UniversalApiContract.winmd</HintPath>
</Reference>
</ItemGroup>
</Project>
I've just went an obvious way, made a simple UWP program to add prefixes and namespaces to those tags (just in case someone's interested):
public sealed partial class MainPage : Page
{
public MainPage()
{
this.InitializeComponent();
this.Loaded += MainPage_Loaded;
}
private async void MainPage_Loaded(object sender, RoutedEventArgs e)
{
// 1. run the following command to make your .xaml files accessible to UWP:
// XCOPY <your_solution_dir>/*.xaml C:\Users\<you>\Pictures\XAML /E
// 2. Delete \bin and \obj directories from there (optional)
// 3. Add Pictures capability to your manifest (imho the easiest one to use)
// <Capabilities>
// <uap:Capability Name = "picturesLibrary" />
// </Capabilities>
var assembly = typeof(ResourceDictionary).Assembly;
var regulars = assembly
.GetExportedTypes()
.Where(type => typeof(DependencyObject).IsAssignableFrom(type) && type.IsClass)
.Select(type => new { Namespace = type.Namespace, TypeName = type.Name, Prefix = type.Namespace.Split('.').Last().ToLowerInvariant() })
.GroupBy(x => x.Prefix)
.Select(x => new {
Regex = new Regex($"(</?)(?={string.Join("|", x.Select(n => n.TypeName))})"),
Replacements = x.Select(y => new Replacement(y.Namespace, y.Prefix)).First() })
.ToDictionary(x => x.Regex, x => x.Replacements);
var namespaceAttributes = new Regex("<(?<=[\b\\w\\d\\D]).*(xmlns)[^>]+", RegexOptions.Singleline);
var picturesDirectory = KnownFolders.PicturesLibrary;
var sourceDirectory = await picturesDirectory.GetFolderAsync("XAML");
var xamlFiles = await GetXamlFilesAsync(sourceDirectory);
var fixedFiles = 0;
foreach (var xamlFile in xamlFiles)
{
var markup = await FileIO.ReadTextAsync(xamlFile);
var matchedReplacements = new List<Replacement>();
foreach (var replacer in regulars)
{
if (replacer.Key.IsMatch(markup))
{
matchedReplacements.Add(replacer.Value);
markup = replacer.Key.Replace(markup, $"$&{replacer.Value.Prefix}:");
}
}
if (matchedReplacements.Count == 0) continue;
var nsAttributes = namespaceAttributes.Match(markup);
if (nsAttributes.Success && markup.Length > nsAttributes.Length)
{
markup = nsAttributes.Result("$&" + Environment.NewLine +
string.Join(Environment.NewLine,
matchedReplacements.Where(replacement => !markup.Contains($"xmlns:{replacement.Prefix}")).Select(replacement =>
$"xmlns:{replacement.Prefix}=\"clr-namespace:{replacement.Namespace};assembly=Windows.Foundation.UniversalApiContract\"")))
+ markup.Substring(nsAttributes.Length);
}
await FileIO.WriteTextAsync(xamlFile, markup);
fixedFiles++;
}
await new Windows.UI.Popups.MessageDialog($"{fixedFiles} of {xamlFiles.Count} xaml files were fixed").ShowAsync();
}
async Task<IList<StorageFile>> GetXamlFilesAsync(StorageFolder topFolder)
{
var xamlFiles = new List<StorageFile>();
var folders = await topFolder.GetFoldersAsync();
foreach (var folder in folders)
{
xamlFiles.AddRange((await folder.GetFilesAsync()).Where(f => StringComparer.OrdinalIgnoreCase.Equals(f.FileType, ".xaml")));
xamlFiles.AddRange(await GetXamlFilesAsync(folder));
}
return xamlFiles;
}
private readonly struct Replacement
{
public Replacement(string #namespace, string prefix)
{
Namespace = #namespace; Prefix = prefix;
}
public readonly string Namespace;
public readonly string Prefix;
}
}
<xaml:ResourceDictionary
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
xmlns:local="using:Ifs.Uma.UI.Controls"
xmlns:nav="using:Ifs.Uma.UI.Navigation"
xmlns:xaml="clr-namespace:Windows.UI.Xaml;assembly=Windows.Foundation.UniversalApiContract"
xmlns:controls="clr-namespace:Windows.UI.Xaml.Controls;assembly=Windows.Foundation.UniversalApiContract"
xmlns:shapes="clr-namespace:Windows.UI.Xaml.Shapes;assembly=Windows.Foundation.UniversalApiContract">
<xaml:Style TargetType="local:PageHeader">
<xaml:Setter Property="Height" Value="48" />
<xaml:Setter Property="Background" Value="{ThemeResource IfsAppBackgroundBrush}" />
<xaml:Setter Property="Template">
<xaml:Setter.Value>
<controls:ControlTemplate TargetType="local:PageHeader">
<controls:Grid Background="{TemplateBinding Background}"
BorderBrush="{TemplateBinding BorderBrush}"
BorderThickness="{TemplateBinding BorderThickness}">
<!-- Grid and other controls -->
</controls:Grid>
</controls:ControlTemplate>
</xaml:Setter.Value>
</xaml:Setter>
</xaml:Style>
</xaml:ResourceDictionary>
It all went fine, but resulted in a message that type <controls:ControlTemplate /> does not support direct content. This type is pretty much within every .xaml file. TemplateBinding and other binding types also not found. Perhaps, it's not the way to fix the issue, there might be an SDK missing or something.

C#: Unhandled exception. System.TypeLoadException: Could not load type 'System.Drawing.Color'

ANSWER for this question thanks to Jeremy C.:
There is no KeePass nuget package for the Net5.0 yet. Thats why there is that error message. Thanks Jeremy C. for the help and answers.
QUESTION:
Im getting this error after starting my solution.
Unhandled exception. System.TypeLoadException: Could not load type 'System.Drawing.Color' from assembly 'Splat, Version=3.0.0.0, Culture=neutral, PublicKeyToken=null'.
Already used google and tried to find a fix for it and also red all articles about similiar errors like "System.Drawing.Font" or "System.Drawing.Image". But theres nothing really helpful and nothing really informative about 'System.Drawing.Color'.
Ive got the code example and package from here:
github.com/wismna/ModernKeePassLib
This is my code:
.csproj
<PropertyGroup>
<OutputType>Exe</OutputType>
<TargetFramework>net5.0</TargetFramework>
</PropertyGroup>
<ItemGroup>
<PackageReference Include="ModernKeePassLib" Version="2.45.1" />
<PackageReference Include="System.Drawing.Common" Version="5.0.2" />
</ItemGroup>
</Project>
And:
using ModernKeePassLib;
using ModernKeePassLib.Interfaces;
using ModernKeePassLib.Keys;
using ModernKeePassLib.Serialization;
using System;
using System.Linq;
using System.Text;
namespace KeePasso
{
class Program
{
static void Main()
{
var dbpath = #"C:\Users\prusinma\Desktop\KeePassDatabase\Database.kdbx";
var keypath = #"C:\Users\prusinma\Desktop\KeePassDatabase\Database.key";
var masterpw = "1234abcd";
Console.WriteLine("init done");
byte[] DBPathBytes = Encoding.ASCII.GetBytes(dbpath);
byte[] KeyPathBytes = Encoding.ASCII.GetBytes(keypath);
var ioConnection = IOConnectionInfo.FromByteArray(DBPathBytes);
var compositeKey = new CompositeKey();
compositeKey.AddUserKey(new KcpPassword(masterpw)); // Password
compositeKey.AddUserKey(new KcpKeyFile(IOConnectionInfo.FromByteArray(KeyPathBytes))); // Keyfile
var db = new PwDatabase();
db.Open(ioConnection, compositeKey, new NullStatusLogger());
var kpdata = from entry in db.RootGroup.GetEntries(true)
select new
{
Group = entry.ParentGroup.Name,
Title = entry.Strings.ReadSafe("Title"),
Username = entry.Strings.ReadSafe("UserName"),
Password = entry.Strings.ReadSafe("Password"),
URL = entry.Strings.ReadSafe("URL"),
Notes = entry.Strings.ReadSafe("Notes")
};
db.Save(new NullStatusLogger());
var contents = db.IOConnectionInfo.Bytes;
string bitString = BitConverter.ToString(contents);
Console.WriteLine(bitString);
Console.WriteLine(kpdata.ToString());
}
}
}
Those classes were moved into their own nuget package. Add it to your project and you should be good to go: https://www.nuget.org/packages/System.Drawing.Common/
From the project directory at the command line:
dotnet add package System.Drawing.Common
Closer inspection reveals ModernKeepPass targets.netstandard1.2 and will not work with 5's System.Drawing nuget package without being upgraded to target the new framework.
https://github.com/wismna/ModernKeePassLib/blob/master/ModernKeePassLib/ModernKeePassLib.csproj
<PropertyGroup>
<TargetFramework>netstandard1.2</TargetFramework>

How to set the culture in a dotnetcore xunit test

I have the following unit test that I'm porting from a .Net Framework library to .Net core xunint test library. The project the unit test needs to be added to is
https://github.com/dotliquid/dotliquid
and is being added to the selected file as show here
The unit test I'm trying to add is
[Test]
public void ParsingWithCommaDecimalSeparatorShouldWork()
{
var ci = new CultureInfo(CultureInfo.CurrentCulture.Name)
{
NumberFormat =
{
NumberDecimalSeparator = ","
, NumberGroupSeparator = "."
}
};
Thread.CurrentThread.CurrentCulture = ci;
var t = Template.Parse("{{2.5}}");
var result = t.Render( new Hash(), CultureInfo.InvariantCulture );
Assert.AreEqual( result, "2.5" );
}
However the test fails to compile in dotnet core.
Severity Code Description Project File Line Suppression State
Error CS1061 'Thread' does not contain a definition for
'CurrentCulture' and no extension method 'CurrentCulture' accepting a
first argument of type 'Thread' could be found (are you missing a
using directive or an assembly
reference?) DotLiquid.Tests(net451) C:\Users\phelan\workspace\dotliquid\src\DotLiquid.Tests\OutputTests.cs 113 N/A
I need to have different unit tests with different cultures. I would like to create an XUnit theory where each instance passes in a different culture for the unit test to verify against. How is this done in .NetCore?
I looked at some of the dotnet source and I found this.
CultureInfo.DefaultThreadCurrentCulture = ci;
Basically it looks like you can set the default thread current culture from a static property of CultureInfo rather than from Thread.CurrentThread
poking around a bit more I found this
public CultureInfo CurrentCulture
{
get
{
Contract.Ensures(Contract.Result<CultureInfo>() != null);
return CultureInfo.CurrentCulture;
}
set
{
Contract.EndContractBlock();
// If you add more pre-conditions to this method, check to see if you also need to
// add them to CultureInfo.DefaultThreadCurrentCulture.set.
if (m_CurrentCulture == null && m_CurrentUICulture == null)
nativeInitCultureAccessors();
CultureInfo.CurrentCulture = value;
}
}
This is in Thread.cs. So you can set the CultureInfo.CurrentCulture property explicitly.
example:
CultureInfo.CurrentCulture = new CultureInfo("en-GB"); ;
Assert.Equal("£1,000.00", String.Format("{0:C}", 1000));
CultureInfo.CurrentCulture = new CultureInfo("en-US"); ;
Assert.Equal("$1,000.00", String.Format("{0:C}", 1000));
csproj file for unit test project:
<Project Sdk="Microsoft.NET.Sdk">
<PropertyGroup>
<TargetFramework>netcoreapp1.0</TargetFramework>
<IsPackable>false</IsPackable>
<ApplicationIcon />
<OutputType>Library</OutputType>
<StartupObject />
</PropertyGroup>
<ItemGroup>
<PackageReference Include="Microsoft.NET.Test.Sdk" Version="15.3.0-preview-20170425-07" />
<PackageReference Include="xunit" Version="2.2.0" />
<PackageReference Include="xunit.runner.visualstudio" Version="2.2.0" />
</ItemGroup>
</Project>
The solution is to set
CultureInfo.DefaultThreadCurrentCulture = ci;
and then spin up a new thread. This will set the current culture for the next thread. The final test case is.
[Test]
public void ParsingWithCommaDecimalSeparatorShouldWork()
{
var ci = new CultureInfo(CultureInfo.CurrentCulture.Name)
{
NumberFormat =
{
NumberDecimalSeparator = ","
, NumberGroupSeparator = "."
}
};
CultureInfo.DefaultThreadCurrentCulture = ci;
var result = "";
var thread = new Thread
( delegate()
{
Console.WriteLine(CultureInfo.CurrentCulture.NumberFormat.NumberDecimalSeparator);
Console.WriteLine(CultureInfo.CurrentCulture.NumberFormat.NumberGroupSeparator);
var t = Template.Parse("{{2.5}}");
result = t.Render(new Hash(), CultureInfo.InvariantCulture);
} );
thread.Start();
thread.Join();
Assert.AreEqual(result, "2.5");
}
which is a bit messy but get the job done.

Categories