Sorry, that I don't answer with an existing API from Windows that uses the UPNP service, but it migh help you
You could also use a STUN-server on the internet, there are many open ones, every VOIP provider has one.
http://en.wikipedia.org/wiki/STUN
http://tools.ietf.org/html/rfc3489
e.g. open an UDP-socket, connect to stun.gmx.net on port 3478 and send a paket like this:
using System;
using System.Net;
using System.Collections.Generic;
using System.Text;
using System.Security.Cryptography;
namespace xxx
{
class STUNPacket
{
static RNGCryptoServiceProvider m_rand=new RNGCryptoServiceProvider();
private byte[] m_requestid=new byte[16];
public STUNPacket()
{
m_rand.GetBytes(m_requestid);
}
public byte[] CreateRequest()
{
byte[] packet=new byte[0x1c] {
//Header:
0x00,0x01, //Art des STUN-Pakets: 0x0001=Binding Request
0x00,0x08, //Länge des Pakets ohne Header
0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, //Transkations-ID
//Message-Attribute:
0x00,0x03, //Typ: Change-Request
0x00,0x04, //Länge: 4 Bytes
0x00,0x00,0x00,0x00 //Weder IP, noch Port ändern
};
for(int i=0;i<16;i++)
packet[i+4]=m_requestid[i];
return packet;
}
public IPEndPoint ParseResponse(byte[] paket)
{
if (paket.Length<20)
throw new Exception("STUN-Response zu kurz, um einen Header zu haben");
if (paket[0]!=1||paket[1]!=1)
throw new Exception("STUN-Reposne hat falschen Typ, muss Binding-Response sein");
for (int i=0;i<16;i++)
if (paket[i+4]!=m_requestid[i])
throw new Exception("STUN-Antwort hat falsche Transkations-ID");
int size=paket[2]*256+paket[3];
int pos=20;
for(;;)
{
if (size<4)
throw new Exception("Verbleibende Nachricht zu kurz für weiteren Attributheader, "+
"Mapped-Adress-Attribut nicht gefunden");
int attrsize=paket[pos+2]*256+paket[pos+3];
if (pos+4+attrsize>paket.Length)
throw new Exception("Attributheader hat Länge, die nicht mehr ins Paket passt");
//Wenn kein Mapped-Adress-Attribut, dann überspringen
if (paket[pos]!=0||paket[pos+1]!=1)
{
pos+=attrsize;
continue;
}
if (attrsize<8)
throw new Exception("Mapped-Adress-Attribut ist zu kurz");
if (paket[pos+5]!=1)
throw new Exception("Adreßfamilie von Mapped-Adress ist nicht IPV4");
int port=paket[pos+6]*256+paket[pos+7];
IPAddress adress=new IPAddress(new byte[4] { paket[pos+8],paket[pos+9],paket[pos+10],paket[pos+11] });
return new IPEndPoint(adress,port);
}
}
}
}
The IP-address returned by ParseResponse should be your ip adress like the outside world sees it.
Note that will not be able to get your external ip without either the help of an internet server or directly via upnp from your server