Check out my new blog at https://shibumiware.blogspot.com

Monday, May 26, 2008

Microsoft Project Fx (mpFx) - Entity Factory

A common pattern across the PSI is illustrated by the following pseudo-code (which doesn't account for disposal):

MainDataSet mainDataSet = new MainDataSet()

MainDataSet.Row row = mainDataSet.NewRow()

row.Attribute_1 = "some value"

row.Attribute_2 = "some other value"

mainDataSet.AddNewRow(row);

ProjectServer.SomeQueueMethod(mainDataSet)

I wrote a factory wrapper that makes this a bit easier.  Here is the top of the call chain, where use my EntityFactory to create a new ProjectDataSet with a single Project row populated with basic information:

EntityFactory.AutoCreateGuids = true;

using (ProjectDataSet project = EntityFactory.NewProject("Test", true, DateTime.Now))
{
    Debug.Print(project.Project[0].PROJ_UID.ToString());

    _ProjectServer.Projects.Create(project, false, true);                
}

The EntityFactory current has several overloaded methods for creating a ProjectDataSet.  Eventually it will house methods for creating all primary entities in Project Server (project, resource, task, assignment, and custom field).    Here is the project creation methods:

public class EntityFactory
{
    #region Static Fields

    private static bool _AutoCreateGuid = true;

    #endregion

    #region Public Properties

    public static bool AutoCreateGuids
    {
        get { return _AutoCreateGuid; }
        set { _AutoCreateGuid = value; }
    }

    #endregion

    #region Project Creation Methods

    /// <summary>
    /// Create empty project row
    /// </summary>
    /// <returns></returns>
    public static ProjectDataSet NewProject()
    {
        ProjectDataSet projectDataSet = new ProjectDataSet();
        
        ProjectDataSet.ProjectRow project  = projectDataSet.Project.NewProjectRow();

        if (AutoCreateGuids)
        {
            project.PROJ_UID = Guid.NewGuid();                    
        }

        projectDataSet.Project.AddProjectRow(project);

        return projectDataSet;                        
    }

    /// <summary>
    /// Create project row with name 
    /// </summary>
    /// <param name="name">Project Name</param>
    /// <returns></returns>
    public static ProjectDataSet NewProject(string name)
    {
        ProjectDataSet project = NewProject();

        project.Project[0].PROJ_NAME = name;

        return project;
    }

    /// <summary>
    /// Create project with name and guid
    /// </summary>
    /// <param name="name">Project Name</param>
    /// <param name="guid">Project GUI</param>
    /// <returns></returns>
    public static ProjectDataSet NewProject(string name, Guid guid)
    {
        ProjectDataSet project = NewProject(name);

        project.Project[0].PROJ_UID = guid;

        return project;
    }

    /// <summary>
    /// Create project with name, set schedule from (SFS or SFF) and relevant date (start for SFS, finish for SFF)
    /// </summary>
    /// <param name="name">Project Name</param>
    /// <param name="scheduleFromStart">True to schedule from Start Date, false to schedule from Finish Date</param>
    /// <param name="date">if 'schedleFromStart' = true, Start Date; false, Finish Data</param>
    /// <returns></returns>
    public static ProjectDataSet NewProject(string name, bool scheduleFromStart, DateTime date)
    {
        ProjectDataSet project = NewProject(name);            

        if (scheduleFromStart)
        {
            project.Project[0].PROJ_INFO_SCHED_FROM = true;
            project.Project[0].PROJ_INFO_START_DATE = date;

        }
        else
        {
            project.Project[0].PROJ_INFO_SCHED_FROM = false;
            project.Project[0].PROJ_INFO_FINISH_DATE = date;
        }

        return project;

    }
}
 

CreateProject looks like this:

public Guid Create(ProjectDataSet project, bool validateOnly, bool wait)
{               
    Guid jobGuid = Guid.NewGuid();

    _Parent.ProjectsWebService.QueueCreateProject(jobGuid, project, validateOnly);

    if (wait)
    {
        string errorMessage;

        _Parent.Queue.WaitOnJobStatus(jobGuid, 
                                      JobState.Success, 
                                      _Parent.QueueStatusRetryCount, 
                                      _Parent.QueueStatusSleepDuration, 
                                      out errorMessage);

    }

    return jobGuid;                
    
}

Notice the "wait" parameter, which causes mpFx to wait on the queued job to complete.  The wait is controlled by a repeat count and a sleep duration.  It looks like this:

public void WaitOnJobStatus(Guid jobGuid, JobState jobState, int count, int duration, out string errorString)
{
    JobState currentState;

    errorString = string.Empty;

    for (int i = 0; i < count - 1; i++)
    {                
        currentState = _Parent.QueueWebService.GetJobCompletionState(jobGuid, out errorString);

        if (currentState == jobState)
        {
            return;
        }

        Thread.Sleep(duration);
    }

    throw new Exception(errorString);
}

Note that exception handling and other fundamentals are left out for clarity.  Making progress, slowly but surely.  Thanks to all for the ideas!

No comments :

Disclaimer

Content on this site is provided "AS IS" with no warranties and confers no rights. Additionally, all content on this site is my own personal opinion and does not represent my employer's view in any way.