none
How to use CSOM to get a list of draft projects on Project Online or Project Server 2016? RRS feed

  • Question

  • I have an application that uses the Client Side Object Model (CSOM) to access projects that reside in Project Server 2016 and Project Online.   When I use CSOM to query for a list of all projects on the server, I see only the published projects.   The query looks like this:

    mProjContext.Load(mProjContext.Projects);
    mProjContext.ExecuteQuery();
    foreach (PublishedProject proj in mProjContext.Projects) 
    {
    // do something with each project
    }

    I need to access not only published projects but also draft projects that were created in Microsoft Project Professional but have not yet been published.   I find nothing in MSDN or Stack Overflow that mentions the topic of listing the existing draft projects via CSOM.  There is just silence!  I can definitely access such draft projects in older versions of Project Server (2010, 2013) where I can still use the old PSI asmx (SOAP) interface from my client app.  But this interface is no longer supported for Project Online nor for Project Server 2016.   Does anyone know how to list and access draft projects via CSOM??

    Thanks for any insight!


    ...Jim Black




    • Edited by Jim Black CG Thursday, July 21, 2016 10:00 PM clarification
    Thursday, July 21, 2016 9:57 PM

Answers

  • Hello,

    From Jim's query he was stating that projects that have only been saved and not published are not accessible via CSOM. I tested this via the APIs (admittedly against Project Server 2013 on prem as stated in my posts) and this worked.

    I have just tested against Project Online (via the REST API  - _api/ProjectServer/Projects) and can confirm that draft projects are not available.

    These will need to be published at least once to be available in the APIs.

    Paul


    Paul Mather | Twitter | http://pwmather.wordpress.com | CPS | MVP | Downloads

    • Marked as answer by Jim Black CG Friday, July 22, 2016 4:14 PM
    Friday, July 22, 2016 1:50 PM
    Moderator

All replies

  • Hello,

    COSM, JSOM and REST (_API/ProjectServer/Projects) include projects that are only saved and not published version exists. Maybe I'm missing something? Here is a quick PowerShell script that is filtered to only display the projects that have never been published:

    $projContext = New-Object Microsoft.ProjectServer.Client.ProjectContext($pwaPath)
    #$projContext.Credentials = $credentials    
        
    $projContext.Load($projContext.Projects)
    $projContext.ExecuteQuery()
    
    $projContext.Projects | select Id, Name, LastSavedDate, LastPublishedDate | where {$_.LastPublishedDate -eq '01/01/0001 00:00:00'}

    Paul


    Paul Mather | Twitter | http://pwmather.wordpress.com | CPS | MVP | Downloads


    Friday, July 22, 2016 9:21 AM
    Moderator
  • By the way, the code snippet above was just created for an on-prem instance of Project Server 2013.

    Paul


    Paul Mather | Twitter | http://pwmather.wordpress.com | CPS | MVP | Downloads

    Friday, July 22, 2016 9:22 AM
    Moderator
  • Hi Paul. I am not sure I understand your answer, but I definitely understand what Jim is asking.

    In my opinion, CSOM, REST and OData DO NOT give you the ability to look at draft (or "working") projects. They only return "published" projects. I had the same annoying thought about this when I first discovered this, but ever since then, i just tell all my customers that they need to publish their projects. So far I have been able to work around this limitation by doing that.

    Jim is there a specific reason why you want to access the draft/working version of the project?

    Otherwise, unless Paul has a better idea, I don't think this is supported anymore.

    Friday, July 22, 2016 1:26 PM
  • Hello,

    From Jim's query he was stating that projects that have only been saved and not published are not accessible via CSOM. I tested this via the APIs (admittedly against Project Server 2013 on prem as stated in my posts) and this worked.

    I have just tested against Project Online (via the REST API  - _api/ProjectServer/Projects) and can confirm that draft projects are not available.

    These will need to be published at least once to be available in the APIs.

    Paul


    Paul Mather | Twitter | http://pwmather.wordpress.com | CPS | MVP | Downloads

    • Marked as answer by Jim Black CG Friday, July 22, 2016 4:14 PM
    Friday, July 22, 2016 1:50 PM
    Moderator
  • Paul,

    I could have sworn this was not the case when I tested this over a year ago, but regardless, maybe the confusion was that with CSOM c# code it looks like this:

    foreach (PublishedProject proj in mProjContext.Projects) { // do something with each project }

    Which implies that it ONLY returns "published" projects since mProjContext.Projects seems to be a collection of PublishedProject.

    Friday, July 22, 2016 2:02 PM
  • I very rarely use CSOM - mainly JSOM and REST. If I do use CSOM it is normally via PowerShell as I'm normally only testing as it is quicker to test with. If you have access to a PS2013 farm, that code snippet added to the rest of the PowerShell script would return projects that are only in a "Working" or "draft" state. I didn't just make up the LastPublishedDate value of  '01/01/0001 00:00:00' :)

    Either way, in Project Online it does appear the projects would need to be published at least once.

    Paul


    Paul Mather | Twitter | http://pwmather.wordpress.com | CPS | MVP | Downloads

    Friday, July 22, 2016 2:55 PM
    Moderator
  • Paul and Carlos,

    Thanks to both of you for jumping in on this.   I think Paul has provided a definitive answer and cleared our confusion!

    I tested this via the APIs (admittedly against Project Server 2013 on prem as stated in my posts) and this worked. I have just tested against Project Online (via the REST API - _api/ProjectServer/Projects) and can confirm that draft projects are not available.

    Paul's last statement agrees with what I am seeing, but I was not testing Project Server on premises at the time, which I plan to do now!  I will probably see that the items of type DraftProject are available in the returned collection.  So I'm thinking that Microsoft just turned off inclusion of draft projects in the collection when they deployed the ProjectServer technology as ProjectOnline.  (If they turned it off, they can probably turn it back on!)

    Carlos, in answer to your questions:

    1) My sample code cast the loop variable as a PublishedProject for the convenience of loop-body statements that I omitted from the sample.  If I had been able to retrieve a DraftProject, my code would have thrown an exception, but since I didn't test on-premises MSPS 2013, I never hit that exception (yet).

    2) Why do I need to access draft projects?  OnePager is project-visualization software, and many of my customers want to see its graphics as they build/edit project plans in Microsoft Project Professional connected to Project Online/Server.  They don't just want to see the graphics after they publish them for their colleagues to see.


    ...Jim Black




    • Edited by Jim Black CG Friday, July 22, 2016 4:23 PM grammar
    Friday, July 22, 2016 4:12 PM
  • Paul, I have confirmed what you reported: we can use CSOM to retrieve draft projects from on-premises Project Server 2013, but they are omitted for the same query with Project Online.  So there we have it.  Maybe we can persuade Microsoft to enable this feature on Project Online.  If not, we'll just tell our users "Sorry, access to draft projects is not supported by Project Online". 

    Thanks again to both of you, Paul and Carlos, for so quickly confirming and enlarging my understanding of this situation.  I hope I can return the favor some day!


    ...Jim Black

    Friday, July 22, 2016 10:40 PM
  • As far as I tested, getting a list of draft projects is not supported for Project Online after retiring the PSI support.

    I developed an alternative approach, that works for Project Online. Instead of quering a project service, it get a list from the a security category page (default My Projects), where a list of all projects is retrieved when you open it.

    For the following code I use the great HtmlAgilityPack library:

    public static List<string> GetDraftProjects(string pwAurl, string username, string password) {
        var draft = new List<string>();
        var netcred = username == string.Empty ? CredentialCache.DefaultNetworkCredentials : new NetworkCredential(username, password);
        var wc = new CookieWebClient();
        wc.Headers.Add("Content-Type", "application/atom");
        if (pwAurl.ToLower().Contains("sharepoint.com")) {
            var spoCred = new SharePointOnlineCredentials(netcred.UserName, netcred.SecurePassword);
            var authCookie = spoCred.GetAuthenticationCookie(new Uri(pwAurl));
            var myCookieContainer = new CookieContainer();
            myCookieContainer.Add(new Uri(pwAurl),new Cookie("SPOIDCRL", authCookie.TrimStart("SPOIDCRL=".ToCharArray())));
            wc.CookieContainer = myCookieContainer;
        } else {
            wc.Credentials = netcred;
        }

        var docCategory = new HtmlDocument();
        var dl = wc.DownloadString(pwAurl + "/_layouts/15/PWA/Admin/AddModifyCategory.aspx?categoryUid=1ccc9d5c-dc9d-4a72-84ba-cc21636b9161"); // Category My Projects
        docCategory.Load(new MemoryStream(Encoding.UTF8.GetBytes(dl)));

        var alphaList = docCategory.DocumentNode.SelectNodes(
            "//td[@id='ctl00_ctl00_PlaceHolderMain_PWA_PlaceHolderMain_idFormSectionProjects_ctl02_idSwpProjects_AlphaList_Container']/select/option");
        var betaList = docCategory.DocumentNode.SelectNodes(
            "//td[@id='ctl00_ctl00_PlaceHolderMain_PWA_PlaceHolderMain_idFormSectionProjects_ctl02_idSwpProjects_BetaList_Container']/select/option");
        if (alphaList != null)
            draft.AddRange(alphaList.Select((t, i) =>
            HttpUtility.HtmlDecode(t.ParentNode.InnerText.Split(new[] { "\r\n\t\t" }, StringSplitOptions.RemoveEmptyEntries)[i].Replace("\r\n\t", "").Replace("–", "-"))
            ));

        if (betaList != null)
            draft.AddRange(betaList.Select((t, i) =>
            HttpUtility.HtmlDecode(t.ParentNode.InnerText.Split(new[] { "\r\n\t\t" }, StringSplitOptions.RemoveEmptyEntries)[i].Replace("\r\n\t", "").Replace("–", "-"))
            ));
        return draft;
    }


    Hope this helps!

    Berend van der Zwaag




    • Edited by bvdzwaag Saturday, January 7, 2017 11:21 PM
    Saturday, January 7, 2017 10:58 PM
  • Hi Berend,

    Thanks for the suggestion.  When I get back to this challenge, I'll have a look and see if it works in our situation.

    Jim


    ...Jim Black


    • Edited by Jim Black CG Sunday, January 8, 2017 11:24 PM typo
    Sunday, January 8, 2017 11:23 PM