.NET MAUI Setting an item SelectedIndex on Page Load is Delayed - checkbox

When the view appears on the screen there is a short delay setting the values to each control. Is it possible to set the values before the user sees the view?
public UserSettingsView()
{
InitializeComponent();
LoadAsync();
}
private async void LoadAsync()
{
try
{
// Loading data from API
Languages = await _languageService.GetAsync(AccessToken);
USStates = await _uSStateService.GetAsync(AccessToken);
// Assigning the list to the ItemSource of each Picker.
ddlLanguages.ItemsSource = Languages;
ddlUSStates.ItemsSource = USStates;
// Getting the user's preferred settings
var userSettings = await _accountService.GetSettingsAsync(UserID, AccessToken);
if (userSettings != null)
{
// Setting user values to each Picker control.
// This is where the delay happens.
ddlLanguages.SelectedIndex = Languages.FindIndex(x => x.ID == userSettings .LanguageID);
ddlUSStates.SelectedIndex = USStates.FindIndex(x => x.ID == userSettings .USStateID);
cbAge.IsChecked = currentSettings.AgeQualified;
}
}
catch
{
await DisplayAlert("Oh no!", "Error loading the page", "OK");
}
}

To resolve the delay, I am passing the two lists for the languages and the States from the previous page.
public UserSettingsView(List<Language> _languages, List<USState> _usStates)
{
InitializeComponent();
Languages = _languages;
USStates = _usStates;
LoadAsync();
}
private async void LoadAsync()
{
try
{
ddlLanguages.ItemsSource = Languages;
ddlUSStates.ItemsSource = USStates;
var currentSettings = await _accountService.GetSettingsAsync(UserID, AccessToken);
if (currentSettings != null)
{
ddlLanguages.SelectedIndex = Languages.FindIndex(x => x.ID == currentSettings.LanguageID);
ddlUSStates.SelectedIndex = USStates.FindIndex(x => x.ID == currentSettings.USStateID);
switchAgeQualification.IsToggled = currentSettings.AgeQualified;
}
}
catch
{
await DisplayAlert("Error", "Could not load page data", "OK");
}
}

If I understand correctly, you currently have a line like this:
await Navigation.PushModalAsync(new UserSettingsView());
I don't see the types of the properties involved, but the basic idea is to do all the slow awaits BEFORE doing new UserSettingsView....
Something like this:
public class UserSettingsData
{
SomeType1 Languages;
SomeType2 USStates;
SomeType3 UserSettings;
}
...
// Slow await calls.
var data = await UserSettingsView.PrepAsync(UserId, AccessToken);
// Now create and display the view.
await Navigation.PushModalAsync(new UserSettingsView(data));
...
public static async UserSettingsData PrepAsync(SomeType4 UserId, SomeType5 AccessToken)
{
var data = new UserSettingsData();
data.Languages = await _accountService.GetSettingsAsync(...);
data.USStates = await ...;
data.UserSettings = await ...;
}
public UserSettingsView(UserSettingsData data)
{
...
// NOT AN ASYNC METHOD, so happens immediately, before page is shown.
Load(data);
}
// NOT AN ASYNC METHOD, so happens immediately.
private void Load(UserSettingsData data)
{
Languages = data.Languages;
USStates = data.USStates;
var userSettings = data.UserSettings;
...
// if still need DisplayAlert
Dispatcher.InvokeOnMainThread(async () =>
await DisplayAlert...
);
}
Replace "SomeType" etc with your actual types.

Related

EF Core LogIn Taking a Long Time

I'm trying to make an endpoint for logging in with a token in ASP.NET Core. The API is using EFCore, but my code is taking a long time to log me in.
This is the service:
public async Task<AuthModel> GetTokenAsync(UserLoginDto model)
{
var authModel = new AuthModel();
var user = await _userManager.FindByEmailAsync(model.Email);
if (user is null || !await _userManager.CheckPasswordAsync(user, model.Password))
{
authModel.Message = "Email or Password is incorrect!";
return authModel;
}
var jwtSecurityToken = await CreateJwtToken(user);
var rolesList = await _userManager.GetRolesAsync(user);
authModel.IsAuthenticated = true;
authModel.Token = new JwtSecurityTokenHandler().WriteToken(jwtSecurityToken);
authModel.Email = user.Email;
authModel.Username = user.UserName;
//authModel.ExpiresOn = jwtSecurityToken.ValidTo;
authModel.Roles = rolesList.ToList();
if (user.RefreshTokens.Any(t => t.IsActive))
{
var activeRefreshToken = user.RefreshTokens.FirstOrDefault(t => t.IsActive);
authModel.RefreshToken = activeRefreshToken.Token;
authModel.RefreshTokenExpiration = activeRefreshToken.ExpiresOn;
}
else
{
var refreshToken = GetRefreshToken();
authModel.RefreshToken = refreshToken.Token;
authModel.RefreshTokenExpiration = refreshToken.ExpiresOn;
user.RefreshTokens.Add(refreshToken);
await _userManager.UpdateAsync(user);
}
return authModel;
}
Endpoint:
[HttpPost]
public async Task<ActionResult> Login([FromBody]UserLoginDto loginDto)
{
if (!ModelState.IsValid)
return BadRequest(ModelState);
var result = await _authService.GetTokenAsync(loginDto);
if (!string.IsNullOrEmpty(result.RefreshToken))
{
_authService.SetRefreshTokenInCookie(result.RefreshToken, result.RefreshTokenExpiration);
}
return Ok(result);
}

