MSDN UK Team blog

Get all the latest Microsoft developer news, tools, downloads, tutorials and tips right here, every day.
Search Form
Unfiltered HTML
Developers code with microsoft

Article: Building Azure and SharePoint Applications: An Introduction

Unfiltered HTML
Unfiltered HTML

Article: Building Azure and SharePoint Applications: An Introduction

Rate This
  • Comments 2

By Tom Carter

Here, we’re going to quickly cover building a simple file uploader that will utilize SharePoint Online (SPO) for storage and an Azure web role for an interface.

Cloud considerations

First things first, if you’re running SPO your API shrinks dramatically to code that will run in the sandbox, in a sequential workflow or as part of the Client Object Model- this reduces the risk to the server from faulty/malicious code. If you’re running SharePoint on-premises, you are totally unrestricted with the code you run and as such, your customization can go deeper. With this solution, we’ll only be using the Client Object Model.

Authentication scenarios also change between cloud/on-premises SharePoint. SharePoint Online uses Claims-based authentication and its own internal token service. As such, you can do simple authentication using a SAML exchange or integrate with Azure Access Control Services for authenticating based upon LiveId, OAuth, Windows, etc. or implementing SSO. You should read more about this here (http://blogs.technet.com/b/speschka/archive/2011/05/05/federated-saml-authentication-with-sharepoint-2010-and-azure-access-control-service-part-1.aspx ). We’ll just be authenticating using a SAML exchange and saving the cookie on the Azure instances - our site users won’t be set up as users on SharePoint.

Setting up SharePoint

We’ll need to create a document library that the Web Role will have permission to write to – I’ll assume that you’ve set up a user specifically for the role to connect as. Open your site and choose ‘New Document Library’ from the ‘Site Actions’ menu:

clip_image002

Give it a name like ‘Azure Uploads’ and leave everything else as default, press ‘Create’. Then, on the Ribbon of the newly create library, choose ‘Library Settings’.

clip_image003

Choose ‘Permissions for this document library’ from the ‘Permissions and Management’ section. Press the button ‘Stop Inheriting Permissions’ and confirm the warning dialog that pops up. Then choose ‘Grant Permissions’ and search for our user – choose to ‘Grant users permission directly’ and select ‘Contribute’ (or any equivalent permission level that give read/write access). Press ‘OK’ and our user will have the correct permissions. We’re now ready to actually write the Azure application!

Less Talk, More Code

There’s some prerequisites to building everything – you’ll want the SharePoint Client Object Model Redistributable from here (http://www.microsoft.com/en-us/download/details.aspx?id=21786), WIF for claims-based authentication from here (http://msdn.microsoft.com/en-US/evalcenter/dd440951.aspx) and of course the Azure SDK for .net here (http://www.windowsazure.com/en-us/develop/downloads/).

Once all that’s installed, open up VS2010 and create a new Azure project called ‘AzureSpoUploader’, choose to add a MVC 3 (or 4) web role called ‘WebUploader’ and select ‘Internet Application’ as the web role type, ensuring that you’re using the Razor view engine.

Add the following references to the WebUploader project: Microsoft.IdentityModel, Microsoft.SharePoint.Client, Microsoft.SharePoint.Client.Runtime, System.ServiceModel, System.Runtime.Serialization. Set each added reference to ‘Copy Local=True’ in it’s properties – this will ensure the library is copied to Azure when it’s deployed.

Add the ClaimsWrapper.cs file to the project – this will perform the claims-based authentication with SPO for us.

Now we’ll start adding code to the HomeController.cs file – the first thing we need to do is add the claims wrapper and some connection settings as members. These connection settings will be stored in the Azure service configuration file rather than in the web.config or hardcoded, as this will let us change these values from the management portal without having to redeploy the role or change the web.config in blob storage.

 

privatereadonly String sharepointSiteUrl;

        private readonly String sharepointUsername;

        private readonly String sharepointPassword;

        private readonly String sharepointLibrary;

        private readonly ClaimsWrapper wrapper;

 

        public HomeController()

        {

            if (RoleEnvironment.IsAvailable)

            {

                sharepointSiteUrl = RoleEnvironment.GetConfigurationSettingValue("SharepointSiteUrl");

                sharepointUsername = RoleEnvironment.GetConfigurationSettingValue("SharepointUsername");

                sharepointPassword = RoleEnvironment.GetConfigurationSettingValue("SharepointPassword");

                sharepointLibrary = RoleEnvironment.GetConfigurationSettingValue("SharepointLibrary");

            }

 

            wrapper = new ClaimsWrapper(sharepointSiteUrl, sharepointUsername, sharepointPassword);

        }

Now is probably a good time to populate these values in the configuration files – you can do this straight in the XML files, but creating them in the properties screen of the web role will update web.config files for all build configurations. Right-click on the WebUploader role in the Azure project (not the web role project) and select ‘Properties’

clip_image004

Go to the ‘Settings’ tab and add settings for ‘SharepointSiteUrl’, ‘SharepointUsername’, ‘SharepointPassword’ and ‘SharepointLibrary’ with ‘SharepointSiteUrl’ being the full address of the site – e.g. https://mycompanysite.sharepoint.com and ‘SharepointLibrary’ being the name of the library. The screen should resemble this:

clip_image005

Now, back in the HomeController, add the method ‘LoadLibraryDocuments’:

 

[NonAction]

        private IEnumerable<String>LoadLibraryDocuments(ClientContextcontext, String libraryName)

        {

            List<String>fileNames = new List<String>();

 

            List sharedDocumentsList = context.Web.Lists.GetByTitle(libraryName);

            ListItemCollection listItems = sharedDocumentsList.GetItems(CamlQuery.CreateAllItemsQuery());

            context.Load(sharedDocumentsList);

            context.Load(listItems);

            context.ExecuteQuery();

 

            foreach (var item in listItems)

            {

                fileNames.Add(item["FileLeafRef"].ToString()); //load the name of the file

            }

 

            return fileNames;

        }

The method accepts an argument of type ClientContext, which represents all the functions and objects of the Client Object Model and the name of the list to query – it returns an enumerable collection of file names in the library. Of note here is the CAML query (CAML is the XML-based SharePoint internal query language) generated to return all fields – we could hand-code this to return only specified fields, or perform matching and sorting, etc. but here we’ve just used a default one for simplicity. You can learn more about CAML here (http://msdn.microsoft.com/en-us/library/ms426449.aspx). We have to explicitly call ‘Load’ on each item we require before ‘ExecuteQuery’ – with is the method that actually performs the request to SharePoint.

Next, change the Index action to attach the claims wrapper and call ‘LoadLibraryDocuments’

 

publicActionResultIndex()

        {

            ViewBag.Message = "Upload a document to the library";

 

            ClientContext context = new ClientContext(sharepointSiteUrl);

            context.ExecutingWebRequest += wrapper.ClientContextExecutingWebRequest;

 

            ViewBag.fileNames = LoadLibraryDocuments(context, sharepointLibrary);

 

            return View();

        }

 

The important part here is the event handler which attaches the local cookie store so any authentication cookies are sent along with the request.

To deal with user uploading a file, we’ll need a post action:

 

[HttpPost]

        public ActionResult Index(HttpPostedFileBase file)

        {

            if (file.ContentLength > 0)

            {

                ClientContext context = new ClientContext(sharepointSiteUrl);

                context.ExecutingWebRequest += wrapper.ClientContextExecutingWebRequest;

 

                Web web = context.Web;

                List library = web.Lists.GetByTitle(sharepointLibrary);

                Byte[] input = new Byte[file.ContentLength];

                file.InputStream.Read(input, 0, file.ContentLength);

                var fileToCreate = library.RootFolder.Files.Add(new FileCreationInformation

                {

                    Content = input,

                    Url = file.FileName,

                    Overwrite = true

                });

 

                context.Load(fileToCreate);

                context.ExecuteQuery();

 

                ViewBag.fileNames = LoadLibraryDocuments(context, sharepointLibrary); //fetch the updated list of documents

 

            }

            returnView();

        }

 

Similar to the Get action for Index but we load in the posted file’s input stream and use it populate a new FileCreationInformation object, which is used to create the new file on the server. We call ExecuteQuery twice in this action – once to post the file, and again to reload the list of library files.

There’s no point having these methods without the user’s input, so change Index.cshtml in the ‘Home’ folder of ‘Views’ to this:

 

@{

    ViewBag.Title = "SharePoint Uploader";

}

@section featured {

    <sectionclass="featured">

        <divclass="content-wrapper">

            <hgroupclass="title">

                <h1>@ViewBag.Title.</h1>

                <h2>@ViewBag.Message</h2>

            </hgroup>

            <p>

                <formaction="" method="post"enctype="multipart/form-data">

                <inputtype="file" id="file"name="file" />

                <buttontype="submit">

                    Save</button>

                </form>

            </p>

        </div>

    </section>

}

<h3>Existing Documents:</h3>

 

<ol>

    @foreach (varfileinViewBag.fileNames)

    {

        <li>@file</li>

    }

</ol>

Now, you should be ready to debug and test it out! You can add new files to the library and view existing files. This solution could be extended to make it a lot more scalable and efficient – rather than directly uploading the file from the web role, you could use the Azure Queue Service to queue up all additions and action them all with a worker role. The list of files could be retrieved periodically (or in response to a change) and cached using the Azure Caching Service (which is a fantastic distributed cache that you can even use as shared storage!). Of course it would be good to be able to download files through the web application too. You could set up workflow or event handlers on the SharePoint site to perform business logic when files are changed or to add metadata – there are endless possibilities!

 

clip_image001Tom Carter
Shaping Cloud

http://shapingcloud.com/

Tom works for Shaping Cloud - a Manchester, UK - based development house and consultancy specialising in designing and implementing cloud-based solutions.  His background is in web development with a whole host of Microsoft technologies – with experience in architecting, developing and supporting SharePoint solutions. Shaping Cloud are co-founders of the UK Windows Azure Group and run monthly meetings in Manchester city-centre.

  • Nicely done. I like to try it out. Btw, the site ShapingCloud is slow and it is taking 4-6 sec to load....

    thanks

    -Praveen.

  • I've placed the associated solution file on github here: github.com/.../AzureSpoUploader  . If you want to use the ClaimsWrapper.cs code (and make your life easier) you'll need to grab this.

    Thanks,

    Tom

Page 1 of 1 (2 items)
Leave a Comment
  • Please add 5 and 1 and type the answer here:
  • Post