Andrew Coates ::: MSFT

It's all about community!

  • Andrew Coates ::: MSFT

    Azure Announcements at Build

    • 0 Comments

    Early this morning at the Build Conference we announced some exciting new Windows Azure tooling and service enhancements.

    Check out the announcement on the Windows Azure team blog.

  • Andrew Coates ::: MSFT

    Visual Studio 2010 Tips and Tricks Session

    • 0 Comments

    As part of our developer readiness outreach, our Visual Studio Product Manager, Ibrahim Hamza, has organised what sounds like an excellent session on maximising your productivity with Visual Studio 2010.

    Learn how to become a Visual Studio coding guru! In this fast-paced session, learn to write code faster than a speeding bullet, leap around large projects in a single bound, and become more powerful than a locomotive with the debugger. We take a wild ride through C# and Visual Basic IDE features in Microsoft Visual Studio 2010 and indispensible out-of-the-box solutions that will help you get your job done better and faster.

    This is an online session that, unusually for this kind of thing, is running in daytime hours in Australia! Might even be worth gathering your development team and making a training afternoon of it.

    Tuesday 27 September 2011, 14:00-16:00 AEST

    Sign up here.

  • Andrew Coates ::: MSFT

    TechEd Australia Session Recordings and Decks

    • 0 Comments

    Update 4 Sep 2011 - The videos and slides are beginning to appear on the Channel 9 TechEd Australia 2011 Site.

    Once again we've captured all of the main track sessions from TechEd Australia this year. We grabbed whatever video went to the screen and whatever audio went to the speakers. This means we've got almost 170 75-minute sessions to do the following to:

    1. Edit the files to remove the extra time at the beginning and the end then re-encode
    2. Upload the 200+ MB file to an Azure blob
    3. Process the high quality file to produce about 5 other formats including audio only, a couple of MP4 versions, at least one more WMV and some jpg thumbnails, as well as a smooth-streaming version
    4. Upload the slides to the an Azure blob
    5. Create the landing page for each session which will allow you to view the session and/or download any or all of the formats in 3 and 4 above (linked from http://channel9.msdn.com/Events/TechEd/Australia/Tech-Ed-Australia-2011)

    As of right now, numbers 1 and 4 are complete. Number 2 is about 10% done, number 3 is yet to start and while the pages are up (5), there's not yet a link to even the slides. Of course, if you were at TechEd Australia, you can log into the Schedule Builder and download slides from there.

    I'll keep this blog updated every once in a while with the progress of things.

  • Andrew Coates ::: MSFT

    August 2011 Windows Azure Releases

    • 0 Comments

    While I was overseas, the Windows Azure team announced the availability of the

    Grab 'em while they're, if not hot then at least luke warm.

  • Andrew Coates ::: MSFT

    Counting the number of sections in an OpenXML Document

    • 0 Comments

    1/4/11 - Updated a couple of images and some of the code explanation

    Adam Cogan asked me a question the other day that asked (among other things) "How do you know if a doc has multiple sections?"

    In Word, of course, you can break a document up into sections by inserting a section  break from the Breaks button in the Page Setup group on the Page Layout tab:

    Inserting section breaks manually in Word is easy

    It turns out that counting these programmatically is really easy using the OpenXML SDK 2.0 (download)

    I created a new console application, added a reference to DocumentFormat.OpenXML and WindowsBase and used this code:

    Count Sections in Word Docx
    1. using System;
    2. using System.Collections.Generic;
    3. using System.Linq;
    4. using System.Text;
    5. using System.IO.Packaging;
    6. using DocumentFormat.OpenXml.Wordprocessing;
    7. using DocumentFormat.OpenXml.Packaging;
    8. using DocumentFormat.OpenXml.Office2010.Word;
    9.  
    10. namespace CountSections
    11. {
    12.   class Program
    13.   {
    14.     static void Main(string[] args)
    15.     {
    16.       if (args.Length != 1)
    17.       {
    18.         Console.WriteLine("Usage: CountSections <filename>");
    19.       }
    20.       else
    21.       {
    22.         using (WordprocessingDocument d =
    23.             WordprocessingDocument.Open(args[0], false))
    24.         {
    25.           Console.WriteLine("Found {0} section(s)",
    26.               d.MainDocumentPart.Document.Body.Descendants().
    27.               OfType<SectionProperties>().Count()
    28.               );
    29.         }
    30.         Console.WriteLine("Press any key ...");
    31.         Console.ReadKey();
    32.       }
    33.     }
    34.   }
    35. }

    In it I take the filename passed as an argument and open it ReadOnly (line 22-23). I then find the number of sections using the typed enumerator (lines 26-27)

    I also added the path to a file in the Command Line Arguments edit box in the Debug tab of the project Properties so there's a file being passed in when I press F5:

    Pass a file name in as a command line argument

    Running the program gives the answer very quickly:

    Resulting output - we found 2 sections

    Cool huh?

    Sample file with 2 sections Download

  • Andrew Coates ::: MSFT

    Document Creation and Conversion with the OpenXML SDK and SharePoint 2010 Word Automation Services – Part 2

    • 0 Comments

    A long time ago, I wrote Part 1 of this post, based on the presentation I did at the 2010 SharePoint Conference in Sydney. If you're following along with the code, you may want to review that post so you can set up your development environment to match mine.

    To quickly recap, the last post showed how to create Word (OpenXML, docx) documents programmatically and write them to disk using the OpenXML SDK (and therefore without the requirement for Word/Office on the machine creating the documents).

    In this part, I'll extend the solution to write the documents to a document library in SharePoint and then use Word Automation Services to automatically convert the docx files to PDF format.

    Setup

    To follow along with this walkthrough without changes, setup your SharePoint instance (at http://localhost) as follows:

    • Create a document library called "Created Docs" in the root site
    • Create a document library called "Converted Docs" in the root site

    If you use a remote server, and/or a different site or library names, you'll need to adjust some of the URI and path strings in the code below to make it work.

    Writing to a SharePoint Library

    Carrying on from last time, wire up the click event of the CreateOneSharePointDocumentButton:

    Click event handler
    1. private void CreateOneDocumentOnSharePointButton_Click(object sender, EventArgs e)
    2. {
    3.     gen.CreateOneDocumentOnSharePoint();
    4. }

    Generate a stub for the CreateOneDocumentOnSharePoint() method in the DocGenerator class using the Ctrl+. technique made possible by the Visual Studio 2010 Productivity Power Tools.

    Switch to and add a using statement to the DocGenerator class to give you access to the SharePoint Client Libraries - giving it an alias will help disambiguate the File class later:

    1. using SPC = Microsoft.SharePoint.Client;

    Using the SharePoint Client Libraries, it's very easy to write documents to a document library, and there's no need to write a document to a local drive. This means we'll use a different overload of the OpenXML SDK's WordprocessingDocument.Create() method that writes, not to a file, but to a MemoryStream.

    CreateOneDocumentOnSharePoint
    1. internal void CreateOneDocumentOnSharePoint()
    2. {
    3.   SPC.ClientContext clientContext = new SPC.ClientContext("http://localhost");
    4.   string fileUrl = "/Created Docs/MyVeryVeryCoolDoc.docx";
    5.  
    6.   sw.Reset();
    7.   sw.Start();
    8.  
    9.   using (MemoryStream ms = gen.CreatePackage())
    10.   {
    11.     ms.Seek(0, SeekOrigin.Begin);
    12.     SPC.File.SaveBinaryDirect(clientContext, fileUrl, ms, true);
    13.   }

    In this code, you create a new SharePoint.Client.ClientContext that gives access to the site (in this case at http://localhost, but if you've got things set up differently, change it here).

    Create an overload of the CreatePackage() method in the DocumentCreator class that creates and populates a MemoryStream:

    CreatPackage Overload
    1. internal MemoryStream CreatePackage()
    2. {
    3.  
    4.   MemoryStream ms = new MemoryStream();
    5.   using (WordprocessingDocument package =
    6.     WordprocessingDocument.Create
    7.     (ms, WordprocessingDocumentType.Document))
    8.   {
    9.     CreateParts(package);
    10.   }
    11.  
    12.   return ms;
    13.  
    14. }

    Move the pointer to the start of the MemoryStream and call the File.SaveBinaryDirect() method passing in the ClientContext, a string indicating where the file should be written, the stream and a boolean that tells SharePoint whether or not to overwrite an existing file with the same name.

    Running the app and clicking the One document in SharePoint button shows that it's very fast - in my case 102ms

    Writing 1 document to SharePoint took 0.1 seconds

    Writing lots of documents is fast too - add an event handler to the CreateOneSharePointDocumentButton:

    Click Event Handler
    1. private void CreateManyDocumentsOnSharePointButton_Click(object sender, EventArgs e)
    2. {
    3.   gen.CreateManyDocumentsOnSharePointInParallel((int)NumberOfDocumentsToCreate.Value);
    4.  
    5. }

    And add a CreateManyDocumentsOnSharePointInParallel() method that uses a Parallel.For() loop to call CreatePackage() and File.SaveBinaryDirect() for as many files as you create:

    Create lots of SharePoint Docs
    1. internal void CreateManyDocumentsOnSharePointInParallel(int NumberOfDocs)
    2. {
    3.   SPC.ClientContext clientContext = new SPC.ClientContext("http://localhost");
    4.   string fileUrl = "/Created Docs/MyEvenCoolerDoc{0:D5}.docx";
    5.  
    6.   sw.Reset();
    7.   sw.Start();
    8.  
    9.   Parallel.For(0, NumberOfDocs, i =>
    10.   {
    11.  
    12.     using (MemoryStream ms = gen.CreatePackage())
    13.     {
    14.       ms.Seek(0, SeekOrigin.Begin);
    15.       SPC.File.SaveBinaryDirect(clientContext, string.Format(fileUrl, i), ms, true);
    16.     }
    17.  
    18.   });
    19.  
    20.   sw.Stop();
    21.  
    22.   System.Windows.Forms.MessageBox.Show(string.Format(
    23.       "Wrote {3} documents to SharePoint ({1}{2}) in {0} ms (using parallel processing)",
    24.       sw.ElapsedMilliseconds,
    25.       clientContext.Url,
    26.       fileUrl,
    27.       NumberOfDocs));
    28.  
    29. }

    This is also pretty fast - in my case 40ms per document.

    Writing 100 documents to SharePoint (in parallel) took 4 seconds

    Navigating to the document library shows all those documents sitting just where you'd expect to see them:

    Cool documents created en-masse

    Converting Word Documents to a Fixed Format (PDF or XPS)

    PDFUp until now, we've not had to use Word (or any other Office client) as all we've been doing is generating documents, not rendering them. Just like you can create an HTML document without requiring a browser, it's perfectly valid to create a Word document (or any other OpenXML format document) without using Word.

    However, to view the document, or to create a fixed version of it like PDF or XPS, it's necessary to render it. Up until the release of SharePoint 2010, the highest fidelity way to do this was to open the document in Word. Of course, doing that on the server was fraught with difficulty. Word is not designed to be a server-side tool - it throws (sometimes modal) dialogs, it spends a lot of resources on updating the screen and it's not optimised for multi-processor, large memory scenarios. When there is a user interacting with Word though, the bottleneck is rarely the computer.

    The SharePoint team addressed this problem with the Word Automation Services feature in SharePoint 2010 (standard edition and higher). Word Automation Services is the client code from Word with the UI bits stripped out and optimised to run as a server process. All of the rendering engine is available for SharePoint to use without any of the issues (both technical and from a licensing point of view) of using Word on a server. There's lots of great info on Word Automation Services on MSDN and elsewhere. Here's the list of resources I provided in the first post in this series:

    Word Automation Services (WAS) document conversion jobs run as as an asynchronous server-side job that can either be scheduled automatically (for example, when a document is placed in a folder) or programmatically. Either way, the job won't start immediately, just the next time the WAS scheduler runs. The frequency of the scheduler running is set in Central Administration - see the links above for details on how to set it up. I set it to the minimum interval - one minute.

    Interacting programmatically with the service is pretty straightforward, but there are two gotchas:

    1. the .NET libraries are 3.5 only, so the project you create must be a .NET 3.5 project, and
    2. the calls will fail (with cryptic exceptions) if it's not a 64-bit call, so you must target either x64 or Any processor type, not x86.

    Create a new console application and make sure that the target framework is 3.5.

    Create a new console application targetting Framework 3.5

    Open the Visual Studio Configuration Manager dialog by dropping down the Solution Configurations drop-down on the Visual Studio Standard toolbar (or choosing Configuration Manager from the Build menu):

    Choose Configuration Manager

    Next, add a Solution Platform:

    image

    to target Any CPU (or x64)

    image

    Now you're ready to start building.

    Converting a single document to PDF

    Add references to the Microsoft.SharePoint and Microsoft.Office.Word.Server assemblies.

    Add using statements for those assemblies:

    1. using Microsoft.SharePoint;
    2. using Microsoft.Office.Word.Server.Conversions;

    Add a couple of static string properties to the class that you can adjust to suit the way you've got your SharePoint setup configured:

    1. // If you manually installed Word Automation Services, then replace the name
    2. // in the following line with the name that you assigned to the service when
    3. // you installed it.
    4. static string cWordServicesName = "Word Automation Services";
    5. static string siteUrl = "http://localhost";

    Now you can initiate the conversion of a single document:

    Convert a single document
    1. private static void SingleConv()
    2. {
    3.   using (SPSite spSite = new SPSite(siteUrl))
    4.   {
    5.     ConversionJob job = new ConversionJob(cWordServicesName);
    6.     job.UserToken = spSite.UserToken;
    7.     job.Settings.UpdateFields = true;
    8.     job.Settings.OutputFormat = SaveFormat.PDF;
    9.     job.AddFile(siteUrl + "/Created%20Docs/MyAwesomeDoc.docx",
    10.         siteUrl + "/Converted%20Docs/MyAwesomeDoc.pdf");
    11.     job.Start();
    12.     Console.WriteLine("Job ID: {0} started", job.JobId);
    13.     Console.WriteLine("Press the any key ...");
    14.     Console.ReadKey();
    15.   }
    16. }

    There are a few things to note here.

    Firstly, you get a reference to the Site using the SharePoint libraries, not the SharePoint Client libraries that we used to write the Word docs to the list in the first place.

    Next, you need to pass a user token to the new ConversionJob, and you get that from the SPSite user token.

    Third, you specify the output format using the SaveFormat enumeration.

    Finally, remember the service is performed asynchronously and so although you get a Job ID back, you don't get any more information about the job status (more on that when we do bulk conversions)

    Converting documents to PDF en-masse

    Converting whole libraries at once is also very easy. The ConversionJob class has an AddLibrary() method that takes as parameters a source and destination SPList object.

    Converting whole libraries
    1. private static void BulkConv()
    2. {
    3.   using (SPSite spSite = new SPSite(siteUrl))
    4.   {
    5.     Console.WriteLine("Starting conversion job");
    6.     ConversionJob job = new ConversionJob(cWordServicesName);
    7.     job.UserToken = spSite.UserToken;
    8.     job.Settings.UpdateFields = true;
    9.     job.Settings.OutputFormat = SaveFormat.PDF;
    10.     job.Settings.OutputSaveBehavior = SaveBehavior.AlwaysOverwrite;
    11.     SPList listToConvert = spSite.RootWeb.Lists["Created Docs"];
    12.     SPList listToPopulate = spSite.RootWeb.Lists["Converted Docs"];
    13.     job.AddLibrary(listToConvert, listToPopulate);
    14.     job.Start();
    15.     Console.WriteLine("Bulk conversion job {0} started", job.JobId);
    16.     ConversionJobStatus status = new ConversionJobStatus(cWordServicesName,
    17.         job.JobId, null);
    18.     Console.WriteLine("Number of documents in conversion job: {0}", status.Count);
    19.     while (true)
    20.     {
    21.       System.Threading.Thread.Sleep(5000);
    22.  
    23.       status.Refresh();
    24.       if (status.Count == status.Succeeded + status.Failed)
    25.       {
    26.         Console.WriteLine("{2} Completed, Successful: {0}, Failed: {1}",
    27.             status.Succeeded, status.Failed, DateTime.Now);
    28.         break;
    29.       }
    30.       Console.WriteLine("{2} In progress, Successful: {0}, Failed: {1}",
    31.           status.Succeeded, status.Failed, DateTime.Now);
    32.     }
    33.  
    34.     Console.ReadKey();
    35.   }
    36. }

    Checking the status of the job is straightforward (as long as you have the JobId - a GUID uniquely identifying this conversion job). The ConversionJobStatus object holds information about the conversion job including how many documents are to be converted, how many have been converted successfully and how many have failed. Calling the Refresh() method gets the most up-to-date status and you can use that to poll for completion. Remember that jobs only start every <n> minutes, where n is a setting in SharePoint Central Administration

    Converting documents is an asynchronous process

    The result is a SharePoint list full of PDF files, created without ever needing to open Word.

    A library full of converted PDFs

    A converted PDF in Adobe Reader

    Conclusion

    The combination of the OpenXML SDK and Word Automation Services makes server-side document creation simple, scalable and efficient. This is definitely a tool worth adding to your arsenal.

    Source Code

    I've zipped up the two solutions - the document creation (.NET 4.0) WinForms project and the document conversion (.NET3.5) project for you to download and play with. Notice that they are NOT production ready - they're illustrative only. Use them at your peril, your mileage may vary, contents may be hot no guarantees etc … you know the drill.

    Document Creation Solution Download (241kB)
    Document Conversion Solution Download (115kB)

  • Andrew Coates ::: MSFT

    Windows Azure Toolkit for Social Games & Tankster Version 1.0 | Nathan Totten

    • 0 Comments

    This looks like it could be a lot of fun. I think I've figured out what my son and I are going to do in our spare time for the next little while.

    Windows Azure Toolkit for Social Games & Tankster Version 1.0 | Nathan Totten

  • Andrew Coates ::: MSFT

    LightSwitch Decks from TechEd NZ

    • 0 Comments

    I presented two sessions at TechEd NZ last week and I've attached the decks here for anyone who's interested.

    Introducing Visual Studio LightSwitch DEV203

    Visual Studio LightSwitch Beyond the Basics DEV308

  • Andrew Coates ::: MSFT

    Frankly Speaking - Casting the Pod

    • 0 Comments

    Frankly Speaking Logo

    Can't believe I haven't blogged about this.

    For just over nine months now, Michael Kordahi and I have been producing a Podcast called Frankly Speaking. It's hard to believe we've recorded just over a session per week for 41 weeks. We've had a bunch of great guests and we generally just chat about current tech things with a bit of a Microsoft bent.

    You can subscribe to the feed here or via iTunes here.

  • Andrew Coates ::: MSFT

    Test Post from Word 2010

    • 0 Comments

    I've not posted from Word 2010 before (I prefer Live Writer), but I had a question from a colleague as to how to set it up. If this appears, it looks like I managed.

Page 47 of 47 (470 items) «4344454647