Uploading File Attachments to Yammer

Working with attachments to message postings in Yammer has been something that I’ve had a few questions on over time and just recently had a chance to take a look at it.  I decided to blog about it only because there appears to be such paucity of information around folks that have actually done this successfully.  Unfortunately the Yammer developer documentation is skimpier than ever in providing you useful information and examples for getting this done.  So…I’ve again updated my original .NET library for working with Yammer that I described here:  http://blogs.technet.com/b/speschka/archive/2013/10/05/using-the-yammer-api-in-a-net-client-application.aspx.  I’ve modified the MakePostRequest method so that you can pass in a local file name and content type, and it will upload the file to Yammer and add it as an attachment to a message posting.  All this for the unbelievably low price of “free”.  🙂


So to include an attachment with your post in Yammer now, calling the MakePostRequest method looks something like this:

response = MakePostRequest(msg, messageUrl + “.json”, accessToken, “”, “C:\\Users\\speschka\\Desktop\\Yammer Sales Handbook.docx”, “application/vnd.openxmlformats-officedocument.wordprocessingml.document”);

In this case I got the long funky attachment content type from looking at a Fiddler trace while I was figuring this out.  In practice, I haven’t really determined how important it is to get this correct at all.  It doesn’t block the file upload itself, which uses a multipart/form-data content type for the upload.  In terms of getting it to work, what I’ve found the easiest to implement is using the pending attachment method that Yammer describes in their documentation.  This allows me to operate on the file upload(s) separately from posting to a group or whatever.  When you do a pending attachment upload you send the file up to Yammer, and as you might expect, it sends you a big chunk of JSON back to tell you what it did with it.  As with other features in my .NET examples, I wrote up some classes to deserialize the data that Yammer sends back so you can easily refer to properties of the upload.  In this case, when you upload a pending attachment Yammer sends you back an ID, and then you need to include that ID when you make your message post.  Here’s a brief example of adding that to the body that I’m going to post to Yammer:

//upload the file so we can get the attachment ID

YammerFileUpload ya = UploadFile(attachmentName, authHeader, uploadContentType);

//add the attachment info to the form post message body

postBody += “&pending_attachment1=” + ya.id;

The other perfectly delicious part to this whole puzzle is the URL where you upload your files. This part I found NO WHERE in the Yammer documentation, so Fiddler to the rescue again.  Turns out you can send a pending upload to https://files.yammer.com/v2/files and then just add your access token to the query string, i.e. ?access_token=blah.

In any case, this should be enough to get you uploading files to Yammer in most cases, and serve as a code example for other scenarios not covered here (like upload multiple files).  I’ve broken the file upload process itself into a separate method to make it more easily extendible should you need to do so.  Enjoy!

 

 

You can download the attachment here:

Using Yammer Open Graph in .NET – Part 1

I’ve already written about using the Yammer APIs from a .NET client application here:  http://blogs.technet.com/b/speschka/archive/2013/10/05/using-the-yammer-api-in-a-net-client-application.aspx.  This post is the next logical step in that journey, which is working with Yammer Open Graph items from .NET.  A little background is probably in order though, like what is this Yammer Open Graph thing and how or why would I use it?  Well, the Open Graph object in Yammer is in many ways kind of analogous to a placeholder representing some URL-addressable content.  For example, it could represent a web site, a document in SharePoint, or anything else that you can refer to by Url.

What’s cool about Open Graph objects (OGO) is that you can have a full blown discussion associated with them, just like you would a Yammer group.  You can also Follow an OGO so you can be alerted to updates on it, and you can Share an OGO too.  Within the discussion area for an OGO you can also create all of your typical Yammer content – uploads, polls, praises, events and announcements.  Probably the biggest difference between an OGO and a Yammer group is that there isn’t the same notion of security – there aren’t public and private OGOs and you don’t join them: you just choose to follow them or not.  Creating OGO also creates an entry in the user’s activity stream as well, so they will see that when going to the Yammer home page.

From a data standpoint, what’s also interesting about OGO is that they provide a much richer data structure than a typical Yammer group.  An OGO allows you to associate the Url I mentioned earlier, as well as an Actor (kind of like who owns this OGO); the OGO is then linked to the Actor’s profile in Yammer.  Each OG write activity also includes an action – like Create, etc; in practice I’ve found that the Create and Update actions are the only ones that consistently do “something”.  You can also associate one or more users with an Activity, which really just means that you can choose to notify them when you apply your OGO action.  In addition to the URL you can also provide a title, description and image for the OGO.

