Wednesday, March 7, 2012

How to generate Timesheet from Microsoft Team Foundation Server (TFS) 2010 2012

There is not straight forward way to generate timesheet using standard TFS query. Here is concept and sample code to generate Timesheet data from Team Foundation Server (TFS) 2010 using Client Object Model. The code works on following assumption and facts. 
  • You are using “Work Completed” field to track time spend on Work Item. On UI it could be anything. E.g. “Completed” on schedule tab.
  • This field is always having incremental values. That means changes values from 5 to 4 indicate you have decreased time spent which is impractical in real world.
  • You have access to all items for which you want to generate Timesheet.
The Idea
  • Connect to TFS using Client Object Model.
  • Use query to fetch all work item you are interested. In this case, I am interested to fetch all item updated on and after Mar 5, 2012.
  • Loop through all item.
  • For each item, loop through History items and look for change in field “Work Completed”
  • and difference of change is non zero
  • Log required information to CSV file.
  • That’s it, your timesheet is ready to open in Excel.
Working code:
using System;
using Microsoft.TeamFoundation.Client;
using Microsoft.TeamFoundation.WorkItemTracking.Client;
using System.Net;
using System.Collections.Generic;
using System.IO;

namespace TFS_Timesheet
{
    public class TimeEntry
    {
        public string Name { get; set; }
        public DateTime Date { get; set; }
        public int Id { get; set; }
        public string Title { get; set; }
        public double Hours { get; set; }
        public string Comments { get; set; }
    }

    class Program
    {
        static void Main(string[] args)
        {
            if (args.Length < 5)
            {
                Console.WriteLine("Invalid Argument");
                Console.WriteLine("TFS_Timesheet.exe TFSURL UserName Password Domain StartDate");
                Console.WriteLine("TFS_Timesheet.exe http://server:port/dir/defaultcollection <UserName> <Password> <Domain> 2012-03-05");
            }
            else
            {
                Console.WriteLine("Timesheet Started!");
                List timeEntries = new List();
                DateTime startFrom = DateTime.Parse(args[4] + "T00:00:00.0000000");
                StreamWriter timesheet = File.CreateText("c:\\timesheet.csv");
                timesheet.WriteLine("Name,Date,TFSId,Title,Hours");

                Uri collectionUri = new Uri(args[0]);

                NetworkCredential cre = new NetworkCredential(args[1], args[2], args[3]);

                // Connect to the server and the store. 
                TfsTeamProjectCollection teamProjectCollection =
                   new TfsTeamProjectCollection(collectionUri, cre);

                WorkItemStore workItemStore = teamProjectCollection.GetService();
                WorkItemCollection workItems = workItemStore.Query("SELECT [System.Id], [System.ChangedDate], [System.Title], [System.State] FROM WorkItems WHERE [System.ChangedDate] >= '" + startFrom.ToLongDateString() + "' ORDER BY [System.ChangedDate]");
                foreach (WorkItem workItem in workItems)
                {

                    if (workItem == null)
                        continue;

                    if (workItem.IsValid() == false)
                    {
                        continue;
                    }

                    foreach (Revision rev in workItem.Revisions)
                    {
                        foreach (Field field in rev.Fields)
                        {
                            if (field.Name == "Completed Work" && field.OriginalValue != field.Value && Convert.ToDateTime(rev.Fields[CoreField.ChangedDate].Value) >= startFrom)
                            {
                                TimeEntry entry = new TimeEntry();
                                entry.Id = workItem.Id;
                                entry.Date = Convert.ToDateTime(rev.Fields[CoreField.ChangedDate].Value);
                                entry.Name = rev.Fields[CoreField.ChangedBy].Value.ToString();
                                entry.Title = workItem.Title;
                                entry.Hours = Convert.ToDouble(field.Value) - Convert.ToDouble(field.OriginalValue);
                                timeEntries.Add(entry);
                                Console.WriteLine(entry.Name + "\t" + entry.Date + "\t" + entry.Id + "\t" + entry.Hours);
                                timesheet.WriteLine(entry.Name + "," + entry.Date.ToShortDateString() + "," + entry.Id + ",\"" + entry.Title + "\"," + entry.Hours);
                            }
                        }
                    }
                }
                timesheet.Close();
                timesheet.Dispose();
                Console.WriteLine("Timesheet Completed!");
                
            }
            Console.Read();
        }
    }
}

Enjoy!

Monday, January 23, 2012

How to Parse HTML using C# code?

There are situation where data is not directly available in form used by program. The data is in on HTML page but have good well formatted structure (table, divs, spans, paragraph). In this situation many tools are available to directly access site and scraping html as required. To further process this data some manual efforts required.

