Outlook Contacts API - Paging Results - c#

I'm trying to display ALL the Outlook contacts for a selected account. When an account has a few thousand contacts, the following code only shows the first n contacts. The contactResults object has a MorePagesAvailable property and a GetNextPageAsync() method available, but I clearly do NOT know how to use them. Can someone please enlighten me.
string token = (string)Session["access_token"];
string email = (string)Session["user_email"];
// Since we have the token locally from the Session, just return it here
OutlookServicesClient client = new OutlookServicesClient(new Uri("https://outlook.office.com/api/v2.0"), async () => { return token; });
client.Context.SendingRequest2 += new EventHandler<SendingRequest2EventArgs>((sender, e) => InsertXAnchorMailboxHeader(sender, e, email));
var contactResults = await client.Me.Contacts
.OrderBy(c => c.DisplayName)
.Take(2500)
.Select(c => new DisplayContact(c))
.ExecuteAsync();
foreach (DisplayContact displayContact in contactResults.CurrentPage)
System.Diagnostics.Debug.WriteLine(displayContact);

var contactResults = await client.Me.Contacts
.OrderBy(c => c.DisplayName)
.Select(c => new DisplayContact(c))
.ExecuteAsync();
while (true)
{
foreach (DisplayContact displayContact in contactResults.CurrentPage)
System.Diagnostics.Debug.WriteLine(displayContact);
if (contactResults.MorePagesAvailable)
contactResults = await contactResults.GetNextPageAsync();
else
break;
}

Related

FILEREF_UPGRADE_NEEDED using GetFile function of TLSharp

I'm trying to dowload a file from a conversation in telegram. I`m using TLSharp lib...
Please check my code:
var result = await client.GetContactsAsync();
var user = result.Users
.OfType<TLUser>()
.FirstOrDefault(x => x.Phone == "<phoneNumber>");
var inputPeer = new TLInputPeerUser() { UserId = user.Id };
var res = await client.SendRequestAsync<TLMessages>(new TLRequestGetHistory() { Peer = inputPeer });
var document = res.Messages
.OfType<TLMessage>()
.Where(m => m.Media != null)
.Select(m => m.Media)
.OfType<TLMessageMediaDocument>()
.Select(md => md.Document)
.OfType<TLDocument>()
.First();
var resFile = await client.GetFile(
new TLInputDocumentFileLocation()
{
AccessHash = document.AccessHash,
Id = document.Id,
Version = document.Version
},
(int)Math.Pow(2, Math.Ceiling(Math.Log(document.Size, 2))) * 4);
This code is getting this exception:
FILEREF_UPGRADE_NEEDED
Please, there are any way to get a file from an conversation without get this error?
TLSharp seems no longer maintained. You might want to switch to WTelegramClient which is similar but better.
Then you can use the helper method that simplify the download process:
using (var stream = File.Create(outputFilename))
await client.DownloadFileAsync(document, stream);

EF Core async select InvalidOperationException

The following code
var merchant = await _dbContext.Merchants
.Include(m => m.Users)
.SingleAsync(m => m.MerchantId == id);
var userTasks = merchant.Users.Select(async u =>
{
var roles = await _userManager.GetRolesAsync(u);
return new MerchantUser
{
UserName = u.UserName,
Role = string.Join(",", roles)
};
}).ToList();
var users = await Task.WhenAll(userTasks);
return View(new MerchantViewModel
{
MerchantId = merchant.MerchantId,
MerchantName = merchant.Name,
MerchantUsers = users.ToList()
});
sometimes returns this error:
System.InvalidOperationException: A second operation started on this context before a previous operation completed.
However, this code does not. To my understanding, it's doing the same thing so I don't understand why it's failing.
var merchant = await _dbContext.Merchants
.Include(m => m.Users)
.SingleAsync(m => m.MerchantId == id);
var users = new List<MerchantUser>();
foreach (var user in merchant.Users)
{
var roles = await _userManager.GetRolesAsync(user);
users.Add(new MerchantUser
{
UserName = user.UserName,
Role = string.Join(",", roles)
});
}
return View(new MerchantViewModel
{
MerchantId = merchant.MerchantId,
MerchantName = merchant.Name,
MerchantUsers = users
});
var userTasks = merchant.Users.Select(async u => { … }).ToList();
var users = await Task.WhenAll(userTasks);
This will asynchronously start all those Select tasks at the same time and then wait for them to complete. So this will run multiple things in parallel. Since you are querying the user manager inside, this will not work since the underlying connection does not support parallel queries.
In contrast, your foreach loop will only run one query at a time, awaiting the GetRolesAsync before the next iteration begins. So instead of working in parallel, the roles will be read sequentially for all users.

Getting Azure AD users is taking way to much time! How to reduce the time?

I am getting Azure AD users into a list to be used in a dropdown, but it takes about at least 8/9 seconds to do the call... I know this can probably be reduced... So I will place my code here, hoping that someone can give me a better idea of how to change the code to a better one.
public async Task<List<Microsoft.Graph.User>> getAzureUsers()
{
IConfidentialClientApplication confidentialClientApplication = ConfidentialClientApplicationBuilder
.Create("***")
.WithTenantId("***")
.WithClientSecret("***")
.Build();
ClientCredentialProvider authProvider = new ClientCredentialProvider(confidentialClientApplication);
GraphServiceClient graphClient = new GraphServiceClient(authProvider);
List<Microsoft.Graph.User> utilizadores = new List<Microsoft.Graph.User>();
var user = await graphClient.Users
.Request()
.Select(p => new {
p.DisplayName,
p.UserPrincipalName,
p.Id
})
.GetAsync();
utilizadores.AddRange(user.CurrentPage);
while (user.NextPageRequest != null)
{
user = await user.NextPageRequest.GetAsync();
utilizadores.AddRange(user.CurrentPage);
}
return utilizadores;
}
public async Task<ViewModelColaboradores> GetVM()
{
bool colExist = false;
List<Microsoft.Graph.User> utilizadores = new List<Microsoft.Graph.User>();
List<UserAD> nomes = new List<UserAD>();
utilizadores = await getAzureUsers();
ViewModelColaboradores vm = new ViewModelColaboradores();
foreach (var n in utilizadores)
{
foreach (var col in _context.RH_Colaboradores)
{
if (n.DisplayName == col.Nome)
{
colExist = true;
}
}
if (!colExist)
{
nomes.Add(new UserAD { DisplayName = n.DisplayName, Id = n.Id, Email = n.UserPrincipalName });
}
colExist = false;
}
vm.usersAd = nomes;
return vm;
}
and then I just call GETVM to get the viewmodel with the users inside. Any ideas?
You can use pagination to improve the performance.
You can have a search-based dropdown(non-paginated) or scroll based dropdown (paginated - that fetches new items on scrolling down and fetches scroll up results from cache).
C# sample code:
public async Task<AzureUserDto> GetUsersPage(int pageSize, string skipToken)
{
var filterString = $"startswith(givenName, '{firstName}')";
var queryOptions = new List<QueryOption>
{
new QueryOption("$top", pageSize)
};
if (!string.IsNullOrEmpty(skipToken))
{
queryOptions.Add(new QueryOption("$skiptoken", skipToken));
}
var azureUsers = await GraphServiceClient.Users
.Request(queryOptions)
.Filter(filterString)
.Select(x => new
{
x.Id,
x.DisplayName,
x.GivenName,
x.Surname,
x.UserPrincipalName,
x.AccountEnabled,
x.Identities,
x.BusinessPhones,
x.JobTitle,
x.MobilePhone,
x.OfficeLocation,
x.PreferredLanguage,
x.Mail
})
.GetAsync();
// Get SkipToken, if exists
var skipToken = azureUsers
.NextPageRequest?
.QueryOptions?
.FirstOrDefault(
x => string.Equals("$skiptoken", x.Name, StringComparison.InvariantCultureIgnoreCase))?
.Value;
var azureUserDto = new AzureUserDto
{
// Map the azureUsers to AzureUsersDto or something similar and return
// don't forget to include the SkipToken
};
return azureUsers;
}
For more details on how to implement the latter method, you can visit Paging Microsoft Graph data in your app and Microsoft Graph API: C# / Filtering / Pagination.

