Click here to Skip to main content
15,868,340 members
Articles / Programming Languages / C#
Article

Forms Designer Friendly Background Intelligent Transfer Service (BITS) wrapper

Rate me:
Please Sign up or sign in to vote.
4.83/5 (18 votes)
4 Sep 2006CPOL6 min read 303.3K   4K   70   111
Create BITS copy jobs using the Forms Designer. All features of BITS are available, and easy to use managed wrapper with all COM interop details hidden.

Sample Image - Managed_BITS.png

Introduction

There are a few articles about the Background Intelligent Transfer Service or BITS here. I wanted to add something more. Using BITS with COM interop isn't really difficult, but I thought this would be a fun project to do anyway.

For a complete reference on BITS, do read all about it on MSDN first.

When I started, I had some goals in mind.

  • Completely Forms Designer friendly that works as much like ListView and ListViewItem as possible.
  • Wrap all features of BITS through version 3.0.
  • Easy to use and relatively idiot proof. Someone's always making a better idiot, but I try.
  • Automatic handling of certain events. Fear not control freaks, all of the automatic handling can be shut off on a job by job basis.
  • All exceptions coming from my code derive from a common base class. You'll only need one catch handler. If I didn't throw the exception, then InnerException will contain the exception thrown by COM or the CLI.

Here's a simple example of creating a download job.

C#
System.Net.BITS.Manager manager = new System.Net.BITS.Manager();
System.Net.BITS.Job job = new System.Net.BITS.Job("Simple Job");

job.Files.Add("http://www.someplace.com/download/file.zip", "c:\file.zip");
manager.Jobs.Add(job);
job.Resume();

That's pretty easy. You could get away with doing this little. BITS will take care of the download, and IBackgroundCopyJob.Complete() will automatically be called when the job completes. If there's an error, IBackgroundCopyJob.Cancel() will automatically be called.

What this example lacks is a way to know when the job finishes. You can do this in one of two ways, using polling or events. Polling works just fine, use a timer to check the job state, or if you need something synchronous a simple loop will work.

C#
while (job.State != JobState.Cancelled && 
       job.State != JobState.Acknowledged)
    Sleep(1000);

// we're done! Do Something

Of course, polling is not the best approach. The job will eventually finish one way or another, but the loop above could take a while. Let's use events instead.

C#
    System.Net.BITS.Manager manager = new System.Net.BITS.Manager();
    System.Net.BITS.Job job = new System.Net.BITS.Job("Simple Job");

    manager.OnModfication += new 
      EventHandler<JobModificationEventArgs>(manager_OnModfication);

    job.Files.Add("http://www.someplace.com/download/file.zip", 
                  "c:\file.zip");
    manager.Jobs.Add(job);
    job.Resume();
}

private void manager_OnModfication(object sender, 
                     JobModificationEventArgs e)
{
    if (e.Job.State == JobState.Cancelled && 
        e.Job.State == JobState.Acknowledged)
    {
        // we're done! Do Something
    }
}

There's a lot more to BITS that what is in this example. Fortunately for me, it's documented by Microsoft already. I did add a few things, so I'll go over them. Not everything will be covered, just the important stuff.

General

Each version of BITS adds more features. Be sure to check what version of BITS was instantiated. An exception will be thrown if you try to use features from a higher version of BITS than what you have on your machine. You won't get the exception in the designer. You can set everything in the designer, you'll get the exception as soon as your code runs. Be careful not to set properties in the designer if you want to support older versions of BITS.

I didn't test everything! Sorry. I tested a lot of the functionality on both XP and Vista. I did not try an upload with reply job.

Not everything works as Microsoft has documented. When running on XP, if you set a command line notification, it will not run unless you set Job.EventsEnabled to false. Doing so means no events will fire for that job. You can still use polling. Command line notifications do work as documented on Vista. By the way, setting a command line notification in the OnTransferred event doesn't work. You have to set the command line sooner.

The documentation on MSDN is not up to date, and some of the stuff added in BITS version 3.0 is not documented.

