.NET Component AlKhemeia.Geo – list of countries, cities and many more functionality

Introduction

You can find the source code here and to see this component in action please visit http://geo.alkhemeia.com

This article aims at explaining

  • Alkhemeia.Geo component
  • How to get a list of countries and cities
  • A list of methods to extract useful information
  • Entities involved

Based on ISO standards, AlKhemeia.Geo, a .NET class library, provides a comprehensive list of Countries and Cities. The component not only provides a list of country/city but also a list of methods to extract useful information out of the database maintained in a resource file in XML format.

The Code

The library consists of two entities

Country.cs

public class Country
 {
 public string ISO { get; set; }
 public string ISO3 { get; set; }
 public string fips { get; set; }
 public string ISONumeric { get; set; }
 public string CountryName { get; set; }
 public string Capital { get; set; }
 public double? AreaSqKm { get; set; }
 public int? Population { get; set; }
 public string Continent { get; set; }
 public string tld { get; set; }
 public string CurrencyCode { get; set; }
 public string CurrencyName { get; set; }
 public string Phone { get; set; }
 public string Languages { get; set; }
 public int geonameid { get; set; }
 public string neighbours { get; set; }
/// <summary>
/// Get an instance of System.Globalization.CultureInfo object based on country name. 
/// Issue:
/// There is a possibility that a country may have more than one cultures. This approach currently does not address that.
/// </summary>
public CultureInfo CultureInfo
{
 get
 {
    return CultureInfo.GetCultures(CultureTypes.AllCultures)
               .Where(c => c.EnglishName.ToLower()
                          .Contains(CountryName.ToLower())).FirstOrDefault();
 }
}
/// <summary>
/// Get an instance of System.Globalization.RegionInfo object 
/// based on country name. 
/// </summary>
public RegionInfo RegionInfo
{
   get
   { 
     return new RegionInfo(ISO);
   }
}
}

City.cs

public class City
{
 public int GeoNameId { get; set; }
 public string Name { get; set; }
 public string AsciiName { get; set; }
 public string AlternateNames { get; set; }
 public float Latitude { get; set; }
 public float Longitude { get; set; }
 public string FeatureClass { get; set; }
 public string FeatureCode { get; set; }
 public string CountryCode { get; set; }
 public string CC2 { get; set; }
 public string Admin1Code { get; set; }
 public string Admin2Code { get; set; }
 public string Admin3Code { get; set; }
 public string Admin4Code { get; set; }
 public int Population { get; set; }
 public string Elevation { get; set; }
 public string Dem { get; set; }
 public string TimeZone { get; set; }
 public string ModificationDate { get; set; }
}

What can be achieved?

  • Find country by ISO code
  • Find country by name
  • Find neighbouring countries of a country
  • Find a list of countries based on population
  • Find a list of countries based on area in square kilometres
  • Find a list of countries in a continent
  • A list of key value pair of continent iso code and name
  • Calculate distance between two countries based on their capitals
  • Find city by ISO code
  • Calculate distance between any two cities
  • Find a list of cities in a country

The methods available for both Cities and Countries are exposed by following interfaces:

ICountryRepository.cs

public interface ICountryRepository : IBaseRepository<Country>    {        
   /// <summary>
   /// Find country by primary key ISO
   /// </summary>
   /// <param name=&amp;quot;iso&amp;quot;>the primary key</param>
   /// <returns>Country</returns>
   Country FindCountry(string iso);

   /// <summary>
   /// Finds a country by name
   /// </summary>
   /// <param name=&amp;quot;name&amp;quot;>country name</param>
   /// <returns>Country</returns>
   Country FindByName(string name);
   
   /// <summary>
   /// Find neighbouring countries of speicified country
   /// </summary>
   /// <param name=&amp;quot;country&amp;quot;>The country</param>
   /// <returns>List of neighbouring countries</returns>
   IList<Country> FindNeighbouringCountries(Country country);     

   /// <summary>
   /// Find countries with the population greater than the specified number
   /// </summary>
   /// <param name=&amp;quot;population&amp;quot;>The population</param>
   /// <returns>List of countries</returns>
   IList<Country> FindCountryWithPopulationGreaterThan(int population);

   /// <summary>
   /// Find countries with the area greater than specified number
   /// </summary>
   /// <param name=&amp;quot;areaSqKm&amp;quot;>Area in square kilometers</param>
   /// <returns>List of countries</returns>
   IList<Country> FindCountryWithAreaGreaterThan(int areaSqKm);

