Pre-requisites For a project to use P4API.NET, p4api.net.dll and p4bridge.dll must be in the build output directory. On creation of a new console application, the Debug output location would be: ...\SolutionDir\ProjectDir\bin\Debug\. Next, add p4api.net.dll as a project reference by clicking Add Reference... on the References node of the project in the solution explorer in Visual Studio and browsing to the location of the newly added p4api.net.dll.

Using P4API.NET Client programs interact with the Perforce server by: Initializing a connection. Sending commands. Closing the connection.

Initializing a connection To connect to the Perforce server, your client application must call the Connect() method; for example: // initialize the connection variables // note: this is a connection without using a password string uri = "localhost:6666"; string user = "admin"; string ws_client = "admin_space"; // define the server, repository and connection Server server = new Server(new ServerAddress(uri)); Repository rep = new Repository(server); Connection con = rep.Connection; // use the connection variables for this connection con.UserName = user; con.Client = new Client(); con.Client.Name = ws_client; // connect to the server con.Connect(null); // initialize the connection variables // note: this is a connection without using a password // that sets the application name and version. // This information will appear when commands are // recorded in the server log as // [ProgramName/ProgramVersion] string uri = "localhost:6666"; string user = "admin"; string ws_client = "admin_space"; // define the server, repository and connection Server server = new Server(new ServerAddress(uri)); Repository rep = new Repository(server); Connection con = rep.Connection; // use the connection variables for this connection con.UserName = user; con.Client = new Client(); con.Client.Name = ws_client; // set the program name and version P4.Options options = new P4.Options(); options["ProgramName"] ="MyP4API.NET_APP"; options["ProgramVersion"] ="2015.1.105.4164"; // connect to the server con.Connect(options); // initialize the connection variables // note: this is a connection using a password string uri = "localhost:6666"; string user = "admin"; string ws_client = "admin_space"; string pass = "password"; // define the server, repository and connection Server server = new Server(new ServerAddress(uri)); Repository rep = new Repository(server); Connection con = rep.Connection; // use the connection variables for this connection con.UserName = user; con.Client = new Client(); con.Client.Name = ws_client; // connect to the server con.Connect(null); // login to the server to get credential // (using null for options and user params) Credential cred = con.Login(pass, null, null); // get server metadata and check version // (using null for options parameter) ServerMetaData p4info = rep.GetServerMetaData(null); ServerVersion version= p4info.Version; string release = version.Major; For information on SSL connections, refer to the TrustAndConnect method.

Setting Command Time Out The Command Time Out duration defaults to 5 seconds. If a command times out, P4API.NET will throw a P4CommandTimeOutException. After a connection has been established the Command Time Out can be changed in Repository.Connection.CommandTimeout: // initialize the connection variables // note: this is a connection without using a password string uri = "localhost:6666"; string user = "admin"; string ws_client = "admin_space"; // define the server, repository and connection Server server = new Server(new ServerAddress(uri)); Repository rep = new Repository(server); Connection con = rep.Connection; // use the connection variables for this connection con.UserName = user; con.Client = new Client(); con.Client.Name = ws_client; // connect to the server con.Connect(null); // change the Command Time Out to 20 seconds con.CommandTimeout = TimeSpan.FromSeconds(20);

Sending commands To send commands to the Perforce server, your client can use P4 API.NET methods; for example: // set the options for the p4 changes command string clientName = "admin_space"; int maxItems = 5; string userName = "admin"; ChangesCmdOptions options = new ChangesCmdOptions(ChangesCmdFlags.LongDescription, clientName, maxItems, ChangeListStatus.None, userName); // run the command against the current repository IList<Changelist> changes = rep.getChangelists(options); // changes will contain the data returned by the command // p4 changes -L -c admin_space -m 5 -u admin // set the options for the p4 edit command string depotPath = "//depot/main/test.txt"; int changelist = 0; // create FileSpec with null for ClientPath, LocalPath, and VersionSpec FileSpec fileToCheckout = new FileSpec(new DepotPath(depotPath), null, null, null) // using null for FileType EditCmdOptions options = new EditCmdOptions(EditFilesCmdFlags.None, changelist, null); // run the command with the current connection IList<FileSpec> filesCheckedOut = con.Client.EditFiles(options, fileToCheckout); // filesCheckedOut will contain the data returned by the command // p4 edit //depot/main/test.txt // and the file will be checked out in the default pending changelist // set the options for the p4 submit command // 0 to specify default pending changelist, null for changelist since we are using the default string description = "update to test.txt"; // set reopen to false ClientSubmitOptions clientOptions = new ClientSubmitOptions(false,SubmitType.SubmitUnchanged) SubmitCmdOptions options = new SubmitCmdOptions(SubmitFilesCmdFlags.None, 0, null, description, clientOptions) // create FileSpec with null for ClientPath, LocalPath, and VersionSpec string depotPath = "//depot/main/test.txt"; FileSpec fileToSubmit = new FileSpec(new DepotPath(depotPath), null, null, null) // run the command with the current connection SubmitResults results= con.Client.SubmitFiles(options, fileToSubmit); // results will contain the data returned by the command // p4 submit -d "update to test.txt" //depot/main/test.txt

