Tuesday, November 25, 2008

Employee Directory WebPart


I recently had the challenge of implementing a webpart for a client to show a list of employees that was Presence Aware. Initially I could not get the awareness to work until I stumbled across some very useful resources that explained the 'hey presto' solution to get this working.

I followed this guide to implement the web part in Microsoft Office SharePoint Server. Then this older article to solve my problems with Presence awareness

Good luck and if you follow the guides I have listed you should have no problems. They will also provide you with a great base for extending the capabilities of the webpart.

Wednesday, April 11, 2007

Web Services Contract First - WSCF (Thinktecture)

One of my old favourites is approaching web services development from a contract first approach as opposed to developing in Visual Studio using a methods based approach. I recently completed a project using the WSCF tool and had in my mind to start my web services by developing the contract first. Now that brings me to another interesting point about contract first development - For most people and teams WSDL is really too complicated to hand craft . So here is my checklist that led me to adopt the WSCF tool for my project:
  • Design contract first to avoid dependence on inherited objects e.g. datasets
  • Don't want to handcraft complicated WSDL
  • Rich generation of strongly typed objects
  • Efficient handling of object collections
  • Proxy classes that lend themselves to quick programming related tasks
  • Code generation so I could concentrate on implementing the methods
  • Approach contact first by designing the XSD's first

I encourage you to play with this tool using the provided walkthrough which will give you a good basic understanding of how it works. From there you can experiment with a whole host of code generation features for your objects and WSDL. An especially nice feature is the tight integratation in the Visual Studio 2005 IDE. Please note are quite a few limitations with WSCF so it is not a panacea for all your web service ills. The forum on the thinktecture site will give guidance on what you can and can't do.

Enjoy!

Tuesday, April 10, 2007

PSI - Add Resource custom field values based on a Lookup table values

When you are trying to add values based on Project Server 2007 lookup values the code can get a little tricky so I thought I would outline the steps and include the appropriate code for your reference.

1. Establish a ResourceDataset object
2. Populate the ResourceDataset using the Resource GUID
3. Call my AddResCF function as below passing in the value text (Please refer to the inline comments for further direction)