So, I was searching for HTML parser in .NET but did not find quick way to do it. Came cross WebBrowser Control. There are different ways of using this control but to parse simple HTML from stream or text here is one way with sample.


public partial class Form1 : Form
    {
        public Form1()
        {
            InitializeComponent();
        }

        private void Form1_Load(object sender, EventArgs e)
        {
            webBrowser1.Navigate("http://kalpish.blogspot.com");
            webBrowser1.DocumentCompleted += new WebBrowserDocumentCompletedEventHandler(webBrowser1_DocumentCompleted);
        }

        void webBrowser1_DocumentCompleted(object sender, WebBrowserDocumentCompletedEventArgs e)
        {
            //Lets say following HTML I got from either database or stream or any other resource and converted to HTML

            string strHTML = @"lt;div id='testDiv'>
                                <table>
                                    <tr>
                                        <td>
                                            Header1</td>
                                        <td>
                                            Header2</td>
                                        <td>
                                            Header3</td>
                                    </tr>
                                    <tr>
                                        <td>
                                            Data1</td>
                                        <td>
                                            Data2</td>
                                        <td>
                                            Data3</td>
                                    </tr>
                                    <tr>
                                        <td>
                                            Data4</td>
                                        <td>
                                            Data7</td>
                                        <td>
                                            &nbsp;</td>
                                    </tr>
                                    <tr>
                                        <td>
                                            Data5</td>
                                        <td>
                                            &nbsp;</td>
                                        <td>
                                            Data10</td>
                                    </tr>
                                    <tr>
                                        <td>
                                            Data6</td>
                                        <td>
                                            Data8</td>
                                        <td>
                                            &nbsp;</td>
                                    </tr>
                                </table>
                                </div>
                                ";

            //Now Load HTML to HTML Document
            webBrowser1.Document.Body.InnerHtml = strHTML;

            //Find Top Div with id='testDiv'
            HtmlElement testDiv = webBrowser1.Document.GetElementById("testDiv");

            //Find all row in in this Div
            HtmlElementCollection rows = testDiv.GetElementsByTagName("tr");
            string currentMantisData = string.Empty;
            foreach (HtmlElement row in rows)
            {

                currentMantisData += "\r\n";
                HtmlElementCollection cols = row.GetElementsByTagName("td");
                foreach (HtmlElement col in cols)
                {
                    currentMantisData += (!string.IsNullOrEmpty(col.InnerText) ? col.InnerText.Trim() : string.Empty) + ",";
                }
            }
            MessageBox.Show(currentMantisData);
        }        
    }

Thursday, August 25, 2011

HTML Encoding & Decoding in JavaScript

It is easy to encode and decode HTML in server side code. When it comes to JavaScript there are many different way to do it. One simple way to achieve this is below.

Instead of relying on inbuilt function/method below code is using browser it self to encode and decode content. This way conversion between text is exactly same as browser renders.

Code simply create temporary DIV element and creates text node in this. This is same as rendering text in to DIV element. By doing this browser will encode the text added to DIV and then innerHTML will give encoded HTML. Do not forget to clean up temporary DIV from memory allocation point of view.

function encodeHTML (str)
{
var div = document.createElement('div');
var text = document.createTextNode(str);
div.appendChild(text);
str = div.innerHTML;
div.removeNode();
return str;
}

function decodeHTML (str)
{
var div = document.createElement('div');
div.innerHTML = str;
str = div.innerText;
div.removeNode();
return str;
}

Sunday, December 20, 2009

SharePoint 2010 Questions

Few days back I was looking for interview questions on SharePoint 2010 but didn't find good source. I have created one set here. Answers to question is either true or false.

