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.

 

 

Using Azure Active Directory for Single Sign On with Yammer

This is a pretty interesting topic that I think is going to be gaining momentum moving forward.  As many of you know, when you create a new o365 tenant you automatically get an Azure Active Directory (AAD) instance provisioned for you at the same time.  For those of you who have purchased an Enterprise o365 tenant, you now also receive a Yammer network with it (NOTE:  I’m not a licensing guy, I can’t answer licensing questions, and there are different flavors of tenants and licenses that I can’t and won’t ever be able to explain).  If you’re familiar with Yammer, you also know that today it also has its own user directory.  We typically will set up directory synchronization from an on premises Active Directory to Yammer to keep the directory up to date.  For authentication though, if you want single sign on we usually suggest using ADFS if you’re a Windows shop.  Going forward though, Azure Active Directory is another alternative you can use.

The main reasons why you would want to use AAD instead of ADFS is one of time and money.  If you use ADFS, then you are responsible for building out a highly-available ADFS infrastructure.  That will mean 2 or more servers of any number of things:  ADFS, ADFS proxy, reverse proxy, firewall, and/or load balancer.  That can really add up when you think about the number of servers involved, the cost to acquire OS licenses, and the cost to patch, maintain and operate them.  On the other hand, AAD takes care of all of that infrastructure for you, and is included with any o365 tenant.  It’s free up to about 500k users I think (again – I’m not a licensing guy so check if you are concerned).  You can also just create an AAD instance with a regular Azure subscription.

So if you are convinced of the goodness of AAD for this purpose, the good news is getting it set up is relatively straight-forward.  The steps you will want to do are:

  1. Add your on premise domain to your o365 subscription.
    1. Go to the o365 Admin pages and click on Domains

    2. Click on Add a Domain

    3. Follow the wizard to add your on premises domain to your o365 tenant

  2. Set up directory synchronization between your on premises Active Directory and o365

    1. Go to the o365 admin pages and click on Users and Groups, then AD synchronization set up

    2. Install AAD module for PowerShell

    3. Activate synchronization in tenant

    4. Install the dirsync tool and run

    5. After dirsync is completed, make at least one on premise user a Global Admin in o365

  3. Run the following PowerShell script using the AAD PS module:

Connect-MsolService
Import-Module MSOnlineExtended -Force
$replyUrl = New-MsolServicePrincipalAddresses –Address “https://saml.yammer.com/sp/ACS.saml2
New-MsolServicePrincipal –ServicePrincipalNames @(“yammer/sso”) -DisplayName “Yammer Federation” -Addresses $replyUrl

You should see output afterwards that looks like this:

  4.  Capture the AppPrincipalID from the output and provide that along with your domain name (i.e. contoso.com) to Yammer support, along with the rest of the documentation they request with the SSO checklist they have at http://success.yammer.com/integrations/single-sign-on/.

You should be good to go at that point, and can do all of your authentication completely in the cloud using AAD.

What You Must Know if Using Azure Active Directory for SSO with Yammer

I posted a while back regarding how to configure Yammer and Azure Active Directory (AAD) together so that you could use it for single sign on to your Yammer network – http://blogs.technet.com/b/speschka/archive/2014/01/08/using-azure-active-directory-for-single-sign-on-with-yammer.aspx.  There is an important part of the configuration that you need to be aware of however.  Like all identity providers, AAD uses a token signing certificate so that you know when you get a token that is signed with it, you can trust where it came from.  Also, like all good identity providers, AAD will periodically roll over it’s token signing certificate and issue a new one.  The token signing certificates that AAD uses are currently good for two years.  So here’s the problem – what happens when that token signing certificate expires and a new one is rolled into place?  Unfortunately, if you do nothing, your users will no longer be able to authenticate successfully into Yammer because they do not automatically track the expiration of token signing certificates.  That is the point of this post.

So you have the bad news…and…I don’t really have a lot of good news.  This certificate management may change in the future, I couldn’t really say for sure right now.  It will certainly help if you let your Yammer customer service rep know that this is important to you if it is.  In the meantime, I’ve written another little tool to try and help you out as best we can.  If you provide your AAD instance name, it will download the token signing certificate for your tenant and then let you know what the expiration is.  It can also add a Task reminder to Outlook to remind you as the expiration date is approaching so you can work with Yammer support to get your token signing certificate updated with them.  I’ve included the source code so you can modify as you need; the Task functionality requires Outlook 2013 as well, which you may not have.

 

AAD still makes a good choice for authenticating with Yammer, this is just some information so you can plan the additional management that you’ll need to stay on top of when you use it.

You can download the attachment here:

Using the Yammer API in a .NET Client Application

UPDATE 12/17/2013:  The authentication process Yammer uses to issue an access code changed recently.  If you have been getting a 404 error when executing the 3rd line of code previously described below to get the token, then read the updated step 3 below and/or grab the updated code attached to this post.

