How to use OdataNextLink in Microsoft Graph API Beta 5 - c#

I was using the Microsoft Graph API 1.0 but have updated to the Beta in order to use CustomSecurityAttributeValue support.
I've managed to port most of the code but I can't see any way to process multiple results pages.
Previously you would just do something like
if (membersPage.NextPageRequest != null)
membersPage = await membersPage.NextPageRequest.GetAsync();
But NextPageRequest no longer exists, the only available information is OdataNextLink which is a string with no obvious way to request the next page or create a raw request using the url.
Code I have so far:
public async Task<IEnumerable<Microsoft.Graph.Beta.Models.User>> GetGraphUsersInGroups(IEnumerable<string> groupIds, string? searchText = null)
{
Dictionary<String, Microsoft.Graph.Beta.Models.User> users = new Dictionary<String, Microsoft.Graph.Beta.Models.User>();
foreach (var groupId in groupIds)
{
try
{
var membersPage = await GraphClient.Groups[groupId].Members
.GetAsync((memberRequest) => {
memberRequest.Headers.Add(new KeyValuePair<string, string>("$count", "true"));
memberRequest.Headers.Add(new KeyValuePair<string, string>("ConsistencyLevel", "eventual"));
memberRequest.QueryParameters.Count = true;
memberRequest.QueryParameters.Orderby = new[] { "displayName" };
if (searchText != null)
memberRequest.QueryParameters.Search = $"\"displayName:{searchText}\"";
});
while (membersPage != null)
{
foreach (var member in membersPage.Value.OfType<Microsoft.Graph.Beta.Models.User>())
{
users[member.Id] = member;
}
if (membersPage.OdataNextLink != null)
{
// How to use membersPage.OdataNextLink???
}
else
break;
}
}
catch(Exception ex)
{
Console.WriteLine(ex.Message);
Console.WriteLine(ex.StackTrace);
}
}
return users.Values;
}

You should use the PageIterator, see an example below:
var users = new List<User>();
var userResponse = await serviceClient.Users.GetAsync((builder) => {
// builder.SomeStuff
});
// Added the namespace here, just for some clarity :-)
var pageIterator = Microsoft.Graph.PageIterator<User,UserCollectionResponse>
.CreatePageIterator(serviceClient, userResponse, (user) =>
{
users.Add(user.Id);
return true; });

Related

How to get the TTL of multiple Redis keys from C# StackExchange.Redis