If you have the System.Net.Bits assembly and the project that uses it in the same solution, Visual Studio can have problems in the designer. The sample project does this. I reference System.Net.BITS as a file reference not as a project reference, and whenever I change something in System.Net.BITS, I usually have to quit Visual Studio and rerun, otherwise the designer gets goofy.

The Manager Class

You will need to create an instance of Manager. You can create more than one, but one is all you need. It wraps IBackgroundCopyManager. It will try to instantiate the highest version of the BITS COM class. If BITS is not installed on your machine, you'll still be able to create a Manager, the constructor won't throw an exception. This will let you use the Forms Designer even when BITS is unavailable.

The Manager maintains the list of jobs. A job doesn't do anything unless it's in the Jobs collection. Just like ListViewItem, you can set its properties but its doesn't live until it's in a ListViewItemCollection. The Jobs collection is, by default, automatically populated with the jobs in IEnumBackgroundCopyJobs belonging to the current user. You can shut that off if you wish, or get all jobs belonging to all users. The Manager has an Update method. You can use Update to check IEnumBackgroundCopyJobs for new jobs, or remove jobs BITS no longer maintains. I.e., when one of your jobs completes, if you call JobCollection.Update(), your job will no longer be in the Jobs collection.

Jobs can be added or removed from the collection at any time. When removed from the collection, the IBackgroundCopyJob maintained by BITS still exists. If it was downloading before, it'll still be downloading. The job object is simply no longer connected to the IBackgroundCopyJob. This also means you can quit your app and your jobs will still be there when you start up again.

The Manager also has the job related events. Even though all events are connected to a job, it's much easier to connect to an event once than have to do it for each and every job. Not only that, BITS likes to send events as soon as possible, and often. By putting the events in the Manager class, you won't miss an event.

BITS likes to send lots of events and on different threads. BITS doesn't queue up events for the same job. You can have multiple events pre-empting each other. I think that's annoying. So I wrapped all the events in a Mutex.

The Job Class

For the most part, this is just a wrapper around IBackgroundCopyJob. Most things about a job are exposed as properties. Creating a job is not the same thing as creating the IBackgroundCopyJob. In order to support the designer, all of the designer settable properties are cached in the job until you call a method to create the actual IBackgroundCopyJob. I added a JobState for this case, called JobState.Inactive. When you construct the job, it will be in this state. If you call Job.Activate() or Job.Resume(), then the IBackgroundCopyJob is created. Any properties set at design time are set on the IBackgroundCopyJob. This is also when the files are added to the IBackgroundCopyJob as well.

Jobs can be cloned. All the job properties are set on the clone. Even the credentials. This will only work if you set all the credentials in this job instance. There's no way to get them from the IBackgroundCopyJob. So if your jobs collection was populated with an existing job, it won't have any credentials cached in it.

Jobs maintain a collection of files. While designing a job, you can add and removes files as you wish. Once the IBackgroundCopyJob is created, you can no longer remove files. For some reason, BITS doesn't support it.

Some properties, like ProxySettings, return a class. This is nice and handy, but there's a caveat. Don't go doing this.

C#
job.ProxySettings.ProxyUsage = ProxyUsage.NoProxy;

It won't do anything. I could have made that work but decided against it. IBackgroundCopyJob.SetProxySettings() expects three arguments. If something is wrong with one of them, an exception is thrown. So if you want to change the proxy settings, you have to change them all at once.

C#
JobProxySettings settings = job.ProxySettings;

settings.ProxyUsage = ProxyUsage.NoProxy;
job.ProxySettings.ProxyUsage = settings;

Doing the above will result in a call to IBackgroundCopyJob.SetProxySettings().

References

History

  • 09/04/2006: Posted to CodeProject.

License

This article, along with any associated source code and files, is licensed under The Code Project Open License (CPOL)


Written By
Software Developer (Senior) Adobe, LLC
United States United States
This member has not yet provided a Biography. Assume it's interesting and varied, and probably something to do with programming.