So with that bit of background on what an OGO is, let’s talk about how one can actually work with it in a .NET application.  First, as I mentioned above, you want to start with the the code I included in my original post on using Yammer with .NET that I referenced above; all of my Yammer code just continues to build off of that.  I’ve added some new classes to serialize and deserialize the data for OGO in the sample application, and I’ve added those classes to the attachment for this post.  The object model I built for OGO then looks something like this:

– Open Graph Item

    – Activity

        – Actor

            – Name

            – Email

        – Action

        – Object

            – Url

            – Type (I use document, but it can be page, place, person, department, team, project, folder, file, document, image, audio, video, or company)

            – Title

            – Image

            – Description

        – Message

        – Private

        – Users (this is a list of the Actor type above)

To actually create a new OGO then I just create an instance of my OGO .NET class that I described above and start setting properties.

YammerGraphObject go = new YammerGraphObject();

go.Activity.Actor = new YammerActor(“Steve Peschka”, “speschka@yammo.onmicrosoft.com”);
go.Activity.Message = “This is for the new vacation policy document.”;  
go.Activity.Action = “create”;

So I’ve created the object I’m going to send to Yammer and plugged in the Actor (me!) who will be the contact for it.  Now I’m going to add a couple of other people that I want to notify about the new OGO:

go.Activity.Users.Add(new YammerActor(“Anne Wallace”, “annew@yammo.onmicrosoft.com”));
go.Activity.Users.Add(new YammerActor(“Garth Fort”, “garthf@yammo.onmicrosoft.com”));

The next thing I’m going to do is really create the “meat” of the OGO – the content – and then associate it with my OGO:

YammerGraphObjectInstance jo = new YammerGraphObjectInstance();

jo.Url = “https://www.foo.com/vacation.docx”;  
jo.Title = “Vacation Policy”;  
jo.Description = “This document details our corporate vacation policy.”;
jo.Image = “http://www.travelofix.com/wp-content/uploads/2012/03/vacation.jpg”;
jo.Type = “document”;

go.Activity.Object = jo;

Now the rest of it is going to be very similar to what I showed in my previous posts.  To create the OGO, I need to do a POST to the Yammer REST endpoint.  That means I need to create some forms data to send to the endpoint out of my OGO.  Fortunately, in my class I override the ToString() method so you can just call that to create your forms data then post it up to Yammer.  I also get to reuse the same MakePostRequest method that I created in my original .NET classes for working with Yammer…like this:

string postData = go.ToString();
response = MakePostRequest(postData, graphPostUrl, accessToken, “application/json”);

The Url that I’m posting to – “graphPostUrl” – is covered in the Yammer Open Graph documentation, which can be found at http://developer.yammer.com/opengraph/.  For OGO that endpoint is https://www.yammer.com/api/v1/activity.json. 


With that, you have it – you’ve just created a new Yammer Open Graph item.  In Part 2 I’ll explain how to read and create new postings to the newsfeed for the OGO.

See Part 2 Here:  http://blogs.technet.com/b/speschka/archive/2014/05/29/using-yammer-open-graph-in-net-part-2.aspx

You can download the attachment here:

Using Yammer Open Graph in .NET – Part 2

In the first part of this series – http://blogs.technet.com/b/speschka/archive/2014/05/29/using-yammer-open-graph-in-net.aspx – I described how to create a Yammer Open Graph object (OGO).  In this posting I’ll explain how to create a new post in the newsfeed for the OGO, as well as read all messages that have been posted to that OGO.  Just like the previous post, you should always begin by downloading the code from my original post on using the Yammer APIs from a .NET client application:  http://blogs.technet.com/b/speschka/archive/2013/10/05/using-the-yammer-api-in-a-net-client-application.aspx.  Make sure you also visit part 1 of this mini series and download the class attached to the post that is used to serialize and deserialize OGO items in .NET.

Now, with all that in hand, let’s talk about creating and reading messages for an OGO.  Fortunately, if you’ve used the other code in my original post on the Yammer APIs in .NET, it will look pretty similar.  Before we get into actually creating or reading messages though, there is one fundamental task that you have to do in both cases – you need the OGO ID.  The reason why is that we’re delving into the somewhat, um, undocumented world of Yammer REST APIs and OpenGraph.  Now like anything, there can be a variety of ways that you get the OGO ID you need.  Arguably the best place to do it is when you actually create the OGO; you will get a JSON string in response.  The JSON that you get back can be deserialized into the YammerGraphObjectItem class that I posted in part 1 of this series.  When you look at it you’ll see that it has an object_id property; what I’ve done in some cases is just taken that value after I create the item and write it to a database so I can use it later (for cases just like this).  If you didn’t do that, or that isn’t feasible for some reason, then you need to grab it some other way.  Your choices for doing so are a little less than awesome however.  As a practical matter, I’ve only found two ways of digging up the object ID after the fact that work reliably – using Yammer search or posting an update to the original OGO.  Let’s look at each of those options in a little more detail.

To use search you can use the code I posted in yet another post about using the Yammer API for integrating search results here:  http://blogs.technet.com/b/speschka/archive/2014/03/11/integrating-yammer-and-sharepoint-2013-search-results.aspx and here: http://blogs.technet.com/b/speschka/archive/2014/03/12/enhancing-the-yammer-search-results-and-messages-samples-and-deserialization.aspx (yes, I AM starting to realize that this whole unstructured data thing can be a real PITA to use when you’re just trying to accomplish a basic task).

Once you have that code, you can go ahead and query Yammer.  The question you may have is “what do I search for”?  Ha, 🙂 the answer is you search for the Url associated with your OGO.  If you’re using the sample code I posted previously, your code to search Yammer would look something like this:

response = MakeGetRequest(searchUrl + “?search=” + Url + “&match=any-exact”, accessToken);
YammerSearchResults ysr = YammerSearchResults.GetInstanceFromJson(response);

where “Url” in the first line of code is the Url associated with your OGO (you should know all about what the accessToken is and how to get it from my other posts on this topic).  Now you may or may not get back search results, and this is another pain point.  If ALL you’ve done is create an OGO, in my experience the OGO will not be returned in the search results.  However, if you have at least ONE newsfeed item created for your OGO then you WILL get it back in search results.  If you do get search results back, then you need to do a little digging with LINQ to get the object ID you need.  Here’s the code I use for that:

if ((ysr != null) && (ysr.Messages.Messages.Count > 0))
{
    var msgs = from YammerMessage ym in ysr.Messages.Messages
        where ym.Attachments.Count > 0 &&
        ym.Attachments[0].WebUrl == Url
        select ym;

    List<YammerMessage> yMsgs = msgs.ToList<YammerMessage>();

    if (yMsgs.Count > 0)
    {
        gi = new YammerGraphObjectItem();
        gi.object_id = yMsgs[0].Attachments[0].RecordID;
    }
}

So if I found the item using search, then I look for an item that has an attachment where the WebUrl property matches the Url of my OGO.  Each attachment has a RecordID property, and for an OGO it’s the object ID.  So I can grab that piece of data from there and then use it to work with my OGOs.  If I didn’t get any search results back, then the only way I found to get the object ID again is just to create a “fake” update to the OGO.  When you do that, just like when you create an OGO, it returns the object ID.  Just like when you create it, you need the Url associated with the OGO in order to update it.  Here’s some code showing a minimalistic “fake” update (I just keep adding myself as a follower to the OGO):

YammerGraphObject go = new YammerGraphObject();

go.Activity.Action = “follow”;
go.Activity.Actor = new YammerActor(“Steve Peschka”, “speschka@yammo.onmicrosoft.com”);
go.Activity.Private = true;

YammerGraphObjectInstance jo = new YammerGraphObjectInstance();
jo.Url = Url;
go.Activity.Object = jo;

string postData = go.ToString();
response = MakePostRequest(postData, graphPostUrl, accessToken, “application/json”);

gi = JsonConvert.DeserializeObject<YammerGraphObjectItem>(response);

I set the Private property of the Activity to true so that it won’t bother trying to email anyone, which I don’t want to happen since it’s a “fake” update.  Otherwise, I plug the OGO Url into the Url property, convert all that object stuff to a string that the REST API understands, and then send in my POST request to do the update.  I take the string I get back and use the NewtonSoft JSON library to convert it to an instance of a YammerGraphObjectItem so I can pull the object_id property out of there.

