How to fix SQL Exception happening only in android?

meydanmeydan Member ✭✭

I'm using xamarin forms to develop a cross-platform app. As part of my app, I have a login page where the user enters his credentials and gets authenticated. I'm using entity framework core and I'm connecting to a SQL server which is hosted on Azures cloud. The code works and I can log in successfully, but only with IOS and UWP, if i try with Android I receive this exception:

System.Data.SqlClient.SqlException:
If I continue the debugging I receive another exception which is:

System.Data.SqlClient.SqlException: Snix_PreLogin (provider: SNI_PN6, error: 31 - SNI_ERROR_31) Snix_PreLogin (provider: SNI_PN6, error: 31 - SNI_ERROR_31)
This is my Icommand:

LoginCommand = new Command(async () => await Login());
this is my method inside the view-model:

private async Task Login()
{
    IsBusy = true;
    if (String.IsNullOrWhiteSpace(_emailField) || String.IsNullOrWhiteSpace(_passwordField))
        await App.Current.MainPage.DisplayAlert("Error", "All fields must contain values.", "Ok");
    else
    {
        if (await DatabaseHandler.LoginUser(_emailField, _passwordField))
        {
            App.CurrentAccount = new UserAccount { Email = _emailField, Password = _passwordField };
            App.Current.MainPage = new MainPage();
        }
        else
            await App.Current.MainPage.DisplayAlert("Error", "Email or password are incorrect.", "Ok");
    }
    IsBusy = false;
}

and this is my method inside the DatabaseHandler:

public static async Task<bool> LoginUser(string email, string password)
{
    AzureContext AzureDb = new AzureContext();
    App.CurrentAccount = await AzureDb.UserAccounts.SingleOrDefaultAsync(account => account.Email == email && account.Password == password);
    return (App.CurrentAccount == null) ? false : true;
}

Another thing worth mentioning is that when I comment out the IsBusy lines in the Login method which are responsible for the activity indicator, I no longer get an exception. But, it's still not working, instead of an exception the UI just freezes for a long time and after it unfreezes nothing happens.

Help would be appreciated.

