How to retrieve all contacts list in xamarin forms - c#

I tried to use plugin Xamarin.Forms.Contacts and followed the github link,
https://gist.github.com/enisn/25fd0a63a849854fb6103aa681be9963
But, when I compile and debug nothing is shown on screen. I added the plugin to Android and iOS also and setup the required permissions.
In the first line of GetContacts() Debugger dies and does not move to another line.
public ContactList()
{
InitializeComponent();
GetContacs();
}
#pragma warning restore CS4014 // Because this call is not awaited, execution of the current method continues before the call is completed
async Task GetContacs()
{
var contacts = await Plugin.ContactService.CrossContactService.Current.GetContactListAsync();
lstContacts.BindingContext = contacts;
},
I also followed the tutorial on link, https://www.xamboy.com/2019/10/10/getting-phone-contacts-in-xamarin-forms/
In this tutorial, i found issue with the permission function, debugger dies here also, in the if condition to verify permissions.
`public async Task<bool> RequestPermissionAsync()
{
contactPermissionTcs = new TaskCompletionSource<bool>();
// Verify that all required contact permissions have been granted.
if (Android.Support.V4.Content.ContextCompat.CheckSelfPermission(CrossCurrentActivity.Current.Activity, Manifest.Permission.ReadContacts) != (int)Permission.Granted
|| Android.Support.V4.Content.ContextCompat.CheckSelfPermission(CrossCurrentActivity.Current.Activity, Manifest.Permission.WriteContacts) != (int)Permission.Granted)
{
// Contacts permissions have not been granted.
RequestContactsPermissions();
}
else
{
// Contact permissions have been granted.
contactPermissionTcs.TrySetResult(true);
}
return await contactPermissionTcs.Task;
}`
This also did not work.
Is there anyway or suggestion that would make my task easier?

Starting from Xamarin.Essentials 1.6.0-pre5 and latter, the new API GetAllAsync() that has been introduced, allows you to grab all contacts.
Example from Microsoft Documentation
ObservableCollection<Contact> contactsCollect = new ObservableCollection<Contact>();
try
{
// cancellationToken parameter is optional
var cancellationToken = default(CancellationToken);
var contacts = await Contacts.GetAllAsync(cancellationToken);
if (contacts == null)
return;
foreach (var contact in contacts)
contactsCollect.Add(contact);
}
catch (Exception ex)
{
// Handle exception here.
}
It is supported on Android, iOS and UWP, as already mentioned in the question adding the required permissions on each platform is important in order for this API to work, fore details refers to Xamarin.Essentials: Contacts.

Related

How could I check if a user has a role in discord.NET?