Whew!  That’s a lot of background information, but now you know how to go get that OGO ID if you weren’t able to capture it when it was created.  Now that you have the ID, everything is downhill from here.  So, going back to our original problem statement, let’s work on creating a new post in the discussion of the OGO.  The good news is, it’s pretty simple:

string myMessage = “This is a message from my OGO!”;

string msg = “body=” + myMessage + “&attached_objects[]=open_graph_object:” +
    gi.object_id + “&skip_body_notifications=true”;

string response = MakePostRequest(msg, messageUrl + “.json”, accessToken);

if (!string.IsNullOrEmpty(response))
{
    //it worked!  You can look at the return message using code like this:
    //YammerGraphMessages newMsg = YammerGraphMessages.GetInstanceFromJson(response);
}

A couple of things to point out here:  first, the gi.object_id above is what I got from getting my OGO ID using one of the two methods I described earlier in this post.  I just created a simple method that looks for it in search, and if it doesn’t find it there then it does a “fake” update to get the ID and returns the YammerObjectGraphItem as shown in the code above.  Second, the “messageUrl” you see in the MakePostRequest method is the same exact Url that we use for creating new messages in groups.  You will find this in the Yammer Developer docs (developer.yammer.com) or of course in the sample code I’ve posted previously.  For completeness the Url is https://www.yammer.com/api/v1/messages.&nbsp; See – not bad at all!

Okay, now let’s get the messages that have been posted to my OGO.  Doing that is also very similar to getting them for a Yammer group; here’s some sample code:

string response = MakeGetRequest(messageUrl + “/open_graph_objects/” + gi.object_id + “.json”, accessToken);

YammerGraphMessages yms = YammerGraphMessages.GetInstanceFromJson(response);

foreach (YammerMessage ym in yms.Messages)
{
    //do whatever you want with your messages…for example get the text of the message:
    //ym.MessageContent.PlainText
}

Here are the some points about this code:  first, like above, you’ll notice I’m using the gi.object_id to get the object ID of the OGO.  The second thing is that I’m using the super secret and currently undocumented Url path to get to the OGO item, which you see I append to the messageUrl:  “/open_graph_objects/”.  I then append the ID of the OGO I want and away we go – again, extremely simple at that point.

With that I will conclude this two part series.  You learned how to use .NET to create an Open Graph object in Yammer, how to find the ID of your Open Graph object if you didn’t save it when you created the object, and how to create new items in the newsfeed for the OGO as well as read items in the newsfeed for the OGO.  Hope you find this helpful!

 

Integrating Yammer and SharePoint 2013 Search Results

This post is in response to a question I get pretty frequently when talking about Yammer.  The question that many folks want to know is “how can I crawl my Yammer content from SharePoint?”  Well, unfortunately you can’t, and I have no trick up my sleeve to show you otherwise today to say otherwise.  However, that doesn’t mean that you can’t have a nice consolidated set of search results that includes content from both Yammer and SharePoint, and that’s the point of today’s post.  By the way, this code sample is based on a demo that I showed at the 2014 SharePoint Conference, so for those of you that were looking for some of that code, here you go.

As I’ve mentioned many times when talking to folks about Yammer development, there is a number of REST endpoints for your programming pleasure.  After mentioning this in about three different venues I decided it would just be easier to write something up to demonstrate and that’s exactly what I did.  What we’ll walk through today is the specific implementation that I used for this case.  So to begin with, let’s look at my out of the box search results page when I do a search for products.  Because of the incredibly bad way in which this blog site deals with pictures, I’m just going to give you a link to the picture here; CTRL + Click to open it in a new browser tab:  https://onedrive.live.com/?cid=96D1F7C6A8655C41&id=96D1F7C6A8655C41%217884&v=3&mkt=en-US#cid=96D1F7C6A8655C41&id=96D1F7C6A8655C41%217885&v=3.