Closing the connection To disconnect from the Perforce server, your client application must call the Disconnect() method; for example: // disconnect from the server con.Disconnect();

Running commands directly To run commands that do not have methods in the .NET API, your client can use the P4Command.Run() method; for example: // create a new command using parameters: // repository, command, tagged, arguments string file="//depot/main/test.txt"; P4Command cmd = new P4Command(rep, "attribute", true, file); Options opts = new Options(); opts["-n"] = "fileID"; opts["-v"] = "1"; //run command and get results P4CommandResult results = cmd.Run(opts); // results will contain the data returned by the command // p4 -ztag attribute -n fileID -v 1 //depot/main/test.txt Running command methods is more useful when care about the results of the command and want them parsed for display or to be passed on to other commands. If command results are not important, running the command directly may be preferable.

Working with Options Options have subclasses specific to particular commands. These dictionary objects can also be created directly, for example: ClientCmdOptions clientOpts = new ClientCmdOptions(ClientCmdFlags.Output);
will create the same options as:
Options opts = new Options(); opts["-o"]=null;
A command run with either of these options will use the -o flag. Refer to the Options Constructors for details on specific options flags.
Note that some option flags are mutually exclusive and using them together will result in the same errors that would be returned from the command line. Some examples of proper usage:
// the SubmitCmdOptions class public SubmitCmdOptions(SubmitFilesCmdFlags flags, int changelist, Changelist newChangelist, string description, ClientSubmitOptions submitOptions) // options for submitting from the default changelist // the SubmitCmdOptions and ClientSubmitOptions can vary SubmitCmdOptions submitOpts = new SubmitCmdOptions(SubmitFilesCmdFlags.None, 0, null, "submitting from default changelist", new ClientSubmitOptions(false,SubmitType.SubmitUnchanged)) // options for submitting from a numbered changelist 16 // the SubmitCmdOptions and ClientSubmitOptions can vary SubmitCmdOptions submitOpts = new SubmitCmdOptions(SubmitFilesCmdFlags.IncludeJobs, 16, null, null, new ClientSubmitOptions(false,SubmitType.RevertUnchanged)); // options for submitting a new changelist using a changelist specification where change // is a P4.Changelist // the SubmitCmdOptions and ClientSubmitOptions can vary SubmitCmdOptions submitOpts = new SubmitCmdOptions(SubmitFilesCmdFlags.ReopenFiles, 0, change, null, new ClientSubmitOptions(true,SubmitType.SubmitUnchanged)); // options for submitting a shelved file from a numbered changelist 18 // the SubmitCmdOptions and ClientSubmitOptions can vary SubmitCmdOptions submitOpts = new SubmitCmdOptions(Perforce.P4.SubmitFilesCmdFlags.SubmitShelved, 18, null, null, null);
Here is an example of improper usage of flags that are mutually exclusive:
// the SubmitCmdOptions class public SubmitCmdOptions(SubmitFilesCmdFlags flags, int changelist, Changelist newChangelist, string description, ClientSubmitOptions submitOptions) // improper options for submitting from a numbered changelist 20 // the SubmitCmdOptions and ClientSubmitOptions can vary SubmitCmdOptions submitOpts = new SubmitCmdOptions(SubmitFilesCmdFlags.None, 16, null, "submitting change 20", new ClientSubmitOptions(false,SubmitType.RevertUnchanged));
The above options will return the error "Usage: submit [ -r -f option ] -c changelist#\n" because a changelist number and a description were specified and the -c and -d flags are mutually exclusive.

