6

这是我的第一个 SO 问题,所以如果这个问题不是很清楚或者我遗漏了什么,请告诉我。

仅供参考,我无法附加链接,对于所有错误的格式,我们深表歉意。

概述

我正在尝试使用 Microsoft 提供的 CSOM 库来读取(和写入)Project Server Online 中资源的“实际工作”。只要我正在阅读当前经过身份验证的用户的作业,阅读和编​​写作业和实际工作就可以完美地工作。如果我尝试为其他资源读取此内容,则会收到 GeneralSecurityAccessDenied 错误。

我过去曾使用 Impersonation 完成此操作,如果用户拥有 StatusBrokerPermission,它应该在后台透明地调用,但它似乎对我不起作用。模拟已在 2013+ 中删除,因此不再是一个选项。

问题总结

CSOM 应该透明地启用状态扩展,以允许对当前经过身份验证的用户以外的资源进行状态更新(只要用户具有状态代理权限)。这适用于添加新任务,但在尝试通过 TimePhased 任务更新实际 TimePhased 小时数时不起作用。无法查询分配,因此我们无法调用 SubmitAllStatusUpdates 来提交小时数。

研究

  1. CSOM 的使用场景:https://msdn.microsoft.com/en-us/library/office/jj163082(v=office.15).aspx#pj15_WhatTheCSOM_UsageScenarios

  2. 模拟已弃用:https://msdn.microsoft.com/en-us/library/office/ee767690(v=office.15).aspx#pj15_WhatsNew_Deprecated)

图片:应该代表另一个用户阅读......

  1. 有同样问题的人#1:https://social.technet.microsoft.com/Forums/projectserver/en-US/dccdb543-18a1-4a0e-a948-5d861305516e/how-to-get-resource-assignments-summary-查看数据项目服务器在线 2013?forum=projectonline)

  2. 有同样问题的人#2:http://uzzai.com/ZB43wp95/ps2013-app-how-to-read-and-update-timephased-data-with-jsom-javascript-csom.html

  3. 有同样问题的人#4:https://social.technet.microsoft.com/Forums/Sharepoint/en-US/be27d497-e959-44b6-97cb-8f19fe0278fe/csom-how-to-set-timephase-data- on-an-assignment?forum=project2010custprog

我尝试过的其他事情

  1. 使用 CSOM 和 MsOnlineClaimsHelper 来检索用户的 FedAuth cookie(并使用 CookieContainer 分配它们)。
  2. 使用 REST/OData API。a) https://URL.sharepoint.com/sites/pwa/_api/ProjectServer/EnterpriseResources('c39ba8f1-00fe-e311-8894-00155da45f0e')/Assignments/GetTimePhaseByUrl(start='2014-12-09',end ='2014-12-09')/作业
  3. 为用户启用“StatusBrokerPermission”
  4. 取消选中“仅允许通过任务和时间表更新任务”。服务器设置屏幕中的选项(任务设置和显示)。
  5. 创建 SharePoint 托管的应用程序并使用与上述 CSOM 代码等效的 JSOM 代码。a) 我们编写的代码是从 SharePoint 应用程序中执行的 JavaScript,因此我们不需要提供身份验证。登录的用户拥有 StatusBrokerPermission。
  6. 使用提供商托管的 SharePoint 应用程序并使用上面的 CSOM 代码。我们尝试使用上述 CSOM 的所有身份验证方法,并进行附加测试:a) 使用 Fiddler 查看由 SharePoint 应用身份验证设置的 FedAuth cookie,并覆盖 WebRequest 以手动插入 FedAuth/rtFA cookie:webRequestEventArgs.WebRequestExecutor.WebRequest .CookieContainer = getStaticCookieContainer();
  7. 使用时间表提交时间分段数据。a) 我们只能为当前经过身份验证的用户创建时间表,并且不能使用他不可用的项目/分配填充时间表行(或抛出 GeneralItemDoesNotExist 错误)。
  8. 使用 fiddler 手动发出“SubmitAllStatusUpdates”CSOM 请求,作为不同的用户。a) 这个测试的目的是确定我们是否可以写入时间分段数据,即使我们无法读取它。
  9. 确保项目已签出给当前用户。
  10. 对资源使用管理委派。
  11. 在项目权限内设置所有可用选项。
  12. 使用 Project Web UI 输入其他资源的 TimePhased 数据。
  13. 使用 SharePoint 权限模式而不是项目权限模式。

编码

