joggs 24 Posted September 25, 2018 Posted September 25, 2018 (edited) 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 September 25, 2018 by joggs
joggs 24 Posted September 26, 2018 Author Posted September 26, 2018 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...
Luke 38954 Posted September 26, 2018 Posted September 26, 2018 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?
joggs 24 Posted September 26, 2018 Author Posted September 26, 2018 (edited) 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 September 26, 2018 by joggs
joggs 24 Posted September 26, 2018 Author Posted September 26, 2018 (edited) 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 September 26, 2018 by joggs
Luke 38954 Posted September 26, 2018 Posted September 26, 2018 Its just storage for the credentials so for example the read and save methods could read and write from a file.
joggs 24 Posted September 26, 2018 Author Posted September 26, 2018 (edited) Ok, I'll give it a shot Edited September 26, 2018 by joggs
joggs 24 Posted September 26, 2018 Author Posted September 26, 2018 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.
joggs 24 Posted September 29, 2018 Author Posted September 29, 2018 (edited) 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 September 29, 2018 by joggs
kingargyle 19 Posted September 30, 2018 Posted September 30, 2018 @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. 1
Recommended Posts
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 accountSign in
Already have an account? Sign in here.
Sign In Now