0

I am attempting to get the phone service information on a Xamarin project.

When I call var carrierHelper = DependencyService.Get<ICarrierHelper>();, I get a System.NullReferenceException: Object reference is not set to an instance of an object.

ICarrierHelper.cs

using System;
namespace MyProject
{
    public interface ICarrierHelper
    {
        string GetPhoneCarrier();
    }
}

MyProject.Droid/Helpers/CarrierHelper.cs

using MyProject.Droid;
using Android.Content;
using Android.Telephony;
using Xamarin.Forms;

[assembly: Dependency(typeof(CarrierHelper))]
namespace MyProject.Droid
{
    public class CarrierHelper : ICarrierHelper
    {
        public string GetPhoneCarrier()
        {
            Console.WriteLine("****************************** MAIN ACTIVITY " + MainActivity.Current.ToString());

            TelephonyManager mgr = MainActivity.Current.GetSystemService(Context.TelephonyService) as TelephonyManager;

            Console.WriteLine("****************************** TELEPHONY MANAGER " + mgr.ToString());

            return mgr.NetworkOperatorName;

            //return mgr.SimOperatorName;
        }
    }
}

I have breakpoints in the Droid CarrierHelper.cs that never catch. So, I can only assume that the DependencyService can't find my file at all.

UPDATE (Adding more information and console logs.)

MyDevice.cs

using System;
using Plugin.DeviceInfo;
using Xamarin.Forms;

namespace MyProject
{
public class MyDevice
{
    private static MyDevice current;
    public static MyDevice Current
    {
        get
        {
            if (current == null)
                current = new MyDevice();

            return current;
        }
    }

    public string platform { get; set; }
    public string manufacturer { get; set; }
    public string model { get; set; }
    public string name { get; set; }
    public string os_version { get; set; }
    public string carrier { get; set; }
    public string app_version { get; set; }
    public string app_build { get; set; }

    public MyDevice()
    {
        switch (Device.RuntimePlatform)
        {
            case Device.iOS:
                platform = "iOS";
                break;
            case Device.Android:
                platform = "Android";
                break;
            default:
                platform = "UNKNOWN";
                break;
        }

        manufacturer = CrossDeviceInfo.Current.Manufacturer;
        model = CrossDeviceInfo.Current.Model;
        name = CrossDeviceInfo.Current.DeviceName;
        os_version = CrossDeviceInfo.Current.Version;
        app_version = CrossDeviceInfo.Current.AppVersion;
        app_build = CrossDeviceInfo.Current.AppBuild;

        var carrierHelper = DependencyService.Get<ICarrierHelper>();

        Console.WriteLine("----- CARRIER HELPER " + carrierHelper);

        carrier = DependencyService.Get<ICarrierHelper>().GetPhoneCarrier();

        Console.WriteLine("----- CARRIER: " + carrier);
    }
}
}

The following Console logs print:

----- CARRIER HELPER MyProject.Droid.CarrierHelper

UPDATE (Adding stack trace and info.)

Here is the stack trace:

at MyProject.Droid.CarrierHelper.GetPhoneCarrier () [0x00001] in /MyProject/Helpers/CarrierHelper.cs:14 at MyProject.MyDevice..ctor () [0x000d2] in /MyProject.Core/Models/MyDevice.cs:57 at MyProject.MyDevice.get_Current () [0x0000d] in /MyProject.Core/Models/MyDevice.cs:15 at MyProject.UserDataStore+d__16.MoveNext () [0x00057] in /MyProject.Core/Services/UserDataStore.cs:197

UserDataStore.cs

public async Task UpdateLocation(double lat, double lng)
    {
        try
        {
            if (!CrossConnectivity.Current.IsConnected)
                throw new Exception("Not currently connected to the internet.");

            var model = new
            {
                access_token = $"{Settings.AuthToken}",
                latitude = lat,
                longitude = lng,
                device = MyDevice.Current,
                format = "json"
            };

            var json = JsonConvert.SerializeObject(model);

            var location_content = new StringContent(json, System.Text.Encoding.UTF8, "application/json");

            var response = await client.PostAsync(users_url + location_url, location_content);

            if (!response.IsSuccessStatusCode)
                throw new Exception(response.StatusCode.ToString() + " " + response.ReasonPhrase);
        }
        catch (Exception e)
        {
            Console.WriteLine("ERROR: " + e.Message); // this is where the stack trace is generated

            await LocationDatabase.Connection.SaveLocationAsync(new Location(lat, lng));

            await AppEventDatabase.Connection.SaveEventAsync(new AppEvent("location", e.Message, lat, lng));
        }
    }

This is the error message from the file above:

ERROR: Object reference not set to an instance of an object.

Edie W.
  • 667
  • 2
  • 9
  • 24
  • There can be several reasons the breakpoint doesn't hit, so ignore that. Check the stack trace in the exception to find out which line the exception is coming from. Once you know that, you should be able to work out the problem. My guess would be that `MainActivity.Current` is null, or that the method on it returns null, or that the constructor for the `Current` instance throws the exception. Each of those guesses would lead to an exception on a different line. – Richardissimo Jun 26 '18 at 05:39
  • from where you are calling var carrierHelper = DependencyService.Get(); try to delete obj and bin folder, close project and open again, Rebuild I hope it will work. – Harsh Chaurasia Jun 26 '18 at 05:40
  • You can try DependencyService.Get().GetPhoneCarrier(); – MShah Jun 26 '18 at 05:49
  • @MShah I have tried using DependencyService.Get().GetPhoneCarrier(); with the same results. – Edie W. Jun 26 '18 at 14:11
  • @HarshChaurasia deleting the obj and bin folders and rebuilding didn't help. :( – Edie W. Jun 26 '18 at 14:19
  • @Richardissimo I added the stack trace and some console logs for you. – Edie W. Jun 26 '18 at 14:51
  • Your stack trace points to line 14 in CarrierHelper.cs which is `TelephonyManager mgr = MainActivity.Current.GetSystemService(Context.TelephonyService) as TelephonyManager`, seems like the `CarrierHelper` is found by the dependency service but either `MainActivity.Current`, `Context` or `Context.TelephonyService` is null. – JSteward Jun 26 '18 at 20:03
  • Possible duplicate of [What is a NullReferenceException, and how do I fix it?](https://stackoverflow.com/questions/4660142/what-is-a-nullreferenceexception-and-how-do-i-fix-it) – JSteward Jun 26 '18 at 20:09

1 Answers1

0

You have a catch-22 situation. GetPhoneCarrier() requires MyDevice.Current which is implemented via a lazy-loaded constructor for MyDevice. That constructor resolves ICarrierHelper and calls GetPhoneCarrier(), which requires MyDevice.Current...

I'm assuming that the resolution works out that it has already tried resolving that, and it hasn't completed, so it returns null.

I would suggest that you do less in the MyDevice constructor. Avoid resolving that dependency until you actually need it. That way, the constructor can complete, avoiding the catch-22.

Also beware that your approach to lazy loading isn't thread safe. Consider using Lazy<T> which nicely encapsulates double-checked thread-safe locking.

Richardissimo
  • 5,596
  • 2
  • 18
  • 36