Facebook api call - mutual friends - loop - c#

I have this code which makes a call to Facebook API in order to get the mutual friends on the application for two given users. The parameter nextPage corresponds to facebook api's next page.
Problem is that although I have a limited number of common friends each time, I get errors from Facebook api, for having too many calls per second (about 5 milion/day overall). I tried mocking the call to facebook, to always return null, but that resulted in a CPU overloading due to w3p, with 99% usage. What am I missing?
public async Task<MutualFriendsModel> GetMutualFriends(Guid currentUserGuid,
Guid visitedUserGuid, string nextPage)
{
var currentUser = Get(currentUserGuid);
var visitedUser = _serviceUserLogin.GetByUserId(visitedUserGuid);
var mutualFriends = new MutualFriendsModel();
var hasNextPage = true;
while (hasNextPage && mutualFriends.Users.Count < 25)
{
var facebookResult = await
_facebookApi.GetMutualFriendsFacebookRequest(currentUser.Token,
visitedUser.ProviderKey, nextPage);
if (facebookResult == null) break;
mutualFriends.Update(facebookResult, this, _serviceUserLogin);
nextPage = mutualFriends.NextPageUrl;
hasNextPage = !string.IsNullOrEmpty(mutualFriends.NextPageUrl);
}
return mutualFriends;
}
Also, there is another variation of the above mentioned snippet, which only counts the mutual friends.
private async Task<IList<SavedCommentModel>> MutualFriendsCount(User currentUser,
IList<SavedCommentModel> comments)
{
var usersFriends = new Dictionary<Guid, long>();
foreach (var comment in comments)
{
if (usersFriends.ContainsKey(comment.UserId))
{
comment.TotalMutualFriends = usersFriends[comment.UserId];
}
else
{
var visitedUser = _serviceUserLogin.GetByUserId(comment.UserId);
if (visitedUser.LoginProvider != LoginProvider.Facebook.ToString()) continue;
var facebookResult = await
_facebookApi.GetMutualFriendsFacebookRequest(currentUser.Token, visitedUser.ProviderKey);
if (facebookResult == null) continue;
comment.TotalMutualFriends = facebookResult.Context.Mutual_friends.Summary.Total_Count;
usersFriends.Add(comment.UserId, comment.TotalMutualFriends);
}
}
return comments;
}

Related

UWP addOnLicense.IsActive always true

I've tried various techniques but can't work out why this code always results in a valid(active?) license, even if the user hasn't bought the app add-on.
The function initialises when the app starts.
public async void GetLicenseInfo()
{
if (context == null)
{
context = StoreContext.GetDefault();
// If your app is a desktop app that uses the Desktop Bridge, you
// may need additional code to configure the StoreContext object.
// For more info, see https://aka.ms/storecontext-for-desktop.
}
workingProgressRing.IsActive = true;
StoreAppLicense appLicense = await context.GetAppLicenseAsync();
workingProgressRing.IsActive = false;
if (appLicense == null)
{
messagetextblock.Text = "An error occurred while retrieving the license.";
return;
}
// Use members of the appLicense object to access license info...
// the customer can' t access this feature
messagetextblock.Text = "customer hasn't bought the addon";
// Access the valid licenses for durable add-ons for this app.
foreach (KeyValuePair<string, StoreLicense> item in appLicense.AddOnLicenses)
{
StoreLicense addOnLicense = item.Value;
// Use members of the addOnLicense object to access license info
// for the add-on.
// Specify the kinds of add-ons to retrieve.
string[] productKinds = { "Durable", "Consumable", "UnmanagedConsumable" };
List<String> filterList = new List<string>(productKinds);
StoreProductQueryResult queryResult = await context.GetAssociatedStoreProductsAsync(filterList);
if (addOnLicense.IsActive)
{
// the customer can access this feature
messagetextblock.Text = "customer has bought the addon";
}
}
}
It's hard to tell exactly what could be wrong with your above example. However, I have an app in the market that uses two different types of in app purchases. One to remove ads and one that gets a premium license.
The difference between how you're doing it and I'm doing it is I'm looking for subscription store id in my license skues that are returned with the license.
have you tried this method yet?
public static void CheckForPremiumStatus()
{
#if DEBUG
if (LicenseInformation.ProductLicenses["PremiumStatus"].IsActive)
{
IsPremium = RemoveAds = true;
}
#else
var subscriptionStoreId = "9PMT47KC5W6C";
foreach (var addOnLicense in _appLicense.AddOnLicenses)
{
StoreLicense license = addOnLicense.Value;
if (license.SkuStoreId.StartsWith(subscriptionStoreId))
{
if (license.IsActive)
{
IsPremium = RemoveAds = true;
return;
}
else
{
break;
}
}
}
IsPremium = RemoveAds = false;
#endif
}
You can see the full example here - feel free to copy and paste it if you want. Just swap out the addon store id's

