Tuesday, April 23, 2019

Equatable and Comparable protocol in Swift

In Swift, sort, sorted have two parameter types, one does not have parameter, another one takes a closure.
mutating func sort()
mutating func sort(by areInIncreasingOrder: (Element, Element) throws -> Boolrethrows

Similar for contains method, one takes an element parameter, and another one take a closure.

func contains(_ element: Element) -> Bool
func contains(where predicate: (Element) throws -> Bool) rethrows -> Bool

Which one to use depends on whether the element type conforms to Equatable (for contains method) or Comparable (for sort method) protocol.

When calling sort or contains method with the closure parameter, there is no limitation on element type, so any element can be used for those methods.

However, when calling contains method with an element object parameter, the element type must conforms to Equatable protocol. Equatable protocol defines a == method, so == can be used in swift code to compare whether two elements are equal or not. When contains(element: Element) is called, it internally uses Equatable protocol's == method to compare whether the input parameter is contained in the collection.

Similarly, when calling sort method with empty parameter, the element type must conforms to Comparable protocol. Comparable protocol inherits from Equatable protocol, which defines some additional method of >  <  >=  <=, so those operators can be used to compare two element objects' value in swift code, Sort method internally uses those method to sort the elements in a collection.

In a word, if an element types conforms to Equatable (or Comparable) protocol, then the simple version of sort (or contains) method can be used, otherwise, the one with the closure parameter must be used. 

Tuesday, April 9, 2019

Debug ASP.Net project deployed to MS Azure from Visual Studio

The below steps can be used to debug asp.net core project deployed to MS Azure app service from Visual Studio 2017.
1. From Visual Studio 2017, publish the asp.net core app to Azure, setting the Configuration to "Debug"
2. In MS Azure portal, app service configuration, select Settings->Configuration, and set Remote Debugging to On, and select Remote Visual Studio version to 2017
3. From Visual Studio, select menu of View->Cloud Explorer, find the MS Azure App service item which has the project deployed to, and then right click it, and select "Attach Debugger"



In addition, for debug purpose, you may want to run asp.net application deployed on Azure in development mode, instead of production mode, so that the error page can contain more information about the error.

To do so, in Azure portal, app service's Settings/Configuration section, add a new setting as below:
ASPNETCORE_ENVIRONMENT     Development

Monday, April 1, 2019

Asp.net core project to migrate database scheme in a separate library project

For large asp.net core web project, the data access logic is usually put into a separate project, however, the database connection string is still configured in main project's appsettings.json file, so some extra settings is required when the data access project uses the connection string from main asp.net core project.
The data access library already added the below dependency
microsoft.EntityFrameworkCore
microsoft.EntityFrameworkCore.Design
Microsoft.EntityFrameworkCore.Sqlserver

1. update appsettings.json to include connection string
{
  "Logging": {
    "LogLevel": {
      "Default": "Warning"
    }
  },
  "AllowedHosts": "*",
  "ConnectionStrings": {
   "TravelInsuranceDb":  "Data Source=(localdb)\\MSSQLLocalDB; Initial Catalog=TravelInsurance;Integrated Security=True;"
  }
}


2. in main project's startup.cs, update configureServices method to AddDbContextPool, so that when needed, the custom DBContext object can be created by asp.net core to be used by application
    public void ConfigureServices(IServiceCollection services)
        {
            services.AddDbContextPool<DataAccessDbContext>(options =>
            {
                options.UseSqlServer(Configuration.GetConnectionString("TravelInsuranceDb"));
            });
    

3. in data access library, create a DBContext sub class with a DBSet property
   public class DataAccessDbContext : DbContext
    {
        public DataAccessDbContext(DbContextOptions<DataAccessDbContext> options) : base(options)
        {
        }

        public DbSet<User> Users{get; set;}
    }
}
 public class User
    {
        [Key]
        public String Email { get; set; }  //this is the unique key for each user
    }

4. using dotnet migrations command line tool to create migration script. Whenever the entity structure is updated in the project, a new migration should be added. The -s parameter tells data access project where to find the connection string to connect to the database. After running the below command from data access library folder, the data access project should create the migration cs file for how to do the migration on database
dotnet ef migrations add initialcreate -s ..\travelinsurance\travelinsurance.csproj

5. using dotnet ef database command to update database, and verify the database is created
dotnet ef database update -s ..\travelinsurance\travelinsurance.csproj

6. Assume user entity needs a new int field "Point", first update the User class as below 
    public class User
    {
        [Key]
        public String Email { get; set; }  //this is the unique key for each user
        public int Point { get; set; }
    }
Then run the below command to add a new migration step script in the data access project.
dotnet ef migrations add initialcreate -s ..\travelinsurance\travelinsurance.csproj

7. run the database update command again to update the sql server, and verify the new column is added in the table.
dotnet ef database update -s ..\travelinsurance\travelinsurance.csproj