Okay, so I’ve previously posted about using the Yammer REST endpoints from .NET.  For this example I simply built out from that sample code, as I’ve been suggesting all of you do when you find something else you need to code for that it does not cover.  You can find that original post and sample code at http://blogs.technet.com/b/speschka/archive/2013/10/05/using-the-yammer-api-in-a-net-client-application.aspx.  With that in hand, I decided to write my own REST endpoint for this example.  So why did I decide to do that?

  • I wanted to demonstrate the use of the new CORS support in WebAPI 2.1.  This allows me to define what hosts can make cross-domain calls into my REST endpoint to query for Yammer data.  That gives me an additional layer of security, plus it now lets me make those client-side cross domain calls to my endpoint.
  • I wanted to have something that delivered HTML as the result.  That allows me to ensure that anyone querying Yammer gets the same exact user experience no matter what application they are using.
  • I wanted to have something that could be reused in many different applications – could be other web apps, could be Windows 8 apps, could be mobile apps, whatever – with a simple REST endpoint there’s no end to the possible reuse.
  • In my scenario, I wanted to be able to issue queries against Yammer even for people that didn’t have Yammer accounts.  So in this scenario what I did was to use a service account to make all the query requests.  By “service account”, I just mean I created an account in Yammer whose only purpose in life is to provided me with an access token that I can use to programmatically read or write content with Yammer.  For more details about access tokens in Yammer please see my initial post on this topic that I linked to above.

So with that being said, I started out by adding all the custom classes for serializing Yammer JSON data to my project, along with my code for making GET and POST requests to Yammer (as described in the original blog post).

The next thing I did was build a little console app to test out sending in a query to Yammer and getting back a set of search results.  I do that to a) get down the process for issuing the query and b) getting the JSON back so I can build out a new class into which I can serialize the set of search results.  I’ve attached some source code to this posting, so you can find the YammerSearchResults class and see how I incorporated that into the project.  I’ll also look at it in a little more detail later in this post.

Once I had all of that foundational pieces in place, I created my new WebAPI endpoint.  There are many places out on the web where you can get your WebAPI info; for me I used the example from Mike Wasson here as my starting point for learning everything I needed for this project:  http://www.asp.net/web-api/overview/security/enabling-cross-origin-requests-in-web-api.  With my new WebAPI controller class created, I next enabled CORS support in my project by adding this to the WebApiConfig.cs file (in the App_Start folder)

//enable cross site requests

config.EnableCors();

Now that my project supports CORS, I need to flesh out the where and how for supporting it.  To do that I added this attribute to the WebAPI controller class:

 

[EnableCors(origins: http://localhost:1629,https://saml.vbtoys.com,https://sps2&#8221;, headers: “*”, methods: “*”)]

 

So the main things worth pointing out here are that I added a list of hosts that I trust in the origins attribute.  The “localhost:1629” reference is in there because that’s the web dev server that Visual Studio created for a test web application project I created.  I used that to test the functionality of the REST endpoint in just a standard HTML page before I ever tried to incorporate it into SharePoint.  The saml.vbtoys.com and sps2 hosts are ones that I use for SharePoint provider-hosted apps and SharePoint respectively.  So that allows me to use it both in my provider-hosted apps as well as SharePoint itself.  Finally the headers and methods attributes are configured to allow all headers and methods through.

The next thing I did was create the method in my WebAPI controller that I use to execute the query against Yammer and return results.  The method signature for it looks like this:

 

// GET api/<controller>?search=steve%20peschka

public HttpResponseMessage Get(string search)

 

So as you can see, I’m going to take a string as input – my search string – and I’m going to return an HttpResponseMessage.  Inside my method, the code should look quite familiar if you have seen my original post on Yammer dev with .NET – I’m just using my MakeGetRequest and GetInstanceFromJson methods:

 

List<SearchResult> finds = new List<SearchResult>();

string response = YammerREST.MakeGetRequest(searchUrl + “?search=” + search, accessToken);

YammerSearchResults ysr = YammerSearchResults.GetInstanceFromJson(response);

The “searchUrl” is just the standard Yammer REST endpoint for search, and the “accessToken” is the access token I got for my Yammer service account.  Okay, so I got my set of search results back, but one of the first things I noticed is that the search results that are returned include very little information about the user – basically just a Yammer User ID.  Of course, I not only wanted to show the author information, but I also wanted to show the picture of the Yammer user.  This unfortunately does require making another call out to REST to get this information.  In my particular scenario, I only wanted to show the top 3 results from Yammer, so what I did was simply enumerate through the results and get that user information for each one. 

One of the nice things I was able to do with the YammerSearchResults class that I created for this is I was able to reuse the YammerMessages class that I had created in my original posting.  So my search results include a collection of messages (where each message is a message that matches the search criteria), so I can simply use that code from before to enumerate through the results.  This is what that looks like:

foreach(YammerMessage ym in ysr.Messages.Messages)

{

//get the Yammer User that posted each message so we can pull in their picture url

string userUrl = oneUserUrl.Replace(“[:id]”, ym.SenderID);

response = YammerREST.MakeGetRequest(userUrl, accessToken);

         YammerUser yu = YammerUser.GetInstanceFromJson(response);

 

//some other stuff here I’ll describe next

}

While I’m enumerating through the messages in the search results, I go ahead and make another call out to get the information I want for each user.  Again, I’m able to use the MakeGetRequest and GetInstanceFromJson methods I described in my original post.  With that in hand, I can go ahead and create the dataset I’m going to use to generate the HTML of search results.  In order to do that, I created a local class definition in my controller and a List<> of that class type.  With those pieces in place I can create one record for each search result that includes both the search result information as well as the user information.  My List<> is called “finds” and the code for pulling this all together looks like this (and goes in the enumeration loop above, where it says “some other stuff I’ll describe next”):

                   

//add a new search results

finds.Add(new SearchResult(yu.FullName, yu.WebUrl, yu.FirstName,

ym.MessageContent.RichText, yu.PhotoUrl, DateTime.Parse(ym.CreatedAt),

ym.WebUrl));

 

iCount += 1;

                   

if (iCount == 3)

break;

 

As you can see, I’m plugging in the message from the search result with “ym.MessageContent.RichText”, and all of the rest of the fields are information about the user.  Now that I have my list of search results, the rest of the WebAPI controller method is kind of boring.  I just create a big long string in a StringBuilder instance, I add some style info and then I add HTML for each search result.  I then take the results of the big long string and stick it in an HttpResponseMessage to return, like this:

new HttpResponseMessage()

{

                Content = new StringContent(results),

                StatusCode = System.Net.HttpStatusCode.OK

};

Shaboom, and there you go.  Now, perhaps the best part of all of this is on the SharePoint side.  What I decided to do there was to create a new Search vertical.  All that really means is that I added a new search results page to the Pages library in an Enterprise Search site collection.  You then add a new search navigation item in the search settings for the site, and you point that navigation item at the page you added.  Then you go and customize the page to return whatever search results you want.  I’m not covering this in super detail here obviously because it’s not really on point with this topic, but it should be relatively easy to find on the web.  If not, say so in the comments and we can always cover that in another blog post.

But…I created my new search vertical and then the changes I made to it were pretty simple.  First, I just plugged in the out of the box search results web parts onto it.  Then, I added an out of the box script editor web part above those.  This is really the beauty of this solution to me – I didn’t have to create anything custom in SharePoint at all.  Since it’s all just client side script and code, I didn’t write a custom web part for SharePoint – I just created my script and pasted it into the out of the box web part.  To complete this story, I would LOVE to paste in here the HTML and javascript that I use in the script editor web part to make this all work.  However, it is completely unusable when pasted into the awesome blog editing tools on this site <sarcasm>.  So instead you’ll have to get the attachment to see it – just look for the text file called SharePoint Script Part Snippet.txt.

Now, with all that done, you can click here to see what the final results look here:

https://onedrive.live.com/?gologin=1&mkt=en-US#cid=96D1F7C6A8655C41&id=96D1F7C6A8655C41%217884&v=3

Note that in my particular case I chose to only show search results that were from messages.  You could have just as easily shown search results for people, files, etc.  Also I configured links on the search results so that you can click on any one of them to view the conversation in Yammer.  I also included a link with a “more search results” kind of functionality, and when you click on it a new browser tab opens with the search results page in Yammer, using the query terms that were entered on the page.  So it lets you slide over very easily into Yammer to get the full search experience that it provides too.

Also – as a side note – someone else at SPC mentioned that they took a similar approach but chose to return the results in an OpenSearch compliant Xml format so that it could be added as a federated search result.  That didn’t fit my particular scenario, but it’s an interesting take on things so I’m including it here for your consideration.  Nice work person that made this comment.  🙂  

You can download the attachment here:

Enhancing the Yammer Search Results and Messages Samples and Deserialization

Just as kind of strange coincidence, I was in working on some Yammer message JSON goo and realized that there were actually a couple of other important data elements that comes down in the JSON payload when you get a collection of messages from REST.  That includes both querying for messages directly, as well as getting a collection back in search results.  In addition to the messages themselves, there’s also some info that can be used with the realtime API, as well as what it calls “references”.  The beauty of the references content is that it includes information about each user referenced in the collection of messages that are returned.  I missed this the first time around, just one of the dangers at trying to stare at about 4k of JSON and hoping to extract everything useful out of it.  Mucho love here to Fiddler and it’s JSON parser for snapping me out of it.  🙂

If you read the blog post on integrating search results here:  http://blogs.technet.com/b/speschka/archive/2014/03/11/integrating-yammer-and-sharepoint-2013-search-results.aspx – you saw that when I got a list of search results back, I actually made a second call back to Yammer for each one to get information about the user associated with the message.  By pulling in the references information I no longer need to make those additional round trips now.

So there are two things I wanted to briefly touch on here.  First, I’ve updated the definition of the YammerMessages class; the JSON returned from Yammer is serialized into this class.  I’ve now added additional properties into which the realtime and references information is hydrated when you call GetInstanceFromJSON.  I’ve attached the updated class to this posting so you can download it and use it in your projects and then you will “automatically” get this new goodness.  The second thing is I rewrote the section of code in the search WebAPI service I had so that it uses that References collection now instead of calling back to Yammer.  I’m just going to paste in here the chunk of code from that solution that has changed; if you are going to build on that example I linked to above just plug in this new code:

foreach (YammerMessage ym in ysr.Messages.Messages)

{

                    #region used this method to get the user info by querying Yammer again

                   ////get the Yammer User that posted each message so we can pull in

                   ////their picture url

                   //string userUrl = oneUserUrl.Replace(“[:id]”, ym.SenderID);

                   //response = YammerREST.MakeGetRequest(userUrl, accessToken);

                   //YammerUser yu = YammerUser.GetInstanceFromJson(response);

                   #endregion

                   var yUser = from YammerMessagesReferences yr in ysr.Messages.References

                               where ym.SenderID == yr.ID

                               select yr;

                   YammerMessagesReferences ymr = yUser.First<YammerMessagesReferences>();

                   //add a new search results

                   //finds.Add(new SearchResult(yu.FullName, yu.WebUrl, yu.FirstName, ym.MessageContent.RichText, yu.PhotoUrl, DateTime.Parse(ym.CreatedAt), ym.WebUrl));

                    finds.Add(new SearchResult(ymr.FullName, ymr.WebUrl, ymr.UserName, ym.MessageContent.RichText, ymr.MugshotUrl, DateTime.Parse(ym.CreatedAt), ym.WebUrl));

                    iCount += 1;

                   if (iCount == 3)

                       break;

}

You can download the attachment here:

Some More Advice When Using the Yammer APIs with .NET

I wrote this post a little while back here: http://blogs.technet.com/b/speschka/archive/2013/10/05/using-the-yammer-api-in-a-net-client-application.aspx, and I think I’m going to have to fall on the sword just a bit because I have some code in there that I think has people kind of turned sideways.  I wanted to briefly cover the concept of access tokens, and how you should get them.

Now…in the code I posted the first thing I did was programmatically go through the process of obtaining an access token.  In short, I simulated what would happen if you had a browser based application; in that case the user would be prompted with an OAuth dialog that says hey, do you want to let this application access Yammer on your behalf.  When I first started putting this together I was just learning along the way so threw the code in there just to move past this step and get into “the good stuff”.  In retrospect, it *may* have been a mistake to include that code.  It’s interesting how many people have had issues with it, partially because it’s a little complicated to wrap your head around the implementation, and partially because Yammer changed the login process after the code had initially been posted.

So with that backdrop, let me say this:  if you are getting access tokens for your application, as a general rule you should get them manually and use a service account (preferred), or you should go through the browser and get a proper OAuth acceptance from your user.  I know there are use cases where you will want to get this access token programmatically, I would just say that doing so should be a well-understood exception, not the rule.  As I tried to point out in the post, there are inherent dangers with both approaches.  If you use an access token, it’s good forever so if someone gets their hands on it, then you have potential for data leakage (until you can suspend the account it’s associated with).  If you get the access token programmatically, then you need to have access to the user’s username and password.  That’s even worse in my opinion, because generally that could grant you access to many other things besides just Yammer.  Hopefully no one is regularly storing usernames and passwords around anymore anyways, it’s just a terrible habit to be in.

So the net here is skip that part of the code unless you have a strong business case to do so.  Use a service account (just a Yammer account that you create for your applications) whenever possible.  When you need get per user data your first option should be to have the user OK the access and get your access token that way.  Hopefully this all makes sense, and sorry for those of you who have labored with the code to work around it.  Keep it around – it has a place – but just not in the general case.

Using Impersonation with the Yammer APIs

One of the things that isn’t particularly well known about the Yammer APIs is that its OAuth infrastructure does support a form of impersonation (at least that’s how I describe it).  This can be extraordinarily useful when you need to access data on behalf of another user and do so within the constraints of the content they have rights to see, as well as to create content as if it was posted by them.  You’ll find a small amount of documentation about this on the Yammer developer site at http://developer.yammer.com/authentication near the bottom of the page.  In short, what you need in order to do this is a verified admin account, and then that account can get an access token on behalf of another user; all you need to know is that user’s Yammer ID.

I covered the details on getting an access token for an account in one of my initial posts on Yammer here: http://blogs.technet.com/b/speschka/archive/2013/10/05/using-the-yammer-api-in-a-net-client-application.aspx. This particular post also resulted in some problems for folks trying to obtain access tokens by programmatically going through the OAuth app trust process that a user would click through in a browser.  I further posted about some of the ramifications for doing this and suggested the preferred way of dealing with access tokens here: http://blogs.technet.com/b/speschka/archive/2014/02/06/some-more-advice-when-using-the-yammer-apis-with-net.aspx.  This post sort of ties the concepts in the previous two together in that a) it relies up on using a single service account to work with data in Yammer and b) it uses one of the built in Yammer features to obtain an impersonation access token.  So let’s take a look at this in a little more detail.

As I mentioned above, you’ll want to start by using a service account, and that service account needs to be an verified admin in your Yammer network.  Once you have created and configured the account, I recommend using the methods I described in my previous posts to manually obtain an access token for it.  Once you have that, the rest of the process is relatively straightforward.  Let’s suppose for the sake of illustration that you want to add a user to a Yammer group (not something we recommend doing by the way – we actually discourage it, but it’s a simple API so is good for demonstration purposes).  Assume the user has an ID of 150493 and we want to add him to a Yammer group with an ID of 123456.  At a high level we’re going to do this:

 

1)  Make a request to the tokens REST endpoint and pass to it the ID of the user you want to get an access token for, the client ID of your application, and the access token of your verified admin.

2) Take the JSON you get back and extract from it the access token for the user. 

