Microsoft Graph api code in C# displays only limited number of users - c#

I am running below Microsoft Graph Api code:
using Microsoft.IdentityModel.Clients.ActiveDirectory;
using System;
using System.Net.Http;
using System.Net.Http.Headers;
using System.Threading.Tasks;
namespace AADConsole2
{
class Program
{
private const string aadInstance = "https://login.microsoftonline.com/{0}";
// private const string ResourceUrl = "https://graph.windows.net";
private const string resource = "https://graph.microsoft.com";
private const string GraphServiceObjectId = "XXX";
private const string TenantId = "XXX";
private const string tenant = "XXXX.onmicrosoft.com";
private const string ClientId = "XXX";
private static string appKey= "XXXX";
static string authority = String.Format(System.Globalization.CultureInfo.InvariantCulture, aadInstance, tenant);
private static HttpClient httpclient = new HttpClient();
private static AuthenticationContext context = null;
private static ClientCredential credential = null;
static void Main(string[] args)
{
context = new AuthenticationContext(authority);
credential = new ClientCredential(ClientId, appKey);
Task<string> token = GetToken();
token.Wait();
Console.WriteLine(token.Result);
Task<string> users = GetUsers(token.Result);
users.Wait();
Console.WriteLine(users.Result);
Console.ReadLine();
}
private static async Task<string> GetUsers(string result) {
//throw new NotImplementedException();
string users = null;
var uri = "https://graph.microsoft.com/v1.0/users";
httpclient.DefaultRequestHeaders.Authorization = new AuthenticationHeaderValue("Bearer", result);
var getResult = await httpclient.GetAsync(uri);
if(getResult.Content != null)
{
users = await getResult.Content.ReadAsStringAsync();
}
return users;
}
private static async Task<string> GetToken()
{
AuthenticationResult result = null;
string token = null;
result = await context.AcquireTokenAsync(resource, credential);
token = result.AccessToken;
return token;
}
}
}
I am getting the results of user detail printed on console ,but only limited number of users are printed. i.e only whose name starts with letter 'a'.
And also some user details are missing. How to get all user details .Am i missing some api in this code?
Thanks.

Most Microsoft Graph endpoints return paged result sets. Your initial request only returns the first page of data. To retrieve the next page, you follow the URI provided in the #odata.nextLink property. Each subsequent page will return the next page's #odata.nextLink until you the last page of data (denoted by the lack of a #odata.nextLink in the result). There is a step-by-step walkthrough of how this works at Paging Microsoft Graph data in your app.
The single most important tip I can give you here is to not use $top to force it to return large pages of data. This is an extremely inefficient method for calling the API and inevitably leads to network errors and request throttling. It also doesn't eliminate the need to handle paging since even $top=999 (the maximum) can still return multiple pages.
Implement paging, keep your page sizes small, and process the results after each page is returned before moving on to the next page. This will ensure you capture all of the data and allow your application to pick up where it left off should it encounter any errors during processing.

Something like this will get all of your users. Also if you want properties outside of the default you need need to specify them with a select. Not all properties are returned by default.
String Properties = "Comma Separated List of Properties You actaully Need";
List<User> AllUsers = new List<User>();
IGraphServiceUsersCollectionPage users = graphServiceClient.Users
.Request()
.Select(Properties)
.GetAsync()
.Result;
do
{
QueryIncomplete = false ;
AllUsers.AddRange(users);
if (users.NextPageRequest != null)
{
users = users.NextPageRequest.GetAsync().Result;
QueryIncomplete = true;
}
}while (QueryIncomplete);
return AllUsers;

Related

Azure Function and SharePoint webhook: not getting changes from SharePoint list