I'm trying to find a way to check if a user has X role and performing something if they don't, similar on how it logs it to the console if you use [RequireUserPermission(GuildPermission.Administrator)], just I don't want it to log to the console, EX:
if (has role)
{
// do stuff
} else
{
// do stuff
}
The command I'm trying to implement it into
[Command("clear")]
[RequireUserPermission(GuildPermission.ManageRoles)]
public async Task Clear(int amount)
{
IEnumerable<IMessage> messages = await Context.Channel.GetMessagesAsync(amount + 1).FlattenAsync();
await ((ITextChannel)Context.Channel).DeleteMessagesAsync(messages);
const int delay = 3000;
IUserMessage m = await ReplyAsync($"I have deleted {amount} messages");
await Task.Delay(delay);
await m.DeleteAsync();
Console.Write(amount + " was cleared in a channel");
}
As akac pointed out the precondition you mentioned [RequireUserPermission(...)] checks if any of the roles assigned to a user gives them the permission to do a specific task. Consider the following example. You create a role called "Moderators" and enable the permission "Manage Messages". You then add the precondition [RequireUserPermission(ChannelPermission.ManageMessages)] to your Clear() method. Your Clear() method will now work for anybody in the "Moderators" role because they have permission to manage messages. It will also allow anybody in any other roles with the same permission to use it.
However, if you later decide you don't want "Moderators" to be able to manage messages and remove the permission from that role, your precondition will then automatically stop anyone in that role from using the Clear command.
If you check the users roles instead of their permissions, the users with the "Moderators" role would still be able to use the Clear command to delete messages even though you've removed the permission to manage messages from that role.
If the only reason you want to check the role instead of using the precondition to check their permissions is because you don't want it to log to the console, then this is probably the wrong approach for you. Instead you should consider sticking with the precondition and look at how you're handling the logging to prevent that message from being logged to the console.
If you would still like to check the user's roles, then here is an example of how you could do that in the Clear() method you provided. You will need to add using System.Linq; to the top of the file and replace "RoleName" in the second if statement with the name of the role you want to check.
public async Task Clear(int amount)
{
// Get the user that executed the command cast it to SocketGuildUser
// so we can access the Roles property
if (Context.User is SocketGuildUser user)
{
// Check if the user has the requried role
if (user.Roles.Any(r => r.Name == "RoleName"))
{
IEnumerable<IMessage> messages = await Context.Channel.GetMessagesAsync(amount + 1).FlattenAsync();
await((ITextChannel) Context.Channel).DeleteMessagesAsync(messages);
const int delay = 3000;
IUserMessage m = await ReplyAsync($"I have deleted {amount} messages");
await Task.Delay(delay);
await m.DeleteAsync();
Console.Write(amount + " was cleared in a channel");
}
else
{
await Context.Channel.SendMessageAsync("Sorry, you don't have permission to do that.");
}
}
}
I encountered this issue a couple of days ago, my solution was to create a custom attribute that inherited from Discord.Commands.PreconditionAttribute
I discovered this as I use dotPeek on my Visual Studio install to decompile and read how the command service actually works, as I wanted to know how their attributes worked as well. As part of the command service's execution of the command it checks all preconditions for each command, and only when each are satisfied does it execute the function.
This class has a function called CheckPermissionsAsync
Here is a sample that should work for you:
public class RequiresRoleAttribute : PreconditionAttribute
{
private string m_role;
public RequiresRoleAttribute (string role)
{
m_role = role;
}
public override async Task<PreconditionResult> CheckPermissionsAsync(ICommandContext context, CommandInfo command, IServiceProvider services)
{
if (context.User is SocketGuildUser sgu)
{
if (sgu.Roles.Select(x => x.Name == m_name).Contains(m_name)
{
return PreconditionResult.FromSuccess();
}
}
return PreconditionResult.FromError($"The user doesn't have the role '{m_name}'");
}
}
And the use:
[Command("clear")]
[RequiresRole("RoleName")]
public async Task Clear(int amount)
{
IEnumerable<IMessage> messages = await Context.Channel.GetMessagesAsync(amount + 1).FlattenAsync();
await ((ITextChannel)Context.Channel).DeleteMessagesAsync(messages);
const int delay = 3000;
IUserMessage m = await ReplyAsync($"I have deleted {amount} messages");
await Task.Delay(delay);
await m.DeleteAsync();
Console.Write(amount + " was cleared in a channel");
}
Here is what you do:
You use the RequireRoles attribute.
It has 4 various ways: All, any, specified only, none
Let's say you want to make a ban command, but only want admin and mods to be able to use it. You would do this:
public class Moderation : BaseCommandModule
{
[Command("ban")]
[RequireRoles(RoleCheckMode.Any, "admin", "mod")]
public async Task BanCommand(CommandContext ctx, DiscordMember name, [RemainingText] string reason)
{
}
}
What are you doing here is basically using a precondition to check if any of the user's roles have the ManageRoles permission, the description is confusing.
As far as I know, Discord.net doesn't log such errors, only puts the default error message into the Result of the command, which is then usually sent to the channel as a response. There clearly has to be some place where your code logs such errors.

Easy tables with Xamarin Forms - InvalidOperationException

I am using this tutorial in order to connect a xamarin.forms app with easy tables. I cannot add data to the database in Azure as i get
System.InvalidOperationException
The error message is the following
An insert operation on the item is already in the queue.
The exception happends in the following line of code.
await usersTable.InsertAsync(data);
In order to add a user
var user = new User { Username = "username", Password = "password" };
bool x = await AddUser(user);
AddUser
public async Task<bool> AddUser(User user)
{
try
{
await usersTable.InsertAsync(user);
await SyncUsers();
return true;
}
catch (Exception x)
{
await new MessageDialog(x.Message.ToString()).ShowAsync();
return false;
}
}
SyncUsers()
public async Task SyncUsers()
{
await usersTable.PullAsync("users", usersTable.CreateQuery());
await client.SyncContext.PushAsync();
}
where
IMobileServiceSyncTable<User> usersTable;
MobileServiceClient client = new MobileServiceClient("url");
Initialize
var path = Path.Combine(MobileServiceClient.DefaultDatabasePath, "DBNAME.db");
var store = new MobileServiceSQLiteStore(path);
store.DefineTable<User>();
await client.SyncContext.InitializeAsync(store, new MobileServiceSyncHandler());
usersTable = client.GetSyncTable<User>();
Please check your table. You probably have added the item already. Also, I would suggest that you don't set the Id property for your entity, because you might be inserting a same ID that's already existing in your table. It's probably the reason why the exception is appearing.
Hope it helps!
Some debugging you can do:
1) Turn on diagnostic logging in the backend and debug the backend: https://adrianhall.github.io/develop-mobile-apps-with-csharp-and-azure/chapter8/developing/#debugging-your-cloud-mobile-backend
2) Add a logging delegating handler in your MobileServiceClient setup: https://adrianhall.github.io/develop-mobile-apps-with-csharp-and-azure/chapter3/server/#turning-on-diagnostic-logs
The MobileServicePushFailedException contains an inner exception that contains the actual error. Normally, it is one of the 409/412 HTTP errors, which indicates a conflict. However, it can also be a 404 (which means there is a mismatch between what your client is asking for and the table name in Easy Tables) or 500 (which means the server crashed, in which case the server-side diagnostic logs indicate why).
Easy Tables is just a Node.js service underneath the covers.

