Create a List in the Host Web When Your SharePoint App is Installed…and Remove it from the Recent Stuff List

This is one of those questions that I’ve seen asked a lot but for some reason I’ve never really seen anyone post an answer to it.  I did a quick Bing search before writing this post but didn’t really see anything up there so I’m going to go out on a bit of a limb and guess that maybe there’s still some use for this kind of information.  In my particular scenario I am creating a SharePoint app and when it’s installed I want it to create a list in the host web, because I’ll be using it to store data for my application.  I’m using a provider hosted app so I’m not going to have an app web, but even if I DID have an app web, I’d rather have this list in the host web in case my app is ever uninstalled and then reinstalled later, my application data will still be there and I can pick right up where I left off.

So to get started on this little adventure, I created a new SharePoint application in Visual Studio 2013.  It began as just your basic out of the box application – I just wanted to get it up and working first to verify that all the plumbing is in place.  With that ready to go, the next thing I wanted to do is have something similar to a feature receiver that you have for full trust code that would fire when my app is installed.  Fortunately the cloud app model provides just such a thing.  I just needed to select my SharePoint App project in Visual Studio and in the properties windows there is a property called HandleAppInstalled; just double-click that to change it from it’s default value of false to true and when you do a new WCF endpoint is added to your provider hosted app.  It’s all fleshed out with a basic stub implementation, and then you can add your code in there.  That’s what we’ll begin with.

The stub implementation looks something like this:

public SPRemoteEventResult ProcessEvent(SPRemoteEventProperties properties)
     SPRemoteEventResult result = new SPRemoteEventResult();

     using (ClientContext ctx = TokenHelper.CreateAppEventClientContext(properties, false))
          //blah blah blah

     return result;

Now the challenge is that the CreateAppEventClientContext is geared towards creating a context for an app web, which we don’t want.  So instead we’re going to create a client context the way that Visual Studio 2012 did when you create a provider hosted app, in the default.aspx code behind.  That means we’re going to need the Url to the host web, a context token, and the host name of our application.  Here’s how we’re going to get all of that stuff.

To begin with, you can get the Url to the host web in the SPRemoteEventProperties parameter that is passed into our method.  The properties parameter has an object property called AppEventProperties that contains a URI property called HostWebFullUrl.  So we can get the first parameter we need – the host web Url – like this:  Uri hostUrl = properties.AppEventProperties.HostWebFullUrl.  The context token is actually very easy to get; it’s a property of the properties parameter, so we can get it like this:  properties.ContextToken.  The last thing we need – the host name of our application – is more difficult to get in a WCF.  That’s because you don’t have an HttpContext in a WCF, so you have to reach back into the ServiceContext to get the information you’re looking for.  Fortunately the ServiceContext contains a Host property that has a collection of URIs in the BaseAddresses property.  Here’s a chunk of code to pull out that information:

System.ServiceModel.OperationContext oc = System.ServiceModel.OperationContext.Current;

Uri localUrl = null;

//enumerate through the Host base addresses and look for the SSL connection
foreach (Uri u in oc.Host.BaseAddresses)
     if (u.Scheme.ToLower() == “https”)
          localUrl = u;

UPDATE:  The code above looking through the BaseAddresses works great when you’re using it with the IIS Express web site Visual Studio adds to your project when you create a new SharePoint App.  HOWEVER…it blows up when you move your code to the full blown version of IIS.  What I found in trying to get this working is that the you still get two BaseAddresses; the first one uses the HTTP scheme but IS the correct host name for your WCF service.  The second one uses the HTTPS scheme, but is the fully qualified domain name of the server on which the code is running.  As a result, the code above picks the second host name, but that is NOT the host name registered for the endpoint with SharePoint.  As a result, the code below to get a client context fails and everything blows up at that point.  NOTE:  This is because my IIS web name is not the same as my machine name, which would generally be the case in a production environment.  The code I’m using now that works with both IIS Express as well as IIS is just this:

if (oc.Host.BaseAddresses.Count > 0)
     localUrl = oc.Host.BaseAddresses[0];

I’m looking for the host that is using HTTPS, since that’s what our apps should always communicate over.  It is arguably unlikely that you would have two different host names for HTTP and HTTPS, but you never know so why tempt fate?  Now that I have the three parameters I need I can create my client context for the host web; note that I always FIRST check to make sure that localUrl is not null, which would happen if I had no SSL endpoints on my provider hosted app.  Getting my client context now looks like this:

//this is what was originally here
//using (ClientContext ctx = TokenHelper.CreateAppEventClientContext(properties, false))
using (ClientContext ctx = TokenHelper.GetClientContextWithContextToken(hostUrl.ToString(), properties.ContextToken, localUrl.Authority))

Awesome!  Now that I have a client context for my host web, as long as my user / application has sufficient rights I can create a new list in my host web.  I’m not really going to cover that in great detail because I think creating lists via CSOM is all over the interwebs.  But for completeness here’s a shortened version of my code to create a new list:

Web web = ctx.Web;

ListCreationInformation ci = new ListCreationInformation();
ci.Title = LIST_NAME;
ci.TemplateType = (int)ListTemplateType.GenericList;
ci.QuickLaunchOption = QuickLaunchOptions.Off;
l = web.Lists.Add(ci);

//add a description and some fields in here  
l.Hidden = true;

//this creates the list

Okay, all of that is great, I now have my list in my host web.  There is one important aspect to this scenario though, and that is that my list should be hidden from users.  Now you might think that I have that covered with my ListCreationInformation (ci.QuickLaunchOption) and the Hidden property of the list…but that is not enough.  Unfortunately SharePoint still throws it in the Recent bucket that shows up on the Quick Launch navigation.  In fact the Recent list is NOT a list, it’s a collection of NavigationNode items.  So if you REALLY want your list to be invisible, you need to remove it from over there as well.  Doing that is three step process (NOTE: I’m leaving out all the error handling and try…catch blocks for read-ability; you would of course want that in any code you write…but you knew that, I know…  :-)  ):

Step 1:  Get the quick launch navigation node collection

In this step you’re going to make a call back to get the root web of the site to get the quick launch navigation nodes.  This code is just continued from the create list code above, so it’s still in the “using” statement for my ClientContext (ctx) shown above:

//get the site and root web, where the navigation lives
Site s = ctx.Site;
Web rw = s.RootWeb;

//get the QuickLaunch navigation, which is where the Recent nav lives
ctx.Load(rw, x => x.Navigation, x => x.Navigation.QuickLaunch);

//now extract the Recent navigation node from the collection
var vNode = from NavigationNode nn in rw.Navigation.QuickLaunch
     where nn.Title == “Recent”
     select nn;

NavigationNode nNode = vNode.First<NavigationNode>();

Step 2:  Get the Child Nodes of the “Recent” Navigation Node

Okay, now that I have the “Recent” navigation node, I need to populate it’s child property, which is where I should find a node for the list I just created.  This gets simpler now, here is the code to retrieve that:

//now we need to get the child nodes of Recent, that’s where our list should be found

Step 3:  Find The Node for the New List and Delete It

Now that I have the collection of items in the Recent navigation, I can find my item and delete it like you would any other item via CSOM.  Here’s the code:

var vcNode = from NavigationNode cn in nNode.Children
     where cn.Title == LIST_NAME
     select cn;

//now that we have the node representing our list, delete it
NavigationNode cNode = vcNode.First<NavigationNode>();


And there you have it.  You’ve now created a new list in the host web, made it hidden and not shown on the quick launch bar, and removed it from the Recent navigation list so it is REALLY out of sight.


8 thoughts on “Create a List in the Host Web When Your SharePoint App is Installed…and Remove it from the Recent Stuff List

  1. Tulisan yang bagus soal hosting & toko online ini luar
    biasa bagus. Bagus sekali dan penting diketahui sekali. Semua orang yg
    make maupun tengah mencari jasa hosting terbaik di Indonesia & online shop kudu
    baca ulasan ini. Silakan kunjungi juga website saya ya
    min, banyak tulisan menarik yang bisa jadi berguna buat para pencari jasa web
    hosting. Makasih.


  2. Ulasan keren soal hosting ini sangat bermanfaat. Bagus sekali & bermanfaat.
    Tiap orang yang pakai ataupun sedang cari layanan web hosting terbaik di Indonesia harus baca artikel ini.
    Mampir juga situs saya ya, ada artikel menarik yg pasti bermanfaat
    buat para pemakai layanan web hosting. Thanks.


  3. Hi Steve,
    I have a provider hosted app, with app only permission requested, and granted Full Control to the host-web, in a S2S trust environment (btw: all the certificates are fine, because I can do requests from the app to SharePoint).
    During app installation, I need to create a Document Library in the host web.

    I’ve tried your code, but it doesn’t work, because it seems to be for a Low Trust scenario.

    Do you have tips for the S2S trust case?

    Thank you, Curia Damiano


    • Hi Curia, the type of trust (low vs. high) really shouldn’t materially impact your ability to do something like create a list or library. If it’s really full control app only permissions, then I would make sure you are getting your token correctly to obtain an app only token instead of an app plus user token. I’ve done what you’ve described in both low trust and high trust environments and have never found them to fundamentally be different as it applies to the specific type of thing you are trying to do.


Leave a Reply

Fill in your details below or click an icon to log in: Logo

You are commenting using your account. Log Out / Change )

Twitter picture

You are commenting using your Twitter account. Log Out / Change )

Facebook photo

You are commenting using your Facebook account. Log Out / Change )

Google+ photo

You are commenting using your Google+ account. Log Out / Change )

Connecting to %s