How should I design a business framework ? (Part 2)

Last week, I exposed my opinion about how and why we need to think about designing a business framework. The code example in the first part, was to demonstrate quickly how to separate different layer of the “Business” part, like it’s explained in the “Domain Driven Design”.
In these “Part 2″, I go a little deeper, and I’m detailing “How?” I do in real-life scenario.

1) How a business model is design?

ModelBase (Model abstraction implementation)

using System;

namespace MyCompany.Framework.Business.Models
{
    public abstract class ModelBase
    {
        public Guid Identifier { get; set; }

        public bool IsNew()
        {
            return Identifier.Equals(Guid.Empty);
        }
    }
}

CustomerAccount (Concrete Model / Entity)

using System.Collections.Generic;
using MyCompany.Framework.Business.Models;

namespace MyCompany.ConcreteDomain.Models
{
    public class CustomerAccount : ModelBase
    {
        public string Name { get; set; }
        public string Description { get; set; }
        public string PhoneNumber { get; set; }
        public decimal CreditLimit { get; set; }
    }
}

2) Place to the Business Logic itself

BusinessBase (Business Abstraction implementation)

using System;
using Microsoft.Data.Entity;

using MyCompany.Framework.Business.Data;
using MyCompany.Framework.Business.Models;

namespace MyCompany.Framework.Business.Logic
{
    public abstract class BusinessBase<T, TC> : IDispose
        where T : ModelBase, new()
        where TC: DataContextBase, new()
    {
        protected BusinessBase(T inst)
        {
            CurrentObject = inst;
            if (inst.IsNew())
            {
                inst.Identifier = Guid.NewGuid();
                DataContext.Set<T>().Add(inst);
            }
        }

        public DataContextBase DataContext => BusinessContext<TC>.CurrentContext;
        public T CurrentObject { get; }

        public virtual bool Save()
        {
            DataContext.ChangeTracker.DetectChanges();
            return DataContext.SaveChanges() > 0;
        }

        public virtual bool Delete()
        {
            DataContext.Set<T>().Remove(CurrentObject);
            DataContext.ChangeTracker.DetectChanges();
            return DataContext.SaveChanges() > 0;
        }

        public void Dispose() {}
    }
}

BusinessContext (Business Context Abstraction)

using System;
using System.Linq;
using System.Linq.Expressions;

using MyCompany.Framework.Business.Data;
using MyCompany.Framework.Business.Models;

namespace MyCompany.Framework.Business.Logic
{
    public abstract class BusinessContext<C> where C: DataContextBase, new()
    {
        private static readonly Lazy<C> _dataContext = new Lazy<C>(()=> new C());

        public static DataContextBase CurrentContext => _dataContext.Value;

        public static IQueryable<T> Get<T>(Expression<Func<T, bool>> expr) where T : ModelBase
        {
            return CurrentContext.Set<T>().Where(expr).AsQueryable();
        }
    }
}

CustomerAccountManager (Concrete business implementation)

using MyCompany.ConcreteDomain.Models;
using MyCompany.ConcreteDomain.SqlData;
using MyCompany.Framework.Business.Logic;

namespace MyCompany.ConcreteDomain.Logic
{
    internal sealed class CustomerAccountManager : BusinessBase<CustomerAccount, DbCrmContext>
    {
        public CustomerAccountManager(CustomerAccount inst) : base(inst) { }
    }
}

CRMBusinessContext (Concrete business context)

using MyCompany.ConcreteDomain.SqlData;
using MyCompany.Framework.Business.Logic;

namespace MyCompany.ConcreteDomain.Logic
{
    public sealed class CRMBusinessContext : BusinessContext<DbCrmContext>
    {
        private CRMBusinessContext() { }
    }
}

3) As the last piece into the puzzle, I’ve a Data access abstraction and concrete implementation using Entity Framework 7.

DataContextBase (Abstract Data Access with EF7)

using Microsoft.Data.Entity;

namespace MyCompany.Framework.Business.Data
{
    public abstract class DataContextBase : DbContext
    {
        private readonly string _dbConnString;

        protected DataContextBase(string dbConnString)
        {
            _dbConnString = dbConnString;
        }
        protected override void OnConfiguring(DbContextOptionsBuilder optionsBuilder)
        {
            base.OnConfiguring(optionsBuilder);
            optionsBuilder.UseSqlServer("<MY_DB_STRING>");
        }
    }
}