1. Microsoft SharePoint Foundation 4.0 is build on top of WSS 3.0?
2. SharePoint Server 2010 works with IIS 7.0 only?
3. SharePoint Server 2010 built on top of .NET Framework 3.5?
4. To debug custom code deployed on SharePoint Server 2010 need VS.NET 2010 to start as Admin?
5. PowerShell support effectively replaces STSADM.exe?
6. SharePoint Explorer for site exploration available in VS.NET 2010 uses OOB web services to connect to SharePoint Server 2010?
7. SharePoint Explorer for site exploration available in VS.NET 2010 can’t be extended by Developer?
8. Solution developed using SharePoint 2010 Project template in VS.NET 2010 must have at least one feature?
9. SPI stands for SharePoint Project Items?
10. To debug custom web part in VS.NET 2010, onc should manually attach debugger to W3WP.exe worker process?
11. SharePoint Server 2010 uses new Web 3.0 view technology?
12. In MSF 4.0, “WebDeleted” & “WebDeleting” are new events?
13. MSF 4.0 allows to change asynchronous even to synchronous through Object Model?
14. MSF 4.0 introduces capability to cancel error and redirect user to custom error page?
15. Workflow code does not contain information of current user and runs under system account only?
16. MSF 4.0 introduces the capability to have a relationship behavior enforced by a lookup field?
17. Join can be implemented on Relational List using browser interface?
18. Use of SPLinq gives better performance over CAML while doing join on Relational Lists?
19. MSF 4.0 lists can support 50M items under all(read/write) scenarios?
20. List query size threshold can be enabled at Farm level?
21. Developer have full control to override querying the large list settings?
22. Maximum number of view fields selected for a joined of joins on a list view is 5?
23. Unique column constrains is scoped at Folder level in list?
24. When making existing column unique, exiting data will be deleted?
25. Item level validation allows to setup formula to validate item before it saved?
26. To use Linq with SharePoint, one must learn CAML?
27. DataContext class is core part of Linq for SharePoint?
28. Client Object Model uses Object Model to communicate with SharePoint Server?
29. The XAP files can be deployed to LAYOUTS folders?
30. JavaScript files in are compressed and can’t be modified?
31. VISIO can be used to develop Workflow and VS.NET 2010 is not longer required for workflow development?
32. Workflow developed in SharePoint 2010 Designer can be exported as WSP?
33. SharePoint 2010 web site can be edited in SharePoint Designer 2007?
34. Workflow can be attached at Site Level?
35. External Data Exchange services allows workflow to interact with LOB system?
36. SSP in no longer required in SharePoint Server 2010?
37. Onc should create Custom Services when data and features are specific to site template?
38. BCS is new name for BDC?
39. BCS can be extended by developing .NET Connector Assemblies in VS.NET 2010?
40. BCS uses Process Account to Authentication while accessing LOB?
41. Web Analytics is new Feature in SharePoint Server 2010?
42. External Content Type and Enterprise Content Type are same?
43. Enterprise Content Type are not allowed at Farm Level?
44. Enterprise Content Types can be derived from Site Content Type?
45. Keywords & Tags are new in SharePoint Server 2010?
46. MOSS 2007 Record Router = SharePoint 2010 Document Router?
47. Document Set is collection of documents?
48. Shared Column can’t be created for Document Set?
49. Version can’t be applied on Document Set?
50. Unique document ID service is enabled at Site Collection Level by Default?
51. Enterprise Search do not have PowerShell support?
52. User Contextual Search is available only in FAST Search for SharePoint?
53. Reporting Services ships with SharePoint 2010?
54. MOSS 2007 Reporting Center Template = BI Center Site Template in SharePoint 2010?
55. Excel Services is Server Hosting of Excel calculation Engine?
56. Only Site Collection Administrator can upload Sandboxed solution?
57. Each Sandboxed solution is isolated to its Site collection?
58. Sandboxed solution can be deployed at Web Application Level?
59. Site Definitions can’t be deployed using Sandboxed solutions?
60. Assembly deployed using Sandbox solution are copied to Bin Directory of Web Application?
61. Using Sandbox solution, one can create multiple sub site under same site collection?
62. Sandbox solution can be disabled by Site Collection Administrator using browser interface?
63. Sandbox solution code is compiled against the full SharePoint API?
64. Sandbox solution can be blocked from Central Admin only?
65. One Assembly deployed using one Sandbox solution can be accessed by other Sandbox solution in same Site Collection?

Thursday, July 16, 2009

Code Snippets : SharePoint SOAP Services

SharePoint SOAP Services are great. Easy to use, integrate with other system and access from client side. Most of the time developer do not have access to SharePoint server or have limited access to server. Many time writing simple C# code on server and running console application saves time.

Automating preparative copy, move, setting content etc. can be done fast by using services.

So, without having full access to server such task can be performed by using SharePoint SOAP based web services. 

Code Assumes that SharePoint Services references are added to your project. e.g. Copy Service is at http://server/_vti_bin/Copy.asmx and namespace for Services is SharePointList.SPServices. Same for Lists.asmx.

1) Copy Document Library Item
Below code copies List Item from one library to other library on same server.
SharePointList.SPServices.Copy CopyService = new SharePointList.SPServices.Copy();
SharePointList.SPServices.CopyResult CopyResult = new SharePointList.SPServices.CopyResult();
SharePointList.SPServices.CopyResult[] CopyResultArray = { CopyResult };

string []destURL = new string[] { "http://server/destDocLib/test.doc"};// Multiple destination
string sourceURL = "http://server/SourceDocLib/test.doc";
uint result = CopyService.CopyIntoItemsLocal(sourceURL, destURL, out CopyResultArray);
if (result == 0)
{
foreach (SharePointList.SPServices.CopyResult copyResult in CopyResultArray)
{
if (copyResult.ErrorMessage == null)
{
//Log success message here
}
else
{
//Log exception here
}
}
}
2) Set Document Library/List Column Value
Below code sets column value in specific list item

