Adventures on the edge

Learning new development technologies
    "When living on the bleeding edge - you sometimes have to bleed" -BillKrat

Code first with Entity Framework Core (desktop app)

Source: OPEN SOURCE CODE

NuGet Prerequisites:

  • Microsoft.EntityFrameworkCore
  • Microsoft.EntityFrameworkCore.Design
  • Microsoft.EntityFrameworkCore.Tools
  • Microsoft.EntityFrameworkCore.SqlServer (for SQL Server usage)

First you’ll want to create your data context, you’ll see that mine resides in the data access layer project for my Contact Manager application; which follows best practices and patterns, but makes EF complain (video has a work-around).  My context uses POCO objects from my Model project which has no references to Entity Framework or any other external libraries.

Next create the database tables by launching the NuGet Package Manager console and typing in:

  1. add-Migration <YourContext>
  2. update-database

Your done!   The following video demonstrates how I had a failing unit test because three were no tables in my database.  With the above two steps the tables were generated.

In figure 1 we show the POCO class that generated the tables, and relationships, shown in figure 2.

Video 1 fixing failing unit test because there are tables in the database

ContactTable

Figure 1 Contact Class

Schema

Figure 2 Schema generated from Contact Class

Context

Figure 3 Context code – referencing only POCO objects

How to load Unity IOC configuration from app.config

If you follow the available documentation on MSDN, or on various internet sites such as StackOverflow, you’ll find the app.config configuration in figure 1; it is wrong and you’ll receive the following error:

An error occurred creating the configuration section header for unity: could not load file or assembly ‘Microsoft.Practices.Unity.Configuration…’
Adventures on the edge