3)  Make a POST request to the JSON endpoint to add the user to a group; send along the access token for the user that is being added.

 

See, not too bad.  Here’s what the code actually looks like, I’ll add a couple of comments below.

string tokenInfo = MakeGetRequest(“https://www.yammer.com/api/v1/oauth/tokens.json?user_id=150493&consumer_key=&#8221; + YOUR_CLIENT_ID, yourVerifiedAdminAccessToken);
List<YammerToken> tokens = JsonConvert.DeserializeObject<List<YammerToken>>(tokenInfo);

if (tokens.Count > 0)
{
     //success returns an empty string
     string addToGroupResponse = MakePostRequest(“”, “https://www.yammer.com/api/v1/group_memberships.json?group_id=123456&#8221;, tokens[0].AccessToken);
}

Now a couple of things for discussion.  First, this code uses the techniques that I describe in my original Yammer .NET post here: http://blogs.technet.com/b/speschka/archive/2013/10/05/using-the-yammer-api-in-a-net-client-application.aspx.  For example – how do you get the user ID for a person?  Well I describe some options in that first post; in this case I have a very small network so I had made a call to get all of the users in my network and then I found the one I wanted to use.  When you look at that post you’ll see that I serialize the data for users into an object that includes the ID so in my actual code I can just use something like YammerUser.UserID.

The next thing worth noting is that I’m again using the simplified methods I described in that post to work with the REST endpoints:  MakeGetRequest and MakePostRequest.  If you want more information on those then check out that first posting.  Finally, I used the same methodology I described in that original post to serialize the JSON data that I got from requesting the access token for the user into a .NET object.  That’s where the List<YammerToken> call came from.  This is a new call that I added serialization support for in this post so I’ve attached the class I used for serialization to this posting.

So, as you see, once you have the background and the code from the first Yammer .NET posting I did, the actual process for doing this kind of impersonation with the Yammer REST endpoints is pretty straightforward and easy.  From searching to retrieving content, having the ability to impersonate another user can be quite valuable when building your Yammer applications.