void setColumnValue(string listName, string ID, string columnName, string columnValue)
{
Lists wList = new Lists();
XmlDocument doc = new XmlDocument();
XmlElement newColumnValue = doc.CreateElement("Batch");
newColumnValue.SetAttribute("OnError", "Return");
newColumnValue.InnerXml = "" +
"" + ID + "" + columnValue + "" +
"
";
try
{
XmlNode returnValue = wList.UpdateListItems(listName, newColumnValue);
Console.WriteLine(returnValue.OuterXml);

}
catch (System.Web.Services.Protocols.SoapException ex)
{
Console.WriteLine("Message:\n" + ex.Message + "\nDetail:\n" + ex.Detail.InnerText + "\nStackTrace:\n" + ex.StackTrace);
}
catch (Exception ex)
{
Console.WriteLine("Message:\n" + ex.Message + "\nDetail:\n" + ex.ToString() + "\nStackTrace:\n" + ex.StackTrace);
}
}

More code sample are in pipeline.

Thursday, June 18, 2009

Stop Web Page submit before it is fully loaded in Browser?

Once came across a situation where page loading is slow due to required image loading in JavaScript. Some of the variables are required to set at end of the page load in order to function it as expected. User was clicking on button to post back the page. But, since page is not loaded fully and required variables are not set, post back was not working as expected. To fix this, required a mechanism which will hold past back until page is fully loaded. Below post describes solution to this problem.

Why this check is required?
Requirement is to stop user from submitting web form before page is fully loaded on browser.
How to achieve this?
Find some way to indentify whether page is fully loaded and check this in form submit function every time before submitting form.
Assumption:
Images are loaded at last in page loading life cycle at browser.
JavaScript Solution
Following function checks for all images on page and find if all loaded? If at least one found to be not loaded it returns.
Where to call this method in Page?
Call this function in method being called onSubmit event.
How to DO this in ASP.NET?
In ASP.NET page, Java Script method “WebForm_OnSubmit()”, which is being called when you submit form. You can override this function by adding same function again with additional check for page loaded. Please note that it is necessary that new function should render after standard ASP.NET method is rendered.
Sample
function imagesLoaded()
{
// return variable
var imagesloaded = true;
// All images are saved in an array called document.images. Very usefull
var images = document.images;
// Loop through all the images
for (var i = 0;i
{
if(images[i].complete == false)
{
imagesloaded = false;
break;
}
}
// This will return 0 if one or more images are not loaded and 1 if all images are loaded.
return imagesloaded;
}
function WebForm_OnSubmit()
{
if(!checkImages() )
return false;
… // Standard ASP.NET Code here
}

Friday, December 19, 2008

ASP.NET: Loading Session Variable at Client Side

MOSS 2007 does not allow in-line code and one may require printing session variables in between HTML. Some time one require printing session variable in HTML which is content in Web Part. I started applying different approaches.


Parse Content in Content Editor Web part
First I thought to inherit Content Editor Web Part and Parse the HTML. During parsing and replace special marker with session variable name with actual values. e.g. In HTML write variable name like Your Name : $$SesstionVariableName$$
Unfortunately Content Editor Web part is sealed class so you cannot inherit. Here you feel like you cannot do anything now or write your own content editor web part. But, wait is it good idea to edit Content inside content editor web part at server side?

Play with Java Script and HTML
Idea is to load required session variable in Java Script variable and traverse the DOM to find session marker. Session markers? Yes, hidden inputs as session marker. Let’s take an example, let's say I have session variable named “UserName”. I want this variable to be loaded in between some HTML paragraph
HTML
<
form id="form1" runat="server">
<div>Your Name is <input type="hidden" name="test" value="$$$$"
/
></div>
</form>

Logic to create an array of required session variables in Java Script. We have to tell, what are the session variable names. For that let’s create User Control. Property of User Control will specify the name of session variable as comma separated values. Code behind will load this session variables in Java Script Array.
Something like
var MultiArray = new Object MultiArray['" + sessionvariable + "'] = '" + Session[sessionvariable].ToString () + "';

So far ok. We have session variable at client side now how to find hidden variable in HTML and replace with session values. Let's traverse the DOM and track for HIDDEN input. Once you find it check the name and values. If values is ‘$$$$’ means it is session variable so get the name and find from the array and replace INPUT tag with value.

Here we go! This is just concept. Code is very basic and need correction and runtime error checking. Feel free to use and extend.