How can I update a data with SQFLite in Flutter?

static Future<int?> update(
String cariadi,
) async {
var dbClient = await _db;
return await dbClient?.rawUpdate('UPDATE $_tableName SET $cariadi = ');
}
This is how I created the database
void getCari() async {
List<Map<String, dynamic>> cariler = await DBCari.query();
cariList.assignAll(cariler.map((data) => Cari.fromJson(data)).toList());
}
void updateData(Cari cari) {
DBCari.update(cari.cariadi!);
getCari();
}
Try to connect value = key by creating a controller named CariController.
final _cariController = Get.put(CariController());
onTap: () {
_cariController.update();
},
Finally, I wanted to enable the user to edit the data entered by clicking on the edit part in a button I wanted. But nothing happened when the button was clicked.
What kind of code do I need to write in the database, controller and homepage I created so that the user can edit and update the data entered?
here is a reference :
Future<int> update(Map<String, dynamic> row) async {
Database db = await instance.database;
int id = row[columnId];
return await db.update(table, row, where: '$columnId = ?', whereArgs: [id]);
}
https://github.com/DaymaManish/flutter_sqflite_crud/blob/main/lib/db_manager.dart

How to test an Attribute in Hot Chocolate

Using Hot Chocolate, how do I integration test the implementation of a ObjectFieldDescriptorAttribute?
Given the following implementation:
public class ValidApiKeyAttribute : ObjectFieldDescriptorAttribute
{
public override void OnConfigure(IDescriptorContext descriptorContext, IObjectFieldDescriptor descriptor, MemberInfo member)
{
descriptor
.Use(next => async context =>
{
var httpContextAccessor = context.Services.GetService(typeof(IHttpContextAccessor))
as IHttpContextAccessor;
var authenticationSettings = context.Services.GetService(typeof(IOptions<AuthenticationSettings>))
as IOptions<AuthenticationSettings>;
// --
await next(context);
});
}
}
Which is called from a Query class
public class Query
{
[ValidApiKey]
public IQueryable<Something> GetSomething()
{
// --
}
}
How do I unit test the middleware? I assume I need to mock the FieldDelegate and the IObjectFieldDescriptor? This is what I've got so far:
[Fact]
public async Task Query_GetSomething_Success()
{
// arrange
var request = QueryRequestBuilder.New()
.SetQuery("")
.Create();
//? var fieldDelegate = new FieldDelegate(async (context) => await Task.CompletedTask);
var executor = await new ServiceCollection()
.AddGraphQL()
.AddType<Query>()
.BuildRequestExecutorAsync();
// act and assert
var result = await executor.ExecuteAsync(request);
}

System.Threading.Timer: A second operation was started on this context with

I have Console Application on .NET 5 which is Discord Bot.
While start the application i have the problem with this:
System.InvalidOperationException: A second operation was started on
this context before a previous operation completed. This is usually
caused by different threads concurrently using the same instance of
DbContext. For more information on how to avoid threading issues with
DbContext
And this is happens in Timer
This is in constructor:
_approveTimer = new Timer(async delegate
{
await CheckApproveAsync();
}, null, TimeSpan.Zero,
TimeSpan.FromSeconds(30));
public async Task CheckApproveAsync()
{
var pendingUsers = await _pendingUsers.GetAllAsync();
if (pendingUsers is null || !pendingUsers.Any())
return;
Program.Log.Debug($"Checking {pendingUsers.Count} pending users...");
foreach (var user in pendingUsers)
{
var expired = DateTime.UtcNow > user.ExpirationTime;
if (!expired) continue;
await _pendingUsers.DeleteWithDetachAsync(user);
IonicHelper.GetGuildUserById(_mainGuildId, user.UserId, out var sgUser);
try
{
var msg = await _messageService.GetMessageAsync("register-pending-expired", new FormatData(user.UserId));
await sgUser.SendIonicMessageAsync(msg);
}
catch (Exception ex)
{
await _serverHelper.SendLogAsync(_mainGuildId, "Error", $"{nameof(CheckApproveAsync)} - {ex.Message}");
}
}
var usersValidated = 0;
foreach (var user in pendingUsers)
{
RequestResult codeResult;
string code;
try
{
(codeResult, code) = await GetThirdPartyCodeByEncryptedSummonerIdAsync(user.Region, user.SummonerId);
}
catch (Exception)
{
continue;
}
if (code is null || codeResult != RequestResult.Success)
continue;
var sanitizedCode = new string(code.Where(char.IsLetterOrDigit).ToArray());
if (sanitizedCode != user.ConfirmationCode)
continue;
var (requestResult, summoner) = await GetSummonerByEncryptedPuuIdAsync(user.Region, user.PlayerUUID);
if (requestResult != RequestResult.Success)
{
await _pendingUsers.DeleteWithDetachAsync(user);
continue;
}
var (rankResult, rankData) = await GetLeaguePositionsByEncryptedSummonerIdAsync(user.Region, summoner.Id);
var soloqRank = GetRankModelFromEntry(rankData.FirstOrDefault(x => x.QueueType == "RANKED_SOLO_5x5"));
var summonerIcon = GetSummonerIconUrlById(summoner.ProfileIconId);
var lolData = new LeagueData
{
UserId = user.UserId,
SummonerRegion = user.Region,
PlayerUUID = summoner.Puuid,
AccountId = summoner.AccountId,
SummonerId = summoner.Id,
SummonerName = summoner.Name,
SummonerIcon = summonerIcon,
SummonerLevel = summoner.SummonerLevel,
SummonerRank = $"{soloqRank.Tier} {soloqRank.Rank}"
};
_ = IonicHelper.GetGuildUserById(_mainGuildId, user.UserId, out var sgUser);
await AssignRoleFromRankAsync(sgUser, soloqRank.Tier);
var data = await _leagueRepository.GetByIdAsync(user.UserId);
if (data == null)
{
await _leagueRepository.AddAsync(lolData);
}
usersValidated++;
user.SummonerName = lolData.SummonerName;
await PostValidateAsync(user);
}
Program.Log.Information($"{usersValidated} users validated.");
}
I read that it can be problem that if some method is not awaited, but i've checked it's all awaited. Which suggestions about this?

