September 18, 2008
HTTP Connection Limit in .Net
System.Net.ServicePointManger.DefaultConnectionLimit = 4;
Creating .Net COM objects for interop with VB6
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.
July 16, 2008
A Quick Note On Ports and Sockets
A common misconception is that a socket represents a bound port on a computer (the IP:Port pair). In reality, this is only half of what a socket represents. In fact, a socket represents two IP:Port pairs: one for the host, and one for the client. This means that multiple remote computers can connect to a program via the same port while each connection is represented by a different socket. Each socket is unique because they each have a different remote IP:Port pair even though they all have the same host IP:Port pair. To take this a little further, one remote computer can have multiple connections to a port on a host. This is possible because each remote connection will be bound to different ports on the remote machine, again giving us unique IP:Port pairs for each socket connection.
The way this generally works behind this scenes goes something like this. The host computer will open a socket which it will bind to some port to listen for incoming connections. When a remote computer connects, the listening socket will create a new socket and bind it to the host and connecting remote IP:Port pairs. The original listening socket will then continue listening on its bound port for more incoming connections. Sockets are typically implemented in this way because only a single connection can be represented by a socket at a time. The original socket could have handled the communications of the incoming connection itself, but there would then be no socket open to listen for other incoming connections.
July 2, 2008
Visual Studio Project Settings
First goto the properties page of a project and goto the settings tab. From here you can set up either Application or User settings. It turns out that the differences are pretty self explanitory. A user setting will actually end up in a user.config file burried in the Documents And Settings folder for each user. This means that each user will be able to have a different set of settings for these. Application settings are actually read from the myapp.exe.config file in the application path (usually in Program Files).
To access these settings from code, all you need to do is:
string mySetting = Properties.Settings.Default.MySetting;
If you are accessing a user setting, the program will first look in the user.config file burried in the user's Documents And Settings, then in the myApp.exe.config file, and finally in the hardcoded default values. For an application setting, the same order is used starting at the myApp.exe.config file.
To add to the excitement, it turns out that it is only possible to save user settings from your application. If you are writing to a user setting to the user.config file in the user's Documents And Settings, all you have to do is:
Properties.Settings.Default.MySetting = mySetting;
Properties.Settings.Default.Save();
The main point to recognize here is that even if you uninstall an application, the user settings will stick around in the Application Data for a user, and magically reappear next time the application is installed. These files must be removed if you want to reset your user settings.
January 16, 2008
TableAdapter.Update Error
Error Message: Update requires a valid UpdateCommand when passed DataRow collection with modified rows.
Problem: The update command is missing from the table adapter.
Cause: I believe that this must have occured by changing the database structure after the dataset was created from it.
Solution: Configure the data table of for the table in question. Assure that "Generate Insert, Update and Delete Statments" is checked inside of Advanced Options. Finish the wizard. Your command statements will be rebuilt (including the Update command).
January 4, 2008
The wonderful world of UDP Broadcasts
Now assuming that your server and client will be on two machines that are very close to one another (not spanning across the internet), there is a nice way to build into your server and client that will help the client 'magically' figure out the server's IP address. The answer lies with UDP broadcasts. UDP is similar to TCP in that they both require an IP address and a port number. The beauty of UDP is that it allow something called a broadcast. A broadcast will allow you to send information to a certain port, but to every computer on your network. If there is an application listening on that port on any computer on the network, it will be able to receive the information. There is also a Time To Live (TTL) associated with the UDP broadcast which says how many routers deep the transmission is to go.
The way we will work our 'magic' is by having our client broadcast a message via UDP broadcast to a port that our server will be listening on. Once the server receive the information, it automatically gets the IP address of the client along with it. Once we have the client's IP address, we can send that client a UDP message on a port that it will be listening on to the IP that we obtained. Once the client receives that message, guess what, we now automatically get the IP address of the server. Now that we have the IP address of the server, we can connect to our server via TCP to the port that it is listening on.
Here is an idea of what some of the code may look like.
The following segment of code shows how we can open a UDP socket to listen for any incoming messages on port 4040.
using System.Net;
using System.Net.Sockets;
...
IPEndPoint endpoint = null;
int port = 4040;
UdpClient listener = new UdpClient(port);
byte[] receivedData = listener.Receive(endpoint);
IPAddress addressOfSender = endpoint.Address;
The following segment of code shows how we can open a UDP socket to broadcast a message on port 4040 to all network computers.
using System.Net;
using System.Net.Sockets;
...
int port = 4040;
//IPAddress.Broadcast can be replaced with a specific IP here if we do not want to broadcast to everyone
IPEndPoint broadcastEndpoint = new IPEndPoint(IPAddress.Broadcast, port);
UdpClient broadcaster = new UdpClient();
byte[] broadcastData = /* assign some data do broadcastData */;
broadcaster.Send(broadcastData, broadcastData.Length, broadcastEndpoint);
I have implemented the UDP broadcast mechanism that I have mentioned above into my projects. The result is that now I can put my client and server on any two computers on the network, and they will automatically start communicating with one another without having the user supply an IP address or a port. It is often suggested that if you use this method that you still provide a way to allow the user to manually supply the IP and port in the event that UDP transmission are blocked on some firewall or router. It is also likely that you will want to modify the above code to use asynchronous sends and receives by replacing listener.Receive with listener.BeginReceive and broadcaster.Send with broadcaster.BeginSend. There is, of course, a bit of other code that will be needed to implement asynchronous transmissions, but that is beyond the scope of this article. Happy broadcasting!