Building a FileSpec Commands for working with files and paths will need a FileSpec or a list or an array of FileSpecs as an argument when running the command. A FileSpec consists of a PathSpec (or PathSpecs) and a VersionSpec. The PathSpecs can be DepotPaths, ClientPaths, and LocalPaths. The VersionSpec can be a revision or a revision range. Some examples: // create a FileSpec for //depot/test.txt // using new FileSpec(PathSpec path, VersionSpec version) PathSpec path = new DepotPath("//depot/test.txt"); FileSpec depotFile = new FileSpec(path, null); // create a FileSpec for //depot/test.txt#5 // using new FileSpec(PathSpec path, VersionSpec version) path = new DepotPath("//depot/test.txt"); VersionSpec version = new Revision(5); depotFile = new FileSpec(path, version); // create a FileSpec for //depot/test.txt@16,@22 // (version range between changelists 16 and 22) // using new FileSpec(PathSpec path, VersionSpec version) path = new DepotPath("//depot/test.txt"); VersionSpec lowerChangeID = new ChangelistIdVersion(16); VersionSpec upperChangeID = new ChangelistIdVersion(22); version = new VersionRange(lowerChangeID,upperChangeID); depotFile = new FileSpec(path, version); // create a FileSpec for C:\Users\username\Depot\test.txt#head // using new FileSpec(PathSpec path, VersionSpec version) path = new LocalPath("C:\\Users\\username\\Depot\\test.txt"); version = new HeadRevision(); depotFile = new FileSpec(path, version); // create a FileSpec for //depot/test.txt@labelName // using new FileSpec(PathSpec path, VersionSpec version) path = new DepotPath("//depot/test.txt"); version = new LabelNameVersion("labelName"); depotFile = new FileSpec(path, version); // create a FileSpec for //depot/...@2013/5/27,@now // (version range between 2013/5/27 and now) // using new FileSpec(PathSpec path, VersionSpec version) path = new DepotPath("//depot/..."); DateTimeVersion lowerTimeStamp = new DateTimeVersion(new DateTime(2013,5,27)); DateTimeVersion upperTimeStamp = new DateTimeVersion(DateTime.Now); version = new VersionRange(lowerTimeStamp,upperTimeStamp); depotFile = new FileSpec(path, version);
Refer to the VersionSpec class for additional revision types.

