September 18, 2008

HTTP Connection Limit in .Net

There exists a web specification which suggests a server endpoint only allow up to two connections from any client at a time. The .Net Framework builds this limit in by default. This means that if you are trying to use HTTPWebRequest, WebRequest, etc, and attempt to maintain more than two connections at a time, it simply will not work. There is a rare case where a client application would require more than two maintained connections, though we found one in trying to watch more than two camera feeds from a video server. You can get around this limitation by changing the default connection limit like so:

System.Net.ServicePointManger.DefaultConnectionLimit = 4;

Creating .Net COM objects for interop with VB6

.Net has some nice tools to help you create COM objects. .Net COM objects are slightly different from regular that regular COM objects in that the .Net is still in its intermediate language form. Because of this, you cannot register a .Net COM object with "regsvr32" as usual, you must use "regasm", which comes with the .Net framework.

There are a few project properties that in Visual Studio that will do a lot of the work for you. First, create a standard class library project, or open an existing one. Go to the project properties and change the following settings. On the "Application" tab, click the "Assembly Information" button. Check the box to "make assembly com-visible". This option will wrap your library as a COM library. Next go to the "Build" tab and check the box to "Register for COM interop". This option will automatically register the output dll with regasm on the current machine after a build. The final, optional step is to go to the "Signing" tab and check the box to "Sign the assembly". Choose "New" in the pull-down for the sign file. Give it a name and a password if you would like. Signing helps to keep similar objects in different dlls from getting mixed up during runtime.

Now that we have our project prepped, now we need to create our objects. The only real requirement on your classes is that they have a public constructor. All of the attributes that you will find in this article can be accessed by including the following namespace:

using System.Runtime.InteropServices;

To flag a class as an object that you would like to be available in your COM library, use the following class attribute:

[ClassInterface(ClassInterfaceType.AutoDual)]

This attribute tells the compiler to automatically create an interface for this class and do the other magic that is required to create a COM object. That is all you have to do to create a simple COM object. If you compile right now, you should be able to access the library from the add references portion of a development tool that can use COM libraries.

Often times you will want to have events in your class. To support .Net events, you will need to do a few extra steps. First you must create an interface with METHOD declarations for each one of your events. So for example, this event:

public void delegate MyEventHandler(int a, double b);
public event MyEventHandler MyEvent;

would have a declaration in the interface that looks like this:

void MyEvent(int a, double b);

Now place this attribute on your interface:

[InterfaceType(ComInterfaceType.InterfaceIsIDispatch)]

and this attribute on your class:

[ComSourceInterfaces(typeof(IMyEvents))]

where "IMyEvents" is the name of your interface. DO NOT declare this interface as an interface of your class. The compiler will take care of everything for you underneath. These attributes do some magic that allows other languages to hook into the .Net events properly.

Here is a simple complete example:

using System.Runtime.InteropServices;

[InterfaceType(ComInterfaceType.InterfaceIsIDispatch)]
public interface IMyEvents
{


void MyEvent(int a, double b);

}


[ComSourceInterfaces(typeof(IMyEvents))]
[ClassInterface(ClassInterfaceType.AutoDual)]
public class MyClass
{


public void delegate MyEventHandler(int a, double b);
public event MyEventHandler MyEvent;


public int MyProperty { get; set; }

public void MyMethod() { }

}


To use this COM object in VB6, declare it like normal:

Dim WithEvents myComObject As MyCLass

One thing to note is that VB6 has a bug that gives a compile error whenever you try to call a .Net method that takes an array parameter. In order for arrays to work properly, the parameters must be passed by reference using the 'ref' keyword before the parameter declaration.