Using dictionary of GraphServiceClient is thread safe? - microsoft-graph-api

I have to maintain number of graphClients in my application .
is it better way to store in dictionary? is it thread safe ? what could be the best option ?
IDictionary<string, IGraphServiceClient> dict = new Dictionary<string, IGraphServiceClient>();
private IGraphServiceClient GetGraphServiceClient()
{
IDictionary<string, IGraphServiceClient> dict = new Dictionary<string, IGraphServiceClient>();
var tenantIds = new List<string> { "Tenant1", "Tenant4", "Tenant1", "Tenant1" };
foreach (var tenant in tenantIds)
{
var graphServiceClient = GetGraphServiceClient(tenant);
var users = await graphServiceClient.Users.GetAsync();
}
}
private IGraphServiceClient GetGraphServiceClient(string i)
{
if (!dict.ContainsKey(i))
{
dict.Add(i, new GraphServiceClient(new MyAuthenticationProvider(i)));
}
return dict[i];
}

Dictionaries are not thread-safe. Moreover, even if a dictionary was thread-safe, the composite statements like
private IGraphServiceClient GetGraphServiceClient(string i)
{
if (!dict.ContainsKey(i))
{
dict.Add(i, new GraphServiceClient(new MyAuthenticationProvider(i)));
}
return dict[i];
}
are never thread-safe. You need to guard this with a mutex.

Related

Unable to cast object of type 'Microsoft.Graph.CalendarEventsCollectionPage' to type 'System.Collections.Generic.IEnumerable`

My controller code is lke this,
public async Task<IEnumerable<CalendarEvent>> Get()
{
var scopes = new[] { "https://graph.microsoft.com/.default" };
var tenantId = "xxxxx";
var clientId = "xxxxxx";
var clientSecret = "xxxx";
var clientSecretCredential = new ClientSecretCredential(
tenantId, clientId, clientSecret);
var graphServiceClient = new GraphServiceClient(clientSecretCredential, scopes);
if (User == null!)
{
var user = await graphServiceClient.Users["xxxxx.com"].Calendar
.Events
.Request()
.Select("subject,body,bodyPreview,organizer,attendees,start,end,location")
.GetAsync();
return (CalendarEvent)user;
}
}
Iam getting an error like
Unable to cast object of type 'Microsoft.Graph.CalendarEventsCollectionPage' to type 'System.Collections.Generic.IEnumerable'
I need query that sholud be given in controller.
It's not exactly clear what you are trying to achieve but you can't convert CalendarEventsCollectionPage to IEnumerable. I am assuming that you want to return all events of specific user.
public async Task<List<Event>> GetEventsOfUser(string userId)
{
var events = new List<Event>();
var eventsPages = _client.Users[userId].Calendar.Events.Request()
.Select("subject,body,bodyPreview,organizer,attendees,start,end,location");
while (eventsPages != null)
{
var current = await eventsPages.GetAsync();
events.AddRange(current.CurrentPage);
eventsPages = current.NextPageRequest;
}
return events;
}
You need to fetch every page with NextPageRequest in order to get all events.

Break down activity function

I have an Activity function that reads child elements of a parent in an organization as follows:
[FunctionName("ChildReaderFunction")]
public async Task<List<User>> GetChildren([ActivityTrigger] User parent)
{
var children = await GetChildrenAsync(parent);
return children;
}
public async Task<List<User>> GetChildrenAsync(User parent)
{
var allUsers = new List<User> { parent };
List<User> children = null;
children = await ExecuteQueryAsync("tableName", $"Parent eq '{parent.Id}'");
var taskIndex = 0;
var readTasks = new Task<List<User>>[children.Count(x => x.Childcount > 0)];
foreach (var child in children)
{
if (child.Childcount > 0)
{
readTasks[taskIndex++] = GetChildrenAsync(child);
}
else
{
allUsers.Add(child);
}
}
var validTasks = readTasks.Where(task => task != null).ToList();
if (validTasks.Count > 0)
{
foreach (var result in await Task.WhenAll(validTasks))
{
allUsers.AddRange(result);
}
}
Console.WriteLine($"Got {allUsers.Count} children for {parent.Id}");
return allUsers;
}
This works perfectly when I use premium plan with a timeout of 2 hours. I'm trying to convert this to a consumption plan with a timeout of 10 min. On testing out, I see timeout exception. Is there a way to breakdown this durable function and complete execution in 10 min?
I tried to update this logic by using a queue as follows:
[FunctionName("ChildReaderFunction")]
public async Task<List<User>> GetChildren([ActivityTrigger] User parent)
{
var allUsers = new List<User>();
var directReportEntities = new List<User>();
Queue<User> myQueue = new Queue<Person>();
myQueue.Enqueue(request.Parent);
while (myQueue.Any())
{
var current = myQueue.Dequeue();
if (current.Childcount > 0)
{
var children = await GetChildrenAsync(parent);
foreach (var child in children)
{
myQueue.Enqueue(child);
}
}
allUsers.Add(current);
}
Console.WriteLine($"Got {allUsers.Count} children for {parent.Id}");
return allUsers;
}
public async Task<List<User>> GetChildrenAsync(User parent)
{
return await ExecuteQueryAsync("tableName", $"Parent eq '{parent.Id}'");
}
This also gives a timeout exception. Any suggestions on what other approach I could try?
You might think about trying to figure out which parts of this method are slow. Perhaps it isn't the method itself that is slow but the query to the database. How many rows are you trying to download?
Also, you have a recursive call in your method. That may lead to many queries being executed. Can you think of a different way to grab the data all at once instead of a little bit at a time?

