Jump to content

Xamarin android app. Connection problems


joggs

Recommended Posts

Hi,

I am developing an android app using Xamarin in visual studio.

I am re-using code from my c# windows application that I know is working, but in android I am getting a null object exception that I am not able to trace.

 

Anyone more than me that is using xamarin and android?

 

The code is simple:

  // Developers are encouraged to create their own ILogger implementation
            var logger = new NullLogger();

            // This describes the device capabilities
            var capabilities = new ClientCapabilities();

            // If using the portable class library you'll need to supply your own IDevice implementation.
            var device = new Device
            {
                DeviceName = "MyDeviceName",
                DeviceId = "11"
            };

            // If using the portable class library you'll need to supply your own ICryptographyProvider implementation.
            var cryptoProvider = new CryptographyProvider();

            var client = new ApiClient(logger, "http://192.168.0.100:8096", "My client name", device, "11", cryptoProvider);
            try
            {
                var authResult = new MediaBrowser.Model.Users.AuthenticationResult();
               
                 authResult = await ApiClientHandler.GetApiClient().AuthenticateUserAsync("usernamexxx", "passxxx");

                // Report capabilities after authentication
                await ApiClientHandler.GetApiClient().ReportCapabilities(capabilities);

            }
            catch(Exception e)
            {

                string x = e.ToString();
            }

