Dart future with non async function - dart

I am creating a function for firebase phone auth using Dart. There are two functions getCredential and then signIn. When using a try/catch block I am unsure of how this should be coded. Should the non-async function getCredential be outside of the try/catch block or inside?
Should it be coded as:
// Sign in with phone
Future signInWithPhoneNumber(String verificationId, String smsCode) async {
AuthCredential credential = PhoneAuthProvider.getCredential(
verificationId: verificationId,
smsCode: smsCode,
);
try {
AuthResult result = await _auth.signInWithCredential(credential);
FirebaseUser user = result.user;
return user;
} catch (e) {
print(e.toString());
return null;
}
}
Or should it be coded like this?
// Sign in with phone
Future signInWithPhoneNumber(String verificationId, String smsCode) async {
try {
AuthCredential credential = PhoneAuthProvider.getCredential(
verificationId: verificationId,
smsCode: smsCode,
);
AuthResult result = await _auth.signInWithCredential(credential);
FirebaseUser user = result.user;
return user;
} catch (e) {
print(e.toString());
return null;
}
}
If coded as the second option does the try/catch only work with the async function or both. For example, if the getCredential function generated an error would it be caught in the catch block?

Yes the catch will handle anything that throws in your try block, it's not async specific. To confirm this you could write a function that gets called at the beginning of the try for example:
// this is a function that throws
void doSomething(String param) {
if (param == null) {
throw FormatException('param can not be null');
}
}
Future signInWithPhoneNumber(String verificationId, String smsCode) async {
try {
doSomething(null); // this will be caught
AuthCredential credential = PhoneAuthProvider.getCredential(
verificationId: verificationId,
smsCode: smsCode,
);
AuthResult result = await _auth.signInWithCredential(credential);
FirebaseUser user = result.user;
return user;
} catch (e) {
print(e.toString()); // this prints 'FormatException: param can not be null'
return null;
}
}
So async is not related to whether your function will be caught or not so it's better to use the second option.

Related

Flutter: Phone Auth with firebase not working in iOS

I create an app with flutter using phone authentication by firebase, everything went fine with android, but in iOS I did all things in documentation, still get this error :
the phone auth credential was created with an empty verification id.
my code :
verifyPhoneNumner(String phoneNumber) async {
await auth.verifyPhoneNumber(
timeout: const Duration(seconds: 10),
phoneNumber: completeNumber(phoneNumber),
verificationCompleted: (AuthCredential authCredential) {},
verificationFailed: (authException) {},
codeSent: (String id, [int? forceResent]) {},
codeAutoRetrievalTimeout: (id) {
verificationId = id; // save id in provider to use it in veryfy otp
});
}
verifyOtp(String otp) async {
var credential = await auth.signInWithCredential(
PhoneAuthProvider.credential(
verificationId: verificationId, smsCode: otp)); // otp is textform
if (credential.user != null) {
return true;
} else {
return false;
}
}

Why can't catch exceptions with "catchError" in Dart?

Test:
void testAs() async {
try {
String b = await test();
print(b);
} catch (e) {
print("1 await error");
}
test().then((value) => print(value)).catchError(() {
print("2 then error");
});
}
Future<String> test() {
List<String> bb = ["2222"];
return Future.value(bb[1]);
}
1 await error
RangeError (index): Invalid value: Only valid value is 0: 1
Why is it ineffective?
If I want to deal with "future" through "then", how should I catch the exception and not let it throw out.
Thank you friends,the last problem has been solved,the problem can be solved by adding async and await flags to the test() method.
But there is a new problem, Now I use the correct code and find that it can only be printed once.why can't it print "then success",then the program ends
,modify as follows:
void testAs() async {
try {
await test();
print("await success");
} catch (e) {
print("await error");
}
test().then((value) => print("then success")).catchError((e) {
print("then error");
});
}
Future<String> test() async{
List<String> bb = ["2222"];
return await Future.value(bb[0]);
}
print:await success