   /// <summary>
   /// Find counties by continent
   /// </summary>
   /// <param name=&amp;quot;continent&amp;quot;>The continent</param>
   /// <returns>List of countries</returns>
   IList<Country> FindCountriesByContinent(string continent);
   /// <summary>
   /// Find countries with names containing the specified strings
   /// </summary>
   /// <param name=&amp;quot;term&amp;quot;>a string</param>
   /// <returns>A list of countries</returns>
   IList<Country> FindCountriesWithNameContaining(string term);

   /// <summary>
   /// Find continent keyvalue pairs
   /// </summary>
   /// <returns>List of keyvalue pairs of continents</returns>
   IList<KeyValuePair<string, string>> FindContinentKeyValuePair();

   /// <summary>
   /// Calculate the distance between two countries based on theircapitals as origins
   /// </summary>
   /// <param name=&amp;quot;isoCountryCode1&amp;quot;>ISO Country Code</param>
   /// <param name=&amp;quot;isoCountryCode2&amp;quot;>ISO Country Code</param>        /// <returns>distance in KM</returns>
   double CalculateDistance(string isoCountryCode1, string isoCountryCode2);
}

ICityRepository.cs

public interface ICityRepository : IBaseRepository<City>
{
  /// <summary>
  /// Find cities with the population greater than the specified number
  /// </summary>
  /// <param name=&amp;quot;population&amp;quot;>The population</param>
  /// <returns>List of cities</returns>
  List<City> FindCityWithPopulationGreaterThan(int population);

  /// <summary>
  /// Find all cities for the specified country
  /// </summary>
  /// <param name=&amp;quot;isoCode&amp;quot;>Country ISO code</param>
  /// <returns>List of cities for the specified country</returns>
  IList<City> FindCitiesByCountry(string isoCode);

  /// <summary>
  /// Find cities which name start with name
  /// </summary>
  /// <param name=&amp;quot;name&amp;quot;>Name/search string of the city</param>
  /// <returns>List of cities whose name matches the name</returns>
  IList<City> FindCityByName(string name);

  /// <summary>
  /// Calculates approximate air distance between two cities in kilometers
  /// </summary>
  /// <param name=&amp;quot;isoCountryCode1&amp;quot;>ISO country code1</param>
  /// <param name=&amp;quot;isoCountryCode2&amp;quot;>ISO country code2</param>
  /// <returns>Distance in Kilometers</returns>
  double CalculateDistance(string city1, string city2);
}

How to use the component?

To keep things simple the implementation of ICountryRepository and ICityRepository are limited for extension/modification only within the project itself and exposed via AlKhemeia.Geo.Globe class as shown below:

public class Globe
{
  private static ICountryRepository _countries;
  private static ICityRepository _cities;

  /// <summary>
  /// 
  /// </summary>
  public static ICountryRepository Countries
  {
   get
   {
     if (_countries == null)
     {
       _countries = new CountryRepository();
     }
     return _countries;
   }
  }

  /// <summary>
  /// 
  /// </summary>
  public static ICityRepository Cities
  {
     get
     {
       if (_cities == null)
       {
         _cities = new CityRepository();
       }
       return _cities;
     }
  }
 }

To use this component all you need to do is to reference AlKhemeia.Geo library in your project. Following example shows you how easy it is to use this component.

class Program
{
  static void Main(string[] args)
  {
    var counties = Globe.Countries.FindAll();
    var cities = Globe.Cities.FindAll();

    var list = Globe.Cities.FindAll();

    var distance = Globe.Cities.CalculateDistance(&amp;quot;london&amp;quot;, &amp;quot;islamabad&amp;quot;);
  }
}

More features to come

– Key value pair of Countries/Cities to be used for ASP.NET components such as DropDown list control

– functionality to create tables i.e. alkhemeia_country and alkhemeia_city in case if someone wants to include the data in their own application.

Advertisements
Posted in .NET C# | Tagged , , , , , , | Leave a comment

.NET Simple Membership Provider for SqlServer, MySql, Access or Oracle

You can find the source code here

This SimpleMembershipProvider is written in C#.NET and tested against both SQL Server and MySQL. It is assumed that this will work against other relational databases also.

Description

.NET Simple Membership Provider was originally developed to work with SQL Server database only. The need arisen when we had to migrate our data source from SQL Server to MySQL. The simple membership provider that was initially written for SQL Server in one of our projects did not remain functional against MySQL.

This project is a slight modification of the original implementation of .NET Simple Membership Provider.

How do I get set up?

The Unco.SimpleMembershipProvider is extremely easy to setup. You can either add this project to your existing solution or add just a reference dll of this project to your project. Rest of the setup is similar to .NET Simple Membership Provider that is included in WebMatrix.Data namespace.

  • Follow these steps to setup Unco.MembershipProvider
  • Add a reference of Unco.MembershipProvider to your project.
  • In your web.config along with connection string add the membership provider within tag boundary as follows
