SharpSvn Tutorial

Table Of Contents

Introduction and Prerequisites

This tutorial is meant to serve as a "getting started" type of guide to the SharpSvn API.  It does not cover every aspect of SharpSvn but rather serves as a foothold so you can begin writing useful code rather than spending hours experimenting just to understand the basics.  It should teach you how to use some of the most important classes/methods in the API.  Additionaly, after reading through this tutorial it is my hope that you will have a sense of where to turn if you should happen to get stuck.

This walkthrough assumes a few things.  First, it assumes that you know the basics of how to work with an SVN repository.  Second, it assumes that you have a working SVN repository to test against.  If either of these items are not true then you may have some difficulty following along.  An excellent place to get started with Subversion is by reading through the official documentation at http://svnbook.red-bean.com/en/1.4/svn-book.html.

Something else you should know before getting started is that this tutorial uses Visual Studio 2010, Visual C#, and version 4.0 of the .NET framework.  You may still be able to follow along as long as you can translate what is going on here to older versions of Visual Studio/.NET languages.  I have tried to avoid using any .NET 4.0 specifics here to make any such translations relatively painless.

Finally, if you have any questions/comments/corrections please let me know.  I can be contacted at bctello<the number eight> at gmail dot com.

Setting the Project Up

So to get started we will walk through setting up a windows forms project to access the SharpSvn API.  Although I'm sure that most of the individuals reading this documentation are well aware of how to set up a project in Visual Studio I will be walking through it anyways to ensure everyone is on the same page.

  1. Open Visual Studio and select File->New->Project.  In the 'New Project' dialog, select Visual C# under the 'Installed Templates' menu and Windows Forms Application from the center menu.

  2. In the 'Name' field type MySVNClient.

  3. In the 'Solution' pulldown select 'Create new solution'.  What you have now should look something like this:
    Setting up the project.

  4. Click OK.

Now you are going to need to import the SharpSVN assemblies into your project which will give you access to all of the datatypes and methods available in the SharpSVN API.

  1. Download the appropriate SharpSVN binaries package from http://sharpsvn.open.collab.net.  The various packages are located under the 'Download and Support' tab.
  2. Unzip the package onto your hard drive.  This will create a directory named "SharpSVN."
  3. Open your project in Visual Studio.
  4. In the Solution Explorer expand the node corresponding to your project and right click the "References" sub-folder.  Click 'Add Reference...'

    Right clicking the References folder
  5. Now in the 'Add Reference' dialog which appears, click the Browse tab and browse to the unzipped "SharpSvn" folder.  In that folder you will find the DLL files that you will need to access the SharpSVN methods.
  6. Select 'SharpSvn.dll' and click 'OK'.
    Selecting the DLL file.