Comments and Discussions

 
GeneralRe: Test It Pin
RodgerB22-Mar-07 7:12
RodgerB22-Mar-07 7:12 
GeneralRe: Test It Pin
David Rosa22-Mar-07 8:09
David Rosa22-Mar-07 8:09 
GeneralVersion of DLL Pin
joolzz4-Mar-07 4:22
joolzz4-Mar-07 4:22 
GeneralRe: Version of DLL Pin
RodgerB4-Mar-07 13:44
RodgerB4-Mar-07 13:44 
General64bit OS BITS problem Pin
TominLA21-Jan-07 18:57
TominLA21-Jan-07 18:57 
GeneralRe: 64bit OS BITS problem Pin
RodgerB21-Jan-07 20:20
RodgerB21-Jan-07 20:20 
GeneralRe: 64bit OS BITS problem Pin
TominLA22-Jan-07 8:03
TominLA22-Jan-07 8:03 
GeneralRe: 64bit OS BITS problem Pin
RodgerB22-Jan-07 18:48
RodgerB22-Jan-07 18:48 
0 and 8 should be correct. The size doubles to 16. I don't think you need the "pack".
GeneralRe: 64bit OS BITS problem Fixed Pin
TominLA23-Jan-07 19:24
TominLA23-Jan-07 19:24 
GeneralAdding event handler Pin
TominLA15-Dec-06 8:55
TominLA15-Dec-06 8:55 
GeneralRe: Adding event handler Pin
RodgerB15-Dec-06 9:10
RodgerB15-Dec-06 9:10 
QuestionRe: Adding event handler Pin
TominLA15-Dec-06 9:43
TominLA15-Dec-06 9:43 
AnswerRe: Adding event handler Pin
RodgerB15-Dec-06 10:37
RodgerB15-Dec-06 10:37 
GeneralRe: Adding event handler Pin
TominLA15-Dec-06 11:04
TominLA15-Dec-06 11:04 
GeneralRe: Adding event handler Pin
RodgerB15-Dec-06 11:18
RodgerB15-Dec-06 11:18 
QuestionDownload Job Not Completing Pin
TominLA12-Dec-06 11:35
TominLA12-Dec-06 11:35 
AnswerRe: Download Job Not Completing Pin
RodgerB12-Dec-06 11:49
RodgerB12-Dec-06 11:49 
GeneralRe: Download Job Not Completing Pin
TominLA12-Dec-06 12:02
TominLA12-Dec-06 12:02 
Question~Job Exception: COM object has been separated from its underlying RCW can not be used Pin
ma-kai8-Dec-06 6:01
ma-kai8-Dec-06 6:01 
AnswerRe: ~Job Exception: COM object has been separated from its underlying RCW can not be used Pin
RodgerB8-Dec-06 7:08
RodgerB8-Dec-06 7:08 
AnswerRe: ~Job Exception: COM object has been separated from its underlying RCW can not be used Pin
RodgerB8-Dec-06 7:27
RodgerB8-Dec-06 7:27 
GeneralRe: ~Job Exception: COM object has been separated from its underlying RCW can not be used Pin
ma-kai11-Dec-06 2:56
ma-kai11-Dec-06 2:56 
GeneralRe: ~Job Exception: COM object has been separated from its underlying RCW can not be used Pin
RodgerB14-Dec-06 19:57
RodgerB14-Dec-06 19:57 
AnswerRe: ~Job Exception: COM object has been separated from its underlying RCW can not be used Pin
ma-kai27-Feb-07 5:21
ma-kai27-Feb-07 5:21 
GeneralMonitoring tools for BITS on server Pin
Dave Lenz16-Nov-06 6:30
Dave Lenz16-Nov-06 6:30 

General General    News News    Suggestion Suggestion    Question Question    Bug Bug    Answer Answer    Joke Joke    Praise Praise    Rant Rant    Admin Admin   

Use Ctrl+Left/Right to switch messages, Ctrl+Up/Down to switch threads, Ctrl+Shift+Left/Right to switch pages.