How to efficiently edit data in a database?

The method is supposed to receive data from a server, check if new tokens have been added, and if there are, add them to the database. If the token already exists, update its status but don't add a new row in the table. This is the code I've written so far.
IEnumerable<Token> serverTokens = JsonConvert.DeserializeObject<IEnumerable<Token>>
(server.GetTokens().Content);
IEnumerable<Token> dbTokens = _tokenService.GetAllTokens();
foreach (var token in serverTokens)
{
var dbToken = dbTokens.Where(x => x.Symbol == token.Symbol).FirstOrDefault();
if (dbToken != null)
{
Token editedToken = dbToken;
editedToken.UpdatedOn = DateTime.Now;
editedToken.Active = token.Active;
_tokenService.AddToken(editedToken);
}
else
{
token.UpdatedOn = DateTime.Now;
_tokenService.AddToken(token);
}
}
dbContext.SaveChanges();
The AddToken method is just a simple AddOrUpdate operation.
public void AddToken(Token token)
{
_dbContext.Tokens.AddOrUpdate(token);
//_dbContext.SaveChanges();
}
Now, this code does what it's supposed to, however it's extremely slow. How would I go about optimizing it?
dbTokens.Where(x => x.Symbol == token.Symbol) is IEnumerable
So he will load it each time you call it on the loop.
Store in in a list before the loop
List<Token> dbTokens = _tokenService.GetAllTokens().ToList()

Microsoft Graph. Tracking of page number

I'm implementing a method to get groups from AzureAD with paging and filtering for the displayName property of the groups. Let's center in the paging. I'm actually able to do page results with the $top. But my requirement says that I need to return the data set from a specific page. I'm also able to do that but with not a very elegant solution, making requests to the NextPageRequest object of the results to retrieve the specified page. Here's the code:
public async Task<List<Group>> GetGroups(string filterText, int page, int pageSize = 1)
{
var graphClient = _graphSdkHelper.GetAuthenticatedClient();
List<Group> groups = new List<Group>();
//Microsoft Graph api allows a minimum page size of 1 and maximum of 999
if (pageSize < 1 || pageSize > 999)
{
return groups;
}
try
{
IGraphServiceGroupsCollectionPage graphGroups;
if (!string.IsNullOrEmpty(filterText))
{
graphGroups = await graphClient.Groups.Request().Filter($"startswith(displayName, '{filterText}')").Top(pageSize).GetAsync();
}
else
{
//if filter text is empty, return all groups
graphGroups = await graphClient.Groups.Request().OrderBy("displayName").Top(pageSize).GetAsync();
}
//navigate to the requested page. This is extremly inefficient as we make requests until we find the right page.
//$Skip query parameter doesn't work in groups services
var currentPage = 1;
while (currentPage < page && graphGroups.NextPageRequest != null && (graphGroups = await graphGroups.NextPageRequest.GetAsync()).Count > 0)
{
currentPage = currentPage + 1;
}
foreach (var graphGroup in graphGroups)
{
Group group = _graphSdkHelper.TranslateGroup(graphGroup);
groups.Add(group);
}
}
catch (Exception exception)
{
_logger.LogError(exception, "Error while searching for groups");
}
return groups;
}
Question 1: how can I improve and keep track of which page am I? Is this possible? Now I can just request the next page so if I need to access page 20 for example, means 20 requests to azure.
Regarding this post from the AzureAD Graph Api, this is not possible:
https://social.msdn.microsoft.com/Forums/en-US/199bbf92-642a-4bcc-add4-f8023a7684e2/paging-in-azure-ad-graph-client?forum=WindowsAzureAD
I just refuse to think that it's not possible to do real pagination in AzureAD.
Question 2: How can I get the total amount of groups with just one request. It seems that the $Countquery parameter is not implemented for groups or users:
https://github.com/microsoftgraph/microsoft-graph-docs/blob/master/concepts/query_parameters.md#count-parameter
Thanks