Recently I’ve been doing some work with the Yammer API from a console application.  The Yammer API does not have ton of documentation right now, and what is there is primarily targeted at using the API from a browser-based application.  But what about a classic scheduled task type application?  For example, suppose you wanted to write an application that would go through once a day and post the current leaders in a sales contest you’re having.  Imagine having your app read the data from SQL and then posting the information into the feed.  There just isn’t a lot of details on using it from server side code, and virtually none using .NET so I figured I would share and spread the joy.  Brian on the Yammer team was good enough to get me through a few of the rough spots so thank you Brian.  I also am attaching my console app to this post so that you have sample code to see for yourself.

To begin with, you should take a look at http://developer.yammer.com.  You’ll find the documentation there on the Yammer API and a sprinkling of samples throughout.  The most important part of this process (assuming you have a Yammer network to work in already) is that you need to register a Yammer application.  When you do that you will get a client ID and secret, and you will tell Yammer where token requests for your application should be returned.  This process is explained in the Yammer developer documentation here:  http://developer.yammer.com/introduction/#gs-registerapp.

Once you have your application registered you can start working on your code to call the Yammer APIs.  The first thing you need in order to do anything useful is an access token.  Obtaining an access token in Yammer is very much like getting an OAuth access token for a SharePoint App (and many other apps).  If you’re in the browser, a user would get a prompt where they would be informed that your application would like to access their Yammer information, and the user can allow it or not.  Once you get an access token it is good for a very, very, long time (“years” according to the Yammer documentation) so you don’t need to worry about doing this every time for every user – you can save your access token for a user and reuse it later.

This is important to remember, especially when you are just experimenting, because the Yammer documentation also describes how you can obtain an access token through the browser and then use that for your application.  If you go to http://developer.yammer.com/authentication/, scroll down to the bottom of the page and read the section titled Generate a test access token for instructions on how to do this.

Now in my case, I didn’t want to go that route because I want something a little more hands off and sustainable.  So what I did is go through the process once through the browser, trace everything with Fiddler, and then write some code to simulate a person going through that process.  The flip side of taking this approach is that it does require you to have the credentials of the user you want to simulate granting the application rights to data, so neither option is really perfect.   If you look at the code in my console app you go through this process to get an access token:

  1. Make a request to the oath endpoint in Yammer like this:  https://www.yammer.com/dialog/oauth?client_id=&#8221; + CLIENT_ID + “&redirect_uri=” + REDIR_URL.  In this case, “CLIENT_ID” is the client ID you got when you registered your app, and “REDIR_URL” is the Uri that the response from Yammer should return to when it’s finished.  It’s important to remember that if you test on different machines or in different environments, if you change where the response is going back to you MUST go update your application configuration in Yammer.  If your redirect_uri does not match the configuration of your application, then Yammer will just give you an error.  When you do get a response, there’s an “authenticity” token that you’ll need to extract out of the body and use on your next request.  Fortunately I’ve written wrapper code for making a request and extracting this token so it’s really just two lines of code:  response = MakeGetRequest(permUrl); and then string authToken = GetAuthenticityToken(response);
  2. Next you’re going to take the authenticity token and do an HTTP POST back to Yammer along with the credentials for the user.  When you do that there are also two cookies that you need to start sending along that were created when you made the first request:  yamtrak_id and _workfeed_session_id.  You’ll post that to https://www.yammer.com/session to create a session with Yammer.  Again, I’ve wrapped up the POST and extracting and resubmitting the cookies so you are just making one method call:  postResults = MakePostRequest(postBody, authUrl1).
  3. UPDATE:  This process changes right here as of December 2013.  Yammer has changed the authentication process, so here’s what we do on this step now:  you just need to make the same exact request that you made in step 1, with one difference.  When you make the request, you need to include the Yammer tracking ID and session ID cookie.  I made this all very easy for you by just adding one additional optional parameter to the MakeGetRequest method – AddCookies.  So to make this final request you just need one line of code:  response = MakeGetRequest(permUrl, string.Empty, true);  You should get an access code in the return query string just as you did with the previous code.
  4. Now that you have an access code you can make a request to https://www.yammer.com/oauth2/access_token.json?client_id=&#8221; + CLIENT_ID + “&client_secret=” + CLIENT_SECRET + “&code=” + accessCode.  Just like before, “CLIENT_ID” and “CLIENT_SECRET” are what you got from Yammer when you registered your app; “accessCode” is the access code we got from step 3.  If this works, you’ll get a whole bunch of JSON In return that includes information about the current user, as well as the access token that you’ll need to include in all of your subsequent requests to read or write data into Yammer.