Error handling If a command returns a null, there were likely errors. Errors have different severity levels and do not necessarily mean that a command has failed. P4 API.NET methods will throw a P4Exception if an error of severity E_FAILED or higher is returned. This setting can be changed in P4Exception.MinThrowLevel. For example: // turn off P4Exceptions P4Exception.MinThrowLevel = ErrorSeverity.E_NOEXC;
The following is an example of a command that will throw a P4Exception:
try { // set options for client command ClientCmdOptions clientOpts = new ClientCmdOptions(ClientCmdFlags.Switch); // attempt to get label with p4 -s label testLabel Label label = rep.GetLabel("testLabel", null, clientOpts); } catch (P4Exception ex) { // catch exception and display error message Console.WriteLine(ex.Message); }
Because the error that the command returns is of severity E_FAILED an exception will be thrown. The Message displayed is: Usage: label [ -d -f -g -i -o -t template ] labelname Invalid option: -s. since there is no -s flag for p4 label.
This is an example of a command that will not throw a P4Exception:
// set options for client command try { SyncFilesCmdOptions syncOpts = new SyncFilesCmdOptions(SyncFilesCmdFlags.None, 1); FileSpec depotFile = new FileSpec(new DepotPath("//depot/test.txt"), null, null, null); IList<FileSpec> syncedFiles = rep.Connection.Client.SyncFiles(syncOpts, depotFile); } catch (P4Exception ex) { Console.WriteLine(ex.Message); }
Because the error that the command returns is of severity E_WARN no exception will be thrown. The file, //depot/test.txt is already at the latest revision but the command has still succeeded with a warning of "//depot/test.txt - file(s) up-to-date." syncedFiles will be null.

Sample application: a console specification fetcher This is a console application that connects to a Perforce server and returns Perforce specification information based on user input of 2 words: specification type, specification name. It uses Connection.Login(password) for working with a server at security level 3. Lower security levels should also work and connecting with a user without a password can be done by passing a blank string for password. There is minimal error handling for failed Perforce commands. Since -o is used, specifications that do not yet exist may be returned on entry of a non-existent specification name.

Create a new C# Console Application project and paste the following code into Program.cs: using System; using System.Collections.Generic; using System.Linq; using System.Text; using System.Threading.Tasks; using Perforce.P4; namespace apiConsoleApplication { class Program { static void Main() { string uri = ""; string user = ""; string workspace = ""; string pass = ""; bool exit = false; Server server = new Server(new ServerAddress(uri)); Repository rep = new Repository(server); // establish a connection to a server while(rep.Connection.Status==ConnectionStatus.Disconnected) { // get user input for connection Console.WriteLine("port:"); uri = Console.ReadLine(); Console.WriteLine(""); Console.WriteLine("user:"); user = Console.ReadLine(); Console.WriteLine(""); Console.WriteLine("client:"); workspace = Console.ReadLine(); Console.WriteLine(""); Console.WriteLine("password:"); pass = Console.ReadLine(); Console.WriteLine(""); server = new Server(new ServerAddress(uri)); rep = new Repository(server); Connection con = rep.Connection; con.UserName = user; con.Client = new Client(); con.Client.Name = workspace; // connect bool connected = con.Connect(null); if (connected) { try { // attempt a login Credential cred = con.Login(pass); } catch (Exception ex) { Console.WriteLine(ex.Message); con.Disconnect(); continue; } // get p4 info and show successful connection ServerMetaData info = rep.GetServerMetaData(null); Console.WriteLine("CONNECTED TO " + info.Address.Uri); Console.WriteLine(""); } else { // retry the prompt for connection info continue; } } while(rep.Connection.Status==ConnectionStatus.Connected&&!(exit)) { Options opts= new Options(); opts["-o"] = null; string input = Console.ReadLine(); exit = (input == "exit"); string[] command = input.Split(' '); switch (command[0]) { // on user input of job <job name> get job // and output to console case "job": try { Job job = rep.GetJob(command[1], opts); Console.WriteLine(""); Console.WriteLine(job.ToString()); Console.WriteLine(""); break; } catch (Exception ex) { Console.WriteLine(""); Console.WriteLine(ex.Message); Console.WriteLine(""); break; } // on user input of change <change number> get // change and output to console case "change": try { opts = new Options(); int id = 0; int.TryParse(command[1], out id); Changelist change = rep.GetChangelist(id, opts); Console.WriteLine(""); Console.WriteLine(change.ToString()); Console.WriteLine(""); break; } catch (Exception ex) { Console.WriteLine(""); Console.WriteLine(ex.Message); Console.WriteLine(""); break; } // on user input of client <client name> get // client and output to console case "client": try { Client client = rep.GetClient(command[1]); Console.WriteLine(""); Console.WriteLine(client.ToString()); Console.WriteLine(""); break; } catch (Exception ex) { Console.WriteLine(""); Console.WriteLine(ex.Message); Console.WriteLine(""); break; } // on user input of label <label name> get // label and output to console case "label": try { Label label = rep.GetLabel(command[1]); Console.WriteLine(""); Console.WriteLine(label.ToString()); Console.WriteLine(""); break; } catch (Exception ex) { Console.WriteLine(""); Console.WriteLine(ex.Message); Console.WriteLine(""); break; } // on user input of stream <stream path>get // stream and output to console case "stream": try { Stream stream = rep.GetStream(command[1]); Console.WriteLine(""); Console.WriteLine(stream.ToString()); Console.WriteLine(""); break; } catch (Exception ex) { Console.WriteLine(""); Console.WriteLine(ex.Message); Console.WriteLine(""); break; } // on user input of branch <branch name> get // branch and output to console case "branch": try { BranchSpec branch = rep.GetBranchSpec(command[1]); Console.WriteLine(""); Console.WriteLine(branch.ToString()); Console.WriteLine(""); break; } catch (Exception ex) { Console.WriteLine(""); Console.WriteLine(ex.Message); Console.WriteLine(""); break; } } } } } }