redis servicestack client List.Remove(item) does not work

I'm developing a "Task Control System" that will allow its users to enter task description information including when to execute the task and what environment (OS, browser, etc.) the task requires.
The 'controller' saves the description information and schedules the task. When the scheduled time arrives, the scheduler retrieves the task information and 'queues' the task for a remote machine that matches the required environment.
My first cut at this used a relational database to persist the task descriptions and enough history information to track problems (about 2 weeks worth). But this is not a 'big data' problem and the relationships are simple and I need better performance.
So I'm looking for something that offers more performance.
I'm trying to use redis for this, but I'm having some problems. I'm using ServiceStack.Redis version 3.9.71.0 for the client and Redis 2.8.4 is the server.
This sample code is taken from Dan Swain's tutorial. It's updated to work with ServiceStack.Redis client v 3.9.71.0. Much of it works, but 'currentShippers.Remove(lameShipper);' does NOT work.
Can anyone see why that might be?
Thanks
public void ShippersUseCase()
{
using (var redisClient = new RedisClient("localhost"))
{
//Create a 'strongly-typed' API that makes all Redis Value operations to apply against Shippers
var redis = redisClient.As<Shipper>();
//Redis lists implement IList<T> while Redis sets implement ICollection<T>
var currentShippers = redis.Lists["urn:shippers:current"];
var prospectiveShippers = redis.Lists["urn:shippers:prospective"];
currentShippers.Add(
new Shipper
{
Id = redis.GetNextSequence(),
CompanyName = "Trains R Us",
DateCreated = DateTime.UtcNow,
ShipperType = ShipperType.Trains,
UniqueRef = Guid.NewGuid()
});
currentShippers.Add(
new Shipper
{
Id = redis.GetNextSequence(),
CompanyName = "Planes R Us",
DateCreated = DateTime.UtcNow,
ShipperType = ShipperType.Planes,
UniqueRef = Guid.NewGuid()
});
var lameShipper = new Shipper
{
Id = redis.GetNextSequence(),
CompanyName = "We do everything!",
DateCreated = DateTime.UtcNow,
ShipperType = ShipperType.All,
UniqueRef = Guid.NewGuid()
};
currentShippers.Add(lameShipper);
Dump("ADDED 3 SHIPPERS:", currentShippers);
currentShippers.Remove(lameShipper);
.
.
.
}
}
Fixed the problem by adding these overrides to the 'Shipper' class:
public override bool Equals(object obj)
{
if (obj == null)
{
return false;
}
var input = obj as Shipper;
return input != null && Equals(input);
}
public bool Equals(Shipper other)
{
return other != null && (Id.Equals(other.Id));
}
public override int GetHashCode()
{
return (int)Id;
}
This working example shows how to implement List<>.Contains, List<>.Find, and List<>.Remove. Once applied to the 'Shipper' class the problem was solved!

Dynamics CRM SDK: Execute Multiple Requests for Bulk Update of around 5000 Records