C# OneDrive Stop Constantly Asking For Permissions [duplicate]

I have just started working with the OneDrive API and the sample program that comes with it (OneDriveApiBrowser).
As expected, the first time I logged in (using "Sign In to MSA...", I was asked for credentials, my 2-factor code, and finally a permissions screen asking if I approve of the access that the app wants against my OneDrive account.
But, after I exit the program and restart it, I am not logged in. I repeat going to "Sign In to MSA..." and I am no longer prompted for credentials (as I expected), but I am prompted with the permissions screen again.
Is there a way of having the app log back in without always prompting the user for permission?
For learning how to use the OneDrive API, I am just using the sample code that Microsoft supplied as part of the API located at https://github.com/OneDrive/onedrive-sdk-csharp/tree/master/samples/OneDriveApiBrowser. The code can't be downloaded directly from there, but at the root of this project, https://github.com/OneDrive/onedrive-sdk-csharp. This will download the source for the API as well as the sample code and unit tests.
After doing some more poking around, I finally found out how to do this. My explanation here will be in the context of the sample program mentioned in the original question above.
In the program, in the SignIn method, there was some setup being done which included calling OneDriveClient.GetMicrosoftAccountClient(...), then calling the following:
if (!this.oneDriveClient.IsAuthenticated)
{
await this.oneDriveClient.AuthenticateAsync();
}
So, two things needed to be done. We need the save the result from the code above, then save the RefreshToken value somewhere safe... (It's just a very long string).
if (!this.oneDriveClient.IsAuthenticated)
{
AccountSession accountSession = await this.oneDriveClient.AuthenticateAsync();
// Save accountSession.RefreshToken somewhere safe...
}
Finally, I needed to put an if around the OneDriveClient.GetMicrosoftAccountClient(...) call and only call it if the saved refresh token has not been saved yet (or as been deleted due to code added to the logout call...) If we have a saved refresh token, we call `OneDriveClient.GetSilentlyAuthenticatedMicrosoftAccountClient(...) instead. The entire SignIn method looks like this when I am done.
private async Task SignIn(ClientType clientType)
{
string refreshToken = null;
AccountSession accountSession;
// NOT the best place to save this, but will do for an example...
refreshToken = Properties.Settings.Default.RefreshToken;
if (this.oneDriveClient == null)
{
if (string.IsNullOrEmpty(refreshToken))
{
this.oneDriveClient = clientType == ClientType.Consumer
? OneDriveClient.GetMicrosoftAccountClient(
FormBrowser.MsaClientId,
FormBrowser.MsaReturnUrl,
FormBrowser.Scopes,
webAuthenticationUi: new FormsWebAuthenticationUi())
: BusinessClientExtensions.GetActiveDirectoryClient(FormBrowser.AadClientId, FormBrowser.AadReturnUrl);
}
else
{
this.oneDriveClient = await OneDriveClient.GetSilentlyAuthenticatedMicrosoftAccountClient(FormBrowser.MsaClientId,
FormBrowser.MsaReturnUrl,
FormBrowser.Scopes,
refreshToken);
}
}
try
{
if (!this.oneDriveClient.IsAuthenticated)
{
accountSession = await this.oneDriveClient.AuthenticateAsync();
// NOT the best place to save this, but will do for an example...
Properties.Settings.Default.RefreshToken = accountSession.RefreshToken;
Properties.Settings.Default.Save();
}
await LoadFolderFromPath();
UpdateConnectedStateUx(true);
}
catch (OneDriveException exception)
{
// Swallow authentication cancelled exceptions
if (!exception.IsMatch(OneDriveErrorCode.AuthenticationCancelled.ToString()))
{
if (exception.IsMatch(OneDriveErrorCode.AuthenticationFailure.ToString()))
{
MessageBox.Show(
"Authentication failed",
"Authentication failed",
MessageBoxButtons.OK);
var httpProvider = this.oneDriveClient.HttpProvider as HttpProvider;
httpProvider.Dispose();
this.oneDriveClient = null;
}
else
{
PresentOneDriveException(exception);
}
}
}
}
For completeness, I updated the logout code
private async void signOutToolStripMenuItem_Click(object sender, EventArgs e)
{
if (this.oneDriveClient != null)
{
await this.oneDriveClient.SignOutAsync();
((OneDriveClient)this.oneDriveClient).Dispose();
this.oneDriveClient = null;
// NOT the best place to save this, but will do for an example...
Properties.Settings.Default.RefreshToken = null;
Properties.Settings.Default.Save();
}
UpdateConnectedStateUx(false);
}
The wl.offline_access scope is required by applications to save the user consent information and refresh the access token without a UI prompt.
For more details on the scopes that you can use in your application see https://dev.onedrive.com/auth/msa_oauth.htm#authentication-scopes

How do I login to OneDrive (after the initial time) without seeing the permissions screen

I have just started working with the OneDrive API and the sample program that comes with it (OneDriveApiBrowser).
As expected, the first time I logged in (using "Sign In to MSA...", I was asked for credentials, my 2-factor code, and finally a permissions screen asking if I approve of the access that the app wants against my OneDrive account.
But, after I exit the program and restart it, I am not logged in. I repeat going to "Sign In to MSA..." and I am no longer prompted for credentials (as I expected), but I am prompted with the permissions screen again.
Is there a way of having the app log back in without always prompting the user for permission?
For learning how to use the OneDrive API, I am just using the sample code that Microsoft supplied as part of the API located at https://github.com/OneDrive/onedrive-sdk-csharp/tree/master/samples/OneDriveApiBrowser. The code can't be downloaded directly from there, but at the root of this project, https://github.com/OneDrive/onedrive-sdk-csharp. This will download the source for the API as well as the sample code and unit tests.
After doing some more poking around, I finally found out how to do this. My explanation here will be in the context of the sample program mentioned in the original question above.
In the program, in the SignIn method, there was some setup being done which included calling OneDriveClient.GetMicrosoftAccountClient(...), then calling the following:
if (!this.oneDriveClient.IsAuthenticated)
{
await this.oneDriveClient.AuthenticateAsync();
}
So, two things needed to be done. We need the save the result from the code above, then save the RefreshToken value somewhere safe... (It's just a very long string).
if (!this.oneDriveClient.IsAuthenticated)
{
AccountSession accountSession = await this.oneDriveClient.AuthenticateAsync();
// Save accountSession.RefreshToken somewhere safe...
}
Finally, I needed to put an if around the OneDriveClient.GetMicrosoftAccountClient(...) call and only call it if the saved refresh token has not been saved yet (or as been deleted due to code added to the logout call...) If we have a saved refresh token, we call `OneDriveClient.GetSilentlyAuthenticatedMicrosoftAccountClient(...) instead. The entire SignIn method looks like this when I am done.
private async Task SignIn(ClientType clientType)
{
string refreshToken = null;
AccountSession accountSession;
// NOT the best place to save this, but will do for an example...
refreshToken = Properties.Settings.Default.RefreshToken;
if (this.oneDriveClient == null)
{
if (string.IsNullOrEmpty(refreshToken))
{
this.oneDriveClient = clientType == ClientType.Consumer
? OneDriveClient.GetMicrosoftAccountClient(
FormBrowser.MsaClientId,
FormBrowser.MsaReturnUrl,
FormBrowser.Scopes,
webAuthenticationUi: new FormsWebAuthenticationUi())
: BusinessClientExtensions.GetActiveDirectoryClient(FormBrowser.AadClientId, FormBrowser.AadReturnUrl);
}
else
{
this.oneDriveClient = await OneDriveClient.GetSilentlyAuthenticatedMicrosoftAccountClient(FormBrowser.MsaClientId,
FormBrowser.MsaReturnUrl,
FormBrowser.Scopes,
refreshToken);
}
}
try
{
if (!this.oneDriveClient.IsAuthenticated)
{
accountSession = await this.oneDriveClient.AuthenticateAsync();
// NOT the best place to save this, but will do for an example...
Properties.Settings.Default.RefreshToken = accountSession.RefreshToken;
Properties.Settings.Default.Save();
}
await LoadFolderFromPath();
UpdateConnectedStateUx(true);
}
catch (OneDriveException exception)
{
// Swallow authentication cancelled exceptions
if (!exception.IsMatch(OneDriveErrorCode.AuthenticationCancelled.ToString()))
{
if (exception.IsMatch(OneDriveErrorCode.AuthenticationFailure.ToString()))
{
MessageBox.Show(
"Authentication failed",
"Authentication failed",
MessageBoxButtons.OK);
var httpProvider = this.oneDriveClient.HttpProvider as HttpProvider;
httpProvider.Dispose();
this.oneDriveClient = null;
}
else
{
PresentOneDriveException(exception);
}
}
}
}
For completeness, I updated the logout code
private async void signOutToolStripMenuItem_Click(object sender, EventArgs e)
{
if (this.oneDriveClient != null)
{
await this.oneDriveClient.SignOutAsync();
((OneDriveClient)this.oneDriveClient).Dispose();
this.oneDriveClient = null;
// NOT the best place to save this, but will do for an example...
Properties.Settings.Default.RefreshToken = null;
Properties.Settings.Default.Save();
}
UpdateConnectedStateUx(false);
}
The wl.offline_access scope is required by applications to save the user consent information and refresh the access token without a UI prompt.
For more details on the scopes that you can use in your application see https://dev.onedrive.com/auth/msa_oauth.htm#authentication-scopes

WP8.1 Silverlight - Unexpected License info on LicenseChanged

I am trying to detect In-App-Purchases made by a client app.
I am using the following code
public async Task InitializeInAppPurchase()
{
CurrentApp.LicenseInformation.LicenseChanged += LicenseInformation_LicenseChanged;
var listingInformationTask = CurrentApp.LoadListingInformationAsync();
var listingInformation = await listingInformationTask;
PurchaseProduct(listingInformation.ProductListings.First().Value.ProductId);
}
private void LicenseInformation_LicenseChanged()
{
var receipt = CurrentApp.GetAppReceiptAsync().AsTask().Result;
Console.Writeline(receipt);
}
async void PurchaseProduct(string productId)
{
try
{
// Kick off purchase; don't ask for a receipt when it returns
var result = await CurrentApp.RequestProductPurchaseAsync(productId);
// Now that purchase is done, give the user the goods they paid for
// (DoFulfillment is defined later)
await DoFulfillment(result);
}
catch (Exception ex)
{
// When the user does not complete the purchase (e.g. cancels or navigates back from the Purchase Page), an exception with an HRESULT of E_FAIL is expected.
}
}
//
// Fulfillment of consumable in-app products
public async Task DoFulfillment(PurchaseResults result)
{
var productLicenses = CurrentApp.LicenseInformation.ProductLicenses;
// Check fulfillment for consumable products with hard-coded asset counts
await MaybeGiveMeGold(productLicenses["Test1"], 50, result);
}
// Count is passed in as a parameter
async Task MaybeGiveMeGold(ProductLicense license, int goldCount, PurchaseResults result)
{
if (license.IsConsumable && license.IsActive)
{
await CurrentApp.ReportConsumableFulfillmentAsync(license.ProductId, result.TransactionId);
}
}
When the event LicenseChanged is raised, I am surprised to see that the receipt does not include the transaction which just occurred. I get this
<Receipt Version="1.0" ReceiptDate="2015-06-18T04:41:31.867Z" ReceiptDeviceId="4e362949-acc3-fe3a-e71b-89893eb4f528" CertificateId="FB3D3A6455095D2C4A841AA8B8E20661B10A6112" xmlns="http://schemas.microsoft.com/windows/2012/store/receipt">
<AppReceipt Id="8ffa256d-eca8-712a-7cf8-cbf5522df24b" AppId="01e34c43-fdd8-47a6-a8ba-36ad5b880de9" PurchaseDate="2015-06-18T04:41:31.867Z" LicenseType="Full" />
</Receipt>
whereas the receipt should include a element as documented here
I am using the emulator and I am also using a mock server hosted locally in IIS to return my fake ProductListings from here
Can anyone tell me if there is something that I am doing wrong or if this simply what has been designed by Microsoft?
I know that In App Purchases behave differently on emulators, does anyone know if I would have had the expected behavior if I were using a real device?
Thank you
That behavior was normal because the Marketplace mock hosted locally could not return receipts for any transactions.
To test my In-App-Purchases, I had to
Publish my app in beta mode
Create test IAPs at 0.00$
The code above worked perfectly and the LicenseChanged events is raised almost instantaneously depending on network conditions.

Categories

Resources