private bool AddResCFs(Proxy.ResourceDataSet resourceDS, string CFText)
{
bool result = false;
Guid structGuid = Guid.Empty;
string cf_md_prop_name = "";
Guid cf_md_prop_uid = Guid.Empty;
int cf_md_prop_id = int.MinValue;
byte cf_md_prop_type_enum = byte.MinValue;
try
{

//establish a LookupTable dataset using the name of the lookup table which in my case is a class variable (I haven't included the GetLookup_UID function as its pretty straight forward).
Guid LTGuid = new Guid(CustomUtils.GetLookup_UID(lookupName));
//create a lookup table dataset
Proxy.LookupTableDataSet dsLookup = new Proxy.LookupTableDataSet();

//Populate the LookupDataset using the Guid returned above
dsLookup = utils.LookupTableProxy.ReadLookupTablesByUids(new Guid[] { LTGuid }, false, int.Parse(LANGUAGE_ID.ToString()));

//Now check if the value exists in the Lookup table ( in this instance I am querying the description column instead of the name column) The LU_ValueExists just does a for each on the rows in the LookupTableDataset and set the result to true if the value is located
if (LU_ValueExists(dsLookup,"lt_value_desc", CFText))
{
//Create a ResourceCustomFieldsRow and populate the neccesary columns
Proxy.ResourceDataSet.ResourceCustomFieldsRow cfRow = resourceDS.ResourceCustomFields.NewResourceCustomFieldsRow();

//the following fields are not required but should be set to null for correctness
cfRow.SetNUM_VALUENull();
cfRow.SetFLAG_VALUENull();
cfRow.SetDUR_VALUENull();
cfRow.SetDUR_FMTNull();
cfRow.SetDATE_VALUENull();
cfRow.SetTEXT_VALUENull();

//Next populate the custom fields row with the correct property values using the Enterprise field name (different from LookupTable name). Again I am using a class variable for this purpose.
cf_md_prop_uid = CustomUtils.GetCustomFieldsProps(entfieldName, out cf_md_prop_name, out cf_md_prop_id, out cf_md_prop_type_enum);
if (cf_md_prop_uid != Guid.Empty)
{
cfRow.MD_PROP_UID = cf_md_prop_uid;
cfRow.MD_PROP_ID = cf_md_prop_id;
cfRow.CUSTOM_FIELD_UID = Guid.NewGuid();
cfRow.FIELD_TYPE_ENUM = cf_md_prop_type_enum;
cfRow.CODE_VALUE = skill_struct_uid;
cfRow.RES_UID = (Guid)resourceDS.Resources.Rows[0]["RES_UID"];
//add row to ResourceDataset
resourceDS.ResourceCustomFields.Rows.Add(cfRow);
result = true;
}
else
{
result = false;
}
}
return result;
}

4. Call the UpdateResources of your PSI Resources proxy object
private bool UpdateResourceEntField(Proxy.ResourceDataSet ResourceDS, Guid resGuid)
{
//add situation for exception handling
Proxy.ExceptionHandlers.Situation situation = Proxy.ExceptionHandlers.Situation.AddResourceSkills;
try
{
//check the resource out before calling the update method (I prefer this to the included check-//out boolean included in the function call)
//NB: Remember to include checkin code in your exception handlers as the resource will remain checked out if an handled exception occurs
bool bCheckOut = false;
bCheckOut = CheckOutResource(resGuid);
Proxy.Global.utils.ResourceProxy.UpdateResources(ResourceDS, false, false);
//Checkin the resource
bCheckOut = CheckInResource(resGuid);
return true;
}

Please note the above assumes that you already know the lookup table row value so you can read the loopuptable using a filter with the value specified. Also I have tried at length to just create an empty ResourceDataSet and then just add a populated ResourceCustomFields row but kept getting a GeneralUnhandledException from the PSIErrors collection. NICE!

The above is not a full set of functions but should get you going in the right direction. If I receive enough requests I'll polish it up into a little sample app for download.

Also I thought a little call to action: We have to share our Project Server Interface (PSI) code as MS didn't give us much to go on. The more that gets out there, the easier it will become to find resources on people's blog and discussion groups. Thanks for listening to my rant :-)

Project Server 2007 - SQL (not mdb) Analysis Services Repository

I recently had to install Analysis Services 2005 subsequent to the initial installation of PS2007. I found this great tip and database backup on Christophe Fiessinger's Blog. The post details how to setup a SQL database copy of the Analysis Services repository...read more...

You will need to have the correct products installed and then you can update the ini file for the correct settings as specified in Christophe's post. (check here on Projectified)

Friday, March 30, 2007

PS2007 Task Duration Calculation (based on Days)

This is just a short blog to comment on a little problem I recently ran into regarding updating the duration for a task using the PSI. The problem was 8 inches from the screen (i.e. me) however I thought I would blog about it to save someone else the problem (embarrassment). When adding a task duration to the ProjectDataset.TaskRow object the figure has to represent tenths of minutes as specified in the SDK class documentation. Here is a complete copy of my CreateTask function. Please note the example is written in C# and based on a strongly typed TaskDetails object.

public static void CreateTask(Proxy.ProjectDataSet dataset, int projNum, Proxy.TaskInfo TaskDetails, string name, Guid taskGuid)
{
Proxy.ProjectDataSet.TaskRow taskRow = dataset.Task.NewTaskRow();
taskRow.PROJ_UID = dataset.Project[projNum].PROJ_UID;
taskRow.TASK_UID = taskGuid;
TimeSpan span = TaskDetails.EndDate.Subtract(TaskDetails.StartDate);
int Days = span.Days;
taskRow.TASK_DUR_FMT = (int)PSLibrary.Task.DurationFormat.Day;
taskRow.TASK_DUR = (Days * 4800);
taskRow.TASK_NAME = name;
taskRow.TASK_START_DATE = TaskDetails.StartDate;
taskRow.TASK_FINISH_DATE = TaskDetails.EndDate;
//TaskDetails.Config_Position;
taskRow.TASK_PRIORITY = int.Parse(TaskDetails.Priority);
//TaskDetails.Project_Code;
taskRow.TASK_CONTACT = TaskDetails.TaskOwner;
//TaskDetails.WO_Code;
dataset.Task.AddTaskRow(taskRow);
}


Please note that line taskRow.TASK_DUR_FMT = (int)PSLibrary.Task.DurationFormat.Day only specifies how the duration will be displayed in the Project Server interfaces (PWA & Project Prof).

The 4800 figure should be changed based on the standard working hours in your project calendar. If the calendar used has a different number of working hours you will need to update this figure based on the following calculations:.

Here is how you get to 4800 to represent tenths of a minute.
Standard calendar = 8 hrs per day

8 Hours = 480 minutes

X10 = 4800 tenths of minutes

This presents a problem with maintainability but that is a configuration issue and something you will need to handle separately.

Friday, October 20, 2006

IE 7 - Missing drag links

I still consider IE 7.0 is missing one killer feature that I love about firefox. I would love to be able to drag a link from a page being viewed to the tabs area and either drop it on an existing tab or create a new tab. Otherwise I think the new browser from MS is great and will finally put an end to all those open windows and the naf grouping in the desktop toolbar. Of course I would probably just use Firefox if MS would ensure that the javascript they used on dynamic pages worked in that browser. I can't see that happening any time soon though.

Thursday, May 11, 2006

Project Manager field - Project Server 03

The project managers field is input in the file properties dialog in Project Professional. It is called the author field. This maps backs to the project server database in the msp_projects table and is located in the proj_prop_manager field.