This sent me for a loop as I generally use the Microsoft packages for Unity, but decided that for my open source contact manager application (http://github.com/billkrat/contact-manager) that I will use the latest NuGet version and was surprised when I encountered the error shown in figure 1.

In hindsight it was a rather obvious issue/fix – but I blog about it because if you’re like me you could waste time on this because there is a blatant violation of development standards that forces us to “think outside of the box”, the “standards” box that is.   The namespace does not match the assembly name, reference figure 3.

Since I didn’t add the namespaces manually (I used NuGet) I didn’t realize this until I had to start digging in deep.

Once you update the assembly in the configuration file to reflect Unity.Configuration (as shown in figure 2) you can then follow the documentation available at the Microsoft site for “The Unity Configuration Schema”; it has comprehensive documentation – you can also reference my above GitHub open source project for examples as I use it throughout the application.

UnityNamespace

Figure 1 following documentation generates error

UnityNamespace-fixed

Figure 2 proper configuration for section

UnityNamespace-NuGet

Figure 3 mismatch between assembly name and its namespaces

Github and Visual Studio continuous integration (automated builds)

You can use Visual Studio’s free service for continuous integration for GitHub as easily as you can for TFS.   In the below clip we show how when we push our changes to GitHub, the Visual Studio CI fires processing the build.


The steps follow below:

1. Create the Visual Studio project, disregard the project setup, and go directly to the “Build and Release” link  and click New. 

ss001

Select “GitHub” and log into the system, select your GitHub project from the available list (using … link button)

ss002

Click continue, select the .NET Desktop build template and click “Apply”

ss003

Be sure to select “Private” default for the agent queue, otherwise you’ll be limited to Hosted free minutes (private is unlimited).  Click the Manage link when done.

ss004

From the manage page, download agent to your local drive.

ss005

Note: you can simply unzip it to the agent folder using explorer (easier then using suggested PowerShell command).

Before launching PowerShell it is suggested that you click on your login icon, select Security, and then add a Personal Access Token (PAT).  IMPORTANT: Be sure to copy/paste the provided token somewhere for future use – you won’t be able to uninstall/reconfigure your agent without it.

sspat

Running as admin, launch PowerShell, switch to the folder you unzipped the agent files to, and type “.\config”.  You can select the default prompts as shown below.  Note: since I have unit test that need to run SQL Server (using my credentials) I logged in as “BillKrat”

ss007

The last thing you’ll want to do is click on the “Triggers” link of the build definition and select “Enable continuous integration”.  If you don't check this checkbox then you'll be forced to queue builds - versus it automatically generating a build upon check-in as shown in the video clip above.

ss008

When build is completed you will receive an email notification on the status.

email

Windows Server 2016 installation hangs at 17% [resolved]

Adventures on the edge  Event after I let the installation run all night… 

I used the Task Manager to exit the process and then rebooted the server.  Upon restart it resumed the installation process hanging at 17% again, my internet research indicated that I had to start the Windows Server Essential Manager Service and upon doing so the installation successfully completed.  

Note: I used the Task Manager, selected the services tab, and started it from there.

Resolved

No DbContext was found in assembly EF Core 2.0

Adventures on the edge EF Core 2.0 expects your “Application” to hold your data context (010-100 top left figure 2), but if you follow best practices and patterns your context will reside in the data layer (010-020-010 in green below figure 2) and you’ll receive this message when you try to “Add-Migration” via the Package Manager Console.

NoDbContext
Figure 1 Package Manager Console error message

I love Entity Framework Core 2.0 because our entities can remain POCO objects, effectively allowing us to decouple them from our layers (reference 010-030 ContactDonation.Model in middle-right of image below); later if I have to swap out the EF data access layer (010-020-010 in green below), for lets say an Azure data layer, my presentation and business logic layers won’t be affected.

It is quite problematic that EF Core 2.0 expects to see my data context in the main application (in my presentation layer).  Particularly since my data access layer for the ContactContext will be reused by other business logic layers, e.g., I might reuse it in a totally different application.  Note to mention that I may want to swap out my presentation layer (which has no business logic in it), e.g., for an ASP.NET application.  But I have a work-around….

UseCaseOverview

Figure 2 Separated presentation – MVPVM pattern (for decoupled frameworks)

By “linking” the ContactContext class from my data access layer project to my application (ContactDonationWpf), I can effectively fool Visual Studio into thinking the data context resides in the main application to complete processing.   This permits me to keep my data context neatly decoupled while allowing my POCO entities (below) in a separate ContactDonation.Model project that can be referenced by all layers.

namespace ContactDonation.Model
{
public class Contact
{
public string ContactId { get; set; } // PK
public string UserId { get; set; } // Users use
public string Email { get; set; }
public string Title { get; set; }
public string Name { get; set; }
public string FirstName { get; set; }
public string LastName { get; set; }
public string Middleinitial { get; set; }
public string NickName { get; set; }
public string Spouse { get; set; }
public string Realtives { get; set; }
public string Website { get; set; }

public ICollection<Address> Address { get; set; }
public ICollection<PhoneNumber> PhoneNumbers { get; set; }
public ICollection<Organization> Organizations { get; set; }
public ICollection<Tag> Tags { get; set; }
public string Notes { get; set; }

public Contact()
{
PhoneNumbers = new HashSet<PhoneNumber>();
Organizations = new HashSet<Organization>();
Tags = new HashSet<Tag>();
}
}
public class Address
{
public string AddressId { get; set; } // PK
public string Type { get; set; } // Billing, Residence
public string Street { get; set; }
public string Street2 { get; set; }
public string City { get; set; }
public string State { get; set; }
public string Zip { get; set; }
}

public class Organization
{
public string OrganizationId { get; set; } // PK
public ICollection<Address> Addresses { get; set; }
public ICollection<PhoneNumber> PhoneNumbers { get; set; }

public Organization()
{
Addresses= new List<Address>();
PhoneNumbers = new HashSet<PhoneNumber>();
}
}
public class PhoneNumber
{
public string PhoneNumberId { get; set; } // PK
public string Type { get; set; } // Cell, Work, Home
public string Number { get; set; }
}

public class Tag
{
public string TagId { get; set; } // PK
public string Name { get; set; }
public string Notes { get; set; }
}
}