<membership defaultProvider="SimpleMembershipProvider">
 <providers>
 <clear />
 <remove name="SimpleMembershipProvider" />
 <add name="SimpleMembershipProvider"
 type="Unco.MembershipProvider.SimpleMembershipProvider, Unco.MembershipProvider"
 connectionStringName="DefaultConnection" 
 enablePasswordRetrieval="false" 
 enablePasswordReset="true" 
 requiresQuestionAndAnswer="true" 
 applicationName="/" 
 requiresUniqueEmail="false" 
 passwordFormat="Clear" 
 maxInvalidPasswordAttempts="5" 
 minRequiredPasswordLength="7" 
 minRequiredNonalphanumericCharacters="1" 
 passwordAttemptWindow="10" 
 passwordStrengthRegularExpression=""/>
 </providers>
 </membership>
  • Add a connection string as follows:
<connectionStrings>
 <add name="DefaultConnection"
 connectionString="server=127.0.0.1;user id=mysql;password=mysqlpwd;database=DatabaseName;persistsecurityinfo=True"
 providerName="MySql.Data.MySqlClient"
 />
 </connectionStrings>
  • Replace WebMatrix.WebData namespace with Unco.MembershipProvider in your code file where you will initialize the SimpleMembershipProvider. The code you previously used to work with Sql Server database may look like this
WebSecurity.InitializeDatabaseConnection("DefaultConnection", "UserProfile", "UserId", "UserName", autoCreateTables: true);
  • replace this code with the following:
WebSecurity.InitializeDatabaseConnection("DefaultConnection", DatabaseType.MySql, "UserProfile", "UserId", "UserName", autoCreateTables: true);

where DatabaseType is an enum

public enum DatabaseType
{
 SqlServer, 
 MySql, 
 Oracle, 
 Access
}

To understand how this enum works you will have to investigate the code a bit. In short this is to identify the database and add relevant attributes to the SQL Queries.

You should now be able to use SimpleMembershipProvider with MySql.

Note: Please let me know if you find any issues with this implementation.

Posted in Uncategorized | Leave a comment

System.Data.Entity.Validation.DbEntityValidationResult – Validation failed for one or more entities. See ‘EntityValidationErrors’ property for more details.

While working with Entity Framework 5.x I came across the following error:

“Validation failed for one or more entities. See ‘EntityValidationErrors’ property for more details.”

The description by itself is not helpful at all. It doesn’t tell you the exact cause of the problem. The exception is usually thrown when dbContext.SaveChanges() method is called.

I used database first approach and defined a table Car with following fields:

  • CarId (int: primary key [auto increment])
  • Brand (varchar [required])
  • Model (varchar [required])
  • Description (varchar)
  • Region (varchar [required])

I then wrote the following code:

using (var dbContext = new SampleDBEntities())
{
  var car = new Car()
  {
    Brand = “BMW”,
    Model = “2012”,
    Description = “car description”
  };
  dbContext.Cars.Add(car);
  dbContext.SaveChanges();
}

You can see that required field Region is missing from the car object initializer. When I tried to save changes the system rejects the request and throws an exception because it cannot store null for that property. The exception doesn’t tell the exact reason.

In order to find the culprit, wrap dbContext.SaveChanges() in try/catch block. Write each property to console along with its descrition as shown in the code below. The information written to the console is a lot more helpful then standard exception description.

try
{
  dbContext.SaveChanges();                 
}
catch (DbEntityValidationException ex)
{
  foreach (var entityValidationErrors in ex.EntityValidationErrors)
  {
    foreach (var validationError in entityValidationErrors.ValidationErrors)
    {
      Console.WriteLine(“Property: {0} Error: {1}”,
        validationError.PropertyName,validationError.ErrorMessage);                 }
    }
  }
 }

Note: Use this approach only in the debug mode and remove try/catch in order to make sure that you don’t lose exception thrown in the live environment.

Posted in .NET C#, Entity Framework | Tagged , , | Leave a comment

Hyper-V – how to install legacy network driver for Windows Server 2003 virtual machine

I have recently installed Windows Server 2012 and setup a domain. I then setup a virtual machine with Windows Server 2008 installed on it. I setup an External Virtual Switch using Virtual Switch Manager in Hyper-V manager and used that switch for Network Adapter associated with that virtual machine. Everything worked just as expected and I managed to add the VM to domain setup on the host computer and also successfully connected to internet connection.

I, then, setup another virtual machine with Windows Server 2003 SP2 only to find out that it does not pick up the vNIC. I, then, added legacy network adapter by following these steps

  • Virtual Machine > Settings > Add Hardware
  • Select Legacy Network Adapter and click Add
  • This will add Legacy Network Adapter to the virtual machine
  • Select appropriate Virtual Switch under “Legacy Network Adapter” settings