Posts

  • ShantimohanElchuriShantimohanElchuri USMember ✭✭✭✭✭

    @meydan Try using try-catch in the Login() method so that you get better exception message.

  • meydanmeydan Member ✭✭

    I tried that already didn't get any useful information.
    InnerException - System.IO.IOException
    message : Unable to write data to the transport connection: Connection reset by peer.

  • ShantimohanElchuriShantimohanElchuri USMember ✭✭✭✭✭

    @meydan said:
    I tried that already didn't get any useful information.
    InnerException - System.IO.IOException
    message : Unable to write data to the transport connection: Connection reset by peer.

    Then you should talk to Azure Support. Does the sample for SQL Database on Azure works from all platforms?

  • JohnHardmanJohnHardman GBUniversity mod

    @meydan said:
    I tried that already didn't get any useful information.
    InnerException - System.IO.IOException
    message : Unable to write data to the transport connection: Connection reset by peer.

    I'd call that useful information. It leads to the question "Under what circumstances might the host drop the connection?"

  • meydanmeydan Member ✭✭

    @ShantimohanElchuri said:

    @meydan said:
    I tried that already didn't get any useful information.
    InnerException - System.IO.IOException
    message : Unable to write data to the transport connection: Connection reset by peer.

    Then you should talk to Azure Support. Does the sample for SQL Database on Azure works from all platforms?

    The sample I provided here works flawlessly on IOS and UWP, only Android gives me a hard time.

  • meydanmeydan Member ✭✭

    @JohnHardman said:

    @meydan said:
    I tried that already didn't get any useful information.
    InnerException - System.IO.IOException
    message : Unable to write data to the transport connection: Connection reset by peer.

    I'd call that useful information. It leads to the question "Under what circumstances might the host drop the connection?"

    Well, weirdly enough when I comment out the activity indicator I no longer get that exception.
    I thought the host drops the connection because of the connection timeout in the connection string, but I increased it significantly, and also changed MultipleActiveResultSets to true.
    But nothing helps.

  • meydanmeydan Member ✭✭

    After playing a little with exception handling the full exception is:

    {System.Data.SqlClient.SqlException (0x80131904): Snix_PreLogin (provider: SNI_PN6, error: 31 - SNI_ERROR_31)Snix_PreLogin (provider: SNI_PN6, error: 31 - SNI_ERROR_31) ---> System.AggregateException: One or more errors occurred. (Authentication failed, see inner exception.) ---> System.Security.Authentication.AuthenticationException: Authentication failed, see inner exception. ---> System.AggregateException: One or more errors occurred. (Unable to write data to the transport connection: Connection reset by peer.) ---> System.IO.IOException: Unable to write data to the transport connection: Connection reset by peer. ---> System.Net.Sockets.SocketException: Connection reset by peer at System.Net.Sockets.Socket.Send (System.Byte[] buffer, System.Int32 offset, System.Int32 size, System.Net.Sockets.SocketFlags socketFlags) [0x00016] in <634e1667c20e48cfb6aa884228f8db67>:0 at System.Net.Sockets.NetworkStream.Write (System.Byte[] buffer, System.Int32 offset, System.Int32 size) [0x0009b] in <634e1667c20e48cfb6aa884228f8db67>:0 --- End of inner exception stack trace --- at System.Net.Sockets.NetworkStream.Write (System.Byte[] buffer, System.Int32 offset, System.Int32 size) [0x000e2] in <634e1667c20e48cfb6aa884228f8db67>:0 at System.Data.SqlClient.SNI.SslOverTdsStream.WriteInternal (System.Byte[] buffer, System.Int32 offset, System.Int32 count, System.Threading.CancellationToken token, System.Boolean async) [0x0017b] in :0 --- End of inner exception stack trace --- at System.Threading.Tasks.Task.ThrowIfExceptional (System.Boolean includeTaskCanceledExceptions) [0x00011] in <84c6975c2cbc47b489a2a76477d7a312>:0 at System.Threading.Tasks.Task.Wait (System.Int32 millisecondsTimeout, System.Threading.CancellationToken cancellationToken) [0x00043] in <84c6975c2cbc47b489a2a76477d7a312>:0 at System.Threading.Tasks.Task.Wait () [0x00000] in <84c6975c2cbc47b489a2a76477d7a312>:0 at System.Data.SqlClient.SNI.SslOverTdsStream.Write (System.Byte[] buffer, System.Int32 offset, System.Int32 count) [0x0000f] in :0 at Mono.Net.Security.MobileAuthenticatedStream.b__86_0 () [0x00006] in <634e1667c20e48cfb6aa884228f8db67>:0 at System.Threading.Tasks.Task.InnerInvoke () [0x0000f] in <84c6975c2cbc47b489a2a76477d7a312>:0 at System.Threading.Tasks.Task.Execute () [0x00000] in <84c6975c2cbc47b489a2a76477d7a312>:0 --- End of stack trace from previous location where exception was thrown --- at Mono.Net.Security.MobileAuthenticatedStream.InnerWrite (System.Boolean sync, System.Threading.CancellationToken cancellationToken) [0x000d3] in <634e1667c20e48cfb6aa884228f8db67>:0 at Mono.Net.Security.AsyncProtocolRequest.ProcessOperation (System.Threading.CancellationToken cancellationToken) [0x00196] in <634e1667c20e48cfb6aa884228f8db67>:0 at Mono.Net.Security.AsyncProtocolRequest.StartOperation (System.Threading.CancellationToken cancellationToken) [0x0008b] in <634e1667c20e48cfb6aa884228f8db67>:0 --- End of inner exception stack trace --- at Mono.Net.Security.MobileAuthenticatedStream.ProcessAuthentication (System.Boolean runSynchronously, Mono.Net.Security.MonoSslAuthenticationOptions options, System.Threading.CancellationToken cancellationToken) [0x00252] in <634e1667c20e48cfb6aa884228f8db67>:0 --- End of inner exception stack trace --- at System.Threading.Tasks.Task.ThrowIfExceptional (System.Boolean includeTaskCanceledExceptions) [0x00011] in <84c6975c2cbc47b489a2a76477d7a312>:0 at System.Threading.Tasks.Task.Wait (System.Int32 millisecondsTimeout, System.Threading.CancellationToken cancellationToken) [0x00043] in <84c6975c2cbc47b489a2a76477d7a312>:0 at System.Threading.Tasks.Task.Wait () [0x00000] in <84c6975c2cbc47b489a2a76477d7a312>:0 at Mono.Net.Security.MobileAuthenticatedStream.AuthenticateAsClient (System.String targetHost, System.Security.Cryptography.X509Certificates.X509CertificateCollection clientCertificates, System.Security.Authentication.SslProtocols enabledSslProtocols, System.Boolean checkCertificateRevocation) [0x0003d] in <634e1667c20e48cfb6aa884228f8db67>:0 at (wrapper remoting-invoke-with-check) Mono.Net.Security.MobileAuthenticatedStream.AuthenticateAsClient(string,System.Security.Cryptography.X509Certificates.X509CertificateCollection,System.Security.Authentication.SslProtocols,bool) at Mono.Net.Security.MobileAuthenticatedStream.AuthenticateAsClient (System.String targetHost) [0x00007] in <634e1667c20e48cfb6aa884228f8db67>:0 at System.Net.Security.SslStream.AuthenticateAsClient (System.String targetHost) [0x00006] in <634e1667c20e48cfb6aa884228f8db67>:0 at System.Data.SqlClient.SNI.SNITCPHandle.EnableSsl (System.UInt32 options) [0x0000c] in :0 at System.Data.SqlClient.SNI.SNIProxy.EnableSsl (System.Data.SqlClient.SNI.SNIHandle handle, System.UInt32 options) [0x00000] in :0 ---> (Inner Exception #0) System.Security.Authentication.AuthenticationException: Authentication failed, see inner exception. ---> System.AggregateException: One or more errors occurred. (Unable to write data to the transport connection: Connection reset by peer.) ---> System.IO.IOException: Unable to write data to the transport connection: Connection reset by peer. ---> System.Net.Sockets.SocketException: Connection reset by peer at System.Net.Sockets.Socket.Send (System.Byte[] buffer, System.Int32 offset, System.Int32 size, System.Net.Sockets.SocketFlags socketFlags) [0x00016] in <634e1667c20e48cfb6aa884228f8db67>:0 at System.Net.Sockets.NetworkStream.Write (System.Byte[] buffer, System.Int32 offset, System.Int32 size) [0x0009b] in <634e1667c20e48cfb6aa884228f8db67>:0 --- End of inner exception stack trace --- at System.Net.Sockets.NetworkStream.Write (System.Byte[] buffer, System.Int32 offset, System.Int32 size) [0x000e2] in <634e1667c20e48cfb6aa884228f8db67>:0 at System.Data.SqlClient.SNI.SslOverTdsStream.WriteInternal (System.Byte[] buffer, System.Int32 offset, System.Int32 count, System.Threading.CancellationToken token, System.Boolean async) [0x0017b] in :0 --- End of inner exception stack trace --- at System.Threading.Tasks.Task.ThrowIfExceptional (System.Boolean includeTaskCanceledExceptions) [0x00011] in <84c6975c2cbc47b489a2a76477d7a312>:0 at System.Threading.Tasks.Task.Wait (System.Int32 millisecondsTimeout, System.Threading.CancellationToken cancellationToken) [0x00043] in <84c6975c2cbc47b489a2a76477d7a312>:0 at System.Threading.Tasks.Task.Wait () [0x00000] in <84c6975c2cbc47b489a2a76477d7a312>:0 at System.Data.SqlClient.SNI.SslOverTdsStream.Write (System.Byte[] buffer, System.Int32 offset, System.Int32 count) [0x0000f] in :0 at Mono.Net.Security.MobileAuthenticatedStream.b__86_0 () [0x00006] in <634e1667c20e48cfb6aa884228f8db67>:0 at System.Threading.Tasks.Task.InnerInvoke () [0x0000f] in <84c6975c2cbc47b489a2a76477d7a312>:0 at System.Threading.Tasks.Task.Execute () [0x00000] in <84c6975c2cbc47b489a2a76477d7a312>:0 --- End of stack trace from previous location where exception was thrown --- at Mono.Net.Security.MobileAuthenticatedStream.InnerWrite (System.Boolean sync, System.Threading.CancellationToken cancellationToken) [0x000d3] in <634e1667c20e48cfb6aa884228f8db67>:0 at Mono.Net.Security.AsyncProtocolRequest.ProcessOperation (System.Threading.CancellationToken cancellationToken) [0x00196] in <634e1667c20e48cfb6aa884228f8db67>:0 at Mono.Net.Security.AsyncProtocolRequest.StartOperation (System.Threading.CancellationToken cancellationToken) [0x0008b] in <634e1667c20e48cfb6aa884228f8db67>:0 --- End of inner exception stack trace --- at Mono.Net.Security.MobileAuthenticatedStream.ProcessAuthentication (System.Boolean runSynchronously, Mono.Net.Security.MonoSslAuthenticationOptions options, System.Threading.CancellationToken cancellationToken) [0x00252] in <634e1667c20e48cfb6aa884228f8db67>:0 <--- at System.Data.SqlClient.SqlInternalConnectionTds..ctor (System.Data.ProviderBase.DbConnectionPoolIdentity identity, System.Data.SqlClient.SqlConnectionString connectionOptions, System.Data.SqlClient.SqlCredential credential, System.Object providerInfo, System.String newPassword, System.Security.SecureString newSecurePassword, System.Boolean redirectedUserInstance, System.Data.SqlClient.SqlConnectionString userConnectionOptions, System.Data.SqlClient.SessionData reconnectSessionData, System.Boolean applyTransientFaultHandling) [0x00163] in <fb2d0bc6c8f7446eaa3eaa0ac572f8d3>:0 at System.Data.SqlClient.SqlConnectionFactory.CreateConnection (System.Data.Common.DbConnectionOptions options, System.Data.Common.DbConnectionPoolKey poolKey, System.Object poolGroupProviderInfo, System.Data.ProviderBase.DbConnectionPool pool, System.Data.Common.DbConnection owningConnection, System.Data.Common.DbConnectionOptions userOptions) [0x00144] in :0 at System.Data.ProviderBase.DbConnectionFactory.CreatePooledConnection (System.Data.ProviderBase.DbConnectionPool pool, System.Data.Common.DbConnection owningObject, System.Data.Common.DbConnectionOptions options, System.Data.Common.DbConnectionPoolKey poolKey, System.Data.Common.DbConnectionOptions userOptions) [0x0000c] in :0 at System.Data.ProviderBase.DbConnectionPool.CreateObject (System.Data.Common.DbConnection owningObject, System.Data.Common.DbConnectionOptions userOptions, System.Data.ProviderBase.DbConnectionInternal oldConnection) [0x00184] in :0 at System.Data.ProviderBase.DbConnectionPool.UserCreateRequest (System.Data.Common.DbConnection owningObject, System.Data.Common.DbConnectionOptions userOptions, System.Data.ProviderBase.DbConnectionInternal oldConnection) [0x00040] in :0 at System.Data.ProviderBase.DbConnectionPool.TryGetConnection (System.Data.Common.DbConnection owningObject, System.UInt32 waitForMultipleObjectsTimeout, System.Boolean allowCreate, System.Boolean onlyOneCheckConnection, System.Data.Common.DbConnectionOptions userOptions, System.Data.ProviderBase.DbConnectionInternal& connection) [0x000a4] in :0 at System.Data.ProviderBase.DbConnectionPool.WaitForPendingOpen () [0x00092] in :0 --- End of stack trace from previous location where exception was thrown --- at Microsoft.EntityFrameworkCore.Storage.RelationalConnection.OpenDbConnectionAsync (System.Boolean errorsExpected, System.Threading.CancellationToken cancellationToken) [0x000f9] in :0 at Microsoft.EntityFrameworkCore.Storage.RelationalConnection.OpenAsync (System.Threading.CancellationToken cancellationToken, System.Boolean errorsExpected) [0x0009b] in :0 at Microsoft.EntityFrameworkCore.Query.Internal.AsyncQueryingEnumerable1+AsyncEnumerator[T].BufferlessMoveNext (Microsoft.EntityFrameworkCore.DbContext _, System.Boolean buffer, System.Threading.CancellationToken cancellationToken) [0x00098] in <c486d2adb419411a9a11f423095801e5>:0 at Microsoft.EntityFrameworkCore.SqlServer.Storage.Internal.SqlServerExecutionStrategy.ExecuteAsync[TState,TResult] (TState state, System.Func4[T1,T2,T3,TResult] operation, System.Func4[T1,T2,T3,TResult] verifySucceeded, System.Threading.CancellationToken cancellationToken) [0x00089] in <70780d57b1e644f080d08b633fa994bf>:0 at Microsoft.EntityFrameworkCore.Query.Internal.AsyncQueryingEnumerable1+AsyncEnumerator[T].MoveNext (System.Threading.CancellationToken cancellationToken) [0x00135] in :0 at System.Linq.AsyncEnumerable.SingleOrDefault_[TSource] (System.Collections.Generic.IAsyncEnumerable1[T] source, System.Threading.CancellationToken cancellationToken) [0x000d7] in <afef21b57ad6402f8df4c5299ba699e2>:0 at Microsoft.EntityFrameworkCore.Query.Internal.AsyncLinqOperatorProvider+TaskResultAsyncEnumerable1+Enumerator[T].MoveNext (System.Threading.CancellationToken cancellationToken) [0x00075] in :0 at System.Linq.AsyncEnumerable+SelectEnumerableAsyncIterator2[TSource,TResult].MoveNextCore (System.Threading.CancellationToken cancellationToken) [0x000a6] in <afef21b57ad6402f8df4c5299ba699e2>:0 at System.Linq.AsyncEnumerable+AsyncIterator1[TSource].MoveNext (System.Threading.CancellationToken cancellationToken) [0x00101] in :0 at Microsoft.EntityFrameworkCore.Query.Internal.AsyncLinqOperatorProvider+ExceptionInterceptor1+EnumeratorExceptionInterceptor[T].MoveNext (System.Threading.CancellationToken cancellationToken) [0x00143] in <e66a1f96e9734a7fac7cea0901022728>:0 at Microsoft.EntityFrameworkCore.Query.Internal.QueryCompiler.ExecuteSingletonAsyncQuery[TResult] (Microsoft.EntityFrameworkCore.Query.QueryContext queryContext, System.Func2[T,TResult] compiledQuery, Microsoft.EntityFrameworkCore.Diagnostics.IDiagnosticsLogger`1[TLoggerCategory] logger, System.Type contextType) [0x000d6] in :0 at Life_Programmer.Services.DatabaseServices.DatabaseHandler.LoginUser (System.String email, System.String password) [0x00108] in C:\Users\Meydan\source\repos\Life_Programmer\Life_Programmer\Life_Programmer\Services\DatabaseServices\DatabaseHandler.cs:43 ClientConnectionId:7453d528-808d-4249-b0db-ee7d31c86008}

  • JohnHardmanJohnHardman GBUniversity mod

    @JohnHardman said:

    @meydan said:
    I tried that already didn't get any useful information.
    InnerException - System.IO.IOException
    message : Unable to write data to the transport connection: Connection reset by peer.

    I'd call that useful information. It leads to the question "Under what circumstances might the host drop the connection?"

    Authentication failing would be one thing that would result in the host dropping the connection.

    @meydan said:
    After playing a little with exception handling the full exception is:

    {System.Data.SqlClient.SqlException (0x80131904): Snix_PreLogin (provider: SNI_PN6, error: 31 - SNI_ERROR_31)Snix_PreLogin (provider: SNI_PN6, error: 31 - SNI_ERROR_31) ---> System.AggregateException: One or more errors occurred. (Authentication failed, see inner exception.) ---> System.Security.Authentication.AuthenticationException: Authentication failed, see inner exception. --->

    What could cause authentication to fail?

    @ShantimohanElchuri said:

    @meydan said:
    I tried that already didn't get any useful information.
    InnerException - System.IO.IOException
    message : Unable to write data to the transport connection: Connection reset by peer.

    Then you should talk to Azure Support. Does the sample for SQL Database on Azure works from all platforms?

    That's a good question. Worth checking just in case.

    Many people would suggest using REST to talk to Web Services. That would be my first thought if implementing access to a remote database from a mobile app. Maybe that's old school now? But it is a well trodden path that is easy to test and is known to work.

  • meydanmeydan Member ✭✭

    @JohnHardman said:

    @JohnHardman said:

    @meydan said:
    I tried that already didn't get any useful information.
    InnerException - System.IO.IOException
    message : Unable to write data to the transport connection: Connection reset by peer.

    I'd call that useful information. It leads to the question "Under what circumstances might the host drop the connection?"

    Authentication failing would be one thing that would result in the host dropping the connection.

    @meydan said:
    After playing a little with exception handling the full exception is:

    {System.Data.SqlClient.SqlException (0x80131904): Snix_PreLogin (provider: SNI_PN6, error: 31 - SNI_ERROR_31)Snix_PreLogin (provider: SNI_PN6, error: 31 - SNI_ERROR_31) ---> System.AggregateException: One or more errors occurred. (Authentication failed, see inner exception.) ---> System.Security.Authentication.AuthenticationException: Authentication failed, see inner exception. --->

    What could cause authentication to fail?

    @ShantimohanElchuri said:

    @meydan said:
    I tried that already didn't get any useful information.
    InnerException - System.IO.IOException
    message : Unable to write data to the transport connection: Connection reset by peer.

    Then you should talk to Azure Support. Does the sample for SQL Database on Azure works from all platforms?

    That's a good question. Worth checking just in case.

    Many people would suggest using REST to talk to Web Services. That would be my first thought if implementing access to a remote database from a mobile app. Maybe that's old school now? But it is a well trodden path that is easy to test and is known to work.

    I honestly don't know what might cause authentication to fail.
    But, if I handle the exception so the application won't crash, then after the first try it works as expected.
    So the problem occurs only on the first login try, and only with Android.

  • JohnHardmanJohnHardman GBUniversity mod

    @meydan said:
    But, if I handle the exception so the application won't crash, then after the first try it works as expected.
    So the problem occurs only on the first login try, and only with Android.

    Does the sample that @ShantimohanElchuri mentioned exhibit the same pattern of failure on Android? If not, how does the initial interaction with Azure differ in that sample to what your code does?

  • meydanmeydan Member ✭✭
    edited February 16

    @JohnHardman said:

    @meydan said:
    But, if I handle the exception so the application won't crash, then after the first try it works as expected.
    So the problem occurs only on the first login try, and only with Android.

    Does the sample that @ShantimohanElchuri mentioned exhibit the same pattern of failure on Android? If not, how does the initial interaction with Azure differ in that sample to what your code does?

    As i said my example works on IOS and UWP but not on Android
    And its not supposed to be different it's the same code.

  • JohnHardmanJohnHardman GBUniversity mod

    @meydan said:

    @JohnHardman said:

    @meydan said:
    But, if I handle the exception so the application won't crash, then after the first try it works as expected.
    So the problem occurs only on the first login try, and only with Android.

    Does the sample that @ShantimohanElchuri mentioned exhibit the same pattern of failure on Android? If not, how does the initial interaction with Azure differ in that sample to what your code does?

    As i said my example works on IOS and UWP but not on Android
    And its not supposed to be different it's the same code.

    I think you misunderstood what I asked

  • meydanmeydan Member ✭✭

    I changed the way my app communicates with the database and the problem got solved, instead of communicating from my app directly to the database I'm communicating to it through a web API.

  • NMackayNMackay GBInsider, University mod

    @meydan said:
    I changed the way my app communicates with the database and the problem got solved, instead of communicating from my app directly to the database I'm communicating to it through a web API.

    I'm assuming it's a remote database and not one on the device!

  • meydanmeydan Member ✭✭

    @NMackay said:

    @meydan said:
    I changed the way my app communicates with the database and the problem got solved, instead of communicating from my app directly to the database I'm communicating to it through a web API.

    I'm assuming it's a remote database and not one on the device!

    Yes, it's an azure database.

  • NMackayNMackay GBInsider, University mod

    @meydan said:

    @NMackay said:

    @meydan said:
    I changed the way my app communicates with the database and the problem got solved, instead of communicating from my app directly to the database I'm communicating to it through a web API.

    I'm assuming it's a remote database and not one on the device!

    Yes, it's an azure database.

    Restful approach is the best for scalability.

  • JohnHardmanJohnHardman GBUniversity mod
    edited February 20

    @meydan said:
    I changed the way my app communicates with the database and the problem got solved, instead of communicating from my app directly to the database I'm communicating to it through a web API.

    That's the much more common approach, as mentioned at https://forums.xamarin.com/discussion/comment/364867/#Comment_364867

    Doing it that way has many advantages.

  • meydanmeydan Member ✭✭

    @JohnHardman said:

    @meydan said:
    I changed the way my app communicates with the database and the problem got solved, instead of communicating from my app directly to the database I'm communicating to it through a web API.

    That's the much more common approach, as mentioned at https://forums.xamarin.com/discussion/comment/364867/#Comment_364867

    Doing it that way has many advantages.

    Yea after you said that I checked that approach, and found out that it is the best practice :)

Sign In or Register to comment.