silverlight, using Observables on WCF calls, casting IEvent<T> where T : AsyncCompletedEventArgs

i have a question using Observables in Silverlight 4 to make WCF calls.
Consider the simple webservice call below.
var adminclient = ServiceProxy.WithFactory<AuthenticationClient>();
var results= Observable.FromEvent<AuthorizeAdministratorCompletedEventArgs>(
s => adminclient.AuthorizeAdministratorCompleted += s,
s => adminclient.AuthorizeAdministratorCompleted -= s).ObserveOnDispatcher();
adminclient.AuthorizeAdministratorAsync();
results.Subscribe(e =>
{
//Enable UI Button
});
i have implemented an extension method, that wraps the subscribe method, it does some error validation on the return.
On the return results.Subscribe(e =>
e is System.Collections.Generic.Event<AuthorizeAdministratorCompletedEventArgs>
almost every query will have a different return type such as:
e is System.Collections.Generic.Event<AsyncCompletedEventArgs>
if i had a wrapper that looked something like this, how can i cast every type of xxxCompletedEventArgs to its base type AsyncCompletedEventArgs so that i can access e.EventArgs and inspect the Error property
public static IDisposable Subscribe<TSource>(this IObservable<TSource> source, Action<TSource> onNext = null, Action onError = null, Action onFinal = null)
{
Action<TSource> onNextWrapper = (s) =>
{
var args = (System.Collections.Generic.IEvent<AsyncCompletedEventArgs>)s;
try
{
if (WCFExceptionHandler.HandleError(args.EventArgs))
{
if (onNext != null)
onNext(s);
}
else
{
if (onError != null)
onError();
}
}
finally
{
if (onFinal != null)
onFinal();
}
};
return source.Subscribe<TSource>(onNextWrapper, (e) => { throw e; });
}
The code above will fail
Unable to cast object of type 'System.Collections.Generic.Event1[MyProject.Provider.AuthorizeAdministratorCompletedEventArgs]' to type 'System.Collections.Generic.IEvent1[System.ComponentModel.AsyncCompletedEventArgs]'
This is the method definition of WCFExceptionHandler.HandleError(args.EventArgs))
public static bool HandleError(AsyncCompletedEventArgs e)
I'd probably change you extension method so that it acts to handle the the events as a non blocking operator (much the same as the majority of the Rx extension method operators). Something like:
public static IObservable<IEvent<TEventArgs>> GetHandledEvents<TEventArgs>(this IObservable<IEvent<TEventArgs>> source)
where TEventArgs : AsyncCompletedEventArgs
{
return Observable.CreateWithDisposable<IEvent<TEventArgs>>(observer =>
{
return source.Subscribe(evt =>
{
try
{
if (WCFExceptionHandler.HandleError(evt.EventArgs))
{
observer.OnNext(evt);
}
else
{
observer.OnError(new Exception("Some Exception"));
}
}
finally
{
observer.OnError(new Exception("Some Other Exception"));
}
},
observer.OnError,
observer.OnCompleted);
});
}
Then call it through:
results.GetHandledEvents()
.Finally(() => DoSomethingFinally())
.Subscribe(e =>
{
//Enable UI Button
},
ex => HandleException(ex),
() => HandleComplete());
I think this should solve your issues as the events will funnel through as their original type and it ensures that HandleError gets event args that are the correct type.

Resources