I have written a function to update Default Price List for all the Active Products on the CRM 2013 Online.
//The method takes IOrganization service and total number of records to be created as input
private void UpdateMultipleProducts(IOrganizationService service, int batchSize, EntityCollection UpdateProductsCollection, Guid PriceListGuid)
{
//To execute the request we have to add the Microsoft.Xrm.Sdk of the latest SDK as reference
ExecuteMultipleRequest req = new ExecuteMultipleRequest();
req.Requests = new OrganizationRequestCollection();
req.Settings = new ExecuteMultipleSettings();
req.Settings.ContinueOnError = true;
req.Settings.ReturnResponses = true;
try
{
foreach (var entity in UpdateProductsCollection.Entities)
{
UpdateRequest updateRequest = new UpdateRequest { Target = entity };
entity.Attributes["pricelevelid"] = new EntityReference("pricelevel", PriceListGuid);
req.Requests.Add(updateRequest);
}
var res = service.Execute(req) as ExecuteMultipleResponse; //Execute the collection of requests
}
//If the BatchSize exceeds 1000 fault will be thrown.In the catch block divide the records into batchable records and create
catch (FaultException<OrganizationServiceFault> fault)
{
if (fault.Detail.ErrorDetails.Contains("MaxBatchSize"))
{
var allowedBatchSize = Convert.ToInt32(fault.Detail.ErrorDetails["MaxBatchSize"]);
int remainingCreates = batchSize;
while (remainingCreates > 0)
{
var recordsToCreate = Math.Min(remainingCreates, allowedBatchSize);
UpdateMultipleProducts(service, recordsToCreate, UpdateProductsCollection, PriceListGuid);
remainingCreates -= recordsToCreate;
}
}
}
}
Code Description : There are around 5000 active product records in the System. So I am updating Default Price List for all of them using above code.
But, I am missing here something so that, it has updated only 438 records. It loops through the While statement correctly, but it is not updating all of them here.
What should be the Batchsize when we run this function for the First Time?
Any one can help me here?
Thank you,
Mittal.
You pass remainingCreates as the batchSize parameter but your code never references batchSize so you are just going to reenter that while loop every time.
Also, I'm not sure how you are doing all your error handling but you need to update your catch block so that it doesn't just let FaultExceptions pass-through if they don't contain a MaxBatchSize value. Right now, if you take a FaultException regarding something other than batch size it will be ignored.
{
if (fault.Detail.ErrorDetails.Contains("MaxBatchSize"))
{
var allowedBatchSize = Convert.ToInt32(fault.Detail.ErrorDetails["MaxBatchSize"]);
int remainingCreates = batchSize;
while (remainingCreates > 0)
{
var recordsToCreate = Math.Min(remainingCreates, allowedBatchSize);
UpdateMultipleProducts(service, recordsToCreate, UpdateProductsCollection, PriceListGuid);
remainingCreates -= recordsToCreate;
}
}
else throw;
}
Instead of reactive handling, i prefer proactive handling of the MaxBatchSize, this is true when you already know what is MaxMatchSize is.
Following is sample code, here while adding OrgRequest to collection i keep count of batch and when it exceeds I call Execute and reset the collection to take fresh batch.
foreach (DataRow dr in statusTable.Rows)
{
Entity updEntity = new Entity("ABZ_NBA");
updEntity["ABZ_NBAid"] = query.ToList().Where(a => a.NotificationNumber == dr["QNMUM"].ToString()).FirstOrDefault().TroubleTicketId;
//updEntity["ABZ_makerfccall"] = false;
updEntity["ABZ_rfccall"] = null;
updEntity[cNBAttribute.Key] = dr["test"];
req.Requests.Add(new UpdateRequest() { Target = updEntity });
if (req.Requests.Count == 1000)
{
responseWithResults = (ExecuteMultipleResponse)_orgSvc.Execute(req);
req.Requests = new OrganizationRequestCollection();
}
}
if (req.Requests.Count > 0)
{
responseWithResults = (ExecuteMultipleResponse)_orgSvc.Execute(req);
}

Categories

Resources