Now things get a lot more fun.  Since we’ll regularly be working with JSON when using the Yammer API, I’ve written a bunch of .NET classes that we can use to serialize and deserialize back and forth.  For example, when you get the access token back you can create an instance of one of my classes with code like this:  YammerAccessToken yat = YammerAccessToken.GetInstanceFromJson(response).  Once you do that you can easily refer to all the JSON goo in a .NET world.  So for example, to get the access token you can just refer to yat.TokenResponse.Token.  That is in fact how you will pass your access token to all subsequent requests that require it.

Now let’s start playing with the data.  Suppose you want to read the “All Messages” posts for a user?  It becomes a pretty trivial piece of code:

//make the request to Yammer for messages

response = MakeGetRequest(“https://www.yammer.com/api/v1/messages.json&#8221;, yat.TokenResponse.Token);

 

//serialize the JSON that’s returned into one of Steve’s Yammer objects

YammerMessages yms = YammerMessages.GetInstanceFromJson(response);

 

//enumerate each message and do something

foreach (YammerMessage ym in yms.Messages)

{

Console.WriteLine(“Message:  ” + ym.MessageContent.PlainText);

}

 

If you look at the class I created for messages you’ll see that you can get things like the message ID, sender ID, message type, sender type, Url, thread ID, language, plain text, rich text, attachments, likes, etc.  All of these are simple to retrieve using this custom class.

Now suppose you just want to get information about a particular user?  Again, two lines of code gets you there:

response = MakeGetRequest(currentUserUrl, yat.TokenResponse.Token);

YammerUser yu = YammerUser.GetInstanceFromJson(response);

 

Once you have the YammerUser you can get at things like name, department, job title, photo Url, contact information (like email), network settings, and the list of feeds and groups that they belong to.  The last couple of items are important, because each feed and group contains an identifier, and you have to use that identifier when posting to it.

 

Posting a message to a feed is done via a FORM post, so we can again reuse some of the other code we’ve written.  When you post a new message, Yammer actually returns a message collection back to you containing one message, and you can use the same method described above to serialize it into a class to view the results.  Since this is just sample code, here’s an example of how I let the user running the console app just type in the message that they want posted to the newsfeed:

 

bool broadcastToAll = false;

Console.WriteLine(“Type in the message you want posted to the Yammer IT Group then press enter:”);

string myMessage = Console.ReadLine();

 

//it.GroupID is a group that I got for my user in one of the previous code samples

//the complete list of form variables that you can submit and their definition can

//be found at http://developer.yammer.com/restapi/ in the Manipulating

//Messages section

string msg = “body=” + myMessage + “&group_id=” + it.GroupID + “&broadcast=” + broadcastToAll.ToString();

 

//try adding the message

response = MakePostRequest(msg, (“https://www.yammer.com/api/v1/messages.json&#8221;, yat.TokenResponse.Token);

 

if (!string.IsNullOrEmpty(response))

{

YammerMessages newMsg = YammerMessages.GetInstanceFromJson(response);

Console.WriteLine(“message sent: ” + newMsg.Messages[0].MessageContent.PlainText);

}

 

Posting to a Yammer App page can be done using Yammer’s Open Graph API; they’ve documented it here:  http://developer.yammer.com/opengraph/.  You submit a multi-level chunk of JSON to create an entry using Open Graph, but again, I’ve created a custom object to make it easy for you.  Here’s an example of using my object that wraps the JSON needed for Open Graph:

 

YammerGraphObject go = new YammerGraphObject();

go.Activity.Action = “create”;

go.Activity.Actor = new YammerActor(“Steve Peschka”, “speschka@www.northwinds.com”);

go.Activity.Message = “Hey can we finally get this crazy write stuff working??”;

 

go.Activity.Users.Add(new YammerActor(“Anne Wallace”, “annew@www.northwinds.com”));

go.Activity.Users.Add(new YammerActor(“Garth Fort”, “garthf@www.northwinds.com”));

 

YammerGraphObjectInstance jo = new YammerGraphObjectInstance();

jo.Url = “http://www.vbtoys.com&#8221;;

jo.Title = “yammo objectola”;

 

go.Activity.Object = jo;

 

//the key is really here – I’ve overridden the ToString() method to return a

//JSON payload that can be used with Yammer

string postData = go.ToString();

 

//now we can just post the data to Yammer to create it

response = MakePostRequest(postData, graphPostUrl, yat.TokenResponse.Token, “application/json”);

 

That pretty much wraps it up.  This is far from an exhaustive list of things you can do with Yammer.  What I wanted to do was just to give you a starting point of common tasks and data serialization techniques that you can use to build from.  I think as you look into building with the Yammer API you will be able to use the sample application I’ve attached to this posting as a good starting point and pattern for creating whatever custom Yammer application you like.  Now go get Yammered.   🙂

You can download the attachment here: