[The source code for the projects -- contained within a SharpDevelop combine -- can be downloaded here.]
Introduction
The first installment of this series was little more than a simple proof of concept. We showed that a.c.pro does indeed have an XML interface via HTTP, and that SharpDevelop is a cool and free .NET IDE. All the code we wrote in that first installment can be tossed out, whereas this time around we will start writing code that will be useful enough to hang on to for future installments. Specifically, we will build a little application that will let us select multiple files from disk and then send them all to a.c.pro to be placed as attachments inside a single a.c.pro item. Importantly, as we build that little app, we will also begin building a library of standard routines that we can re-use to communicate with a.c.pro via XML.
An a.c.pro File Uploader
Let's look first at how files are uploaded in a.c.pro's standard web interface. When viewing an individual item, there is an "Attach" button available on the left side.

When you click that button, you get the typical browse-and-upload interface you see in many web applications:

After you complete the process, you can see the uploaded file listed in the "attachments and links" section of the item's page:

It works great, but it's limited to one file at a time and therefore involves a lot of repetition. We'll develop a small Windows Forms app that makes use of the a.c.pro XML interface's SaveAttachment message to upload one or more files in base64 (base64) format.
A New "Combine" in SharpDevelop
As stated at the top of this article, you can throw away everything from the previous article. When ready, startup SharpDevelop and choose File - New - Combine from the menu so you get the dialog box for setting up a new combine. You may recall from the first article that a "combine" is a collection of projects. If you are familiar with Visual Studio .NET or even the older Visual Interdev, then think of a combine as roughly the equivalent of a Solution.
When you create the combine, what you are actually doing is creating both the combine and its first project, which explains why SharpDevelop prompts you to select a project type while you are creating the combine. Select the Windows Application project type, make sure the "Auto create project subdir" is checked (it should be checked by default), then also check the "Create directory for sources". This lets you create a hierarchical structure where the combine's folder will be at the top, and then the Windows Form project -- which will be just one of the projects in the combine -- will get its own folder for sources below that. In the "Name" field you should enter the name for the entire combine -- just call it "acpro", because we'll be creating multiple projects that can work with a.c.pro. In the "New project name" field, on the other hand, you want to put a name that is descriptive of the specific Windows Form project that you're creating as the first project in this combine. Since you'll be creating an app to upload files to a.c.pro, just call it "acproUploader" or something similar. When all is said and done, the dialog should look similar to the following:

After clicking "create" to make the combine and the first project, have a look at the "Project Scout" (equivalent to the Solution Explorer in Visual Studio). If you can't see it by default, choose View - Projects from the menu. It shows that there is both a combine named "acpro" and a project named "acpro":

To be honest with you, this irks me a bit. Here is what I wish it would have done: created the combine named "acpro" (as it did) then the first project named "acproUploader". It created the acproUploader and stored the project file in it, which is nice, but I wish the dialog that you get from File - New - Combine would enable you to specify different names for the combine and its first project.
So let's remedy what it did by re-naming the project to "acproUploader". To do this, right-click the "acpro" project branch (not the top-level combine!) in the Project Scout and choose Rename, then type the new name:

That looks better and makes it clearer that acproUploader is just one project (at the moment the only one) in the acpro combine.
The Form Layout
The form for the acproUploader will be very simple indeed. Because this article assumes that you read the previous article, it also assumes that by now you are relatively familiar with the Windows Forms editor in SharpDevelop. So I won't hold your hand as we go through adding controls to the form. Instead I'll just indicate what controls you need to add and I'll show you screenshots of my own examples.
I'm ok with the file name "MainForm.cs" that SharpDevelop created by default for the Windows Form. If you're not, you can change it. When you look at the code in that file, you'll see that the form's class name is also MainForm. That's also fine with me, but you can change it if you wish. When ready, go to Design view so you can start adding controls.
First and foremost, the form needs textboxes into which the user can input his/her a.c.pro user id and password. It also needs one more textbox where the user can type an a.c.pro item number. For simplicity, we'll assume the user has the a.c.pro item number at hand and can just enter it (or paste it) into the textbox. (The a.c.pro item number is visible via the web interface when you look at the list of a project's items; or, when you view a single item, the item number is near the top of the browser window.)
Some sort of list control is also required so that we can list each file that the user chooses. Then we also need "Add" and "Remove" buttons to add to or take away from the list, plus a button to start the upload and a button to close the form. Besides all of that, all of the text boxes need labels.
For my own simple design, I chose to make the form "wide and short" as opposed to "thin and long" because I want to show the full path of each selected file in a list box control. Because I chose wide rather than long, I put the three text boxes and their labels next to each other on the same horizontal coordinate of the form, and then the file list box below them. At the very bottom I put the four buttons.

Note that while doing this I used the controls' Property Scouts (right-click the control and choose Properties) to change from the default and meaningless names such as "textBox1" to more meaningful names such as "TBUserId".
Let me state categorically that the "wide and short" design is not pretty. I chose it as a simple workaround for one problem: namely, that I had to store somewhere the full path and file names of each file chosen by the user. From a visual perspective, the list box would look better if it was thinner and populated with shortened paths using ellipses, such as "c:\documents and settings\...\myfile.xls". That would mean, however, that the full path would have to be stored somewhere other than as the textual item in the list box. Specifically, we would have to choose some sort of data structure that could hold both our shortened version of the path for display purposes and the true path for uploading purposes. We could, for example, bind an ArrayList of System.IO.FileInfo objects to the list box and refresh the list each time the user uses the Add or Remove buttons. I leave such better solutions to you as extra work!
Code to Close the Form
With the basic form layout complete, we will now begin adding code to the form. We'll start with the simplest (in terms of functionality) control that requires code: the Close button. When clicked it should, as you guessed, close the form. As this is a single form application, this will shutdown the application as well. So we need an event handler for the Close button's Click event. To create a click event handler for the Close button, simply double-click the button itself in the form designer. This will pop open the form's code file and place the cursor inside a Click event handler. The code we need is this simple:
Close();
That's all it takes. You can test it by running the project.
Code to Add and Remove Files from List Box
Now let's concentrate on the Add and Remove buttons and how they modify the contents of the listbox.
The requirement for the Add button is simple: it must open a standard "file open" dialog and allow the selection of one or more files. The .NET Framework's System.Windows.Forms namespace contains an OpenFileDialog class that is precisely what we need. An instance of the class can be conveniently created simply by clicking "OpenFileDialog" in the Tool Scout and then clicking anywhere on the form's design surface. SharpDevelop will then automatically add an instance in the form designer's component tray. The nice thing about having it here is that you can then use the Property Scout to set some of its properties, rather than setting the properties manually via code. Here's a screenshot of the instance of OpenFileDialog created when I added it to the form:

Notice that, in the screenshot, I have selected the component instance and the Property Scout is showing its properties. Use that Property Scout to set a few of the properties as follows:
With our instance of OpenFileDialog ready to go, all we need to do now is to use it. We want to use it when the user clicks Add, so we need an event handler for the Add button's Click event. To create a click event handler for the Add button, just double-click the button itself in the form designer. This will pop you into the code that is "behind" the form and it will do all of the plumbing required to wire a new function to handle the button's click event. We want to show the user our OpenFileDialog instance, accept his choice of file(s) and add it/them to the list. This can be accomplished with only a few lines of code. Here's what I came up with:

The first line simply shows the dialog. The dialog is modal: while it is open, the code stops. After the user closes the dialog -- either by selecting files and clicking "Open" or by canceling it -- the code resumes. The selected files, if any, are collected using the string array that is returned from the OpenFileDialog's FileNames property. We check to see if the array is null or empty, and, if not, we add each array item to the list box's Items collection.
Again, there is definitely room for improvement. In this case, the user can click Add a second time and select the same file(s); if so, with the current code I've shown, duplicates will appear in the list box. Let's fix that right away, because we don't want to upload the same file multiple times for no reason. Thankfully, the list box Items object -- an instance of the ListBox.ObjectCollection class -- has a Contains method that we can use to check if a file already exists in the list. I modified my code to use it:

We also need to be able to remove files from the list box using the Remove button. First, let's be nice to the user and let him select multiple files in the list for removal. Using the list box's Property Scout, set the SelectionMode property to MultiExtended:

Next create an event handler for the Remove button's click event by double-clicking the button in the form's design view. In the event handler we need to know which items are selected and then delete them. The list box's Items collection has a SelectedItems property we can use to determine which file names are selected for removal. How, then, do we remove them? For me, it was tempting to do this:

It looks good, but I immediately got an error reminding me that I cannot use an enumerator (which I'm automatically using because of the foreach) and then destroy one of the objects in the collection it refers to. An enumerator can survive only as long as the collection it refers to remains intact. So, instead, I chose this:

The while loop contains the code that clears the items. But note that I surrounded it with SuspendLayout() and ResumeLayout(). This reduces screen flicker in case you are removing several items from the list -- the list box won't try to keep refreshing its appearance each time you remove one of the items.
An acpro Library Project
Well here we are finally at the fun part. Adding and removing entries from a list box wasn't so interesting. But now we need to think about how we'll get those files up to a.c.pro. We need to write code that...
Each of these three requirements involves some knowledge of the a.c.pro XML service and does not need to have any knowledge of the UI application we are building. Therefore we should put the functionality that we will create to fulfill these requirements into its own, separate C# project that can be compiled as a library and re-used whenever needed. To explain this another way: the three requirements all involve writing code that will be useful in basically any application we write that uses a.c.pro's XML interface. For example, to satisfy the first requirement -- validating the user's credentials -- we will need to write code that creates the a.c.pro XML interface's Login message. Needless to say, that is functionality that we will most likely require in any a.c.pro application we write. The same goes for the rest of the requirements.
With that in mind, let's put any new code that prepares messages for and sends messages to a.c.pro into its own project. We anticipated this kind of decision earlier when we decided that the SharpDevelop combine that we are working in should just be called "acpro", rather than, for example, "acproFileUploader". This way it makes more intuitive sense to add other projects to the existing "acpro" combine: in the end, we'll have an "acpro" combine that contains an "acproUploader" project, an "acproLibrary" project (which we're about to create) and perhaps much more, depending on how many little apps we want to write for a.c.pro.
Right-click the acpro combine in the project scout, then choose Add, then Add Project:

At the New Project dialog, select the Class Library template, name it acproLibrary, make sure the "Auto create project subdir" option is checked, and then specify the path to the acpro combine folder in the Location text box (or use the Browse button to go find it.) Then click Create.

Following those steps precisely will retain a nice folder hierarchy in your file system as well as in the Project Scout. The main combine folder in the file system should now have two children, as this little snippet from my Explorer window shows:

Finally, just delete the MyClass.cs file. Later, after we determine what classes we need, we'll create our own class files.
Determining our Class Library Needs
Though a good acproLibrary project would create a bunch of classes and methods that can help us with any of the a.c.pro XML interface messages, our short term goal is only to send a.c.pro one or more SaveAttachment XML messages; so let's start by only looking at that. The a.c.pro XML Interface Guide shows a sample XML message with a SaveAttachment request:

The root <a.c.pro> element is always required, as is its first child, the <Login> element. After that is the <SaveAttachment> message itself. It takes two attributes -- itemKey and fileName --, a <FileDateTime> element and the <Contents> element which holds a base64 representation of the file contents. (Note: currently only base64 is supported, so be sure to use it.)
We need to think about what kinds of .NET classes we might use to accomplish the construction and sending of such a message. Let's keep those two pieces of functionality -- message construction and message delivery -- separate and put them into their own classes. This means we need some kind of message builder class and then another class that strictly handles delivery. I propose this list of desired classes so far:
acproMessageBuilder
acproDelivery
Now let's think about what needs to go in those classes. For the acproMessageBuilder, all we care about so far is a method to make a SaveAttachment message. We can call it BuildSaveAttachmentMessage, for example.
What would we pass to such a BuildSaveAttachmentMessage method, and what would it return? Well, we need to pass it enough info for it to create the SaveAttachment XML that we see above in that screenshot from the XML Interface Guide: filename, file date and time, a.c.pro item number, etc. I don't want to pass it all that info in separate parameters, so I want us to create an acproAttachment class that represents all of the attributes of an a.c.pro attachment. That acproAttachment class will then have properties for filename, item number, file date and time, etc. I also want it to have a constructor that accepts the path to the file, the encoding scheme to use for turning the binary into a string that can be placed into the <Contents> element (only base64 is supported!), and the mime type. That constructor, when called, will then load up that file and all of its details.
So if we update the list of classes and methods that we so far know that we want to create, it looks like this:
| Class | Property/Method | Parameters | Type |
|---|---|---|---|
| acproMessageBuilder | BuildSaveAttachmentMessage | acproAttachment | ? |
| acproDelivery | ? | ? | ? |
| acproAttachment | (constructor) | string file, string encoding, string mimeType | n/a |
| FileName | n/a | String | |
| FileDateTime | n/a | DateTime | |
| ItemKey | n/a | Int32 | |
| Encoding | n/a | String | |
| MimeType | n/a | String | |
| Contents | n/a | byte[] |
We still have some question marks in there. First of all, what should acproMessage.BuildSaveAttachmentMessage return? One of our design goals should be to work with big strings as little as possible and favor streams instead. So I don't want it to return a big string. Instead, I want it to operate on a Stream. That brings up two other things: what kind of stream and what encoding should be used to write the XML?
After considering this for a while, I decided that the BuildSaveAttachmentMessage should be totally agnostic as to what kind of Stream it is writing to, and what character encoding is being used to create the XML. So instead of it returning a Stream, I decided it should not return anything at all, but rather it should accept an XmlTextWriter as a second parameter. That way the caller -- who has more knowledge of the context of the running application and can make decisions such as which character encoding is appropriate -- can setup the XmlTextWriter and its underlying Stream in anyway it wants, and the acproMessageBuilder class -- which has more knowledge of how to create a properly structured acproSaveAttachment message -- can simply write out the correct XML structure for the message. So we can update our list as follows:
| Class | Property/Method | Parameters | Type |
|---|---|---|---|
| acproMessageBuilder | BuildSaveAttachmentMessage | acproAttachment, XmlTextWriter | void |
| acproDelivery | ? | ? | ? |
| acproAttachment | (constructor) | string file, string encoding, string mimeType | n/a |
| FileName | n/a | String | |
| FileDateTime | n/a | DateTime | |
| ItemKey | n/a | Int32 | |
| Encoding | n/a | String | |
| MimeType | n/a | String | |
| Contents | n/a | byte[] |
But we need a bit more in the acproMessageBuilder class. The BuildSaveAttachmentMessage will give us only the XML for the <SaveAttachment> element -- what about the <Login> element, which is always required, or even the <acpro> element, which is the root of all a.c.pro XML Interface messages? These things are always required in any message sent to a.c.pro, so we might as well encapsulate them together in BuildMessageStart and BuildMessageEnd methods. BuildMessageStart will create the opening of the <acpro> element and also create the entirety of the <Login> element. BuildMessageEnd will close the <acpro> element and finish the document.
Since BuildMessageStart will create the <Login> element, we should pass it the user id and password. Also, since it is naturally the beginning of the entire process of creating an a.c.pro XML message, we may as well allow it to create and return an XmlTextWriter, which we will then pass around as we build other elements into the message. We do not want it to have to decide what kind of Stream object to create, so we will pass it an existing Stream and it will just pop an XmlTextWriter on top of it. And since it will create that XmlTextWriter, we should also tell it what character encoding we want to use.
Let's update our classes and methods list:
| Class | Property/Method | Parameters | Type |
|---|---|---|---|
| acproMessageBuilder | BuildMessageStart | string userid, string password, Stream, Encoding | XmlTextWriter |
| BuildMessageEnd | XmlTextWriter | void | |
| BuildSaveAttachmentMessage | acproAttachment, XmlTextWriter | void | |
| acproDelivery | ? | ? | ? |
| acproAttachment | (constructor) | string file, string encoding, string mimeType | n/a |
| FileName | n/a | String | |
| FileDateTime | n/a | DateTime | |
| ItemKey | n/a | Int32 | |
| Encoding | n/a | String | |
| MimeType | n/a | String | |
| Contents | n/a | byte[] |
By now you can see the sequence of how we would use the acproMessageBuilder to create a message with one SaveAttachment element in it:
At that point, our stream is filled with a complete a.c.pro XML message. Now we just need to deliver it! As our list above shows, we still have all question marks for our planned acproDelivery class. We want to be able to hand this class a Stream filled with a message. Then it will take care of all the network plumbing and just pass us back a Stream representing the response from the a.c.pro web server that it contacts. That's enough for now -- the caller will simply evaluate the response. Perhaps in a later article we will find it useful to create a special class that is dedicated to evaluating the responses to all kinds of a.c.pro XML messages. So all we really need for now in acproDelivery is a SendRequest method that accepts a Stream and returns a Stream. Our new list looks like this:
| Class | Property/Method | Parameters | Type |
|---|---|---|---|
| acproMessageBuilder | BuildMessageStart | string userid, string password, Stream, Encoding | XmlTextWriter |
| BuildMessageEnd | XmlTextWriter | void | |
| BuildSaveAttachmentMessage | acproAttachment, XmlTextWriter | void | |
| acproDelivery | SendRequest | Stream | Stream |
| acproAttachment | (constructor) | string file, string encoding, string mimeType | n/a |
| FileName | n/a | String | |
| FileDateTime | n/a | DateTime | |
| ItemKey | n/a | Int32 | |
| Encoding | n/a | String | |
| MimeType | n/a | String | |
| Contents | n/a | byte[] |
Coding the Classes
We've got no more question marks in our list of desired classes and methods, so we are ready to start coding these classes. I'm not going to go through every step here. Instead, have a look at my code directly by viewing the output from SharpDevelop's excellent Html Export feature (available on the SharpDevelop Project menu) and I'll just mention a few things.
Note that I put all of these classes into the acpro namespace.
Note that acproDelivery has a public static string named Url, which you need to use to specify the Url to your a.c.pro server's XML interface listener. If you are using the publicly available a.c.pro server, then acproDelivery.Url should be set to http://www.acpro.at/xmli.asp.
In acproDelivery.SendRequest, note that the result Stream is a MemoryStream whose position is reset to 0 just before it's returned to the caller. That way the caller can start reading immediately from the returned Stream.
As mentioned earlier, acproFileAttachment's constructor lets you pass the location to the file so that it will then load it up for you, get its bytes and put them into the Contents property, read its last modification date into the FileDateTime property, etc. After that, all you need to do is set the ItemKey property and the attachment object is ready to be passed to acproMessageBuilder.BuildSaveAttachmentMessage.
Meanwhile, back at the button
With our library project ready to go, we still have this stranded Upload button back on the main form in our acproUploader application. Now it's time to write the code for that button's Click event. The code we write will, as you guessed, make use of our new library, so the first thing we need to do is add a reference to the library project. Just right-click the acproUploader project's Reference node in the Project Scout and select Add Reference. Choose the Projects tab in the Add Reference dialog box, click the acproLibrary project in the project list, click the Select button and then OK.
Now go to the form designer and double-click the Upload button to create a handler for the Click event. The handler (or some other method that it calls) should:
To see the entirety of how I did this, you can download the sources and look at MainForm.cs's BtnUploadClick method. But here's the interesting part, which I put into a separate private method that is called by BtnUploadClick:

You can see the foreach loop, wherein a SaveAttachment message is added for each file. Also note I'm using a MemoryStream and that it's position needs to be put to 0 before handing it off to SendRequest, otherwise the code in SendRequest will fail.
Room for improvement
Well, truth be told, there is lots of room for improvement in both the acproUploader and the acproLibrary. Here are just a few examples:
Conclusion
In this article we have put together a relatively useful little app that can upload multiple files at once to an a.c.pro item. We did it all without a spending a cent: we used a.c.pro's public server (http://www.acpro.at) and we used an excellent and freely-available .NET IDE, SharpDevelop, to graphically build our Windows form and to create a separate class library project.
Our special a.c.pro class library is ready for us to extend its functionality later when we want to create applications that use messages beyond just the SaveAttachment message which we implemented today. We have created the acproMessageBuilder class such that it can already handle the beginning and ending of all a.c.pro XML messages -- all it needs now is individual "Build" methods for each kind of message we want to send. And our acproDelivery class is all ready to send any kind of a.c.pro XML message and return the results.