/// <summary>
        /// Will start specified application on loopback
        /// </summary>
        /// <param name="applicationPath">Physical path to application.</param>
        /// <param name="port">Port to listen on.</param>
        /// <param name="virtualPath">Optional. defaults to "/"</param>
        /// <param name="hostName">Optional. Is used to construct RootUrl. Defaults to "localhost"</param>
        public void StartServer(string applicationPath, int port, string virtualPath, string hostName)
        {
            // WebHost.Server will not run on any other IP
            IPAddress ipAddress = IPAddress.Loopback;

            if (!CassiniNetworkUtils.IsPortAvailable(ipAddress, port))
            {
                throw new Exception(string.Format("Port {0} is in use.", port));
            }

            applicationPath = Path.GetFullPath(applicationPath);

            virtualPath = String.Format("/{0}/", (virtualPath ?? string.Empty).Trim('/')).Replace("//", "/");
            hostName    = string.IsNullOrEmpty(hostName) ? "localhost" : hostName;

            StartServer(applicationPath, ipAddress, port, virtualPath, hostName);
        }
 /// <summary>
 /// Combine the RootUrl of the running web application with the relative url
 /// specified.
 /// </summary>
 /// <param name="relativeUrl"></param>
 /// <returns></returns>
 public string NormalizeUrl(string relativeUrl)
 {
     return(CassiniNetworkUtils.NormalizeUrl(RootUrl, relativeUrl));
 }
 /// <summary>
 /// Will start specified application as "localhost" on loopback and first available port in the range 8000-10000 with vpath "/"
 /// </summary>
 /// <param name="applicationPath">Physical path to application.</param>
 public void StartServer(string applicationPath)
 {
     StartServer(applicationPath, CassiniNetworkUtils.GetAvailablePort(8000, 10000, IPAddress.Loopback, true), "/", "localhost");
 }
        /// <summary>
        /// </summary>
        internal void Validate()
        {
            if (string.IsNullOrEmpty(ApplicationPath))
            {
                throw new CassiniException(SR.ErrApplicationPathIsNull, ErrorField.ApplicationPath);
            }

            try
            {
                ApplicationPath = Path.GetFullPath(ApplicationPath);
            }
            catch
            {
            }
            if (!Directory.Exists(ApplicationPath))
            {
                throw new CassiniException(SR.WebdevDirNotExist, ErrorField.ApplicationPath);
            }

            ApplicationPath = ApplicationPath.Trim('\"').TrimEnd('\\');


            if (!string.IsNullOrEmpty(VirtualPath))
            {
                VirtualPath = VirtualPath.Trim('\"');
                VirtualPath = VirtualPath.Trim('/');
                VirtualPath = "/" + VirtualPath;
            }
            else
            {
                VirtualPath = "/";
            }


            if (!VirtualPath.StartsWith("/"))
            {
                VirtualPath = "/" + VirtualPath;
            }


            if (AddHost && string.IsNullOrEmpty(HostName))
            {
                throw new CassiniException(SR.ErrInvalidHostname, ErrorField.HostName);
            }


            IPAddress = ParseIP(IPMode, IPv6, IPAddress).ToString();


            if (VisualStudio) // then STOP HERE.
            {
                // It is fortunate that in order to provide api parity with WebDev
                // we do not need to port scan. Visual Studio balks and refuses to
                // attach if we monkey around and open ports.
                Port     = Port == 0 ? 80 : Port;
                PortMode = PortMode.Specific;
                return;
            }


            switch (PortMode)
            {
            case PortMode.FirstAvailable:

                if (PortRangeStart < 1)
                {
                    throw new CassiniException(SR.ErrInvalidPortRangeValue, ErrorField.PortRangeStart);
                }

                if (PortRangeEnd < 1)
                {
                    throw new CassiniException(SR.ErrInvalidPortRangeValue, ErrorField.PortRangeEnd);
                }

                if (PortRangeStart > PortRangeEnd)
                {
                    throw new CassiniException(SR.ErrPortRangeEndMustBeEqualOrGreaterThanPortRangeSta,
                                               ErrorField.PortRange);
                }
                Port = CassiniNetworkUtils.GetAvailablePort(PortRangeStart, PortRangeEnd,
                                                            System.Net.IPAddress.Parse(IPAddress), true);

                if (Port == 0)
                {
                    throw new CassiniException(SR.ErrNoAvailablePortFound, ErrorField.PortRange);
                }

                break;

            case PortMode.Specific:

                if ((Port < 1) || (Port > 0xffff))
                {
                    throw new CassiniException(SR.ErrPortOutOfRange, ErrorField.Port);
                }


                // start waiting....
                //TODO: design this hack away.... why am I waiting in a validation method?
                int now = Environment.TickCount;

                // wait until either 1) the specified port is available or 2) the specified amount of time has passed
                while (Environment.TickCount < now + WaitForPort &&
                       CassiniNetworkUtils.GetAvailablePort(Port, Port, System.Net.IPAddress.Parse(IPAddress), true) !=
                       Port)
                {
                    Thread.Sleep(100);
                }

                // is the port available?
                if (CassiniNetworkUtils.GetAvailablePort(Port, Port, System.Net.IPAddress.Parse(IPAddress), true) !=
                    Port)
                {
                    throw new CassiniException(SR.ErrPortIsInUse, ErrorField.Port);
                }


                break;

            default:

                throw new CassiniException(SR.ErrInvalidPortMode, ErrorField.None);
            }
        }