Dart: Use Futures to asynchronously fill a static var

I have defined a static var as Map for all instances of my element. If it contains a specific key, it should use the value. If the key is not contains the instance should get the data with a request and save it in the static map, so other instances could use it.
static var data = new Map();
func() {
if (Elem.data.containsKey(['key']) {
list = Elem.data['key'];
}
else {
Helper.getData().then((requestedData) {
list = requestedData;
Elem.data.addAll({ 'key' : requestedData });
}
}
The Problem is that all my instances go into the else, since the key is not contained in the Map at the moment the other instances are at the if. So i need them to wait, until the Data is in the Map.
static var data = new Map();
static Completer _dataCompleter;
Future<bool> func() {
if(_dataCompleter == null) {
_dataCompleter = new Completer();
Helper.getData().then((requestedData) {
list = requestedData;
Elem.data.addAll({ 'key' : requestedData });
_dataCompleter.complete(true);
})
}
if(_dataCompleter.isCompleted) {
return new Future.value(true);
}
return _dataCompleter.future;
}
and call it like
func().then((success) => /* continue here when `key` in `data` has a value.
In response to Günter Zöchbauer. I generally avoid using Completers directly:
static var data = new Map();
static Future _pendingFuture;
Future func() {
if (_pendingFuture == null) {
_pendingFuture = Helper.getData().then((requestedData) {
list = requestedData;
Elem.data.addAll({ 'key' : requestedData });
});
}
return _pendingFuture;
}

Accessing a Service from within an XNA Content Pipeline Extension

I need to allow my content pipeline extension to use a pattern similar to a factory. I start with a dictionary type:
public delegate T Mapper<T>(MapFactory<T> mf, XElement d);
public class MapFactory<T>
{
Dictionary<string, Mapper<T>> map = new Dictionary<string, Mapper<T>>();
public void Add(string s, Mapper<T> m)
{
map.Add(s, m);
}
public T Get(XElement xe)
{
if (xe == null) throw new ArgumentNullException(
"Invalid document");
var key = xe.Name.ToString();
if (!map.ContainsKey(key)) throw new ArgumentException(
key + " is not a valid key.");
return map[key](this, xe);
}
public IEnumerable<T> GetAll(XElement xe)
{
if (xe == null) throw new ArgumentNullException(
"Invalid document");
foreach (var e in xe.Elements())
{
var val = e.Name.ToString();
if (map.ContainsKey(val))
yield return map[val](this, e);
}
}
}
Here is one type of object I want to store:
public partial class TestContent
{
// Test type
public string title;
// Once test if true
public bool once;
// Parameters
public Dictionary<string, object> args;
public TestContent()
{
title = string.Empty;
args = new Dictionary<string, object>();
}
public TestContent(XElement xe)
{
title = xe.Name.ToString();
args = new Dictionary<string, object>();
xe.ParseAttribute("once", once);
}
}
XElement.ParseAttribute is an extension method that works as one might expect. It returns a boolean that is true if successful.
The issue is that I have many different types of tests, each of which populates the object in a way unique to the specific test. The element name is the key to MapFactory's dictionary. This type of test, while atypical, illustrates my problem.
public class LogicTest : TestBase
{
string opkey;
List<TestBase> items;
public override bool Test(BehaviorArgs args)
{
if (items == null) return false;
if (items.Count == 0) return false;
bool result = items[0].Test(args);
for (int i = 1; i < items.Count; i++)
{
bool other = items[i].Test(args);
switch (opkey)
{
case "And":
result &= other;
if (!result) return false;
break;
case "Or":
result |= other;
if (result) return true;
break;
case "Xor":
result ^= other;
break;
case "Nand":
result = !(result & other);
break;
case "Nor":
result = !(result | other);
break;
default:
result = false;
break;
}
}
return result;
}
public static TestContent Build(MapFactory<TestContent> mf, XElement xe)
{
var result = new TestContent(xe);
string key = "Or";
xe.GetAttribute("op", key);
result.args.Add("key", key);
var names = mf.GetAll(xe).ToList();
if (names.Count() < 2) throw new ArgumentException(
"LogicTest requires at least two entries.");
result.args.Add("items", names);
return result;
}
}
My actual code is more involved as the factory has two dictionaries, one that turns an XElement into a content type to write and another used by the reader to create the actual game objects.
I need to build these factories in code because they map strings to delegates. I have a service that contains several of these factories. The mission is to make these factory classes available to a content processor. Neither the processor itself nor the context it uses as a parameter have any known hooks to attach an IServiceProvider or equivalent.
Any ideas?
I needed to create a data structure essentially on demand without access to the underlying classes as they came from a third party, in this case XNA Game Studio. There is only one way to do this I know of... statically.
public class TestMap : Dictionary<string, string>
{
private static readonly TestMap map = new TestMap();
private TestMap()
{
Add("Logic", "LogicProcessor");
Add("Sequence", "SequenceProcessor");
Add("Key", "KeyProcessor");
Add("KeyVector", "KeyVectorProcessor");
Add("Mouse", "MouseProcessor");
Add("Pad", "PadProcessor");
Add("PadVector", "PadVectorProcessor");
}
public static TestMap Map
{
get { return map; }
}
public IEnumerable<TestContent> Collect(XElement xe, ContentProcessorContext cpc)
{
foreach(var e in xe.Elements().Where(e => ContainsKey(e.Name.ToString())))
{
yield return cpc.Convert<XElement, TestContent>(
e, this[e.Name.ToString()]);
}
}
}
I took this a step further and created content processors for each type of TestBase:
/// <summary>
/// Turns an imported XElement into a TestContent used for a LogicTest
/// </summary>
[ContentProcessor(DisplayName = "LogicProcessor")]
public class LogicProcessor : ContentProcessor<XElement, TestContent>
{
public override TestContent Process(XElement input, ContentProcessorContext context)
{
var result = new TestContent(input);
string key = "Or";
input.GetAttribute("op", key);
result.args.Add("key", key);
var items = TestMap.Map.Collect(input, context);
if (items.Count() < 2) throw new ArgumentNullException(
"LogicProcessor requires at least two items.");
result.args.Add("items", items);
return result;
}
}
Any attempt to reference or access the class such as calling TestMap.Collect will generate the underlying static class if needed. I basically moved the code from LogicTest.Build to the processor. I also carry out any needed validation in the processor.
When I get to reading these classes I will have the ContentService to help.

General solution to updating fields for table in Entity Framework 4.0

I want to create a method which can takes the properties I possibly may update and leaving those not interested untouched.
Here is what I did:
public static void updateTable(int id, string field1, string field2, string field3){
using(var context = new Entities()){
var obj = context.Table.Where(x=>x.id == id).FirstOrDefault();
if(obj != null){
obj.field1 = field1;
...
obj.SaveChanges();
}
}
}
But in this pattern, I need to pass all 4 parameters into the method even I just want to update only one field. Is there any generic solution to update only the fields I passed in?
I came up something like this:
public static void updateTable(int id, object data_json){
using(var context = new Entities()){
var obj = context.Table.Where(x=>x.id == id).FirstOrDefault();
if(obj != null){
if(data_json['field1']!=null) //something like this
obj.field1 = data_json['field1'];
...
obj.SaveChanges();
}
}
}
But this can't handle the case that I do want to set a field to be null. Or is there any better solution?
If you don't care about updating relationships, you can use ApplyCurrentValues, which only updates the scalar properties.
E.g:
public static void updateTable(int id, object data_json){
using(var context = new Entities()) {
var obj = context.Table.Where(x=>x.id == id).FirstOrDefault();
context.ApplyCurrentValues("Table", data_json);
}
}
It assumes an entity with the same key is already attached in the graph. In this case, the query for var obj will ensure the object is in the graph, then it's contents are overridden with the scalar properties on the supplied object.
You might need an explicit cast on data_json to ensure it is of the same type contained in the entity set.
Using an ExpandoObject would allow you to send in only the properties you want to set, and would allow you to specify null values as well.
For example:
public static void updateTable(int id, dynamic data){
using(var context = new Entities()){
var obj = context.Table.Where(x=>x.id == id).FirstOrDefault();
if(obj != null){
if (((IDictionary<string, object>)data).ContainsKey("field1"))
obj.field1 = data.field1;
...
obj.SaveChanges();
}
}
}
and you could call it like this:
dynamic data = new ExpandoObject();
data.field1 = 123;
data.field2 = null;
data.field5 = "abc";
MyClass.updateTable(1, data);
Everything can be solved with a moment of reflection. This function solves the problem:
public void UpdateTable(int id, object values)
{
using (var entities = new MyEntities())
{
var valuesType = values.GetType();
var element = entities.MyTable.Where(t => t.ID == id).First();
//We are iterating through all properties of updated element and checking
//if there is value provided for there properties in values parameter
foreach (var property in element.GetType().GetProperties())
{
var valuesProperty = valuesType.GetProperty(property.Name);
//If values contain this property
if (valuesProperty != null)
{
//taking value out of values parameter
var value = valuesProperty.GetValue(values, null);
//setting it in our element to update
property.SetValue(element, value, null);
}
}
entities.SaveChanges();
}
}
Usage:
UpdateTable(125, new { FieldA = 1, FieldB = "ABCD" });
You can even make this method more universal by adding generic table type parameter.

Resources