在此处查看失败的代码截图

    using System;
    using System.Security;
    using Microsoft.ProjectServer.Client;
    using Microsoft.SharePoint.Client;
    namespace ProjectOnlineActuals
    {
        static class Program
        {
            const string projectSite = "https://URL.sharepoint.com/sites/pwa/";
            private const string edward = "c39ba8f1-00fe-e311-8894-00155da45f0e";
            private const string admin = "8b1bcfa4-1b7f-e411-af75-00155da4630b";

            static void Main(string[] args)
            {
                TestActuals();
            }

            private static void TestActuals()
            {
                Console.WriteLine("Attempting test # 1 (login: admin, resource: admin)");
                TestActuals("admin@URL.onmicrosoft.com", "123", admin);

                Console.WriteLine("Attempting test # 2 (login: admin, resource: edward)");
                TestActuals("adminy@hmssoftware.onmicrosoft.com", "123", edward);
                Console.ReadLine();
            }

            private static void TestActuals(string username, string password, string resourceID)
            {
                try
                {
                    using (ProjectContext context = new ProjectContext(projectSite))
                    {
                        DateTime startDate = DateTime.Now.Date;
                        DateTime endDate = DateTime.Now.Date;
                        Login(context, username, password);
                        context.Load(context.Web); // Query for Web
                        context.ExecuteQuery(); // Execute

                        Guid gResourceId = new Guid(resourceID);
                        EnterpriseResource enterpriseResource = context.EnterpriseResources.GetByGuid(gResourceId);
                        context.Load(enterpriseResource, p => p.Name, p => p.Assignments, p => p.Email);
                        Console.Write("Loading resource...");
                        context.ExecuteQuery();
                        Console.WriteLine("done! {0}".FormatWith(enterpriseResource.Name));

                        Console.Write("Adding new resource assignment to collection...");
                        enterpriseResource.Assignments.Add(new StatusAssignmentCreationInformation
                        {
                            Comment = "testing comment - 2016-02-17",
                            ProjectId = new Guid("27bf182c-2339-e411-8e76-78e3b5af0525"),

                            Task = new StatusTaskCreationInformation
                            {
                                Start = DateTime.Now,
                                Finish = DateTime.Now.AddDays(2),
                                Name = "testing - 2016-02-17",
                            }
                        });
                        Console.WriteLine("done!");

                        Console.Write("Trying to save new resource assignment...");
                        enterpriseResource.Assignments.Update();
                        context.ExecuteQuery();
                        Console.WriteLine("done!");

                        Console.Write("Loading TimePhase...");
                        TimePhase timePhase = enterpriseResource.Assignments.GetTimePhase(startDate.Date, endDate.Date);
                        context.ExecuteQuery();
                        Console.WriteLine("done!");

                        Console.Write("Loading TimePhase assignments...");
                        context.Load(timePhase.Assignments);
                        context.ExecuteQuery();
                        Console.WriteLine("done! Found {0} assignments.".FormatWith(timePhase.Assignments.Count));

                        Console.WriteLine("Updating TimePhase assignments...");
                        foreach (var assignment in timePhase.Assignments)
                        {
                            Console.WriteLine("Updating assignment: {0}. ActualWork: {1}".FormatWith(assignment.Name, assignment.ActualWork));
                            assignment.ActualWork = "9h";
                            assignment.RegularWork = "3h";
                            assignment.RemainingWork = "0h";
                        }
                        timePhase.Assignments.SubmitAllStatusUpdates("Status update comment test 2016-02-17");
                        context.ExecuteQuery();
                        Console.WriteLine("done!");

                        Console.WriteLine("Success (retrieved & updated {0} time phase assignments)!".FormatWith(timePhase.Assignments.Count));
                    }
                }
                catch (Exception ex)
                {
                    if (ex.ToString().Contains("GeneralSecurityAccessDenied"))
                        Console.WriteLine("ERROR! - GeneralSecurityAccessDenied");
                    else
                        throw;
                }
                finally
                {
                    Console.WriteLine();
                    Console.WriteLine();
                }
            }

            private static void Login(ProjectContext projContext, string username, string password)
            {
                var securePassword = new SecureString();
                foreach (char c in password)
                    securePassword.AppendChar(c);

                projContext.Credentials = new SharePointOnlineCredentials(username, securePassword);
            }

            static string FormatWith(this string str, params object[] args)
            {
                return String.Format(str, args);
            }
        }
    }

有人可以帮忙吗??

4

0 回答 0