Integrating with ASP.NET Part 1: Perforce source control
There are many flavours of version control out there. Github, Bitbucket, Perforce etc. Ranging from publicly free to enterprise level. This project called for an interface with Perforce, which makes this post somewhat niche but similar principals could be applied to other software. Perforce provide a great number of APIs to integrate with their products, the .NET API being the one I’m going to use. Their documentation & examples provided are also extensive though I was unable to find anything that would allow integration with a .NET web page.
My goal was to create an ASP.NET web app to query & pull content from Perforce(P4). This would be a core piece in a larger Self Service style app aimed at making agile delivery easier for our developers.
The starter for my endeavor is an example solution provided by Perforce to present the branch tree in a C# Windows form. This contained almost exactly what I needed for presenting the branch tree & contents in a web form but had some major blockers in the functionality differences between a windows form project & a web application.
The TreeNode Tag
Using the asp:TreeView control (https://msdn.microsoft.com/en-us/library/e8z5184w(v=vs.140).aspx) to display the P4 contents, I can assign each Perforce branch/folder to a TreeNode element. To prevent a ridiculous loading time, the code will populate child nodes with the P4 subdirectories when each node is clicked by the user, first checking for files then checking for sub-folders. In theory, this should work out easily enough!
NOTE: We also need to set the ExpandDepth property of the TreeView control to 0 so it wont automatically expand nodes the user hasn’t yet clicked on.
The solution provided by Perforce utilises the above process to populate the tree view control, meaning the P4Directory objects need to be stored somewhere, so that when a user clicks on a specific node, that can be fed back into Perforce to retrieve child directories & files. Each sub-directory’s node then stores its own P4Directory object, ready to be retrieved & fed back into Perforce when the user clicks it.
The way this is implemented in the Windows Form solution is using the TreeNode.Tag property which allows storage & retrieval of a custom object.
The problem with migrating this solution to a web application is that the Tag property does not exist in the ASP TreeView control. Here are the 2 TreeNode classes for comparison:
Scouring the internet for a workaround to this led me to several dead ends before finding a suitable solution. The most promising workaround and one that may be perfectly viable in other situations was to create a Custom TreeNode Class. This custom class would implement a Tag object to assign my P4Directory object to. The initial problem with this approach arose when the object was being saved to the View State, to mimic the persistence of a Windows form control object. It was passed to an override method that then tried to serialize it into an array.
This is where I was hit with numerous errors about classes in the P4APInet.dll not being marked as serializable. I decided to contact Perforce’s API support to see if they had any suggestions. They responded almost instantly and pointed me to the source solution for the .NET API from Perforce, where I went through each class that hit an error, one by one, marking each with [Serializable] & recompiling into the dll. Rinse & repeat.
With so much hope I thought this was it! NOPE!
The object contains information about the P4 connection, like timeouts & connection duration that implement the System.Timers.Timer class, which is not serializable. Dead end!
Session State to the rescue
Carrying on in the same thread as the failed custom TreeNode class I thought about using View state directly. It is designed for persisting information on a web page though specifically client side which then led me to session state which stores information server side & can persist across web pages (if needed). This quickly became the most promising solution.
Session variables would normally be set using a string or integer as demonstrated in the Microsoft documentation (https://msdn.microsoft.com/en-us/library/ms178581.aspx)
This wouldn’t work for me as I needed to populate a session variable for all tree nodes the user could click, then retrieve the P4Directory object from the correct variable when the user clicked it. This is where I was able to use each P4Path as the session name, feeding this back in to retrieve the correct session variable.
I set the session variable(s) when the TreeView is being populated (and also when we initially populate the Root node) as demonstrated here:
The session state can then be retrieved when the user clicks to expand a TreeNode. At this point we need to cast the object as a P4Directory type.
This method of using the Session state worked perfectly with the asp:TreeView control. I chose to omit some of the additional settings made within the example Windows form solutions, such as TreeNode images. Some of these were also specific to Windows Forms & were mainly cosmetic.
Tying it all together
With the TreeView code working Ill jump back into how everything tied together.
The first stepping stone is to pull the P4API.NET DLL into your solution. There is also a P4Directory C# class file (found in the Windows form example solution) that adds to the P4 classes.
Once you have these components it’s a case of creating a page & implementing your TreeView control.
As it was part of a wider project I am storing the Perforce server information in the web.config’s <appSettings> section & retrieving that info using the WebConfigurationManager.AppSettings property
You could use the web.config to also store user info but I’ve utilised Perforce’s cmd interface to store username & password securely within the app. Here’s a reference that should help you do the same: https://www.perforce.com/perforce/r15.1/manuals/p4guide/chapter.usingp4.html
Check it out
I have packaged this up as a simple web application solution on Github (https://github.com/cporteou/PerforceWeb). Feel free to try it out or fork if you think of a better approach or want to try something similar with other source control software.
I hope to expand the solution further to include methods to upload to and retrieve files from Perforce, which will use changelists and require a local workspace to work from.
I hope this helps Perforce users interface with their source control in more interesting & useful ways.