DbCrmContext (Concrete Data Access implementation)

using Microsoft.Data.Entity;
using MyCompany.ConcreteDomain.Models;
using MyCompany.Framework.Business.Data;

namespace MyCompany.ConcreteDomain.SqlData
{
    public sealed class DbCrmContext : DataContextBase
    {
        public DbCrmContext() : base("CRMDbConnString") { }

        protected override void OnModelCreating(ModelBuilder modelBuilder)
        {
            base.OnModelCreating(modelBuilder);

            modelBuilder.Entity<CustomerAccount>()
                .ForRelational(b => b.Table("CustomerAccount"))
                .Key(k => k.Identifier);
        }

        public DbSet<CustomerAccount> CustomerAccounts { get; set; }
    }
}

In the part 1, we just create very simple unit tests where we could do this:

[TestMethod]
public void CustomerAccountManager_Save_Succeed()
{
   var custAcct = CustomerAccountManager.Get().FirstOrDefault();
   var custLogic = new CustomerAccountManager(custAcct);
   Assert.IsTrue(custLogic.Save());
}

Instead of calling the “Save” method directly from the “CustomerAccountManager” object instance, I re-write my test case to call the “Save” method from my new “CustomerAccount” object instance.

Like this:

[TestMethod]
public void CustomerAccount_Save_Succeed()
{
   var custAcct = new CustomerAccount
   {
      Name = "Apple Corp",
      Description = "Software and Hardware company",
      CreditLimit = 9000,
      PhoneNumber = "555-555-5555"
   };
   Assert.IsTrue(custAcct.Save());
}

The idea is to keep the ability to do the action from the business object itself, and not have a tight coupling between this business model and the code saving the information into the database.

In fact, I always want to avoid to have the instance method “Save” inside the “CustomerAccount” class.

How I do?

ConcreteModelExtensions

using System;
using System.Linq;
using MyCompany.ConcreteDomain.Models;

namespace MyCompany.ConcreteDomain.Logic.BusinessExtensions
{
    public static class ConcreteModelExtensions
    {
        public static bool Save(this CustomerAccount inst)
        {
            using (var mgr = new CustomerAccountManager(inst))
            {
                return mgr.Save();
            }
        }

        public static bool Delete(this CustomerAccount inst)
        {
            using (var mgr = new CustomerAccountManager(inst))
            {
                return mgr.Delete();
            }
        }
    }
}

Part 2 conclusion

The idea of having an abstraction between data access and business logic seems to be isosteric, in the small project. However, times are changing radically. Projects need to be consume from anywhere outside the standard business sandbox. Cloud computing is not only new buzz words. It’s real needs for every kind of projects. Project needs to have a voice with the external worlds.

If you are facing to use the identical “business logic” for connected/disconnected mobile, web, windows, console and service app. Should we create distinctive code base for each app type?

No, we have to create only one time our “Business” code base and consume it everywhere we need. Because we want to maintain this “Business” logic at only one place.

What’s next?

In the Part 3, I will add another data access source based on Azure Storage Table to archive our CustomerAccount class and retrieve it from there.

Interesting reading & listening:


*NOTE: All code is currently avail via GitHub. It will be updated once I write each part. (https://github.com/lturmel/BusinessFrameworkSample)

How should I design a business framework ? (part 1)

This is “THE” question I’ve asked myself for very long time. Today, I’m answering simply with only two words: “Simplicity” and “Extensibility.”

  • Simplicity: Business framework must be simple to use from your consumer. It’s your business black box, and the consumers don’t need to understand how the works are being done.
  • Extensibility: You must let the possibility to extend for future needs the possibility to change, overrides or implements new functionality. Some day, you will need to reuse some of that functionality for another project or another customer. The base of your “Business framework” will be reused as a “black box” frame set where your put what you need to achieve with a different business context.

I expose this “How to?” article, because we all fall into a project, including these sealed coupling elements:

  • SQL statements wrote inside the UI project (inside the Submit_Click Event handler)
  • UI Thirds parties components were referenced into the business assemblies.
  • Business objects where tight coupling with the database layer.
  • Old WebService soap proxy’s objects were referenced shared between the business layer and ui application.

In most case, those kind of software project are hard to debug and maintains. Sometimes, the project need to be rewrite completely from scratch. Why ? Because It become too hard to understand.

Well, how I do ?

Yes, I’m talking about “Domain-Drive Design”.

Here some very interesting links:

As a concrete example, at your company your have to create an app used to manage Customer Account. Nothing more than a Customer Account.

My first questions will be:

  • Which information I need from the “Customer Account” ?
  • How I will interact with the “Customer Account” ?

At these point, I don’t mind about where the “Customer Account” information is stored and how to renders it to our users. We just need to focus on “business needs”.

The only business needs we have for the moment, regarding the “Customer Account” is:

  • Retrieve (Get the data)
  • Save (push the data somewhere)
  • Delete (erase some data from somewhere)

Here the initial implementation of the business requirements:

MyCompany.Framework.Models.CustomerAccount

using System;

namespace MyCompany.Framework.Models
{
    public sealed class CustomerAccount
    {
        public CustomerAccount()
        {
            CustomerAccountIdentifier = Guid.Empty;
        }

        public Guid CustomerAccountIdentifier { get; set; }
        public string CustomerName { get; set; }
        public string Description { get; set; }
        public string PhoneNumber { get; set; }
        public double CreditLimit { get; set; }
    }
}

MyCompany.Framework.Logic.CustomerAccountManager

using System.Linq;

using MyCompany.Framework.Models;

namespace MyCompany.Framework.Logic
{
    public sealed class CustomerAccountManager
    {
        public CustomerAccountManager(CustomerAccount inst)
        {
            CurrentObject = inst;
        }

        public CustomerAccount CurrentObject { get; private set; }

        public static IQueryable<CustomerAccount> Get()
        {
            CustomerAccount[] elms =
            {
                new CustomerAccount { CustomerName = "Apple Corp", Description = "Fruit vendors", PhoneNumber = "1-514-999-9999", CreditLimit = 1000.50},
                new CustomerAccount { CustomerName = "Microsoft Corp", Description = "Hologram producer", PhoneNumber="1-514-888-8888", CreditLimit = 9999.99},
                new CustomerAccount { CustomerName= "AOL", Description = "Broadband Internet provider", PhoneNumber = "1-514-777-7777", CreditLimit = 50}, 
            };
            return elms.AsQueryable();
        }

        public bool Save()
        {
            // Save the CurrentObject somewhere...
            return true;
        }

        public bool Delete()
        {
            // Delete the CurrentObject somewhere...
            return true;
        }
    }
}

MyCompany.Framework.Logic.UnitTests

using System;
using System.Linq;
using Microsoft.VisualStudio.TestTools.UnitTesting;

using MyCompany.Framework.Logic;
using MyCompany.Framework.Models;

namespace MyCompany.Framework.Logic.UnitTests
{
    [TestClass]
    public class CustomerAccountManagerTests
    {
        [TestMethod]
        public void CustomerAccountManager_Get_All()
        {
            Assert.IsTrue(CustomerAccountManager.Get().Any(x=> true));
        }

        [TestMethod]
        public void CustomerAccountManager_Save_Succeed()
        {
            var custAcct = CustomerAccountManager.Get().FirstOrDefault();
            var custLogic = new CustomerAccountManager(custAcct);
            Assert.IsTrue(custLogic.Save());
        }

        [TestMethod]
        public void CustomerAccountManager_Save_Failed()
        {
            Assert.Inconclusive();
        }

        [TestMethod]
        public void CustomerAccountManager_Delete_Succeed()
        {
            var custAcct = CustomerAccountManager.Get().FirstOrDefault();
            var custLogic = new CustomerAccountManager(custAcct);
            Assert.IsTrue(custLogic.Save());
        }

        [TestMethod]
        public void CustomerAccountManager_Delete_Failed()
        {
            Assert.Inconclusive();
        }
    }
}

At this point, what should I have?

  • A project named “MyCompany.Framework.Models
    • Contains your business object “Customer Account
  • A project named “MyCompany.Framework.Logic
    • Contains your business logic responsible to manage your “Customer Account” entities.
  • A project named “MyCompany.Framework.Logic.UnitTests
    • We are now capable of have a test’s scenario for our “Customer Account” business logic.

Part 1 Conclusion:

The main idea with this very simple “How I should design a business framework?” is about to be able of identify the “Business needs“. Once the “Business need” is identified, we are ready to implement the skeleton of some basic “Business” tests cases. I agree, the “Save, Delete and Retrieve” is common for all kinds of information. However, that’s a start for implements your pattern on how your “Business” framework will be shaped.

What’s next?

In the part 2, we will implement the “DataAccess” layer and figure an abstraction about “where’s the data should go.

*NOTE: All code is currently avail via GitHub. It will be updated once I write each part. (https://github.com/lturmel/BusinessFrameworkSample)

Part One in video:

Using GPS with Xamarin.Forms app on IOS, Android and Windows Phone

*** Update (May 16 @ 1h15AM) ***

Again, I receive a tweet

2015-05-16_01-20-49

The entire implementation can be replace by Geolocator nuget package. This package is pretty simple. It took me 5 minutes to replace my implementation and test it on iOS, Android and Windows phone platform.

You can also have access to the source code via GitHub.

Some awesome plugins are avail on gitHub for Xamarin.Forms.

Original post

My app use geo-localization to get access to mobile device location. Last summer, when I wrote the code of my Xamarin mobile app, I just implemented without any standard way.

I’m currently refactoring the entire code of my app, and I found the needs to isolate how specific features is implemented. The GPS features it one of those. I decide to share my codes. It’s not perfect for the moment, and I suppose others optimizations too, but it works.

Place inside your shared code, that you will use with the “DependencyService”.


using System;

namespace CompanyName.App.Shared
{
	public interface ILocation : IDisposable
	{
            bool IsRunning{ get;}
	    void Start();
	    void Stop();
            void PostSinglePosition(AsyncCallback callbackMethod);
	}
}

iOS


using System;
using System.Net;
using System.Threading.Tasks;
using System.Collections.Generic;

using Foundation;
using UIKit;
using CoreLocation;
using MapKit;

using Xamarin;
using Xamarin.Forms;

[assembly:Dependency(typeof(IOSLocation))]

namespace CompanyName.App.iOS
{
	public sealed class IOSLocation : ILocation
	{
		#region private members

		private CLLocationManager _locMgr;
		private Task _postTask;
                private GeoPoint _lastPosition;

		#endregion

		#region ILocation implementation

        public bool IsRunning{ get; set; }

		public void PostSinglePosition(AsyncCallback callbackMethod){
			var loc = (new CLLocationManager()).Location;
			if (loc == null)
				return;
			var pointToPost = new GeoPoint {
				Latitude = (float)loc.Coordinate.Latitude,
				Longitude = (float)loc.Coordinate.Longitude,
				Altitude = (float)loc.Altitude,
				Speed = (float)loc.Speed
			};
			// TODO: Share your location with anythings your want 
		}

		public void Stop(){
            _locMgr.StopUpdatingLocation();
            IsRunning = false;
        }

		public void Start(){
			try{
                Xamarin.Forms.Device.BeginInvokeOnMainThread(()=>{
                    if(this._locMgr == null){
                        this._locMgr = new CLLocationManager ();
        				_locMgr.RequestAlwaysAuthorization();
        				_locMgr.RequestWhenInUseAuthorization();
                    }
                    _locMgr.AuthorizationChanged += (object sender, CLAuthorizationChangedEventArgs e) => {
					    if(e.Status == CLAuthorizationStatus.AuthorizedAlways || e.Status == CLAuthorizationStatus.AuthorizedWhenInUse){
    						this._locMgr.DistanceFilter = 2;
    						this._locMgr.DesiredAccuracy = 1;

    						nint taskId = UIApplication.SharedApplication.BeginBackgroundTask (() => {});
    						_postTask = new Task (() => {
    							try {
    								this._locMgr.LocationsUpdated += PostNewLocation;
    								UIApplication.SharedApplication.EndBackgroundTask (taskId);
    								_locMgr.DistanceFilter = 2;
    							} catch(Exception ex) {
    								Insights.Report (ex);
    							}
    						});
                            _postTask.Start ();
                            _locMgr.StartUpdatingLocation ();
                            IsRunning = true;
					    }
				    };
                });
            } catch(Exception ex){
                Insights.Report(ex);
			}
		}

		#endregion

		#region IDisposable implementation

		public void Dispose(){
			if(_locMgr != null)
				_locMgr.Dispose();
		}

		#endregion

		#region private methods

		private void PostNewLocation(object sender, CLLocationsUpdatedEventArgs e){
			try {
				CLLocation loc = e.Locations [0];
				MKCoordinateRegion rd = new MKCoordinateRegion ();
				rd.Center.Latitude = loc.Coordinate.Latitude;
				rd.Center.Longitude = loc.Coordinate.Longitude;
				
				GeoPoint pointToPost = new GeoPoint () {
					Latitude = (float)loc.Coordinate.Latitude,
					Longitude = (float)loc.Coordinate.Longitude,
					Altitude = (float)loc.Altitude,
					Speed = (float)loc.Speed
				};
				// TODO: Share your location with anythings your want
			} catch (Exception ex) {
				Insights.Report (ex);
			}
		}

		#endregion
	}
}

Android

AndroidLocationListener.cs


using System;
using System.Linq;
using System.Threading.Tasks;
using System.Collections.Generic;

using Android.App;
using Android.Content;
using Android.Content.PM;
using Android.Runtime;
using Android.Views;
using Android.Widget;
using Android.OS;
using Android.Locations;

using Xamarin;
using Xamarin.Forms;
using Xamarin.Forms.Platform.Android;

namespace CompanyName.App.Android
{
    public class AndroidLocationListener : Java.Lang.Object, ILocationListener
    {
        #region private members

        public LocationManager _locationManager;
        private string _locationProvider;

        #endregion

        #region ILocationListener

        public void InitializeLocationManager()
        {
            _locationManager = (LocationManager)Android.App.Application.Context.GetSystemService(Android.App.Application.LocationService);
            Criteria criteriaForLocationService = new Criteria
                {
                    Accuracy = Accuracy.Fine
                };
            IList<string> acceptableLocationProviders = _locationManager.GetProviders(criteriaForLocationService, true);

            if (acceptableLocationProviders.Any())
                _locationProvider = acceptableLocationProviders.First();
        }

        public void OnLocationChanged(Location location) {
            try {
                System.Diagnostics.Debug.WriteLine("OnLocationChanged");

                var pointToPost = new GeoPoint () {
                    Latitude = (float)location.Latitude,
                    Longitude = (float)location.Longitude,
                    Altitude = (float)location.Altitude,
                    Speed = (float)location.Speed
                };
                // TODO: Share your location with anythings your want
            } catch (Exception ex) {
                Insights.Report (ex);
            }
        }

        public void OnProviderDisabled(string provider) {}

        public void OnProviderEnabled(string provider) {}

        public void OnStatusChanged(string provider, Availability status, Bundle extras) {}

        #endregion
    }
}

AndroidLocation.cs


using System;

using Xamarin;
using Xamarin.Forms;

using CompanyName.App.Shared

[assembly:Dependency(typeof(AndroidLocation))]

namespace CompanyName.App.Android
{
    public sealed class AndroidLocation : ILocation
    {
        #region private members

        private AndroidLocationListener _srv;

        #endregion

        #region ILocation implementation

        public void PostSinglePosition(AsyncCallback callbackMethod){
            // TODO: Share your location with anythings your want
        }

        public void Start(){
            if (_srv == null)
            {
                _srv = new AndroidLocationService();
                _srv.InitializeLocationManager();
            }
            _srv._locationManager.RequestLocationUpdates("gps", 1000, 1, _srv);
            IsRunning = true;
        }

        public void Stop(){
            _srv._locationManager.RemoveUpdates(_srv);
            IsRunning = false;
        }

        public bool IsRunning{ get; set;}

        #endregion

        #region IDispose implementation

        public void Dispose(){ }
    
        #endregion
    }
}

Windows Phone

using System;
using System.Device.Location;
using System.Net;
using System.Threading.Tasks;

using Xamarin;
using Xamarin.Forms;

using CompanyName.App.Shared

[assembly:Dependency(typeof(WpLocation))]

namespace CompanyName.App.WindowsMobile
{
    public sealed class WpLocation : ILocation
    {
        #region private members

        private GeoCoordinateWatcher _locMgr;

        #endregion

        #region ILocation implementation

        public bool IsRunning { get; set; }

        public void PostSinglePosition(AsyncCallback callbackMethod)
        {
            var pos = new GeoCoordinateWatcher(GeoPositionAccuracy.High);
            pos.PositionChanged += async (sender, args) =>
            {
                var pointToPost = new GeoPoint
                {
                    Latitude = (float)pos.Position.Location.Latitude,
                    Longitude = (float)pos.Position.Location.Longitude,
                    Altitude = (float)pos.Position.Location.Altitude,
                    Speed = (float)pos.Position.Location.Speed
                };
                // TODO: Share your location with anythings your want
                pos.Stop();
                pos.Dispose();
            };
            pos.Start();
        }

        public void Start()
        {
            try
            {
                _locMgr = new GeoCoordinateWatcher(GeoPositionAccuracy.High)
                {
                    MovementThreshold = 1,
                };
                _locMgr.PositionChanged += Watcher_PositionChanged;
                _locMgr.Start();
                IsRunning = true;
            }
            catch (Exception ex)
            {
                Insights.Report(ex);
            }
        }

        public void Stop()
        {
            _locMgr?.Stop();
            IsRunning = false;
        }

        #endregion

        #region IDisposable implementation

        public void Dispose()
        {
            _locMgr?.Dispose();
        }

        #endregion

        #region private methods

        private async void Watcher_PositionChanged(object sender, GeoPositionChangedEventArgs<GeoCoordinate> e)
        {
            try
            {
                var pointToPost = new GeoPoint
                {
                    Latitude = (float)e.Position.Location.Latitude,
                    Longitude = (float)e.Position.Location.Longitude,
                    Altitude = (float)e.Position.Location.Altitude,
                    Speed = (float)e.Position.Location.Speed
                };
                // TODO: Share your location with anythings your want
            }
            catch (Exception ex)
            {
                Insights.Report(ex);
            }
        }

        #endregion
    }
}

Android emulator on mac

With Xamarin, by default, we can use the Android emulator. The emulator is the standard emulator ship by Google. Personally, I never like the Google emulator, it’s #sloooowwww.

I’ve also an Android device, we can use it, but in some scenario, we have to test it on different Android versions.

I found interesting to use GenyMotion android emulator. It’s free for personal use. More important: it’s #FAAASSSTTTT and very simple to use.

Here, a short clip on how easy and fast it was to start a Xamarin.Forms application from Xamarin Studio to an new and Empty Android virtual device.

UPDATE (may, 14) / Xamarin Android Player

tweet14may

This night, I receive a tweet from James Montemagno about Xamarin Android Player. In fact, I feel bad, because, I was known it was existing. It was announced last year at the Evolve 2014 events.

So thanks to James to poke me about it.

Here some links about it:

and here… a quick sample from downloading the file to run the Xamarin.Forms android app:

How I did it with Xamarin –> MobileContact ?

I have an app write with Xamarin.Forms, where I need to invite members of my contact list. Nothing too must trivial.

Today, during the diner, I simply take a look on how it’s possible to read the contact list from Windows Phone (8.1) device…

Enough speaking… here how I’ve implement it, with dependency injection.

A great resource about it:

Accessing Native Features via the DependencyService

Inside my Xamarin.Forms app, I’ve create an class Interface named “IMobileContact”

public interface IMobileContact
{
    void AskPermissions();
    List GetLocalPhoneContact();
}

Once the your common class interface is declared, you can implement the usage of these class interface inside you Xamarin.Forms application. On my side, it’s inside a OnAppearing Xamarin.Forms event.

protected override void OnAppearing ()
{
	base.OnAppearing ();
	_contactManager = DependencyService.Get<IMobileContact> ();
	contactGrid.DataSource = _contactManager.GetLocalPhoneContact ().Where (x => !x.Email.ToLower().Equals (WhereIAMContextBase.Instance.CurrentProfile.UserEmail.ToLower ())).OrderBy (x => x.LastName).ThenBy (x => x.FirstName).ToList();
}

And here, how I’ve implemented for each device platform (iOS, Android and Windows Phone)

iOS

[assembly:Dependency(typeof(IOSPhoneContact))]

public class IOSPhoneContact : IMobileContact
{
	#region IPhoneContact Implementation

	public void AskPermissions() {
		NSError err;
		var ab = ABAddressBook.Create (out err);
		var authStatus = ABAddressBook.GetAuthorizationStatus ();
		if (authStatus != ABAuthorizationStatus.Authorized){
			try {
				if(ab != null)
					ab.RequestAccess (delegate(bool granted, NSError error) {
						if (error == null)
							ProcessContactList (ab);
					});
			} catch(Exception ex){
				Insights.Report (ex);
			}
		}
	}

	public List<LocalPhoneContact> GetLocalPhoneContact(){
		var ctnLst = new List<LocalPhoneContact> ();

		NSError err;
		var ab = ABAddressBook.Create (out err);
		var authStatus = ABAddressBook.GetAuthorizationStatus ();

		if (authStatus == ABAuthorizationStatus.Authorized)
			return ProcessContactList (ab);
		else {
			try {
				if(ab != null)
					ab.RequestAccess (delegate(bool granted, NSError error) {
						if (error == null)
							ProcessContactList (ab);
					});
			} catch(Exception ex){
				Insights.Report (ex);
			}
		}
		return ctnLst;
	}
	#endregion
}

Android

[assembly:Xamarin.Forms.Dependency(typeof(AndroidPhoneContact))]

public class AndroidPhoneContact : IMobileContact
{
	public void AskPermissions() { }

	public List<LocalPhoneContact> GetLocalPhoneContact(){
		var ctnLst = new List<LocalPhoneContact> ();

		var uri = ContactsContract.Contacts.ContentUri;
		string[] projection = {
			ContactsContract.Contacts.InterfaceConsts.Id,
			ContactsContract.Contacts.InterfaceConsts.DisplayName,
			ContactsContract.Contacts.InterfaceConsts.PhotoId,
			ContactsContract.Contacts.InterfaceConsts.InVisibleGroup,
		};

		var query = "in_visible_group = 1";
		var loader = new CursorLoader (Application.Context, uri, projection, query, null, null);
		var cursor = (ICursor)loader.LoadInBackground ();
		while(cursor.MoveToNext()) {
			var splitName = cursor.GetString(cursor.GetColumnIndex(projection[1])).Split(' ');
			var firstName = splitName[0];
			string lastName = string.Empty;
			if(splitName.Length >1)
				lastName = splitName[1];

			string email = string.Empty;
			var contactId = cursor.GetString(cursor.GetColumnIndex(projection[0]));
			var cLoader = new CursorLoader (Application.Context, ContactsContract.CommonDataKinds.Email.ContentUri,null, string.Format ("CONTACT_ID={0}", contactId), null, null);
			var cEmails = (ICursor)cLoader.LoadInBackground();

			while(cEmails.MoveToNext()){
				if (!string.IsNullOrEmpty (cEmails.GetString (cEmails.GetColumnIndex ("data1")))) {

					email = cEmails.GetString (cEmails.GetColumnIndex ("data1"));
				}
			}
			cEmails.Close();
			if (!string.IsNullOrEmpty (email)) {
				ctnLst.Add (new LocalPhoneContact {
					FirstName = firstName,
					LastName = lastName,
					Email = email,
					Picture = null
				});
			}
		}
		cursor.Close ();
		return ctnLst;
	}
}

During the time I’ve write this blog post, I’ve just realize how complex my implementation was. In fact, for each distinct mobile platform, the “How” factor is different, and we have to figure this “How to do ?” before writing the abstraction into the concrete implementation.

In another blog post, I will share with you how my abstraction of GPS implementation usable via distinct concrete implementation on each mobile platform.

Which sessions I looked during #Build2015 (post 1 week)

Some interesting #Build2015 sessions was presented. Here which sessions I’ve watched during the last week.

Here the link for the channel9 #build2015 page: https://channel9.msdn.com/Events/Build/2015

Which sessions I looked during #Build2015

Some interesting #Build2015 sessions was presented. Here which sessions I’ve watched during the weekend.

Here the link for the channel9 #build2015 page: https://channel9.msdn.com/Events/Build/2015

Day 1

Day 2