From 40632aa92c0b35f29e3f9ecfff00c79d2ecbc511 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Tommy=20=C3=96man?= Date: Wed, 23 Aug 2023 21:25:09 +0200 Subject: [PATCH] =?UTF-8?q?Fungerande=20version=20av=20skiktad=20l=C3=B6sn?= =?UTF-8?q?ing=20Winforms=20App=20med=20SQlite=20och=20entity=20framework?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- WinFormDi/ContainerConfig.cs | 22 ++++- WinFormDi/Local.db | Bin 0 -> 24576 bytes WinFormDi/Program.cs | 16 +++- WinFormDi/WinFormDi.csproj | 17 ++++ WinFormDi/appsettings.json | 11 +++ WinFormDiApp.BL/Helpers/Extensions.cs | 26 ++++++ WinFormDiApp.BL/Models/AccountRecord.cs | 19 ++++ WinFormDiApp.BL/Models/Common/BaseEntity.cs | 10 +++ WinFormDiApp.BL/Models/Member.cs | 18 ++++ WinFormDiApp.BL/WinFormDiApp.BL.csproj | 13 +++ WinFormDiApp.DAL/ApplicationDbContext.cs | 30 +++++++ WinFormDiApp.DAL/Data/DataSeeder.cs | 38 ++++++++ .../20230822204611_Initial.Designer.cs | 85 ++++++++++++++++++ .../Migrations/20230822204611_Initial.cs | 59 ++++++++++++ .../ApplicationDbContextModelSnapshot.cs | 82 +++++++++++++++++ WinFormDiApp.DAL/WinFormDiApp.DAL.csproj | 29 ++++++ WinFormDiApp.sln | 16 +++- 17 files changed, 485 insertions(+), 6 deletions(-) create mode 100644 WinFormDi/Local.db create mode 100644 WinFormDi/appsettings.json create mode 100644 WinFormDiApp.BL/Helpers/Extensions.cs create mode 100644 WinFormDiApp.BL/Models/AccountRecord.cs create mode 100644 WinFormDiApp.BL/Models/Common/BaseEntity.cs create mode 100644 WinFormDiApp.BL/Models/Member.cs create mode 100644 WinFormDiApp.BL/WinFormDiApp.BL.csproj create mode 100644 WinFormDiApp.DAL/ApplicationDbContext.cs create mode 100644 WinFormDiApp.DAL/Data/DataSeeder.cs create mode 100644 WinFormDiApp.DAL/Migrations/20230822204611_Initial.Designer.cs create mode 100644 WinFormDiApp.DAL/Migrations/20230822204611_Initial.cs create mode 100644 WinFormDiApp.DAL/Migrations/ApplicationDbContextModelSnapshot.cs create mode 100644 WinFormDiApp.DAL/WinFormDiApp.DAL.csproj diff --git a/WinFormDi/ContainerConfig.cs b/WinFormDi/ContainerConfig.cs index 9323517..06bba8b 100644 --- a/WinFormDi/ContainerConfig.cs +++ b/WinFormDi/ContainerConfig.cs @@ -1,26 +1,44 @@ using DIDemoLib; +using Microsoft.EntityFrameworkCore; +using Microsoft.Extensions.Configuration; using Microsoft.Extensions.DependencyInjection; using Microsoft.Extensions.Hosting; using System; using System.Collections.Generic; +using System.Configuration; using System.Linq; +using System.Runtime.CompilerServices; using System.Text; using System.Threading.Tasks; +using WinFormDiApp.DAL; namespace WinFormDi { public static class ContainerConfig { - public static IHost? Configure() + + public static IHost? Configure(IHostBuilder hostBuilder) { - var builder = new HostBuilder() + var configuration = new ConfigurationBuilder() + .SetBasePath(Directory.GetCurrentDirectory()) + .AddEnvironmentVariables() + .AddJsonFile("appsettings.json") + .Build(); + + + var builder = hostBuilder // new HostBuilder() .ConfigureServices((_, services) => { + var conn = configuration.GetConnectionString("DatabaseConnection"); services + .AddDbContext(options => + options.UseSqlite(conn)) .AddTransient() .AddTransient(); }); return builder.Build(); } + + } } diff --git a/WinFormDi/Local.db b/WinFormDi/Local.db new file mode 100644 index 0000000000000000000000000000000000000000..9fa637c666fdbd43b64248e3e2afb1e560ea4314 GIT binary patch literal 24576 zcmeI&Z*S5-90%~0ze+?*d_a~ZdZ|xFHVH5z^31Yz+5iQ+&Ws19>B>nOOUv5BxQCLx z2H%Bm#y8+IUxN=l2+Xy@jL#hTUV7>M;eO>lcOg08_)Xhkl)U$Yk;TZq@IXi;gqMT} zf{@@j!}BsFc_Fo|@Vj`eysnrK%C?v<{1npno(T896~5-be)0_O-Hz5ojV?%*&ZKRnl_TzVyPrvKAp#uZQGxCOsBRV48mwF6^STCJO6DR z;$#2198JnB_t0XKQ4D3d9vz=CYiI@QKwG}Y{54~n)b+<>iSYf^{$ru#k4{Jf#~a25 z^VRr#DrSrIx;X95?MzcS>Nvx|Vvg^Hubq(j!NtnPL{xI+Ykq@X#hmT%$YzXh?=^w0 z=`Oi?fj^ko>@DAi{LRL~@~NqbOz~Y^6dZ3rKP@(oHDUg|ZmxWeSzXyYJImjheca@E z77O16ejz~s0uX=z1Rwwb2tWV=5P$##AaFYc9*fDwR;^Ooue_+$YL#ctt5s9=9OhVV zy<90*D>*(dvG7CS7ZL;@009U<00Izz00bZa0SG_<0=HUVE7`ca`dfh6@BjQy|40yk z00bZa0SG_<0uX=z1Rwwb2yCzb&i@;{xR@FQAOHafKmY;|fB*y_009UKehq{ YAOHafKmY;|fB*y_009U [STAThread] - static void Main() + static void Main(string[] args) { - var host = ContainerConfig.Configure(); + var host = ContainerConfig.Configure(CreateHostBuilder(args)); + using var scope = host.Services.CreateScope(); try { var services = scope.ServiceProvider; + var context = services.GetRequiredService(); + DataSeeder.Initialize(context); + Application.EnableVisualStyles(); Application.SetCompatibleTextRenderingDefault(false); Application.SetHighDpiMode(HighDpiMode.SystemAware); @@ -32,5 +38,11 @@ namespace WinFormDi } } + + public static IHostBuilder CreateHostBuilder(string[] args) => + Host.CreateDefaultBuilder(args); + + + } } \ No newline at end of file diff --git a/WinFormDi/WinFormDi.csproj b/WinFormDi/WinFormDi.csproj index a395e17..8b9cb88 100644 --- a/WinFormDi/WinFormDi.csproj +++ b/WinFormDi/WinFormDi.csproj @@ -9,12 +9,29 @@ + + all + runtime; build; native; contentfiles; analyzers; buildtransitive + + + + + + + + + + Always + + + Always + \ No newline at end of file diff --git a/WinFormDi/appsettings.json b/WinFormDi/appsettings.json new file mode 100644 index 0000000..d43725e --- /dev/null +++ b/WinFormDi/appsettings.json @@ -0,0 +1,11 @@ +{ + "ConnectionStrings": { + "DatabaseConnection": "Data Source=.\\Local.db" + }, + "Logging": { + "LogLevel": { + "Default" : "Warning" + } + }, + "AllowedHosts": "*" +} diff --git a/WinFormDiApp.BL/Helpers/Extensions.cs b/WinFormDiApp.BL/Helpers/Extensions.cs new file mode 100644 index 0000000..eee26eb --- /dev/null +++ b/WinFormDiApp.BL/Helpers/Extensions.cs @@ -0,0 +1,26 @@ +namespace WinFormDiApp.BL.Helpers; + +public static class Extensions +{ + public static bool IsNumeric(this string value) + { + if (!string.IsNullOrEmpty(value)) + { + if (value.All(char.IsDigit)) return true; + else return false; + } + else return false; + } + + public static bool IsDate(this string value) { + if (!string.IsNullOrEmpty(value) && value.Length<20) + { + if (DateTime.TryParse(value, out DateTime date)) + { + return true; + } + else return false; + } + else return false; + } +} diff --git a/WinFormDiApp.BL/Models/AccountRecord.cs b/WinFormDiApp.BL/Models/AccountRecord.cs new file mode 100644 index 0000000..f9045de --- /dev/null +++ b/WinFormDiApp.BL/Models/AccountRecord.cs @@ -0,0 +1,19 @@ +using WinFormDiApp.BL.Models.Common; +using System; +using System.Collections.Generic; +using System.Linq; +using System.Text; +using System.Threading.Tasks; + +namespace WinFormDiApp.BL.Models +{ + public class AccountRecord : BaseEntity + { + public DateTime BetalDatum { get; set; } = DateTime.MinValue; + public string Mottagare { get; set; } = string.Empty; + public string Konto { get; set; } = string.Empty; + public double Belopp { get; set; } + public string Avisering { get; set; } = string.Empty; + + } +} diff --git a/WinFormDiApp.BL/Models/Common/BaseEntity.cs b/WinFormDiApp.BL/Models/Common/BaseEntity.cs new file mode 100644 index 0000000..08c932b --- /dev/null +++ b/WinFormDiApp.BL/Models/Common/BaseEntity.cs @@ -0,0 +1,10 @@ +using System.ComponentModel.DataAnnotations; + +namespace WinFormDiApp.BL.Models.Common +{ + public abstract class BaseEntity + { + [Key] + public int Id { get; set; } + } +} diff --git a/WinFormDiApp.BL/Models/Member.cs b/WinFormDiApp.BL/Models/Member.cs new file mode 100644 index 0000000..eaa4c39 --- /dev/null +++ b/WinFormDiApp.BL/Models/Member.cs @@ -0,0 +1,18 @@ +using WinFormDiApp.BL.Models.Common; +using System; +using System.Collections.Generic; +using System.Linq; +using System.Text; +using System.Threading.Tasks; + +namespace WinFormDiApp.BL.Models; + +public class Member : BaseEntity +{ + public string FirstName { get; set; } = string.Empty; + public string LastName { get; set; } = string.Empty; + public string NickName { get; set; } = string.Empty; + public string PersonType { get; set; } = string.Empty; + public string Email { get; set; } = string.Empty; + +} diff --git a/WinFormDiApp.BL/WinFormDiApp.BL.csproj b/WinFormDiApp.BL/WinFormDiApp.BL.csproj new file mode 100644 index 0000000..db090c3 --- /dev/null +++ b/WinFormDiApp.BL/WinFormDiApp.BL.csproj @@ -0,0 +1,13 @@ + + + + net7.0 + enable + enable + + + + + + + diff --git a/WinFormDiApp.DAL/ApplicationDbContext.cs b/WinFormDiApp.DAL/ApplicationDbContext.cs new file mode 100644 index 0000000..5bb5308 --- /dev/null +++ b/WinFormDiApp.DAL/ApplicationDbContext.cs @@ -0,0 +1,30 @@ +using Microsoft.EntityFrameworkCore.Design; +using Microsoft.EntityFrameworkCore; +using Microsoft.Extensions.Configuration; +using WinFormDiApp.BL.Models; + +namespace WinFormDiApp.DAL +{ + public class ApplicationDbContext : DbContext + { + public ApplicationDbContext(DbContextOptions options) : base(options) { } + + public virtual DbSet Members { get; set; } + public virtual DbSet AccountRecords { get; set; } + } + + public class DesignTimeDbContextFactory : IDesignTimeDbContextFactory + { + public ApplicationDbContext CreateDbContext(string[] args) + { + IConfigurationRoot configuration = new ConfigurationBuilder() + .SetBasePath(Directory.GetCurrentDirectory()) + .AddJsonFile(@Directory.GetCurrentDirectory() + "/../WinFormDi/appsettings.json") + .Build(); + var builder = new DbContextOptionsBuilder(); + var connectionString = configuration.GetConnectionString("DatabaseConnection"); + builder.UseSqlite(connectionString); + return new ApplicationDbContext(builder.Options); + } + } +} \ No newline at end of file diff --git a/WinFormDiApp.DAL/Data/DataSeeder.cs b/WinFormDiApp.DAL/Data/DataSeeder.cs new file mode 100644 index 0000000..c57356f --- /dev/null +++ b/WinFormDiApp.DAL/Data/DataSeeder.cs @@ -0,0 +1,38 @@ +using System; +using System.Collections.Generic; +using System.Linq; +using System.Text; +using System.Threading.Tasks; +using WinFormDiApp.BL.Models; + +namespace WinFormDiApp.DAL.Data +{ + public class DataSeeder + { + public static void Initialize(ApplicationDbContext context) + { + if (!context.Members.Any()) + { + var members = new List() + { + new Member { /*Id = 1,*/ FirstName = "John", LastName="Doe", NickName="Doey", PersonType="Normal", Email = "john@john.com" }, + new Member { /*Id = 2,*/ FirstName = "Michael", LastName="Jordan", NickName="Joardie", PersonType="Normal", Email = "michael@michael.com" } + }; + context.Members.AddRange(members); + context.SaveChanges(); + } + + if (!context.AccountRecords.Any()) + { + var accountRecords = new List() + { + new AccountRecord { /* Id = 1 */ Avisering = "EInvoice", Belopp=10.0, BetalDatum=DateTime.Parse("2023-05-05"), Konto="BG 5787-1030", Mottagare="Kalles Bärplockning" }, + new AccountRecord { /* Id = 1 */ Avisering = "EInvoice", Belopp = 13.0, BetalDatum = DateTime.Parse("2023-05-07"), Konto = "PG 4158502-7", Mottagare = "Nisses Strumpor" } + }; + context.AccountRecords.AddRange(accountRecords); + context.SaveChanges(); + } + + } + } +} diff --git a/WinFormDiApp.DAL/Migrations/20230822204611_Initial.Designer.cs b/WinFormDiApp.DAL/Migrations/20230822204611_Initial.Designer.cs new file mode 100644 index 0000000..7eb6d72 --- /dev/null +++ b/WinFormDiApp.DAL/Migrations/20230822204611_Initial.Designer.cs @@ -0,0 +1,85 @@ +// +using System; +using Microsoft.EntityFrameworkCore; +using Microsoft.EntityFrameworkCore.Infrastructure; +using Microsoft.EntityFrameworkCore.Migrations; +using Microsoft.EntityFrameworkCore.Storage.ValueConversion; +using WinFormDiApp.DAL; + +#nullable disable + +namespace WinFormDiApp.DAL.Migrations +{ + [DbContext(typeof(ApplicationDbContext))] + [Migration("20230822204611_Initial")] + partial class Initial + { + /// + protected override void BuildTargetModel(ModelBuilder modelBuilder) + { +#pragma warning disable 612, 618 + modelBuilder.HasAnnotation("ProductVersion", "7.0.10"); + + modelBuilder.Entity("WinFormDiApp.BL.Models.AccountRecord", b => + { + b.Property("Id") + .ValueGeneratedOnAdd() + .HasColumnType("INTEGER"); + + b.Property("Avisering") + .IsRequired() + .HasColumnType("TEXT"); + + b.Property("Belopp") + .HasColumnType("REAL"); + + b.Property("BetalDatum") + .HasColumnType("TEXT"); + + b.Property("Konto") + .IsRequired() + .HasColumnType("TEXT"); + + b.Property("Mottagare") + .IsRequired() + .HasColumnType("TEXT"); + + b.HasKey("Id"); + + b.ToTable("AccountRecords"); + }); + + modelBuilder.Entity("WinFormDiApp.BL.Models.Member", b => + { + b.Property("Id") + .ValueGeneratedOnAdd() + .HasColumnType("INTEGER"); + + b.Property("Email") + .IsRequired() + .HasColumnType("TEXT"); + + b.Property("FirstName") + .IsRequired() + .HasColumnType("TEXT"); + + b.Property("LastName") + .IsRequired() + .HasColumnType("TEXT"); + + b.Property("NickName") + .IsRequired() + .HasColumnType("TEXT"); + + b.Property("PersonType") + .IsRequired() + .HasColumnType("TEXT"); + + b.HasKey("Id"); + + b.ToTable("Members"); + }); +#pragma warning restore 612, 618 + } + } +} diff --git a/WinFormDiApp.DAL/Migrations/20230822204611_Initial.cs b/WinFormDiApp.DAL/Migrations/20230822204611_Initial.cs new file mode 100644 index 0000000..07e13d7 --- /dev/null +++ b/WinFormDiApp.DAL/Migrations/20230822204611_Initial.cs @@ -0,0 +1,59 @@ +using System; +using Microsoft.EntityFrameworkCore.Migrations; + +#nullable disable + +namespace WinFormDiApp.DAL.Migrations +{ + /// + public partial class Initial : Migration + { + /// + protected override void Up(MigrationBuilder migrationBuilder) + { + migrationBuilder.CreateTable( + name: "AccountRecords", + columns: table => new + { + Id = table.Column(type: "INTEGER", nullable: false) + .Annotation("Sqlite:Autoincrement", true), + BetalDatum = table.Column(type: "TEXT", nullable: false), + Mottagare = table.Column(type: "TEXT", nullable: false), + Konto = table.Column(type: "TEXT", nullable: false), + Belopp = table.Column(type: "REAL", nullable: false), + Avisering = table.Column(type: "TEXT", nullable: false) + }, + constraints: table => + { + table.PrimaryKey("PK_AccountRecords", x => x.Id); + }); + + migrationBuilder.CreateTable( + name: "Members", + columns: table => new + { + Id = table.Column(type: "INTEGER", nullable: false) + .Annotation("Sqlite:Autoincrement", true), + FirstName = table.Column(type: "TEXT", nullable: false), + LastName = table.Column(type: "TEXT", nullable: false), + NickName = table.Column(type: "TEXT", nullable: false), + PersonType = table.Column(type: "TEXT", nullable: false), + Email = table.Column(type: "TEXT", nullable: false) + }, + constraints: table => + { + table.PrimaryKey("PK_Members", x => x.Id); + }); + } + + /// + protected override void Down(MigrationBuilder migrationBuilder) + { + migrationBuilder.DropTable( + name: "AccountRecords"); + + migrationBuilder.DropTable( + name: "Members"); + } + } +} diff --git a/WinFormDiApp.DAL/Migrations/ApplicationDbContextModelSnapshot.cs b/WinFormDiApp.DAL/Migrations/ApplicationDbContextModelSnapshot.cs new file mode 100644 index 0000000..744a85a --- /dev/null +++ b/WinFormDiApp.DAL/Migrations/ApplicationDbContextModelSnapshot.cs @@ -0,0 +1,82 @@ +// +using System; +using Microsoft.EntityFrameworkCore; +using Microsoft.EntityFrameworkCore.Infrastructure; +using Microsoft.EntityFrameworkCore.Storage.ValueConversion; +using WinFormDiApp.DAL; + +#nullable disable + +namespace WinFormDiApp.DAL.Migrations +{ + [DbContext(typeof(ApplicationDbContext))] + partial class ApplicationDbContextModelSnapshot : ModelSnapshot + { + protected override void BuildModel(ModelBuilder modelBuilder) + { +#pragma warning disable 612, 618 + modelBuilder.HasAnnotation("ProductVersion", "7.0.10"); + + modelBuilder.Entity("WinFormDiApp.BL.Models.AccountRecord", b => + { + b.Property("Id") + .ValueGeneratedOnAdd() + .HasColumnType("INTEGER"); + + b.Property("Avisering") + .IsRequired() + .HasColumnType("TEXT"); + + b.Property("Belopp") + .HasColumnType("REAL"); + + b.Property("BetalDatum") + .HasColumnType("TEXT"); + + b.Property("Konto") + .IsRequired() + .HasColumnType("TEXT"); + + b.Property("Mottagare") + .IsRequired() + .HasColumnType("TEXT"); + + b.HasKey("Id"); + + b.ToTable("AccountRecords"); + }); + + modelBuilder.Entity("WinFormDiApp.BL.Models.Member", b => + { + b.Property("Id") + .ValueGeneratedOnAdd() + .HasColumnType("INTEGER"); + + b.Property("Email") + .IsRequired() + .HasColumnType("TEXT"); + + b.Property("FirstName") + .IsRequired() + .HasColumnType("TEXT"); + + b.Property("LastName") + .IsRequired() + .HasColumnType("TEXT"); + + b.Property("NickName") + .IsRequired() + .HasColumnType("TEXT"); + + b.Property("PersonType") + .IsRequired() + .HasColumnType("TEXT"); + + b.HasKey("Id"); + + b.ToTable("Members"); + }); +#pragma warning restore 612, 618 + } + } +} diff --git a/WinFormDiApp.DAL/WinFormDiApp.DAL.csproj b/WinFormDiApp.DAL/WinFormDiApp.DAL.csproj new file mode 100644 index 0000000..e08ed77 --- /dev/null +++ b/WinFormDiApp.DAL/WinFormDiApp.DAL.csproj @@ -0,0 +1,29 @@ + + + + net7.0 + enable + enable + + + + + + all + runtime; build; native; contentfiles; analyzers; buildtransitive + + + + all + runtime; build; native; contentfiles; analyzers; buildtransitive + + + + + + + + + + + diff --git a/WinFormDiApp.sln b/WinFormDiApp.sln index a2e9994..3ef52d5 100644 --- a/WinFormDiApp.sln +++ b/WinFormDiApp.sln @@ -3,9 +3,13 @@ Microsoft Visual Studio Solution File, Format Version 12.00 # Visual Studio Version 17 VisualStudioVersion = 17.6.33829.357 MinimumVisualStudioVersion = 10.0.40219.1 -Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "WinFormDi", "WinFormDi\WinFormDi.csproj", "{940A0A13-2195-47DD-9FDE-16A0C57AF3BF}" +Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "WinFormDi", "WinFormDi\WinFormDi.csproj", "{940A0A13-2195-47DD-9FDE-16A0C57AF3BF}" EndProject -Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "DIDemoLib", "DIDemoLib\DIDemoLib.csproj", "{839E6DE6-4644-4279-A7B1-449BD63897A3}" +Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "DIDemoLib", "DIDemoLib\DIDemoLib.csproj", "{839E6DE6-4644-4279-A7B1-449BD63897A3}" +EndProject +Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "WinFormDiApp.BL", "WinFormDiApp.BL\WinFormDiApp.BL.csproj", "{4D49AE4B-26D6-48C6-B1CA-48D428E95BE0}" +EndProject +Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "WinFormDiApp.DAL", "WinFormDiApp.DAL\WinFormDiApp.DAL.csproj", "{C6E355AD-C907-45D2-815B-A1B4207656FB}" EndProject Global GlobalSection(SolutionConfigurationPlatforms) = preSolution @@ -21,6 +25,14 @@ Global {839E6DE6-4644-4279-A7B1-449BD63897A3}.Debug|Any CPU.Build.0 = Debug|Any CPU {839E6DE6-4644-4279-A7B1-449BD63897A3}.Release|Any CPU.ActiveCfg = Release|Any CPU {839E6DE6-4644-4279-A7B1-449BD63897A3}.Release|Any CPU.Build.0 = Release|Any CPU + {4D49AE4B-26D6-48C6-B1CA-48D428E95BE0}.Debug|Any CPU.ActiveCfg = Debug|Any CPU + {4D49AE4B-26D6-48C6-B1CA-48D428E95BE0}.Debug|Any CPU.Build.0 = Debug|Any CPU + {4D49AE4B-26D6-48C6-B1CA-48D428E95BE0}.Release|Any CPU.ActiveCfg = Release|Any CPU + {4D49AE4B-26D6-48C6-B1CA-48D428E95BE0}.Release|Any CPU.Build.0 = Release|Any CPU + {C6E355AD-C907-45D2-815B-A1B4207656FB}.Debug|Any CPU.ActiveCfg = Debug|Any CPU + {C6E355AD-C907-45D2-815B-A1B4207656FB}.Debug|Any CPU.Build.0 = Debug|Any CPU + {C6E355AD-C907-45D2-815B-A1B4207656FB}.Release|Any CPU.ActiveCfg = Release|Any CPU + {C6E355AD-C907-45D2-815B-A1B4207656FB}.Release|Any CPU.Build.0 = Release|Any CPU EndGlobalSection GlobalSection(SolutionProperties) = preSolution HideSolutionNode = FALSE