Singleton to get the api client: (Embyclient derives from api client with a couple of extra methods...

public static EmbyClient GetApiClient()
        {
            if (_apiClient == null)
            {
                var device = new Device
                {
                    DeviceName = "asdf",
                    DeviceId = "My Device Id"
                };
                var logger = new NullLogger();
                // If using the portable class library you'll need to supply your own ICryptographyProvider implementation.
                var cryptoProvider = new CryptographyProvider();
                _apiClient = new EmbyClient(logger, "http://192.168.0.100:8096", "asdf", device, "asdf", cryptoProvider);
            }

            return _apiClient;
        }

exception is thrown on this row:

authResult = await ApiClientHandler.GetApiClient().AuthenticateUserAsync("usernamexxx", "passxxx");

And is working perfectly in my windows app. 

 

 

{System.NullReferenceException: Object reference not set to an instance of an object.
  at Emby.ApiClient.Net.HttpWebRequestFactory.Create (Emby.ApiClient.Net.HttpRequest options) [0x00070] in <adca890d653b4bfd8613ba04b19aa10a>:0 
  at Emby.ApiClient.Net.HttpWebRequestClient+<GetResponse>d__10.MoveNext () [0x0003b] in <adca890d653b4bfd8613ba04b19aa10a>:0 
--- End of stack trace from previous location where exception was thrown ---
  at System.Runtime.CompilerServices.TaskAwaiter.ThrowForNonSuccess (System.Threading.Tasks.Task task) [0x0003e] in <43dbbdc147f2482093d8409abb04c233>:0 
  at System.Runtime.CompilerServices.TaskAwaiter.HandleNonSuccessAndDebuggerNotification (System.Threading.Tasks.Task task) [0x00028] in <43dbbdc147f2482093d8409abb04c233>:0 
  at System.Runtime.CompilerServices.TaskAwaiter.ValidateEnd (System.Threading.Tasks.Task task) [0x00008] in <43dbbdc147f2482093d8409abb04c233>:0 
  at System.Runtime.CompilerServices.ConfiguredTaskAwaitable`1+ConfiguredTaskAwaiter[TResult].GetResult () [0x00000] in <43dbbdc147f2482093d8409abb04c233>:0 
  at Emby.ApiClient.Net.HttpWebRequestClient+<SendAsync>d__13.MoveNext () [0x00073] in <adca890d653b4bfd8613ba04b19aa10a>:0 
--- End of stack trace from previous location where exception was thrown ---
  at System.Runtime.CompilerServices.TaskAwaiter.ThrowForNonSuccess (System.Threading.Tasks.Task task) [0x0003e] in <43dbbdc147f2482093d8409abb04c233>:0 
  at System.Runtime.CompilerServices.TaskAwaiter.HandleNonSuccessAndDebuggerNotification (System.Threading.Tasks.Task task) [0x00028] in <43dbbdc147f2482093d8409abb04c233>:0 
  at System.Runtime.CompilerServices.TaskAwaiter.ValidateEnd (System.Threading.Tasks.Task task) [0x00008] in <43dbbdc147f2482093d8409abb04c233>:0 
  at System.Runtime.CompilerServices.ConfiguredTaskAwaitable`1+ConfiguredTaskAwaiter[TResult].GetResult () [0x00000] in <43dbbdc147f2482093d8409abb04c233>:0 
  at Emby.ApiClient.ApiClient+<SendAsync>d__30.MoveNext () [0x0009d] in <adca890d653b4bfd8613ba04b19aa10a>:0 
--- End of stack trace from previous location where exception was thrown ---
  at System.Runtime.CompilerServices.TaskAwaiter.ThrowForNonSuccess (System.Threading.Tasks.Task task) [0x0003e] in <43dbbdc147f2482093d8409abb04c233>:0 
  at System.Runtime.CompilerServices.TaskAwaiter.HandleNonSuccessAndDebuggerNotification (System.Threading.Tasks.Task task) [0x00028] in <43dbbdc147f2482093d8409abb04c233>:0 
  at System.Runtime.CompilerServices.TaskAwaiter.ValidateEnd (System.Threading.Tasks.Task task) [0x00008] in <43dbbdc147f2482093d8409abb04c233>:0 
  at System.Runtime.CompilerServices.ConfiguredTaskAwaitable`1+ConfiguredTaskAwaiter[TResult].GetResult () [0x00000] in <43dbbdc147f2482093d8409abb04c233>:0 
  at Emby.ApiClient.ApiClient+<PostAsync>d__94`1[T].MoveNext () [0x0010f] in <adca890d653b4bfd8613ba04b19aa10a>:0 
--- End of stack trace from previous location where exception was thrown ---
  at System.Runtime.CompilerServices.TaskAwaiter.ThrowForNonSuccess (System.Threading.Tasks.Task task) [0x0003e] in <43dbbdc147f2482093d8409abb04c233>:0 
  at System.Runtime.CompilerServices.TaskAwaiter.HandleNonSuccessAndDebuggerNotification (System.Threading.Tasks.Task task) [0x00028] in <43dbbdc147f2482093d8409abb04c233>:0 
  at System.Runtime.CompilerServices.TaskAwaiter.ValidateEnd (System.Threading.Tasks.Task task) [0x00008] in <43dbbdc147f2482093d8409abb04c233>:0 
  at System.Runtime.CompilerServices.TaskAwaiter`1[TResult].GetResult () [0x00000] in <43dbbdc147f2482093d8409abb04c233>:0 
  at Emby.ApiClient.ApiClient+<AuthenticateUserAsync>d__89.MoveNext () [0x0012a] in <adca890d653b4bfd8613ba04b19aa10a>:0 
--- End of stack trace from previous location where exception was thrown ---
  at System.Runtime.CompilerServices.TaskAwaiter.ThrowForNonSuccess (System.Threading.Tasks.Task task) [0x0003e] in <43dbbdc147f2482093d8409abb04c233>:0 
  at System.Runtime.CompilerServices.TaskAwaiter.HandleNonSuccessAndDebuggerNotification (System.Threading.Tasks.Task task) [0x00028] in <43dbbdc147f2482093d8409abb04c233>:0 
  at System.Runtime.CompilerServices.TaskAwaiter.ValidateEnd (System.Threading.Tasks.Task task) [0x00008] in <43dbbdc147f2482093d8409abb04c233>:0 
  at System.Runtime.CompilerServices.TaskAwaiter`1[TResult].GetResult () [0x00000] in <43dbbdc147f2482093d8409abb04c233>:0 
  at EmbyManager.Fragments.FragmentSeenShows+<NewMethod>d__7.MoveNext () [0x000b9] in C:\Users\jorge\source\repos\EmbyManager\EmbyManager\Fragments\FragmentSeenShows.cs:145 }

 

Edited by joggs
Link to comment
Share on other sites

I am still tracing the source of the problem

Looks like it is in the method

 public async Task<T> PostAsync<T>(string url, Dictionary<string, string> args, CancellationToken cancellationToken = default(CancellationToken))
            where T : class
 
Will continue search tonight...
Link to comment
Share on other sites

Hmm, unfortunately I'm not quite sure. It's just a .net standard 2.0 library, which xamarin android supports.

 

Are you using the nuget package, or are you embedding the source into your app?

Link to comment
Share on other sites

Nuget.

I've started to import the source so I can debug in a better way, but exceptions gets thrown in stange situations. Async calls in combination with the android emulator could be the cause.

I know it is almost impossible to give an answer based on the vague info, but It could be possible anyone more than me has tried xamarin and stumbled on the same problem.

 

I've only used the apiclient when coding the different emby apps so far. Thinking about manually connect and perform my commands, now when we have the beautiful swagger api. Something you recommend?

Edited by joggs
Link to comment
Share on other sites

I'd like to try connecting using the connectionManager (multi server usage) and see if that works better, but I cannot find a working example how to implement the ICredentialProvider and how to proceed after the code snippet below that is taken from https://github.com/MediaBrowser/Emby.ApiClient

 

  • How implement ICredentialProvider
  • How proceed after the final row in the example where you have the connectionManager object
// Developers are encouraged to create their own ILogger implementation
			var logger = new NullLogger();

			// This describes the device capabilities
			var capabilities = new ClientCapabilities();

			// If using the portable class library you'll need to supply your own IDevice implementation.
			var device = new Device
            {
                DeviceName = "My Device Name",
                DeviceId = "My Device Id"
            };
			
			// Developers will have to implement ICredentialProvider to provide storage for saving server information
			var credentialProvider = new CredentialProvider();

			// If using the portable class library you'll need to supply your own INetworkConnection implementation.
			var networkConnection = new NetworkConnection(logger);

            // If using the portable class library you'll need to supply your own ICryptographyProvider implementation.
			var cryptoProvider = new CryptographyProvider();
			
			// If using the portable class library you'll need to supply your own IServerLocator implementation.
			var serverLocator = new ServerLocator(logger);

            var connectionManager = new ConnectionManager(logger,
                credentialProvider,
                networkConnection,
                serverLocator,
                "My App Name",
				// Application version
                "1.0.0.0",
                device,
                capabilities,
				cryptoProvider,
                ClientWebSocketFactory.CreateWebSocket);    
Edited by joggs
Link to comment
Share on other sites

After var result = await connectionManager.Connect(address, cancellationToken);

It jumps immediately to 

 
switch (result.State)
            {
                case ConnectionState.Unavailable:
 
I get the feeling it does not even try to connect.
The internet connection on the emulator works and I can reach the emby server.
I think I give up for now. 
Link to comment
Share on other sites

As of now you cannot use the ApiClient class if you develop using Xamarin as it contains unsupported methods.

I instead ended up communicating with the rest api directly using the httpclient class.

 

Logging in: 

public async void GetJSON2()
        {
            string requestUri = "http://192.168.0.100:8096/emby/Users/AuthenticateByName"; 
            dynamic dynamicJson = new ExpandoObject();
            dynamicJson.Username = "xxxx";
            dynamicJson.Password = "yyyy";
            dynamicJson.Pw = "yyyy";
                       
            var json = Newtonsoft.Json.JsonConvert.SerializeObject(dynamicJson);
            
            string applicationName = "appname";
            string deviceName = "devicename";
            string deviceId = "deviceId";
            string applicationVersion = "1.0.0";
            
            var httpClient = new System.Net.Http.HttpClient();
            httpClient.DefaultRequestHeaders.Add("Authorization", "Emby Client=\"" + applicationName + "\", Device=\"" + deviceName + "\", DeviceId=\"" + deviceId + "\", Version=\"" + applicationVersion + "\"");
            System.Net.Http.HttpResponseMessage respon = await httpClient.PostAsync(requestUri, new StringContent(json, System.Text.Encoding.UTF8, "application/json"));
            string responJsonText = await respon.Content.ReadAsStringAsync();
        }

I then automatically generate entity classes by pasting the jsonresponse into the excellent quicktype service (https://app.quicktype.io/ or the quicktype plugin in visual studio ). You will automatically get methods that populates these entity classes as well. You will end up with a typed list of objects from the response and you avoid the json response string hassle.

 

A basic example how you return all seen episodes, using the technique above could be like the example below. You get the whole 'Episodes' objects that contains a typed list with 'items' which are the episodes plus alot of other information. Everything auto generated. The FromJson() method you see in the example below is the autogenerated one that does all the magic populating 'itself'.

public static async Task<Episodes> GetWatchedEpisodes()
        {
            Episodes episodes;
            UserSession userSession = await JsonFacade.GetUserSessionAsync();
            
            string requestUri = "http://192.168.0.100:8096/emby/Users/"+ userSession.User.Id + "/Items?Recursive=true&IncludeItemTypes=Episode&sortby=SeriesSortName,SortName&SortOrder=Ascending&filters=IsPlayed";
            string responJsonText;
            var httpClient = new System.Net.Http.HttpClient();
            httpClient.DefaultRequestHeaders.Add("X-Emby-Token",  userSession.AccessToken);
            try
            {
                System.Net.Http.HttpResponseMessage respon = await httpClient.GetAsync(requestUri);
                responJsonText = await respon.Content.ReadAsStringAsync();
                episodes=Episodes.FromJson(responJsonText);

            }
            catch (Exception)
            {

                throw;
            }

            return episodes;
        } 
Edited by joggs
Link to comment
Share on other sites

kingargyle

@joggs  You may be interested in the following Library that may make setting the endpoints up yourself easier for Xamarian.

 

https://github.com/reactiveui/refit

 

I ended up using Retrofit2 for Android for my Kotlin/Java project to provide similar functionality.   The provide Api just didn't fit my needs, and I like the finer control I have by creating the client myself anyways.

  • Like 1
Link to comment
Share on other sites

Create an account or sign in to comment

You need to be a member in order to leave a comment

Create an account

Sign up for a new account in our community. It's easy!

Register a new account

Sign in

Already have an account? Sign in here.

Sign In Now
×
×
  • Create New...