When I started my VM it detected the network adapter but unfortunately couldn’t pick up the driver which made me google for the solution. One of the article I came across on Microsoft website was titled “Hyper-V: Avoid using a legacy network adapter on Windows Server 2003 (x64) and Windows XP Professional (x64)” which forced me to look for other solution and I ended up wasting half of my precious Sunday L

I didn’t give up my search to find the solution for my problem and finally I came across the following blog. This helps to find out the driver for legacy network adapter already available on Vista machine. I have Windows 7 installed on one of my other machines so I followed the procedure as explained in the blog. Everything is exactly the same as explained except the directory name which is slightly different but close enough to identify. On Vista the directory is located at

–          %windir%\system32\driverstore\FileRepository\dc21x4vm.inf_7d8c6569

While on Windows 7 the driver information is located in

–          %windir%\system32\driverstore\FileRepository\dc21x4vm.inf_amd64_neutral_8887242a56ee027e

Copy all files to a CD or create ISO image file so you can browse it using DVD drive associated with VM.

Start VM and when asked browse to this directory on DVD and install drivers. That’s it all done and you should be good to go.

Posted in Hyper-V, Legacy Network Adapter, Uncategorized | Tagged , , , , | 5 Comments

Determining how long a database will be IN RECOVERY (SQL Server 2008)

I have come across a situation where SQL Server crashed in the middle a process of shrinking log files of a database of size 10+ GB. After restarting SQL Server I saw the database in question has gone IN RECOVERY mode. Before I started sorting this issue out I needed to know whether the system is doing anything or not. For that reason, after googling for 10 odd minutes I came across a very useful post by TIM Laqua and decided to log it in my own blog in case I need the script in future.

Here is the useful blog . Hope it helps the folks who accidentally came across this blog.

Posted in SQL Server | Tagged , | Leave a comment

Microsoft Dynamics CRM 2011 Server installation – Setup failed to validate specified Reporting Services Report Server

This blog is in connection with my blog “The instance name must be the same as computer name”. (read this post if you have changed your server name after SQL server installation)

During CRM 2011 installation I came across the  error “Setup failed to validate specified Reporting Services Report Server”. This was due to renaming the server after SQL server installation.

In event viewer the exception looks similar to this:

Web service request FindItems to Report Server http://server_name/reportserver/ReportService2005.asmx failed with SoapException. Error: The report server cannot open a connection to the report server database. A connection to the database is required for all requests and processing.

I managed to resolve this issue by following these steps and hope these help you too:

– as you may have renamed your machine after SQL server installation then you may have to read this blog first in order to rename the machine name bound to SQL server instance

– Run SQL server Reporting Services Configuration Manager

– Connect to it using the current server name and appropriate Report Server Instance

– Select Database tab

– You will see that under “Current Report Server Database” section the SQL Server Name is set to your old machine name (we need to get rid of this bad boy, stay tuned)

– Click Change Database button

– Select option “Choose an existing report server database”

– for Server Name type in your new machine name

– select ReportServer as your Report Server Databse

– then next, next until you finished

– restart SQL Server Reporting service and try installing again and you will be OK, I HOPE!!!!

 

 

Posted in Uncategorized | 8 Comments

Microsoft Dynamics CRM 2011 Server installation – “The instance name must be the same as computer name”

Recently I have come across an issue “The instance name must be the same as computer name” while Microsoft Dynamics CRM 2011 performs a system check during installation.

Image

During diagnostic check CRM performs a query against the server bound to the SQL server instance and throws an exception if there are any inconsistencies.

The reason was that I setup a virtual machine using a VHD preloaded with Windows Server 2008 R2 and SQL Server 2008 R2 installation and rename the server afterwards. The SQL server is still bound to the server name which does not exist any more.

To correct this issue follow these very simple steps.

– execute built-in stored procedure “sp_helpserver” (this will return the server names bound to the current instance of SQL server and your machine should not be listed in the results.)

– To change information you have to first drop the server name that doesn’t exist anymore by executing stored procedure as sp_dropserver ‘OLD_SERVERNAME’

– then add a new entry with current server name by running the procedure as sp_addserver ‘CURRENTNAME’, ‘LOCAL’

– restart SQL server service

– reinstall CRM and you are good to go

– if you have come across this issue the same way as I did then you may come across similar issue with Reporting server too that prevents CRM installation “Setup failed to validate specified Reporting Services Report Server”. The solution is discussed here

Posted in Microsoft Dynamics CRM, SQL Server | 1 Comment