Метод Statusing.ReadStatusForResource
Возвращает данные, отчеты о состоянии для указанного назначения или для всех назначений указанного ресурса. Не требуется олицетворение ресурса.
Пространство имен: WebSvcStatusing
Сборка: ProjectServerServices (в ProjectServerServices.dll)
Синтаксис
'Декларация
<SoapDocumentMethodAttribute("https://schemas.microsoft.com/office/project/server/webservices/Statusing/ReadStatusForResource", RequestNamespace := "https://schemas.microsoft.com/office/project/server/webservices/Statusing/", _
ResponseNamespace := "https://schemas.microsoft.com/office/project/server/webservices/Statusing/", _
Use := SoapBindingUse.Literal, ParameterStyle := SoapParameterStyle.Wrapped)> _
Public Function ReadStatusForResource ( _
resid As Guid, _
assnid As Guid, _
mindate As DateTime, _
maxdate As DateTime _
) As StatusingDataSet
'Применение
Dim instance As Statusing
Dim resid As Guid
Dim assnid As Guid
Dim mindate As DateTime
Dim maxdate As DateTime
Dim returnValue As StatusingDataSet
returnValue = instance.ReadStatusForResource(resid, _
assnid, mindate, maxdate)
[SoapDocumentMethodAttribute("https://schemas.microsoft.com/office/project/server/webservices/Statusing/ReadStatusForResource", RequestNamespace = "https://schemas.microsoft.com/office/project/server/webservices/Statusing/",
ResponseNamespace = "https://schemas.microsoft.com/office/project/server/webservices/Statusing/",
Use = SoapBindingUse.Literal, ParameterStyle = SoapParameterStyle.Wrapped)]
public StatusingDataSet ReadStatusForResource(
Guid resid,
Guid assnid,
DateTime mindate,
DateTime maxdate
)
Параметры
resid
Тип: System.GuidGUID ресурса.
assnid
Тип: System.GuidИдентификатор GUID назначения. Guid.empty возвращает все назначения.
mindate
Тип: System.DateTimeНачало диапазона дат. Используйте DateTime.MinDate для выбора с самого начала.
maxdate
Тип: System.DateTimeКонец диапазона дат. Используйте DateTime.MaxDate , чтобы указать до конца.
Возвращаемое значение
Тип: WebSvcStatusing.StatusingDataSet
Возвращает StatusingDataSet.
Замечания
Разрешения Project Server
Разрешение |
Описание |
---|---|
Позволяет пользователям для чтения и обновления состояния от имени ресурса. Глобальное разрешение. |
Примеры
Пример для WCF и запланированные вручную задачи: В примере UpdateStatus_ManualTasks — это тестовое приложение, которое выполняет следующие действия, для задачи, запланированной вручную или автоматически запланированную задачу:
Анализирует имя проекта, имя задачи, количество проработанных часов, optionalassigned ресурсов и необязательные состояние комментария.
Если отсутствует ресурс не указан, то предполагается, что пользователь приложения назначена задача.
Получает GUID для пользователя, назначенного для указанной задачи.
Получает и проверяет данные назначения. Предполагается, что только один ресурс может быть назначен.
Создает строку changeXml для метода UpdateStatus . Для простой проверки преобразует отчет о часах процента завершения (максимальное 100). Если пользователь приложения указывает другой ресурс, добавляет атрибут ResID элемент Assn в строке changeXml .
Вызывает UpdateStatus, а затем вызывает SubmitStatusForResourceдля одного назначения.
Вызывает ReadStatusForResource для получения обновленной StatusingDataSet.
Приложение записывает наборов данных и значение changeXml XML-файлов, для использования при тестировании.
Использование тестового приложения UpdateStatus , выполните следующие действия.
Создайте тестовый проект, добавить два задач, запланированных вручную, задайте длительность задачи и Дата начала и добавьте себя и еще один пользователь как ресурсы. Назначьте одну задачу для вас и других задач другого пользователя.
Например назовите проект тестированию проекта, имя задачи T1 и T2 и задайте длительность каждой задачи до трех дней. Предположим, пользователь 1 — это имя пользователя и других пользователей: 2 пользователя. Назначение T1 1 пользователей и назначение T2 пользователю 2.
For configuration of the WCF endpoints, create an app.config file. For information about using the code sample in a Microsoft Visual Studio 2010 project and creating an app.config file, see Необходимые условия для примеров кода на основе WCF в Project 2013.
Запустите тесты, используя различные параметры. В разделе метод Usage в следующем коде для получения параметров. Например выполните следующие тесты в окне командной строки:
UpdateStatus -p "Test project" -t "T1" -hours 6 -c "This is a comment"
Отображает выходные данные:
Updating status for User 1 on task 'T1': 6 hours Manually scheduled task
UpdateStatus -p "Test project" -t "T1" -hours 6 -r "User 2" -c "This is a comment"
Пользователь 2 не назначена задача T1, поэтому приложения отображается The assignment on task 'T1' is for User 1, not for User 2.
UpdateStatus -p "Test project" -t "T2" -hours 6 -r "User 2" -c "This is a comment"
Отображает выходные данные:
Updating status for User 2 on task 'T2': 6 hours Manually scheduled task
После каждого теста обратитесь в Центр утверждения в Project Web App для обновления состояния.
Примечание
При добавлении вручную запланированного задания, которое не имеет даты начала или длительность, значение по умолчанию — 8 часов работы. По-прежнему можно назначать ресурсы для задачи и обновить состояние. К примеру Если задач, которыми T3 начала не даты или длительности и использование тестового приложения UpdateStatus Установка шесть часов работы для ресурса, Project Server задает дату начала для T3 дату начала проекта и добавляет шесть часов фактических трудозатрат. После принятия обновления состояния, можно добавить столбцы Фактические трудозатраты и Оставшиеся трудозатраты в представление диаграммы Ганта в Project профессиональный 2010. Работа для T3 составляет 8 часов, фактические трудозатраты — 6 часов и оставшиеся трудозатраты — это два часа. Если вы добавили Фактические трудозатраты строки в области сведений в представлении использования ресурсов или Использование задач, можно также просмотреть 6 часов фактических трудозатрат.
Полноценным решением Visual Studio находится в Project 2010 пакет SDK для загрузки.
using System;
using System.Data;
using System.Globalization;
using System.IO;
using System.Linq;
using System.Text;
using System.ServiceModel;
using System.Security.Principal;
using System.Xml;
using PSLibrary = Microsoft.Office.Project.Server.Library;
namespace Microsoft.SDK.Project.Samples.UpdateStatus
{
class Program
{
private const string ENDPOINT_PROJECT = "basicHttp_Project";
private const string ENDPOINT_RESOURCE = "basicHttp_Resource";
private const string ENDPOINT_STATUSING = "basicHttp_Statusing";
// Change the output directory for your computer.
private const string OUTPUT_FILES = @"C:\Project\Samples\Output\";
private const string XML_FILE1 = "UpdateStatus_jc_BasicProjectInfo.xml";
private const string XML_FILE2 = "UpdateStatus_jc_FullProjectInfo.xml";
private const string XML_FILE3 = "UpdateStatus_jc_ChangeXml.xml";
private const string XML_FILE4 = "UpdateStatus_jc_NewStatus.xml";
private static SvcProject.ProjectClient projectClient;
private static SvcResource.ResourceClient resourceClient;
private static SvcStatusing.StatusingClient statusingClient;
private static string projectName = string.Empty; // Project name.
private static string taskName = string.Empty; // Task name.
private static string resName = string.Empty; // Assigned resource name.
private static string requestedResName = string.Empty; // Requested resource name.
private static string appUserName = string.Empty; // Application user name.
private static DateTime minDate = DateTime.Today; // Minimum date for statusing data.
private static DateTime maxDate = DateTime.Today; // Maximum date for statusing data.
private static decimal hoursWorked = 0.0M; // Number of hours worked on the assignment.
private static string comment = string.Empty; // Comment for status submission.
private static bool showUsage = false;
private static StreamWriter writer;
static void Main(string[] args)
{
string outFilePath1 = OUTPUT_FILES + XML_FILE1;
string outFilePath2 = OUTPUT_FILES + XML_FILE2;
string outFilePath3 = OUTPUT_FILES + XML_FILE3;
string outFilePath4 = OUTPUT_FILES + XML_FILE4;
writer = new StreamWriter(outFilePath3);
Guid projUid = Guid.Empty; // GUID of the project.
Guid taskUid = Guid.Empty; // GUID of the task.
Guid assnUid = Guid.Empty; // GUID of the assignment.
Guid resUid = Guid.Empty; // GUID of the assigned resource.
Guid requestedResUid = Guid.Empty; // GUID of the requested resource, for submitting status.
Guid myUid = Guid.Empty; // GUID of the application user.
double regularWork = 0; // Assignment working time at the regular rate,
// in thousandths of minutes.
bool isTaskManual = false; // Specifies whether the task is manually scheduled.
if (!ParseCommandLine(args))
{
Usage();
ExitApp();
}
try
{
ConfigClientEndpoints(ENDPOINT_PROJECT);
ConfigClientEndpoints(ENDPOINT_RESOURCE);
ConfigClientEndpoints(ENDPOINT_STATUSING);
WindowsIdentity winId = WindowsIdentity.GetCurrent();
appUserName = winId.Name;
myUid = resourceClient.GetCurrentUserUid();
Console.WriteLine("User: {0}; PWA GUID: {1}", appUserName, myUid.ToString());
// Get the basic information for the project.
SvcProject.ProjectDataSet projectDs = projectClient.ReadProjectStatus(
Guid.Empty, SvcProject.DataStoreEnum.PublishedStore, projectName,
(int)PSLibrary.Project.ProjectType.Project);
Console.WriteLine("XML output for ReadProjectStatus:\n\t{0}",
outFilePath1);
projectDs.WriteXml(outFilePath1);
projUid = projectDs.Project[0].PROJ_UID;
if (projUid == Guid.Empty)
throw (new ArgumentException(
string.Format("\nThe project '{0}' does not exist.", projectName)));
// Get the full information for the project.
projectDs = projectClient.ReadProject(projUid,
SvcProject.DataStoreEnum.PublishedStore);
Console.WriteLine("XML output for ReadProject:\n\t{0}", outFilePath2);
projectDs.WriteXml(outFilePath2);
bool isCurrentUser; // Specifies whether the assignment is for the current user.
// Get requested resource GUID. Exit if the requested resource is not a project resource.
if (string.IsNullOrEmpty(requestedResName))
{
// The current user is the requested resource.
isCurrentUser = true;
// Use a Linq query over the typed ProjectDataSet to check whether
// the app user is a resource on the project.
var query = from r in projectDs.ProjectResource
where r.RES_UID == myUid
select new { r.RES_NAME };
foreach (var resRow in query)
{
requestedResName = resRow.RES_NAME;
requestedResUid = myUid;
}
}
else
{
isCurrentUser = false;
var query = from r in projectDs.ProjectResource
where r.RES_NAME == requestedResName
select new { r.RES_UID };
foreach (var resRow in query)
{
requestedResUid = resRow.RES_UID;
}
}
if (requestedResUid == Guid.Empty)
{
if (string.IsNullOrEmpty(requestedResName))
requestedResName = appUserName;
throw (new ArgumentException(
string.Format("\nThe resource '{0}' is not on the project '{1}'",
requestedResName, projectName)));
}
// Get the assignment data for the task.
for (int i = 0; i < projectDs.Assignment.Count; i++)
{
if (projectDs.Assignment[i].TASK_NAME == taskName)
{
taskUid = projectDs.Assignment[i].TASK_UID;
assnUid = projectDs.Assignment[i].ASSN_UID;
resUid = projectDs.Assignment[i].RES_UID;
regularWork = projectDs.Assignment[i].ASSN_WORK;
minDate = projectDs.Assignment[i].ASSN_START_DATE;
maxDate = projectDs.Assignment[i].ASSN_FINISH_DATE;
// Get the assigned resource name.
for (int j = 0; j < projectDs.ProjectResource.Count; j++)
{
if (projectDs.ProjectResource[j].RES_UID == resUid)
{
resName = projectDs.ProjectResource[j].RES_NAME;
break;
}
}
// Is the task manually scheduled?
for (int t = 0; t < projectDs.Task.Count; t++)
{
if (projectDs.Task[t].TASK_UID == taskUid)
{
isTaskManual = projectDs.Task[t].TASK_IS_MANUAL;
break;
}
}
break;
}
}
ValidateAssignment(isCurrentUser, resUid, myUid, assnUid, requestedResUid);
string changeXml = CreateChangeXml(projUid, assnUid, resUid,
hoursWorked, regularWork, isCurrentUser);
Console.WriteLine("XML output for ChangeXml:\n\t{0}", outFilePath3);
writer.WriteLine(changeXml);
Console.ForegroundColor = ConsoleColor.Yellow;
string yellowString = "\nUpdating status for {0} on task '{1}': {2} hours\n\t";
yellowString += (isTaskManual) ? "Manually scheduled task" : "Auto-scheduled task";
Console.WriteLine(yellowString, resName, taskName, hoursWorked);
Console.ResetColor();
statusingClient.UpdateStatus(changeXml);
Guid[] assignments = { assnUid };
statusingClient.SubmitStatusForResource(resUid, assignments, comment);
SvcStatusing.StatusingDataSet statusingDs =
statusingClient.ReadStatusForResource(resUid, assnUid, minDate, maxDate);
Console.WriteLine("\nXML output for ReadStatusForResource:\n\t{0}", outFilePath4);
statusingDs.WriteXml(outFilePath4);
}
catch (FaultException fault)
{
// Use the WCF FaultException, because the ASMX SoapException does not
// exist in a WCF-based application.
Console.ForegroundColor = ConsoleColor.Red;
WriteFaultOutput(fault);
Console.WriteLine();
showUsage = true;
}
catch (Exception ex)
{
Console.ForegroundColor = ConsoleColor.Red;
Console.WriteLine(ex.Message);
Console.WriteLine();
showUsage = true;
}
finally
{
writer.Close();
Console.ResetColor();
if (showUsage) Usage();
ExitApp();
}
}
// Validate the assignment and the resource.
private static void ValidateAssignment(bool isCurrentUser, Guid resUid, Guid myUid,
Guid assnUid, Guid requestedResUid)
{
if (!isCurrentUser && resUid == myUid)
throw (new ArgumentException(
string.Format("\nThe assignment on task '{0}' is for {1}, not for {2}",
taskName, resName, requestedResName)));
if (assnUid == Guid.Empty)
throw (new ArgumentException(
string.Format("\nNo assignment for {0} on task '{0}'", resName, taskName)));
if (requestedResUid != resUid)
throw (new ArgumentException(
string.Format("\nResource '{0}' does not match assignment on task '{1}'",
requestedResName, taskName)));
}
/// <summary>Create a ChangeXml string for the UpdateStatus method.</summary>
/// <param name="projUid">Project GUID</param>
/// <param name="assnUid">Assignment GUID</param>
/// <param name="resUid">Resource GUID</param>
/// <param name="hoursWorked">Number of hours worked.</param>
/// <param name="totalRegHours">
/// Total assigned hours at the regular rate, in thousandths of minutes.</param>
/// <param name="isCurrentUser">True if the assignment is for the current user.</param>
/// <returns></returns>
private static string CreateChangeXml(Guid projUid, Guid assnUid, Guid resUid,
decimal hoursWorked, double totalRegHours, bool isCurrentUser)
{
StringBuilder cXmlBuilder = new StringBuilder("<Changes>");
cXmlBuilder.AppendFormat("<Proj ID=\"{0}\">", projUid.ToString());
cXmlBuilder.AppendFormat("<Assn ID=\"{0}\"", assnUid.ToString());
// If the assignment is not for the current user, add the ResID attribute,
// and then close the Assn element.
if (isCurrentUser)
cXmlBuilder.Append(">");
else
cXmlBuilder.AppendFormat(" ResID=\"{0}\">", resUid.ToString());
// Specify the process ID (PID) for percent work complete.
// The "Supported Project Fields and Field Information for Statusing ChangeXML"
// SDK article shows the PID value is 251658274.
string pidPctWorkComplete = PSLibrary.AssnConstID.s_apid_pct_wrk_complete.ToString(
CultureInfo.InvariantCulture);
// Calculate the percent work complete.
int pctComplete = Convert.ToInt32(100 * hoursWorked /
Convert.ToDecimal(totalRegHours / 1000 / 60));
if (pctComplete > 100) pctComplete = 100;
cXmlBuilder.AppendFormat("<Change PID=\"{0}\">{1}</Change>", pidPctWorkComplete,
pctComplete.ToString());
cXmlBuilder.Append("</Assn></Proj></Changes>");
return cXmlBuilder.ToString();
}
// Extract a PSClientError object from the WCF FaultException object, and
// then display the exception details and each error in the PSClientError stack.
private static void WriteFaultOutput(FaultException fault)
{
string errAttributeName;
string errAttribute;
string errOut;
string errMess = "".PadRight(30, '=') + "\r\n"
+ "Error details: " + "\r\n";
PSLibrary.PSClientError error = Helpers.GetPSClientError(fault, out errOut);
errMess += errOut;
PSLibrary.PSErrorInfo[] errors = error.GetAllErrors();
PSLibrary.PSErrorInfo thisError;
for (int i = 0; i < errors.Length; i++)
{
thisError = errors[i];
errMess += "\r\n".PadRight(30, '=') + "\r\nPSClientError output:\r\n";
errMess += thisError.ErrId.ToString() + "\n";
for (int j = 0; j < thisError.ErrorAttributes.Length; j++)
{
errAttributeName = thisError.ErrorAttributeNames()[j];
errAttribute = thisError.ErrorAttributes[j];
errMess += "\r\n\t" + errAttributeName
+ ": " + errAttribute;
}
}
Console.ForegroundColor = ConsoleColor.Red;
Console.WriteLine(errMess);
Console.ResetColor();
}
// Use the endpoints defined in app.config to configure the client.
public static void ConfigClientEndpoints(string endpt)
{
if (endpt == ENDPOINT_PROJECT)
projectClient = new SvcProject.ProjectClient(endpt);
else if (endpt == ENDPOINT_RESOURCE)
resourceClient = new SvcResource.ResourceClient(endpt);
else if (endpt == ENDPOINT_STATUSING)
statusingClient = new SvcStatusing.StatusingClient(endpt);
}
// Parse the command line. Return true if there are no errors.
private static bool ParseCommandLine(string[] args)
{
int i;
bool error = false;
int argsLength = args.Length;
for (i = 0; i < argsLength; i++)
{
if (error) break;
if (args[i].StartsWith("-") || args[i].StartsWith("/"))
args[i] = "*" + args[i].Substring(1).ToLower();
switch (args[i])
{
case "*projectname":
case "*p":
if (++i >= argsLength) return false;
projectName = args[i];
break;
case "*taskname":
case "*t":
if (++i >= argsLength) return false;
taskName = args[i];
break;
case "*resourcename":
case "*r":
if (++i >= argsLength) return false;
requestedResName = args[i];
break;
case "*hours":
case "*h":
if (++i >= argsLength) return false;
hoursWorked = Convert.ToDecimal(args[i]);
break;
case "*comment":
case "*c":
if (++i >= argsLength) return false;
comment = args[i];
break;
case "*?":
default:
error = true;
break;
}
}
return !error;
}
private static void Usage()
{
string example = "Usage: UpdateStatus -p \"Project Name\" -t \"Task name\" -h 3"
+ "\r\n\t\t[-r \"Resource Name\"] [-d 6/29/2011] [-c \"This is a comment\"]";
Console.WriteLine(example);
Console.WriteLine(" -projectName | -p: Name of the project.");
Console.WriteLine(" -taskName | -t: Name of the assigned task.");
Console.WriteLine(" -hours | -h: Number of hours worked.");
Console.WriteLine(" -resourceName | -r: Resource name. Default is the current user.");
Console.WriteLine(" -date | -d: Date of the work. Default is non-timephased.");
Console.WriteLine(" -comment | -c: Comment for submitted status.");
}
private static void ExitApp()
{
Console.Write("\nPress any key to exit... ");
Console.ReadKey(true);
Environment.Exit(0);
}
}
// Helper method: GetPSClientError.
class Helpers
{
/// <summary>
/// Extract a PSClientError object from the ServiceModel.FaultException,
/// for use in output of the GetPSClientError stack of errors.
/// </summary>
/// <param name="e"></param>
/// <param name="errOut">Shows that FaultException has more information
/// about the errors than PSClientError has. FaultException can also contain
/// other types of errors, such as failure to connect to the server.</param>
/// <returns>PSClientError object, for enumerating errors.</returns>
public static PSLibrary.PSClientError GetPSClientError(FaultException e,
out string errOut)
{
const string PREFIX = "GetPSClientError() returns null: ";
errOut = string.Empty;
PSLibrary.PSClientError psClientError = null;
if (e == null)
{
errOut = PREFIX + "Null parameter (FaultException e) passed in.";
psClientError = null;
}
else
{
// Get a ServiceModel.MessageFault object.
var messageFault = e.CreateMessageFault();
if (messageFault.HasDetail)
{
using (var xmlReader = messageFault.GetReaderAtDetailContents())
{
var xml = new XmlDocument();
xml.Load(xmlReader);
var serverExecutionFault = xml["ServerExecutionFault"];
if (serverExecutionFault != null)
{
var exceptionDetails = serverExecutionFault["ExceptionDetails"];
if (exceptionDetails != null)
{
try
{
errOut = exceptionDetails.InnerXml + "\r\n";
psClientError =
new PSLibrary.PSClientError(exceptionDetails.InnerXml);
}
catch (InvalidOperationException ex)
{
errOut = PREFIX + "Unable to convert fault exception info ";
errOut += "a valid Project Server error message. Message: \n\t";
errOut += ex.Message;
psClientError = null;
}
}
else
{
errOut = PREFIX
+ "The FaultException e is a ServerExecutionFault, "
+ "but does not have ExceptionDetails.";
}
}
else
{
errOut = PREFIX
+ "The FaultException e is not a ServerExecutionFault.";
}
}
}
else // No detail in the MessageFault.
{
errOut = PREFIX + "The FaultException e does not have any detail.";
}
}
errOut += "\r\n" + e.ToString() + "\r\n";
return psClientError;
}
}
}