Trying to make up a function that takes a list of redis keys, and outputs a list of timespans for the time to live (TTL) of the keys. I'm not familiar with Lua Scripting though. I've tried following other guides online for this, but am unable to get something to work for this situation. Any insight would be super helpful and very reusable.
public async Task<TimeSpan?[]> GetTTLManyAsync(string[] keySet)
{
try
{
var db = await this.GetDatabaseAsync();
string script = #"...";
...
var keysCasted = keySet.Select(k => new RedisKey(k)).ToArray();
var result = await db.ScriptEvaluateAsync(script, keysCasted);
...
return ...[array of timespans];
}
catch (Exception e)
{
WriteLogException(e);
return null;
}
}`
Here is a rough solution I worked out.
public async Task<List<TimeSpan?>> GetTTLManyAsync(IEnumerable<string> keys)
{
List<string> returnList = new List<string>();
try
{
var db = await this.GetDatabaseAsync();
string script = #"local result = {}
for i,key in ipairs(KEYS) do
local ttl = tonumber(redis.call('ttl', key))
result[i] = ttl
end
return result";
var result = await db.ScriptEvaluateAsync(script, keys.Select(k => new RedisKey(k)).ToArray());
var arrResult = ((double[])result).Select(ttl =>
{
if (ttl == -2) return default(TimeSpan?); // Key does not exist
else if (ttl == -1) return default(TimeSpan?); // No expiration set.
else return TimeSpan.FromSeconds(ttl);
}).ToList();
return arrResult;
}
catch (Exception e)
{
WriteLogException(e);
}
// Fill w/ empty values
return new List<TimeSpan?>(new TimeSpan?[keys.Count()]);
}

How to send the Mongo collection with key value pair in .net core

I want return the mongo collection with key value pair like bellow
{
"message":"Success",
"Success":1,
"data":{"key","value"}
}
I am using bellow code to return the document
try
{
dynamic jObj = JObject.FromObject(val);
var Collection = _database.GetCollection<BsonDocument>("Registeration");
string id = jObj._id;
var filter = Builders<BsonDocument>.Filter.Eq("_id", new ObjectId(id));
var doc = Collection.Find(filter).FirstOrDefault();
if(doc != null)
{
return doc.ToJson();
}
else
{
return doc.Add("Success","0").Add("Mesaage","No Data Found").ToJson();
}
}
catch(Exception exp)
{
Console.WriteLine(exp.StackTrace);
return false;
}
I change my mode like this
if(doc != null)
{
var t = new BsonDocument();
t.Add("Success","1").Add("data",doc);
return t.ToJson();
}
Now it's working with expected output.
Thank you...

Method not found Microsoft.Owin.Security.Notifications.MessageReceivedNotification

Recently i've updated packages in an mvc project with owin to 4.0.0
Now up until now I was able to solve a lot of issues with this upgrade (other packages that needed upgrading etc)
But currently I'm stuck on this exception:
Method not found: 'System.Func`2<Microsoft.Owin.Security.Notifications.MessageReceivedNotification`2<Microsoft.IdentityModel.Protocols.OpenIdConnectMessage,Microsoft.Owin.Security.OpenIdConnect.OpenIdConnectAuthenticationOptions>,System.Threading.Tasks.Task> Microsoft.Owin.Security.OpenIdConnect.OpenIdConnectAuthenticationNotifications.get_MessageReceived()'.
I've tried googling, I've tried putting a breakpoint on the inflicted class (constructor get's hit but the method that throws the exception never gets hit even)
Anyone has a clue on what to try next? Or even better on how to fix this one?
protected override async Task<AuthenticationTicket> AuthenticateCoreAsync()
{
if (Options.CallbackPath.HasValue && Options.CallbackPath != (Request.PathBase + Request.Path))
{
return null;
}
OpenIdConnectMessage openIdConnectMessage = null;
if (string.Equals(Request.Method, "POST", StringComparison.OrdinalIgnoreCase)
&& !string.IsNullOrWhiteSpace(Request.ContentType)
&& Request.ContentType.StartsWith("application/x-www-form-urlencoded", StringComparison.OrdinalIgnoreCase)
&& Request.Body.CanRead)
{
if (!Request.Body.CanSeek)
{
//this._logger.WriteVerbose("Buffering request body");
// Buffer in case this body was not meant for us.
var memoryStream = new MemoryStream();
await Request.Body.CopyToAsync(memoryStream);
memoryStream.Seek(0, SeekOrigin.Begin);
Request.Body = memoryStream;
}
var form = await Request.ReadFormAsync();
Request.Body.Seek(0, SeekOrigin.Begin);
openIdConnectMessage = new OpenIdConnectMessage(form);
}
if (openIdConnectMessage == null)
{
return null;
}
ExceptionDispatchInfo authFailedEx = null;
try
{
var messageReceivedNotification = new MessageReceivedNotification<OpenIdConnectMessage, OpenIdConnectAuthenticationOptions>(this.Context, this.Options)
{
ProtocolMessage = openIdConnectMessage
};
await this.Options.Notifications.MessageReceived(messageReceivedNotification);
if (messageReceivedNotification.HandledResponse)
{
return null;
}
if (messageReceivedNotification.Skipped)
{
return null;
}
// runtime always adds state, if we don't find it OR we failed to 'unprotect' it this is not a message we should process.
AuthenticationProperties properties = null;
if (properties == null)
{
return null;
}
}
catch (Exception exception)
{
// We can't await inside a catch block, capture and handle outside.
authFailedEx = ExceptionDispatchInfo.Capture(exception);
}
if (authFailedEx != null)
{
//Refresh the configuration for exceptions that may be caused by key rollovers.The user can also request a refresh in the notification.
if (this.Options.RefreshOnIssuerKeyNotFound && authFailedEx.SourceException.GetType() == typeof(SecurityTokenSignatureKeyNotFoundException))
{
this.Options.ConfigurationManager.RequestRefresh();
}
var authenticationFailedNotification = new AuthenticationFailedNotification<OpenIdConnectMessage, OpenIdConnectAuthenticationOptions>(this.Context, this.Options)
{
ProtocolMessage = openIdConnectMessage,
Exception = authFailedEx.SourceException
};
await this.Options.Notifications.AuthenticationFailed(authenticationFailedNotification);
if (authenticationFailedNotification.HandledResponse)
{
return null;
}
if (authenticationFailedNotification.Skipped)
{
return null;
}
authFailedEx.Throw();
}
return null;
}
}
The above code is the least amount of code needed to make this error occur, as soon as the code uses anything that comes from options.notifications the application immediately crashes with a method not found exception.
Notification property has been setup as follows:
Notifications = new OpenIdConnectAuthenticationNotifications
{
RedirectToIdentityProvider = context =>
{
if (Startup.IsApiRequest(context.Request))
{
context.HandleResponse();
return Task.FromResult(0);
}
context.ProtocolMessage.RedirectUri = redirectUri;
context.ProtocolMessage.PostLogoutRedirectUri = postLogoutRedirectUri;
return Task.FromResult(0);
},
AuthenticationFailed = context =>
{
context.OwinContext.Response.Redirect("/Home/Error");
context.HandleResponse(); // Suppress the exception
return Task.FromResult(0);
},
AuthorizationCodeReceived = context =>
{
var userIdentity = context.AuthenticationTicket.Identity;
userIdentity = userIdentity.TransformClaims();
context.AuthenticationTicket = new AuthenticationTicket(
userIdentity,
context.AuthenticationTicket.Properties
);
return Task.FromResult(0);
},
SecurityTokenReceived = context => Task.FromResult(0),
}
});
Little fyi I'm not the original developer of this code....
Try to replace
using Microsoft.IdentityModel.Protocols;
with
using Microsoft.IdentityModel.Protocols.OpenIdConnect;
everywhere in your code. That should solve the issue.

How to Update campaign in Bing Ads?

For Update campaign I am using this Code
public async Task<List<long?>> updateCampaign(Campaign campaign,string status)
{
try
{
campaign.Status = (CampaignStatus)(int)Enum.Parse(typeof(CampaignStatus), status);
var request = new UpdateCampaignsRequest
{
Campaigns = new Campaign[] { campaign },
CustomerId = "xxxxxx",
UserName = "something#outlook.com",
Password = "something#123",
ApplicationToken = "myApplicationToken",
CustomerAccountId = "123456",
DeveloperToken = "1234567890"
};
CampaignService = new ServiceClient<ICampaignManagementService>(_authorizationData);
CampaignService.RefreshOAuthTokensAutomatically = false;
var result = (await CampaignService.CallAsync((s, r) => s.UpdateCampaignsAsync(r), request));
if (result.TrackingId != null)
{
return result.CampaignIds.ToList();
}
else
{
return new List<long?>();
}
}
catch (Exception ex)
{
ErrorLog.log(ex);
return new List<long?>();
}
}
When I run this code, I got this error "Invalid client data. Check the SOAP fault details for more information"
thanks.
For updating the Campaign we can use "BulkServiceManager" for bulk updating of the campaign,you can use this service single campaign update also.
public async Task<List<long?>> updateCampaign(List<Campaign> campaigns)
{
try
{
var listBulkCampaign = new List<BulkCampaign>();
foreach (var campaign in campaigns)
{
var _bulkCampaign = new BulkCampaign()
{
Campaign = campaign
};
listBulkCampaign.Add(_bulkCampaign);
}
BulkServiceManager bulkServiceManager = new BulkServiceManager(_authorizationData);
string fileName = bingCampaignUpdate.csv;
var campaigns = (await bulkServiceManager.UploadEntitiesAsync(new EntityUploadParameters
{
Entities = listBulkCampaign,
OverwriteResultFile = true,
ResultFileDirectory = FileDirectory,
ResultFileName = fileName,
ResponseMode = ResponseMode.ErrorsAndResults
})).OfType<BulkCampaign>().ToList();
return new List<long?>();
}
catch (Exception ex)
{
ErrorLog.log(ex);
return new List<long?>();
}
}
You have to download .csv report and update the Campaigns.
I hope it helps you

How to create async http requests in a loop?

Yesterday I've found out how to create several async http requests without async/await. But today I need to do it in a loop: if some of responses don't satisfy some condition - I need to change a request for them and send these requests again. It may be repeated several times.
I've tried this code:
do
{
var loadingCoordinatesTasks = new List<Task<Terminal>>();
var totalCountOfTerminals = terminalPresetNode.ChildNodes.Count;
var uiTaskScheduler = TaskScheduler.FromCurrentSynchronizationContext();
foreach (var terminal in terminals.Except(_terminalsWithCoordinates))
{
var address = terminal.GetNextAddress();
var webRequest = (HttpWebRequest)WebRequest.Create(GeoCoder.GeoCodeUrl + address);
var webRequestTask = Task.Factory.FromAsync<WebResponse>(webRequest.BeginGetResponse,
webRequest.EndGetResponse,
terminal);
var parsingTask = webRequestTask.ContinueWith(antecedent =>
{
// Parse the response
});
loadingCoordinatesTasks.Add(parsingTask);
}
Task.Factory.ContinueWhenAll(loadingCoordinatesTasks.ToArray(), antecedents =>
{
foreach (var antecedent in antecedents)
{
var terminalWithCoordinates = antecedent.Result;
if (antecedent.Status == TaskStatus.RanToCompletion &&
!terminalWithCoordinates.Coordinates.AreUnknown)
{
_terminalsWithCoordinates.Add(terminalWithCoordinates);
_countOfProcessedTerminals++;
}
}
});
} while (_countOfProcessedTerminals < totalCountOfTerminals);
but is it possible to check the condition in while just after every single set of requests executed?
You can perform the check after increasing the count:
_countOfProcessedTerminals++;
if (_countOfProcessedTerminals >= totalCountOfTerminals)
{
break;
}
Is _countOfProcessedTerminals thread-safe though?
I manage to do it using recursion:
public void RunAgainFailedTasks(IEnumerable<Task<Terminal>> tasks)
{
Task.Factory.ContinueWhenAll(tasks.ToArray(), antecedents =>
{
var failedTasks = new List<Task<Terminal>>();
foreach (var antecedent in antecedents)
{
var terminal = antecedent.Result;
// Previous request was failed
if (terminal.Coordinates.AreUnknown)
{
string address;
try
{
address = terminal.GetNextAddress();
}
catch (FormatException) // No versions more
{
continue;
}
var getCoordinatesTask = CreateGetCoordinatesTask(terminal, address);
failedTasks.Add(getCoordinatesTask);
}
else
{
_terminalsWithCoordinates.Add(terminal);
}
}
if (failedTasks.Any())
{
RunAgainFailedTasks(failedTasks);
}
else
{
// Display a map
}
}, CancellationToken.None,
TaskContinuationOptions.None,
TaskScheduler.FromCurrentSynchronizationContext());
}
private Task<Terminal> CreateGetCoordinatesTask(Terminal terminal, string address)
{
var webRequest = (HttpWebRequest)WebRequest.Create(GeoCoder.GeoCodeUrl + address);
webRequest.KeepAlive = false;
webRequest.ProtocolVersion = HttpVersion.Version10;
var webRequestTask = Task.Factory.FromAsync<WebResponse>(webRequest.BeginGetResponse,
webRequest.EndGetResponse,
terminal);
var parsingTask = webRequestTask.ContinueWith(webReqTask =>
{
// Parse the response
});
return parsingTask;
}

Categories

Resources