I'm using a couple of Azure Functions with SharePoint webhook.
The first function is the one used to save messages from SharePoint webhook to a queue (Azure storage queue). This is the function content:
[FunctionName("QueueFunction")]
public static async Task<HttpResponseMessage> Run([HttpTrigger(AuthorizationLevel.Anonymous, "post", Route = null)]HttpRequestMessage req, TraceWriter log)
{
log.Info($"Webhook was triggered!");
// Grab the validationToken URL parameter
string validationToken = req.GetQueryNameValuePairs()
.FirstOrDefault(q => string.Compare(q.Key, "validationtoken", true) == 0)
.Value;
// If a validation token is present, we need to respond within 5 seconds by
// returning the given validation token. This only happens when a new
// web hook is being added
if (validationToken != null)
{
log.Info($"Validation token {validationToken} received");
var response = req.CreateResponse(HttpStatusCode.OK);
response.Content = new StringContent(validationToken);
return response;
}
log.Info($"SharePoint triggered our webhook...great :-)");
var content = await req.Content.ReadAsStringAsync();
log.Info($"Received following payload: {content}");
var notifications = JsonConvert.DeserializeObject<ResponseModel<NotificationModel>>(content).Value;
log.Info($"Found {notifications.Count} notifications");
if (notifications.Count > 0)
{
// get the cloud storage account
string queueName = "MYQUEUE";
CloudStorageAccount storageAccount = CloudStorageAccount.Parse(Environment.GetEnvironmentVariable("AzureWebJobsStorage"));
CloudQueueClient queueClient = storageAccount.CreateCloudQueueClient();
CloudQueue queue = queueClient.GetQueueReference(queueName);
await queue.CreateIfNotExistsAsync();
// store each notification as a queue item
foreach (var notification in notifications)
{
string message = JsonConvert.SerializeObject(notification);
log.Info($"Adding to {queueName}: {message}");
await queue.AddMessageAsync(new CloudQueueMessage(message));
log.Info($"added.");
}
// if we get here we assume the request was well received
return new HttpResponseMessage(HttpStatusCode.OK);
}
The message in queue is correctly added.
Then I've another function triggered by queue. This is the code of the function:
[FunctionName("OCRFunction")]
public static void Run([QueueTrigger("MYQUEUE", Connection = "QueueConn")]string myQueueItem, TraceWriter log)
{
log.Info($"C# Queue trigger function processed: {myQueueItem}");
string siteUrl = "https://MYSHAREPOINT.sharepoint.com/sites/MYSITE";
log.Info($"Processing notifications...");
string json = myQueueItem;
var data = (JObject)JsonConvert.DeserializeObject(json);
string notificationResource = data["resource"].Value<string>();
ClientContext SPClientContext = LoginSharePoint(siteUrl);
log.Info($"Logged in SharePoint");
GetChanges(SPClientContext, notificationResource, log);
}
public static ClientContext LoginSharePoint(string BaseUrl)
{
// Login using UserOnly Credentials (User Name and User PW)
ClientContext cntReturn;
string myUserName = config["spUN"];
string myPassword = config["spPWD"];
SecureString securePassword = new SecureString();
foreach (char oneChar in myPassword) securePassword.AppendChar(oneChar);
SharePointOnlineCredentials myCredentials = new SharePointOnlineCredentials(myUserName, securePassword);
cntReturn = new ClientContext(BaseUrl);
cntReturn.Credentials = myCredentials;
return cntReturn;
}
static void GetChanges(ClientContext SPClientContext, string ListId, TraceWriter log)
{
Web spWeb = SPClientContext.Web;
List myList = spWeb.Lists.GetByTitle("MY LIST");
SPClientContext.Load(myList);
SPClientContext.ExecuteQuery();
ChangeQuery myChangeQuery = GetChangeQueryNew(ListId);
var allChanges = myList.GetChanges(myChangeQuery);
SPClientContext.Load(allChanges);
SPClientContext.ExecuteQuery();
log.Info($"---- Changes found : " + allChanges.Count());
foreach (Change oneChange in allChanges)
{
if (oneChange is ChangeItem)
{
int myItemId = (oneChange as ChangeItem).ItemId;
log.Info($"---- Changed ItemId : " + myItemId);
ListItem myItem = myList.GetItemById(myItemId);
Microsoft.SharePoint.Client.File myFile = myItem.File;
ClientResult<System.IO.Stream> myFileStream = myFile.OpenBinaryStream();
SPClientContext.Load(myFile);
SPClientContext.ExecuteQuery();
byte[] myFileBytes = ConvertStreamToByteArray(myFileStream);
[...] SOME CODE HERE [...]
myItem["OCRText"] = myText;
myItem.Update();
SPClientContext.ExecuteQuery();
log.Info($"---- Text Analyze OCR added to SharePoint Item");
}
}
}
public static ChangeQuery GetChangeQueryNew(string ListId)
{
ChangeToken lastChangeToken = new ChangeToken();
lastChangeToken.StringValue = string.Format("1;3;{0};{1};-1", ListId, DateTime.Now.AddMinutes(-1).ToUniversalTime().Ticks.ToString());
ChangeToken newChangeToken = new ChangeToken();
newChangeToken.StringValue = string.Format("1;3;{0};{1};-1", ListId, DateTime.Now.ToUniversalTime().Ticks.ToString());
ChangeQuery myChangeQuery = new ChangeQuery(false, false);
myChangeQuery.Item = true; // Get only Item changes
myChangeQuery.Add = true; // Get only the new Items
myChangeQuery.ChangeTokenStart = lastChangeToken;
myChangeQuery.ChangeTokenEnd = newChangeToken;
return myChangeQuery;
}
public static Byte[] ConvertStreamToByteArray(ClientResult<System.IO.Stream> myFileStream)
{
Byte[] bytReturn = null;
using (System.IO.MemoryStream myFileMemoryStream = new System.IO.MemoryStream())
{
if (myFileStream != null)
{
myFileStream.Value.CopyTo(myFileMemoryStream);
bytReturn = myFileMemoryStream.ToArray();
}
}
return bytReturn;
}
public static async Task<TextAnalyzeOCRResult> GetAzureTextAnalyzeOCR(byte[] myFileBytes)
{
TextAnalyzeOCRResult resultReturn = new TextAnalyzeOCRResult();
HttpClient client = new HttpClient();
client.DefaultRequestHeaders.Add("Ocp-Apim-Subscription-Key", "XXXXXXXXXXXXXXXXXXXX");
string requestParameters = "language=unk&detectOrientation=true";
/* OCR API */
string uri = "https://MYOCRSERVICE.cognitiveservices.azure.com/vision/v3.0/ocr" + "?" + requestParameters;
string contentString = string.Empty;
HttpResponseMessage response;
using (ByteArrayContent content = new ByteArrayContent(myFileBytes))
{
content.Headers.ContentType = new MediaTypeHeaderValue("application/octet-stream");
response = await client.PostAsync(uri, content);
contentString = await response.Content.ReadAsStringAsync();
resultReturn = JsonConvert.DeserializeObject<TextAnalyzeOCRResult>(contentString);
return resultReturn;
}
}
Before current approach with two functions, I was using a single function where I managed the notifications and I executed some code to update a field in my SharePoint list. This method was having some problem when I was receiving many notifications from SharePoint so I decided to use queue as suggested in Microsoft documentation. This solution was working fine with a single notification received and my SharePoint list item were updated without problem.
To avoid problems with multiple notification, I decided to split functions, one registering notifications in a queue and the other executing some operations and updating a SharePoint field.
The first one function QueueFunction is working fine, the second one is triggering correctly but it is not getting changes from SharePoint list even if I just add one item.
I've tried to check GetChanges code to find why it is always returning no changes, but the code is the same of the one I used when I had only one function, so I can't understand why the behaviour is changed.
What's wrong with my approach? Is there something I could do to correct the second function?
According to the comments, just summarize the solution as below for other communities reference:
Use a function to save the message in a queue and then call an azure web job, the problem was caused by the the running time of the function may exceed 5 minutes.
By the way, the default timeout of azure function(with consumption plan) is 5 minutes, we can see all of the default timeout for different plan on this page (also shown as below screenshot).
If we want longer timeout, we can set the functionTimeout property in host.json of the function(but can not exceed the Maximum timeout). Or we can also use higher plan for the function app, such as Premium plan and App Service plan.

Invalid domain name Azure Active directory issue and Migration to Microsoft Graph C# application

I am trying to run below code to get the user details as response from Azure Active Directory :
using Microsoft.IdentityModel.Clients.ActiveDirectory;
using System;
using System.Net.Http;
using System.Net.Http.Headers;
using System.Threading.Tasks;
namespace AADConsole2
{
class Program
{
private const string aadInstance = "https://login.microsoftonline.com/{0}";
private const string resource= "https://graph.windows.net";
private const string GraphServiceObjectId = "XXX";
private const string TenantId = "XXXXX";
private const string tenant = "company.onmicrosoft.com";
private const string ClientId = "XXXX";
private static string appKey= "XXXXXXXXXXXXXXXX";
static string authority = String.Format(System.Globalization.CultureInfo.InvariantCulture, aadInstance, tenant);
private static HttpClient httpclient = new HttpClient();
private static AuthenticationContext context = null;
private static ClientCredential credential = null;
static void Main(string[] args)
{
context = new AuthenticationContext(authority);
credential = new ClientCredential(ClientId, appKey);
Task<string> token = GetToken();
token.Wait();
Console.WriteLine(token.Result);
Task<string> users = GetUsers(token.Result);
users.Wait();
Console.WriteLine(users.Result);
Console.ReadLine();
}
private static async Task<string> GetUsers(string result) {
//throw new NotImplementedException();
string users = null;
string queryString = "test";
var uri = "https://graph.windows.net/{your_tenant_name}.onmicrosoft.com/users?api-version=1.6";
httpclient.DefaultRequestHeaders.Authorization = new AuthenticationHeaderValue("Bearer", result);
var getResult = await httpclient.GetAsync(uri);
if(getResult.Content != null)
{
users = await getResult.Content.ReadAsStringAsync();
}
return users;
}
private static async Task<string> GetToken()
{
AuthenticationResult result = null;
string token = null;
result = await context.AcquireTokenAsync(resource, credential);
token = result.AccessToken;
return token;
}
}
}
I am getting below error:
uMCJ9.FdttazjoKYZWP_SmC5B7Nd3kOF-jRs62WLKYovDA8qMvybLTw8yIUoihp7I00ctJGJHDoEbhbIi0XHp9Ujdq0bNPlG-L5SoE9IFSoxX3ZQOZwSf90b_nDapbHJ8KCHZUnCBOwVnYiTXtpIQfrDVqqENarrIGa_uUbiriomYiB8gVkKWe6PB-I4lsYPEmMNnnpdvIf1eV_CsTmvUA54Ch1Zdip9mxrzRqrUqsx6vUTo0riCmiCxRg7mH2DuMaEPTZuQAMwhrQM_EwNsgx1yX1VsCKkL1Gu7CV_dqW5xxYlE7NEQmorT8W6aySbiBzsUWisJNnaR8RqZzeAUlSVMKBiw
{"odata.error":{"code":"Request_BadRequest","message":{"lang":"en","value":"Invalid domain name in the request url."},"requestId":"01ab745b-8a3f-48cc-9542-0c6abcae8950","date":"2020-02-17T22:41:28"}}
r
Also ,help me in getting tenant name ( it's a name or alphanumeric id ?) ,currently i am just using below tenant name.
private const string tenant = "company.onmicrosoft.com";
I only want to use Microsoft Graph API in this code. Thanks.
i also want to know the whether this code is using Microsoft Graph or
Azure AD.
This code is using Azure AD Graph API. It works fine if the request uri is correct.You should use your tenant name, not company.onmicrosoft.com, and you must specify the api-version. So the request uri should be
var uri = "https://graph.windows.net/{your_tenant_name}.onmicrosoft.com/users?api-version=1.6";
If the tenant name is wrong, you will encounter Invalid domain name error.
I am not sure whether to use https://graph.microsoft.com or
https://graph.windows.net.
You can use either one. But the official document strongly recommend that you use Microsoft Graph instead of Azure AD Graph API to access Azure Active Directory (Azure AD) resources.
If you want to use Microsoft Graph API, just change the value of resource and request api url. The resource will be https://graph.microsoft.com. The request api url will be var uri = "https://graph.microsoft.com/v1.0/users";.
Note: Remember to grant your application the correct permissions in Azure portal and grant admin consent.

Access token validation failure Microsoft Graph API

I am building a console application in C#. I want to make some calls to Microsoft Graph API to access and edit some Excel files in my SharePoint so I can automate some processes in my Organization.
The logic of the app is simple.
I call Azure Active Directory to authenticate this console application using the clients credential flow which means we will provide a clientsID and AppKey. I took the clientsID and AppKey from Azure Active Directory > App Registrations.
Then I want to receive the access token and use this to make a GET Request to the Microsoft Graph API.
E.g https://graph.microsoft.com/v1.0/me/
But then response I get is this:
{
"error": {
"code": "InvalidAuthenticationToken",
"message": "Access token validation failure. Invalid audience.",
"innerError": {
"request-id": "0a3ec**************",
"date": "2019-10-15T13:54:33"
}
}
}
Below you will find the full code of my application with the two methods of getting the access token and calling the Graph API:
using Microsoft.IdentityModel.Clients.ActiveDirectory;
using System;
using System.Collections.Generic;
using System.Globalization;
using System.IdentityModel.Tokens;
using System.IO;
using System.Linq;
using System.Net;
using System.Net.Http;
using System.Net.Http.Headers;
using System.Text;
using System.Threading.Tasks;
using AuthenticationContext = Microsoft.IdentityModel.Clients.ActiveDirectory.AuthenticationContext;
namespace Project_Budget
{
class Program
{
private const string clientId = "14f1****************";
private const string aadInstance = "https://login.microsoftonline.com/{0}";
private const string tenant = "******.onmicrosoft.com";
private const string resource = "https://graph.windows.net";
private const string appKey = "IKV***********";
static string authority = String.Format(CultureInfo.InvariantCulture, aadInstance, tenant);
private static HttpClient httpClient = new HttpClient();
private static AuthenticationContext context = null;
private static ClientCredential credential = null;
static void Main(string[] args)
{
context = new AuthenticationContext(authority);
credential = new ClientCredential(clientId,appKey);
Task<string> token = GetToken();
token.Wait();
//Console.WriteLine(token.Result + "\n");
Task<string> graphCall = GetExcelFile(token.Result);
graphCall.Wait();
Console.WriteLine(graphCall.Result + "\n");
Console.ReadLine();
}
private static async Task<string> GetExcelFile(string result)
{
string apiJsonResult = null;
var apiCallString = "https://graph.microsoft.com/v1.0/me/";
httpClient.DefaultRequestHeaders.Authorization = new AuthenticationHeaderValue("Bearer", result);
var getResult = await httpClient.GetAsync(apiCallString);
if (getResult.Content != null)
{
apiJsonResult = await getResult.Content.ReadAsStringAsync();
}
return apiJsonResult;
}
private static async Task<string> GetToken()
{
AuthenticationResult result = null;
string token = null;
result = await context.AcquireTokenAsync(resource, credential); //authentication context object
token = result.AccessToken;
return token;
}
}
}
I have given all the access required for the app to run. Also I run the query on Graph Explorer and runs properly.
Why do I get this error on the console application?
Ideally, the resource should actually be
private const string resource = "https://graph.microsoft.com";
But you still need to select the scopes that you want to target in your application.
The way you are doing it at the moment does seem to acquire/set the relevant scopes which is done for you by Graph Explorer.
I would suggest following this quick start tutorial on how to build a dot net core console app and you should be up and running in no time.
It uses the MSAL library which works better than the ADAL library you are using in your scenario.
https://learn.microsoft.com/en-us/graph/tutorials/dotnet-core
I think the problem is with resource value you're specifying in your code.
Current Code: (This resource value https://graph.windows.net corresponds to Azure AD Graph API which is older API)
private const string resource = "https://graph.windows.net";
Try changing this to: (This resource value https://graph.microsoft.com corresponds to newer Microsoft Graph API which is the one you're calling in code that comes later var apiCallString = "https://graph.microsoft.com/v1.0/me/";)
private const string resource = "https://graph.microsoft.com";

Failing to get Team details from a c# console app while it works from Graph Explorer

I need to collect Microsoft Teams data from a C# console application using Microsoft Graph.
I am using ADAL and cloned the authentication methods from the https://github.com/microsoftgraph/console-csharp-connect-sample sample.
The only difference is that I am using an HttpClient client and not a GraphServiceClient that does not implement Teams objects.
The list of required permissions have been determined with a Fiddler trace of a request made with Graph Explorer (no need for User.Read.All or User.Write.All) :
User.Read, Mail.Send, Files.ReadWrite, User.ReadWrite, User.ReadBasic.All, Sites.ReadWrite.All, Contacts.ReadWrite, People.Read, Notes.ReadWrite.All, Tasks.ReadWrite, Mail.ReadWrite, Files.ReadWrite.All, Calendars.ReadWrite
Everything works fine with my console app as long as I am not requesting any Teams resource:
I can get the list of groups "that are Teams" with the following
request: https://graph.microsoft.com/beta/groups?$filter=resourceProvisioningOptions/any(v:v eq 'Team')&$select=id,displayname,groupTypes,resourceBehaviorOptions,resourceProvisioningOptions
I can successfully get the group details with: https://graph.microsoft.com/beta/groups/{groupId}
But when I try to get the team view of that group (which I am member of) it fails with HTTP
403-Unautorized:
https://graph.microsoft.com/beta/groups/{groupId}/team
Very
frustrating to see that this last step is working well from the
Graph Explorer
My problem is very similiar with Access Denied when querying Teams in Microsoft Graph but in my case I am member of the teams I am trying to access and the request works with Graph Explorer.
Code details:
class AuthenticationHelper
{
// The Client ID is used by the application to uniquely identify itself to the v2.0 authentication endpoint.
static string clientId = Constants.ClientId;
// The list of required permissions have been determined with a Fiddler trace of a request made with Graph Explorer
// e.g. below are the permissions Grap Explorer requires to run the sample requests
public static string[] Scopes = {
"User.Read"
, "Mail.Send"
, "Files.ReadWrite"
, "User.ReadWrite"
, "User.ReadBasic.All"
, "Sites.ReadWrite.All"
, "Contacts.ReadWrite"
, "People.Read"
, "Notes.ReadWrite.All"
, "Tasks.ReadWrite"
, "Mail.ReadWrite"
, "Files.ReadWrite.All"
, "Calendars.ReadWrite"
};
public static PublicClientApplication IdentityClientApp = new PublicClientApplication(clientId);
public static string UserToken = null;
public static DateTimeOffset Expiration;
//-----------------------------------------------------------------------------------------------------------------
public static async Task<HttpClient> GetAuthenticatedHttpClient()
{
HttpClient client = null;
try
{
client= new HttpClient(new HttpClientHandler { UseCookies = true });
var token = await GetTokenForUserAsync();
client.DefaultRequestHeaders.Authorization = new AuthenticationHeaderValue("Bearer", token);
// This header has been added to identify our sample in the Microsoft Graph service. If extracting this code for your project please remove.
client.DefaultRequestHeaders.Add("SampleID", "TestCSharp-AzureToken");
return client;
}
catch (Exception ex)
{
Debug.WriteLine("Could not create a graph client: " + ex.Message);
}
return client;
}
//-----------------------------------------------------------------------------------------------------------------
public static async Task<string> GetTokenForUserAsync()
{
AuthenticationResult authResult;
try
{
IEnumerable<IAccount> accounts = await IdentityClientApp.GetAccountsAsync();
IAccount firstAccount = accounts.FirstOrDefault();
authResult = await IdentityClientApp.AcquireTokenSilentAsync(Scopes, firstAccount);
UserToken = authResult.AccessToken;
}
catch (Exception)
{
if (UserToken == null || Expiration <= DateTimeOffset.UtcNow.AddMinutes(5))
{
authResult = await IdentityClientApp.AcquireTokenAsync(Scopes );
UserToken = authResult.AccessToken;
Expiration = authResult.ExpiresOn;
}
}
return UserToken;
}
}
//----------------------------------------------------
// Console entry point
class Program
{
//public static GraphServiceClient client;
public static HttpClient _client;
static async Task<string> GetHttpResponse(string url)
{
string responseBody = null;
_client = await AuthenticationHelper.GetAuthenticatedHttpClient();
HttpResponseMessage response = await _client.GetAsync(url);
response.EnsureSuccessStatusCode();
using (HttpContent content = response.Content)
{
responseBody = await response.Content.ReadAsStringAsync();
logger.Trace(responseBody);
}
return responseBody;
}
static void Main(string[] args)
{
// call 1 is working: list groups that "are Microsoft Teams"
string s;
string url = "https://graph.microsoft.com/beta/groups?$filter=resourceProvisioningOptions/any(v:v eq 'Team')&$select=id,displayname,groupTypes,resourceBehaviorOptions,resourceProvisioningOptions";
s = await GetHttpResponse(url);
Console.WriteLine(s);
// call 2 is working: Display details of one of these groups
Console.Write($"Enter the id of the group/teams to search for: ");
string groupId = Console.ReadLine().Trim().ToLower();
url = $"https://graph.microsoft.com/beta/groups/{groupId}";
s = await GetHttpResponse(url);
Console.WriteLine(s);
// call 3 is failing: Display the team view of this groups
url = url + "/team";
s = await GetHttpResponse(url);
Console.WriteLine(s);
}
}
You're missing a scope. You need to have Group.Read.All in order to read a Group or Team.

How can I get the links on my Facebook wall with the .NET Facebook SDK?

I'm using the SDK found here...
http://facebooksdk.net/
And the documentation seems to be severely lacking at this point.
After searching around awhile and experimenting I pieced this together.
First you'll need to set up an App at https://developers.facebook.com/ to retrieve your AppSecret and AppId.
Then you need to find your UserId. It's the id field when you visit https://graph.facebook.com/{username}
It turns out that one of the challenges is that AccessTokens expire. So you also have to write code that will retrieve a new AccessToken when the previous one expires.
And this is what I came up with...
public static class FacebookUpdates
{
private static string AppId = "00000000";
private static string AppSecret = "xxxxxxxxx";
private static string UserID = "0000000000";
private static string AccessToken;
public static dynamic GetLinks()
{
var fb = new FacebookClient();
if (string.IsNullOrEmpty(AccessToken)) AccessToken = GetAccessToken(fb); // Cache the result in static variable AccessToken
fb.AccessToken = AccessToken;
var query = string.Format("SELECT link_id, title, url FROM link WHERE owner = {0} LIMIT 5", UserID);
dynamic parameters = new ExpandoObject();
parameters.q = query;
dynamic results;
try
{
results = fb.Get("/fql", parameters);
}
catch (FacebookOAuthException)
{
AccessToken = GetAccessToken(fb); // Cache the result in static variable AccessToken
fb.AccessToken = AccessToken;
// Retry with new AccessToken
results = fb.Get("/fql", parameters);
}
return results;
}
private static string GetAccessToken(FacebookClient fb)
{
dynamic result = fb.Get("oauth/access_token", new
{
client_id = AppId,
client_secret = AppSecret,
grant_type = "client_credentials"
});
return result.access_token;
}
}
Now you can create a user control that calls GetLinks() in the codebehind (sorry this example is in VB)...
Public Shared FacebookLinks As Object = FacebookUpdates.GetLinks().data
And then the user control might look like this...
<%# OutputCache Duration="600" VaryByParam="None" %>
<%# Control Language="vb" AutoEventWireup="false" CodeBehind="FacebookUpdates.ascx.vb" Inherits="FacebookUpdates" %>
<%For Each Link In FacebookLinks%>
<p><%= Link.title%></p>
<%Next%>
If you're not writing an ASP.NET application or the like, you don't need to write code. Try just using Windows PowerShell and http://facebookpsmodule.codeplex.com.

Categories

Resources