You now have access to everything in the SharpSVN namespace and some extra goodies (which we won't be dealing with here) as well.  If you want to see everything that you can now access, just open up the Object Browser by clicking View->Object Browser and right clicking the arrow next to the SharpSvn node.
seeing what's in the SharpSVN assembly
As you can see, there are several other namespaces included in the SharpSvn assembly but we will not be using them for this walkthrough.

As a final setup step in getting this project set up, we will get the main form laid out properly.

  1. Open the form 'Form1' in design view.  At this point all you should see is a blank form with the title Form1.

  2. In the Solution Explorer rename Form1.cs to SvnClient.cs

  3. Change the properties of the form as follows:

    • Name: SvnClient

    • Text: SVN Client

    • Size: 325,120

  4. Add a label to the form with the following properties:

    • Name: lblPrompt

    • Location: 38,9

    • Text: Select an SVN command to run and then click 'Go'.

  5. Add a ComboBox to the form and change it's properties as follows:

    • Name: cbCmdList

    • Location: 92,25

    • Size: 121,21

  6. Add two buttons to the form and set their properties as follows:

    • Name (first button): btnGo

    • Location: 81,52

    • Size: 44,23

    • Text: Go

    • Name (second button): btnQuit

    • Location: 149,52

    • Size: 75,23

    • Text: Quit

  7. Now double click the 'Quit' button which should bring you into the btnQuit_Click method.  In the body of the function type:

    • Application.Exit();

  8. You should now have a form which looks similar to the image below.  It doesn't have to look exactly the same but if you want to be able to copy and paste the code in this walkthrough you should at least make sure the names of your controls match what has been listed above.
    An image of the baseline client.

  9. Save your project, make sure it builds, and that the Quit button actually closes the application.

Getting Started With the SharpSVN API

Now that you have the baseline form for our demo project set up we can get to working with the API.  The first thing you need to know is that the SharpSvn namespace contains most of the types you will need to write a basic client.  If you have added the SharpSvn.dll assembly to your project as outlined above, you can access the SharpSvn namespace by simply typing using SharpSvn; at the top of your code files.
Adding the using statement.

The second thing you need to know is that the SharpSvn.SvnClient class encapsulates the functionality of a Subversion client.  If there is something that you can do with a Subversion client program then it is likely something you can do via some function in the SvnClient class.  From this point on our demo program is going to proceed by walking through how to perform some of the basic functions of an svn client application by using the SvnClient class. 

Using SvnClient to Perform Some Common SVN Operations

svn checkout

The first example is how to perform the svn checkout operation using the SharpSvn method SvnClient.CheckOut. We'll start by creating a new form which will have fields into which the user can type data for the 'svn checkout' operation.  It will also have a button labeled 'checkout' which will gather all of the user specified data and perform the actual checkout.

  1. In Visual Studio, click Project->Add Windows Form...

  2. In the 'Add New Item' dialog which appears, make sure that 'Windows Form' is selected and enter 'frmCheckout.cs' in the 'Name:' field

  3. Click 'Add'

  4. Add three labels to the form:

    • Name (first label): lblRepoURI

    • Location: 13, 12

    • Text: Repository URI:

    • Name (second label): lblLocalPath

    • Location: 13, 44

    • Text: Local Path

    • Name (third label): lblRevision

    • Location: 12,47

    • Text: Revision:

  5. Add three text boxes to the form:

    • Name (first text box): tbRepoURI

    • Location: 102, 12

    • Size: 247,20

    • Name (second text box): tbLocalPath

    • Location: 102, 44

    • Size: 247, 20

    • Name (third text box): tbRevision

    • Location: 102, 71

    • Size: 75,20

  6. Add two buttons to the form:

    • Name (first button): btnCheckout

    • Location: 102, 97

    • Text: Checkout

    • Name (second button): btnCancel

    • Location: 183, 97

    • Text: Cancel

  7. Now set the properties of frmCheckout itself as follows:

    • CancelButton: btnCancel

    • Size: 377, 172

    • Text: svn checkout

  8. The new form should look something like this:
    The checkout form

  9. Now open the SvnClient form and click the ComboBox cbCmdList.

  10. In the properties window for cbCmdList open the 'Items' collection editor.

  11. Enter the string 'svn checkout' on its own line and click OK.

  12. Double click the 'Go' button which should bring you to the code editor for the method btnGo_Click().

  13. Change the btnGo_Click method so it matches the following code:

    private void btnGo_Click(object sender, EventArgs e)
    {
        object command = cbCmdList.SelectedItem;
        if(command == null) //If the combo box was empty
        {
            MessageBox.Show("Please select an SVN command from the pull down menu.");
            return;
        }
        switch (command.ToString())
        {
            case "svn checkout": //Open the svn checkout box
                frmCheckout checkOutFrm = new frmCheckout();
                checkOutFrm.ShowDialog();
                break;
            default: //User probably typed something invalid
                MessageBox.Show("Please select a valid SVN command from the pull down menu.");
                break;
        }

    }

  14. Now save and run your project.  Select 'svn checkout' from the combo box on the main form, click 'Go' and make sure it opens the 'svn checkout' form.

  15. Now that we have the checkout form laid out and working the way we want, we can add some SVN functionality to it (finally!).  Start by opening the frmCheckout.cs form in design view and double clicking the 'Checkout' button.  This should bring you to the code editor.

  16. At the top of the code for frmCheckout type

    •  using SharpSvn;

  17. Change the method btnCheckout_Click() so that it looks like the following:
     
    private void btnCheckout_Click(object sender, EventArgs e)
    {

        if (tbLocalPath.Text.Length == 0|| tbRepoURI.Text.Length == 0)
        {
            MessageBox.Show("The 'Repository URI' and 'Local Path' fields cannot be empty.");
            return;
        }

        //SvnUpdateResult provides info about what happened during a checkout
        SvnUpdateResult result;

        //we will use this to tell CheckOut() which revision to fetch
        long revision;

        //SvnCheckoutArgs wraps all of the options for the 'svn checkout' function
        SvnCheckOutArgs args = new SvnCheckOutArgs();

        //path is the path where the local working copy will end up
        string path = tbLocalPath.Text;

        if (long.TryParse(tbRevision.Text,out revision))
        {
            //set the revision number if the user entered a valid number
            args.Revision = new SvnRevision(revision);
        }
        //if args.Revision is not set, it defaults to fetch the HEAD revision.
        else MessageBox.Show("Invalid Revision number, defaulting to HEAD");

        //the using statement is necessary to ensure we are freeing up resources
        using (SvnClient client = new SvnClient())
        {
            try
            {
                //SvnUriTarget is a wrapper class for SVN repository URIs
                SvnUriTarget target = new SvnUriTarget(tbRepoURI.Text);

                //this is the where 'svn checkout' actually happens.
                if (client.CheckOut(target, path, args, out result))
                    MessageBox.Show("Successfully checked out revision " + result.Revision + ".");
            }
            catch (SvnException se)
            {
                MessageBox.Show(se.Message,
                "svn checkout error",
                MessageBoxButtons.OK,
                MessageBoxIcon.Error);
            }
            catch (UriFormatException ufe)
            {
                MessageBox.Show(ufe.Message,
                "svn checkout error",
                MessageBoxButtons.OK,
                MessageBoxIcon.Error);
            }
        }

    }

    This is the actual code which performs the checkout operation so lets take a moment to make sure we understand what's going on here. 

    First, the method it all centers around is SvnClient.CheckOut().  Notice that the overload we have used here takes four arguments.  The first argument is an SvnUriTarget which is a wrapper class which converts standard URI's to a format that the Subversion libraries can use.  The second is a string which should be a valid path on the local machine.  This is the path to which the working copy will be checked out.  The third argument is of type SvnCheckoutArgs which is a wrapper class for the arguments to the 'svn checkout' function.  Notice how we specified which revision we wanted to checkout by modifying the revision property of args and then passing it as the third argument to CheckOut().  Many of the functions in SharpSVN have their own argument classes that are used in the same manner.  The final argument is an output argument of type SvnUpdateResult.  This class can provide you with basic information about what happened during a 'svn checkout' operation.  Again, several of the SharpSVN methods have similar result types which can be used to retrieve information about the result of a method call.

    The CheckOut method has several different overloads which require fewer arguments in case you decide you don't need one of them for some reason.  CheckOut(4) has been shown here because it is the overload with the highest arity so knowing how to use this version means you can use all of them.

    The next item of interest is the
    using(SvnClient client = new SvnClient()) block.  We need to include this to ensure that any memory/network connections which get allocated to client are freed up as quickly as possible.  What it does, for those who are unfamiliar with using statements is defines a limited scope during which client will exist.  Once the using block is exited, client goes out of scope and is immediately disposed of via a call to Dispose().

    Finally, notice that we are catching the SvnException class here.  There are a considerable number of different Exception classes in SharpSVN but this one is the base class for all of them.  It gives you access to high level diagnostic information such as human readable error messages, operating system error codes, and even the error codes generated by the native subversion libraries that SharpSVN runs on top of.  If you need more specific information, you should look to the more specific exception classes.  We will not be going over those here however.

  18. Now go ahead and save your project and make sure that it builds.  Run the project in Debug mode, select 'svn checkout' and click 'Go'

    HINT: If you are like me and running this project in Visual Studio 2010 with the .NET 4.0 framework, you likely just encountered a nasty FileLoadException saying something like "Mixed mode assembly is built against version 'v2.0.50727' of the runtime and cannot be loaded in the 4.0 runtime without additional configuration information."  To fix this, you need to create an XML configuration file telling Visual Studio to make the runtime .NET 2.0 compatible.   This file needs to be called MySvnClient.exe.config and should be saved to your projects debug/bin folder.  For example, on my machine I have to save it as

    C:\Users\Brady\My Documents\Visual Studio 2010\Projects\MySvnClient\MySvnClient\bin\Debug\MySvnClient.exe.config

    The content of this file should be as follows:

    <configuration>
        <startup useLegacyV2RuntimeActivationPolicy="true">
            <supportedRuntime version="v4.0"/>
        </startup>
    </configuration>

    Now restart the SvnClient application.  Select 'svn checkout' and click 'Go' again and you should not receive that exception any longer.

  19. Once you have the svn checkout form displayed, enter a valid SVN repository URI in the top text box and a valid local path in the middle text box (SharpSvn will create a directory if it doesn't exist).  Click Checkout.

  20. Click 'OK' in the box informing you that the HEAD revision will be checked out.

  21. Depending on the size of your repository there may be a delay but once all the files have been downloaded and checked out, you will receive a confirmation window telling you which revision was checked out.  Navigating to the path you entered should confirm that the files have all been downloaded succesfully!

svn commit

To demonstrate how to use SvnClient.Commit we will be adding another form to the MySvnClient program.  This form will also gather data from the user and then perform the commit operation once a 'commit' button is clicked.

  1. Lets start adding the new form to our project by clicking Project->Add Windows Form...  Now make sure that 'Windows Form' is selected and name it frmCommit.cs.  Click 'OK'

  2. Add an OpenFileDialog to the form and set its properties as follows:

    • Name: ofdFileSelector

    • CheckFileExists: True

    • CheckPathExists: True

    • FileName: ""

  3. Add two labels to the form and set their properties as follows:

    • Name (first label): lblFileName

    • Location: 12, 20

    • Text: File:

    • Name (second label): lblMessage

    • Location: 12, 42

    • Text: Message:

  4. Add two text boxes to the form and set their properties as follows:

    • Name (first text box): tbFileName

    • Location: 71, 13

    • Size: 238, 20

    • Name (second text box): tbMessage

    • Location: 71, 39

    • Size: 319,20

  5. Add three buttons to the form and set their properties as follows:

    • Name (first button): btnBrowse

    • Location: 315, 12

    • Text: Browse...

    • Name (second button): btnCommit

    • Location: 109,65

    • Text: Commit

    • Name (third button): btnCancel

    • Location: 206, 65

    • Text: Cancel

  6. Set the properties of frmCommit itself as follows:

    • CancelButton: btnCancel

    • Size: 418, 138

    • Text: Svn Commit

  7. That is the entire layout for the checkout form.  It should look something like this:
    The basic commit form

  8. Now that you have the layout done lets add the commit form to our list of svn commands in the main form.  Open SvnClient.cs in the design window and open the Items property editor for the ComboBox cbCmdList.

  9. On its own line type:

    svn commit

    and click 'OK'

  10. Double click the 'Go' button to bring you back to the btnGo_Click method.

  11. In the switch statement you are going to add some code between the "svn checkout" case and the default case.  The final code should look  like the following (new code displayed in bold font and old code shortened to ... for brevity):

    case "svn checkout": //Open the svn checkout form
        ...
    case "svn commit": //Open the svn commit form
        frmCommit commitForm = new frmCommit();
        commitForm.ShowDialog();
        break;

    default:
        ...

  12. Save your project, run it, and make sure that you can get to the new commit form from the main form.  Quit the program.

  13. Open up frmCommit in design view and double click the 'Browse...' button to bring you to the code for the btnBrowse_Click method.

  14.  Add this code as the body of btnBrowse_Click()

    if (ofdFileSelector.ShowDialog() == DialogResult.OK)
    {
        tbFileName.Text = ofdFileSelector.FileName;
    }

  15. Bring frmCommit back up in design view and double click the 'Commit' button to bring up the code for the btnCommit_Click method.  Now we are going to be inserting the code that will actually be committing our repository.

  16. The first thing we are going to do is add another assembly to our project.  The assembly name is SharpSvn.UI.  It is important to us because it contains the SharpSvn.UI namespace.  This namespace contains code that makes handling authentication extremely easy.  To add the assembly, follow the same steps you used to add the SharpSvn.dll assembly but instead of choosing SharpSvn.dll, choose SharpSvn.UI.dll instead (they should be in the same directory).

  17. At the top of the code for frmCommit.cs add the following two lines of code:

    using SharpSvn;
    using SharpSvn.UI;

  18. Now go back to the body of the btnCommit_Click method and add the code shown in bold below:

     private void btnCommit_Click(object sender, EventArgs e)
    {
        if (tbFileName.Text.Length == 0)
       
    {
            MessageBox.Show("Please enter a valid filename in the 'File:' box");
            return;
       
    }

        //This object allows us to provide options for 'svn commit'
        SvnCommitArgs args = new SvnCommitArgs();

        //This is how you specify a commit message.
        args.LogMessage = tbMessage.Text;

        //This is where results for 'svn commit' are stored
        SvnCommitResult result;

        //again, remember to include the using statement with SvnClients
        using (SvnClient client = new SvnClient())
       
    {
            try
           
    {
                //Bind allows the client to prompt the user for authentication info.
                SvnUI.Bind(client, this);

                //This method is the equivalent of 'svn commit'
                client.Commit(tbFileName.Text, args, out result);
                if(result != null)
                    MessageBox.Show("Successfully commited revision " + result.Revision);
                else
                    MessageBox.Show("No changes have been made to working copy since it was checked out.");
           
    }
            catch (SvnException se)
           
    {
                MessageBox.Show(se.Message + "Error: " + se.SvnErrorCode + Environment.NewLine,
                "svn commit error",
                MessageBoxButtons.OK,
                MessageBoxIcon.Error);
           
    }
       
    }
    }

    As before lets take a moment to step through this code and make sure that we understand everything that's going on here.

    The first thing to notice is the SvnCommitArgs class.  Just like SvnCheckoutArgs, this class allows you to specify options to the 'svn commit' command.  In this example we are specifying the commit message by setting the LogMessage property of args before using it as an argument to Commit. 

    Also, notice that we are again using a class which allows us to analyze the results of a commit operation (SvnCommitResult).  If you are curious as to why we are checking whether or not result is null after the call to Commit it is because result is only initialized by Commit if there is at least one file which needs to be committed.  In other words, if your working copy has not been changed since you checked it out, Subversion/SharpSVN does not waste time sending anything over the network and thus nothing is changed in the repository.  SharpSvn indicates an unchanged repository by leaving result uninitialized.

    One of the big things to take away from this example is the call to SvnUI.Bind.  This method is helpful because it makes authentication so easy.  All you have to do is call Bind on an SvnClient and a Windows form before any call which could require authentication and automagically you have nice little username/password windows which pop up whenever you need to provide credentials.  This function also gives you the ability to use SSL certificates but we wont be getting into that here.

    Finally, the call to client.Commit is what actually executes the 'svn commit' operation.  Again, we use the catch all SvnException for error handling but feel free to use some of the more specific exception types if that does not fit your needs.

  19. Now save your project, run it, open the svn commit window and make sure you can perform a commit to your repository.

svn proplist

Getting the list of SVN properties for a given node can be useful so lets work on an example of how to do that using SharpSVN.  Again we will demonstrate this functionality by adding 'svn proplist' as a command to our MySvnClient program.  We will be creating a new form which asks the user to specify a file.  Once the user clicks a 'Get Properties' button, all of the SVN properties for that node will be listed in a ListView control for all to see.

  1. Once again lets start off with adding a new form to the MySvnClient project.  Click Project->Add Windows Form... Make sure that 'Windows Form' is selected, name it frmPropList.cs and click 'OK'.

  2. Open frmPropList.cs in the design view and add a ListView control with the following properties:

    • Name: lvProps

    • Columns:

      • Add a column named chFilePath with Text set to "File" and Width set to -2

      • Add a column named chPropName with Text set to "Name" and Width set to -2

      • Add a column name chPropValue with Text set to "Value" and Width set to -2

    • Location: 12, 88

    • Size: 369, 164

    • View: Details

  3. Add a CheckBox to the form with the following properties:

    • Name: cbRecurse

    • Location: 13, 44

    • Text: Recurse into Directories?

  4. Add two Label controls to the form and set their properties as follows:

    • Name (first label): lblFileURI

    • Location: 10, 13

    • Text: File URI:

    • Name (second label): lblProperties

    • Location: 13, 72

    • Text: Properties:

  5. Add a text box to the form and set its properties as follows:

    • Name: tbFileURI

    • Location: 64, 12

    • Size: 318, 20

  6. Add two buttons to the form and set their properties as follows:

    • Name (first button): btnGetProps

    • Location: 216, 40

    • Text: Get Properties

    • Name (second button): btnCancel

    • Location: 306, 40

    • Text: Cancel

  7. Finally set the properties of frmPropList itself as follows:

    • CancelButton: btnCancel

    • Size: 417, 296

    • Text: svn proplist

  8. Now that the form is laid out it should look something like the following:
    The completed proplist form

  9. Open SvnClient.cs in the code editor and update the switch statement in the btnGo_click method as follows:

    case "svn checkout": //Open the svn checkout form
        ...
    case "svn proplist": //Open the svn proplist form
        frmPropList propListForm = new frmPropList();
        propListForm.ShowDialog();
        break;

    default:
        ...

  10. Save your project and run it.  Select 'svn proplist' from the pulldown menu and click 'Go' make sure that the proplist window opens.  Quit the application.

  11. Open frmPropList in the design view and double click the 'Get Properties' button to enter the method btnGetProps_Click().

  12. Modify btnGetProps_Click as follows (don't forget to add the using SharpSvn statement at the top of the code):
      
    private void btnGetProps_Click(object sender, EventArgs e)
    {
        if (tbFileURI.Text.Length == 0)
       
    {
            MessageBox.Show("Please enter a valid file URI in the 'File URI:' box.");
            return;
       
    }

        //Clear out the list view for the next list of properties
        lvProps.Items.Clear();

        //This will be the target file from which we are retrieving properties
         SvnTarget tgt = SvnTarget.FromString(tbFileURI.Text);

        //This collection will contain property collections for each node
        System.Collections.ObjectModel.Collection<SvnPropertyListEventArgs> proplist;

        //This is where we can specify arguments to svn proplist
        SvnPropertyListArgs args = new SvnPropertyListArgs();

        if (cbRecurse.Checked == true)
       
    {
            //This will cause GetPropertyList to get properties recursively.
            args.Depth = SvnDepth.Infinity;
       
    }

        using (SvnClient client = new SvnClient())
       
    {
            try
           
    {
                //This method is what executes svn proplist
                client.GetPropertyList(tgt, args, out proplist);

                //Each SvnPropertyListEventArgs represents the prop. set for a node
                foreach (SvnPropertyListEventArgs node in proplist)
               
    {
                    //Each SvnPropertyValue represents a single name/value property pair
                    foreach (SvnPropertyValue propVal in node.Properties)
                   
    {
                        ListViewItem entry = new ListViewItem(node.Path);
                        entry.SubItems.Add(propVal.Key);
                        entry.SubItems.Add(propVal.StringValue);
                        lvProps.Items.Add(entry);
                   
    }
               
    }
                //refresh the column sizes
                for (int i = 0; i < 3; i++) lvProps.Columns[i].Width = -2;
           
    }
            catch (SvnException se)
           
    {
                MessageBox.Show(se.Message + Environment.NewLine +
                "Error:" + se.SvnErrorCode,
                "svn proplist error",
                MessageBoxButtons.OK,
                MessageBoxIcon.Error);
           
    }
       
    }


    The first new thing that worth mentioning in this example is the use of the SvnTarget class.  SvnTarget is actually the abstract superclass for two concrete classes SvnPathTarget and SvnUriTarget, the former being SharpSvn's representation of a local file path and the latter being SharpSvn's representation of a remote URI.  Any method which takes an SvnTarget as an argument can take either of those two classes but the trick is to use SvnTarget's FromString method which creates the appropriate type for you based on the format of its input string.  For example if you say

    SvnTarget target = SvnTarget.FromString("http://myproj.googlecode.com/svn/trunk/helloworld.c");


    then FromString would create an SvnTarget that can be used as a URI.  On the other hand if you typed

    SvnTarget target = SvnTarget.FromString(@"C:\myproj.helloworld.c");


    then you would get an SvnTarget that can be used as a local file path.

    Next we should talk about the output Collection of SvnPropertyListEventArgs named proplist.  When you run GetPropertyList (the method which executes svn proplist), this collection is populated with one SvnPropertyListEventArgs instance for each node which has properties to report.  This instance holds the entire property set for its corresponding node.  Therefore, if you run the method against a single node you will only ever get a single item in proplist.  So how do you add additional nodes to your property query?  By recursion of course!  The way you normally tell functions in SharpSvn to recurse into directory nodes is by setting args.Depth to some member of the svnDepth enumeration.  For instance, in this example we have set it to svnDepth.Infinity which tells the GetPropertyList function to fully recurse into all directories.  GetPropertyList will now dive into all directories, adding a new entry to proplist for each file on the way.  Once you have your fully populated proplist you can go through each SvnPropertyListEventArgs and grab its property set.  Once you have the property set you can pull each key/value pair.  It's pretty confusing but if you study the two foreach loops above for long enough you will see that what you are dealing with is essentially a collection of collections.

  13. Save your project and run it.  Select svn proplist from the pulldown menu.  Click 'Go'.  Enter a directory from your working copy or a repository into the 'File URI:' box and click 'Get Properties'.  Click the 'Recurse into directories' check box and click 'Get Properties' again.  Make sure that the list view is populated with all the file properties beneath the directory you entered (if you haven't defined any svn properties for you repository you will need to do so before you see anything here).

svn propset

The final example will show you how to set SVN properties on a node in a repository.  The function call which does this is SvnClient.SetProperty.  The interesting thing about this function is that, just like the 'svn propset' command, it allows you to set a property to either a string value or the raw bytes from a file.  We will demonstrate how to do both here.  Again, we will be adding a form to our project to demonstrate the use of the method. 

  1. Start by adding the new form to the project.  Click Project->Add Windows Form...

  2. Make sure that 'Windows Form' is selected, name the new form frmPropSet.cs and click 'OK'

  3. Add an OpenFileDialog to the form:

    • Name: ofdOpenFile

    • FileName: ""

  4. Add two labels to the form:

    • Name (first Label): lblFilePath

    • Location: 9, 19

    • Text: File Path

    • Name (second label): lblPropName

    • Location: 9, 46

    • Text: Property Name:

  5. Add two RadioButton controls to the form:

    • Name (first RadioButton): rbTextValue

    • Location: 12, 75

    • Checked: True

    • Text: Enter a text value:

    • Name (second RadioButton): rbFileValue

    • Location: 12, 101

    • Text: Import value from file:

  6. Add four TextBox controls to the form:

    • Name (first TextBox): tbFilePath

    • Location: 140, 12

    • Size: 286, 20

    • Name (second TextBox): tbPropName

    • Location: 140, 39

    • Size: 286, 20

    • Name (third TextBox): tbTextValue

    • Location: 140, 65

    • Size: 286, 20

    • Name (fourth TextBox): tbFileValue

    • Location: 140, 97

    • Size: 286, 20

  7. Now add three Button controls to the form.

    • Name (first button): btnPropSet

    • Location: 197, 125

    • Text: Set Property

    • Name (second button): btnClose

    • Location: 291, 125

    • Text: Close

    • Name (third button): btnBrowse

    • Location: 432, 95

    • Text: Browse

  8. Now set the properties of the form itself:

    • CancelButton: btnClose

    • Size: 531, 196

    • Text: svn propset

  9. The final form should look something like this:
    The final propset form

  10. Double click the Browse button to open the editor in the btnBrowse_Click method.  Change the code in btnBrowse_Click as follows:

     private void btnBrowse_Click(object sender, EventArgs e)
    {
        if (ofdOpenFile.ShowDialog() == DialogResult.OK)
       
    {
            tbFileValue.Text = ofdOpenFile.FileName;
       
    }
    }

  11. Open SvnClient.cs in design view and open the collection editor for the Items property of cbCmdList.

  12. On its own line add the string:

    svn propset

    and click 'OK'

  13. Double click the 'Go' button to open up its Click event handler.  Add a new case to the switch statement as follows:

    case "svn checkout": //Open the svn checkout form
        ...
    case "svn propset":
        frmPropSet propSetForm = new frmPropSet();
        propSetForm.ShowDialog();
        break;

    default:
        ...

  14. Save your project, run it and make sure that selecting "svn proplist" from the main menu opens our new form.  Make sure that the 'Browse' button opens the OpenFileDialog.  Make sure that selecting a file from the OpenFileDialog populates the bottom text box with the correct file path.  Quit the application.

  15. Open frmPropSet.cs in the code editor and add the following two using statements to the top of the code:

    using System.IO;
    using SharpSvn;

  16. Open frmPropSet.cs in design view and double click the 'Set Property' button to create the method btnPropSet_Click().  Edit the method as follows:

     private void btnPropSet_Click(object sender, EventArgs e)
    {
        using (SvnClient client = new SvnClient())
       
    {
            try
           
    {
                //if using a file value, copy file to a buffer before setting prop.
                if (rbFileValue.Checked)
               
    {
                    //Arrays implement the Generic ICollection interface
                    byte[] buffer = File.ReadAllBytes(tbFileValue.Text);

                    //this is the call which executes svn propset
                    client.SetProperty(tbFilePath.Text, tbPropName.Text, buffer);
                    MessageBox.Show("Added property '" + tbPropName.Text +
                        "' to file " + tbFilePath.Text);
               
    }
                //otherwise we are using a raw string value
                else
               
    {
                    //this is the call which executes svn propset
                    client.SetProperty(tbFilePath.Text, tbPropName.Text, tbTextValue.Text);
                    MessageBox.Show("Added property '" + tbPropName.Text +
                    "' to file " + tbFilePath.Text);
               
    }
           
    }
            catch (SvnException se)
           
    {
                MessageBox.Show(se.Message, "Error adding new property.",
                MessageBoxButtons.OK,
                MessageBoxIcon.Error);
           
    }
            catch (FileNotFoundException fnfe)
           
    {
                MessageBox.Show(fnfe.Message,
                "Invalid file name",
                MessageBoxButtons.OK,
                MessageBoxIcon.Error);
           
    }
            catch (Exception ex)
           
    {
                MessageBox.Show(ex.Message,
                "Error",
                MessageBoxButtons.OK,
                MessageBoxIcon.Error);
           
    }
       
    }
    }

    This example lets you select whether to use a string or the bytes from a file as a property value.  Obviously this is a great feature because you don't have to type large property values by hand.

    The SetProperty function has overloads which take an argument class SvnSetPropertyArgs which operates similarly to the argument classes from the last three examples.

So that's the  end of the walkthrough.  Hopefully it will give you a good idea of how to use the basic classes/methods in the SharpSvn API.

Getting Help

If you ever need help with the SharpSvn project and you can't find an answer to your question in this walkthrough, you will be happy to know that there is help available through the SharpSvn community.  So where can you find this help?  First, you should look through the SharpSvn wiki on http://sharpsvn.open.collab.net to make sure the answer has not already been posted.  If the answer isn't already there, sign up for a CollabNet account and post a question yourself.  I have found that the API developers are pretty good at responding in a timely manner.  Another option is to sign onto the IRC channel #ankhsvn and talk to some of the nice folks on the AnkhSvn project.  AnkhSvn is a plugin for Visual Studio which gives you access to all the functionality of an SVN client right from the IDE.  It is important to you because it uses SharpSvn so most of the AnkhSvn developers are SharpSvn wizards!  Additionally a couple of the folks who run the SharpSvn project are signed on to #ankhsvn pretty regularly.  What this means is if you can't get an answer from #ankhsvn it likely can't be done. 

Please bear in mind however that SharpSvn is an open source project which means that there are folks from all over the world working on it.  If you don't get an answer right away, please be patient, you will get helped.