TLSharp Send message to a group

//get user dialogs
var dialogs = await client.GetUserDialogsAsync() as TLDialogs;
//find channel by title
var chat = dialogs.Chats
.Where(c => c.GetType() == typeof(TLChat))
.Cast<TLChat>()
.FirstOrDefault(c => c.Title == "zgzxbhsrbhdrbh");
//send message
await client.SendMessageAsync(new TLInputPeerChannel() { ChannelId = chat.Id },
"OUR_MESSAGE");
I`m trying this code, but it returns me InvalidOperationException: CHANNEL_INVALID. Can someone help?
You were quite right.
//Get dialogs
var dialogs = await client.GetUserDialogsAsync();
//get user chats
var chats = ((TeleSharp.TL.Messages.TLDialogsSlice)dialogs).Chats;
//find channel by title
var tlChannel = chats.Where(_ => _.GetType() == typeof(TLChannel))
.Select(_=>(TLChannel)_)
.Where(_=>_.Title.Contains("<Channel-Name>"))
.FirstOrDefault();
//send message
await client.SendMessageAsync(new TLInputPeerChannel()
{ ChannelId = tlChannel.Id, AccessHash =(long)tlChannel.AccessHash },
"OUR_MESSAGE");
There is a difference between sending to a group and sending to a channel
In your code, at the end of it, you called a command to send to a channel, and in the first one, you specified the type as a group. This is the latest exception. You can try this code and, God willing, the problem will be solved.
//get user dialogs
var dialogs = (TLDialogsSlice)await client.GetUserDialogsAsync();
//find channel by title
var chat = dialogs.Chats
.Where(c => c.GetType() == typeof(TLChat))
.Cast<TLChat>()
.FirstOrDefault(c => c.Title == "zgzxbhsrbhdrbh");
//send message
await client.SendMessageAsync(new TLInputPeerChat() { ChatId = chat.Id }, "OUR_MESSAGE");

Test connection with TLSharp

I'm trying to send a message with TLSharp but cant,i dont get errors,it just execute the code and do nothing;
This is my method.
public virtual async Task SendMessageTest()
{
string NumberToSendMessage = "+55199999999";
if (string.IsNullOrWhiteSpace(NumberToSendMessage))
throw new Exception("TESTE");
// this is because the contacts in the address come without the "+" prefix
var normalizedNumber = NumberToSendMessage.StartsWith("+") ?
NumberToSendMessage.Substring(1, NumberToSendMessage.Length - 1) :
NumberToSendMessage;
var client = NewClient();
var tsk = client.ConnectAsync();
await client.ConnectAsync();
var result = await client.GetContactsAsync();
var user = result.users.lists
.OfType<TLUser>()
.FirstOrDefault(x => x.phone == normalizedNumber);
if (user == null)
{
throw new System.Exception("Number was not found in Contacts List of user: " + NumberToSendMessage);
}
await client.SendTypingAsync(new TLInputPeerUser() { user_id = user.id });
Thread.Sleep(3000);
await client.SendMessageAsync(new TLInputPeerUser() { user_id = user.id }, "TEST");
}
This is my code,is says is wait for activation,what should i do?
I'm trying to use this method also,but it doenst return nothing too.
I'm new to TelegramApi,what i'm doing wrong?
await client.ConnectAsync();
You should authorize first! And only after that you can call other methods. Look at the examples here.
In general you should write something like this:
var hash = await client.SendCodeRequestAsync(NotRegisteredNumberToSignUp);
var code = Console.ReadLine(); //Input the code, that was sent to your phone
var loggedInUser = await client.MakeAuthAsync(NotRegisteredNumberToSignUp, hash, code);

Categories

Resources