Dart : Make reusable try catch block for error handling

I have simple function login request to server, in this function i have some error handling .
Example Source Code
try {
final response = await http.post(
'${appConfig.baseApiUrl}/${appConfig.userController}/loginUser',
headers: appConfig.headersApi,
body: {
"username": username,
"password": password,
},
);
final Map<String, dynamic> responseJson = json.decode(response.body);
if (responseJson["status"] == "ok") {
List userList = responseJson['data'];
List<UserModel> result = userList.map((e) => UserModel.fromJson(e)).toList();
return result;
} else {
throw CustomError(responseJson['message']);
}
} on SocketException catch (_) {
return Future.error(ConstText.NO_CONNECTION);
} on TimeoutException catch (_) {
return Future.error(ConstText.TIMEOUT_EXCEPTION);
} on FormatException catch (_) {
return Future.error(ConstText.FORMAT_EXCEPTION);
} catch (e) {
return Future.error(e.toString());
}
}
In above source code, I have 4 Handling error like SocketException,TimeoutException,FormatException and UnknownException. This function work fine, but if i create another function for request server i should repeat the error handling again.
My question is , it's possible to make error handling reusable ? I want something like this.
Example Reusable Try Catch
requestServer(yourRequestServer) async{
try{
return yourRequestServer;
}on SocketException catch (_) {
return Future.error(ConstText.NO_CONNECTION);
} on TimeoutException catch (_) {
return Future.error(ConstText.TIMEOUT_EXCEPTION);
} on FormatException catch (_) {
return Future.error(ConstText.FORMAT_EXCEPTION);
} catch (e) {
return Future.error(e.toString());
}
}
How To Use it
Future<String> testLogin(String username,String password)async{
requestServer({
final response = await http.post(
'${appConfig.baseApiUrl}/${appConfig.userController}/loginUser',
headers: appConfig.headersApi,
body: {
"username": username,
"password": password,
},
);
final Map<String, dynamic> responseJson = json.decode(response.body);
if (responseJson["status"] == "ok") {
List userList = responseJson['data'];
List<UserModel> result = userList.map((e) => UserModel.fromJson(e)).toList();
return result;
} else {
throw CustomError(responseJson['message']);
}
});
}
Or if you have another suggestion , i really appreciate that.
Thank's.
Reusing code is always a matter of figuring out what to keep an what to abstract away.
In your case, you want to reuse the catch clauses.
The thing you are abstracting over is the body of the try clause, which appears to contain some asynchronous code.
Since you are abstracting over code, you'll need to pass in a function. That's the only way to make code into an argument value.
So you'll need something like:
Future<T> requestServer(FutureOr<T> computation()) {
try {
return await computation();
} on SocketException catch (_) {
throw ConstText.NO_CONNECTION;
} on TimeoutException catch (_) {
throw ConstText.TIMEOUT_EXCEPTION;
} on FormatException catch (_) {
throw ConstText.FORMAT_EXCEPTION;
} catch (e) {
throw e.toString();
}
}
You can then use it as:
var result = await requestServer(() {
final response = await http.post(...
...
return result;
...
});
I changed the return Future.error(someString); to throw someString because it's the same thing, and the latter is much more readable. You are throwing strings here, not exception or error objects. That's a bold move, but as long as you are the one to catch them again, it's reasonable. It's not a good API for other people to have to catch.

How to return value on async function in flutter?

This is my code
SharedPreferences sharedPreferences;
token() async {
sharedPreferences = await SharedPreferences.getInstance();
return "Lorem ipsum dolor";
}
When I print, I got this message on debug console
Instance of 'Future<dynamic>'
How I can get string of "lorem ipsum..." ? thank you so much
token() is async which means it returns Future. You can get the value like this:
SharedPreferences sharedPreferences;
Future<String> token() async {
sharedPreferences = await SharedPreferences.getInstance();
return "Lorem ipsum dolor";
}
token().then((value) {
print(value);
});
But there is a better way to use SharedPreferences. Check docs here.
In order to retrieve any value from async function we can look at the following example of returning String value from Async function. This function returns token from firebase as String.
Future<String> getUserToken() async {
if (Platform.isIOS) checkforIosPermission();
await _firebaseMessaging.getToken().then((token) {
return token;
});
}
Fucntion to check for Ios permission
void checkforIosPermission() async{
await _firebaseMessaging.requestNotificationPermissions(
IosNotificationSettings(sound: true, badge: true, alert: true));
await _firebaseMessaging.onIosSettingsRegistered
.listen((IosNotificationSettings settings) {
print("Settings registered: $settings");
});
}
Receiving the return value in function getToken
Future<void> getToken() async {
tokenId = await getUserToken();
}
print("token " + tokenId);
Whenever the function is async you need to use await for its response otherwise Instance of 'Future' will be output

Web API Token Authentication throws exception No authentication handler is configured to handle the scheme: Microsoft.AspNet.Identity.Application

I have implemented Token Authentication for Web API using ASP.Net Core by following the solution mentioned in following post
Token Based Authentication in ASP.NET Core
To implement the authentication logic, I have defined following method
public async Task<bool> AuthenticateUser(string email, string password)
{
UserManager<ApplicationUser> _userManager = HttpContext.ApplicationServices.GetService(typeof(UserManager<ApplicationUser>)) as UserManager<ApplicationUser>;
SignInManager<ApplicationUser> _signInManager = HttpContext.ApplicationServices.GetService(typeof(SignInManager<ApplicationUser>)) as SignInManager<ApplicationUser>;
var result = await _signInManager.PasswordSignInAsync(email, password, isPersistent: false, lockoutOnFailure: false);
if (result.Succeeded)
{
return true;
}
else
{
return false;
}
}
and the Post method with is invoked is
[HttpPost]
public dynamic Post([FromBody] AuthRequest req)
{
string email = req.username;
string password = req.password;
try
{
bool isAuthenticated = false;
//implement the authentication logic over here
isAuthenticated = AuthenticateUser(email, password).Result;
if (isAuthenticated)
{
DateTime? expires = DateTime.UtcNow.AddDays(2);
var token = GetToken(req.username, expires);
return new { authenticated = true, entityId = 1, token = token, tokenExpires = expires };
}
}
catch (Exception ex)
{
return new { authenticated = false, message = "Exception: " + ex.Message, detailedmessage = ex.InnerException};
}
return new { authenticated = false };
}
Now the problem...
The Post executes fine on first call and returns the desired result, however, on second call, it throws following exception
No authentication handler is configured to handle the scheme: Microsoft.AspNet.Identity.Application
On debugging I found that this exception is being thrown when following line is executed
var result = await _signInManager.PasswordSignInAsync(email, password, isPersistent: false, lockoutOnFailure: false);
It works fine when invoked for the first time but throws exception on all subsequent calls.
I've been searching for this issue for the past 2 days and all I find is that in Startup.cs app.UseIdentity(); should be invoked before adding the authentication middleware. It's already happeneing in my code.
Please suggest what am I missing here.
Resolved the issue by changing HttpContext.ApplicationServices.GetService() to HttpContext.RequestServices.GetService() in AuthenticateUser() method. My updated method is
public async Task<bool> AuthenticateUser(string email, string password)
{
UserManager<ApplicationUser> _userManager = HttpContext.RequestServices.GetService(typeof(UserManager<ApplicationUser>)) as UserManager<ApplicationUser>;
SignInManager<ApplicationUser> _signInManager = HttpContext.RequestServices.GetService(typeof(SignInManager<ApplicationUser>)) as SignInManager<ApplicationUser>;
var result = await _signInManager.PasswordSignInAsync(email, password, isPersistent: false, lockoutOnFailure: false);
if (result.Succeeded)
{
return true;
}
else
{
return false;
}
}

Resources