---
title: "Parse a URL in C#"
url: https://recursiveai.org/onecontact/cookbook/parse-url/
description: "Parse and normalize a URL in C# with OneContact. Read the host, path and query, with a downloadable .NET example and real output."
version: "1.0.0"
---

# Parse a URL in C#

**OneContact** is a free, open-source contact data library for .NET from Recursive AI. MIT or Apache-2.0, no native dependencies, no network access.

[NuGet](https://www.nuget.org/packages/RecursiveAI.OneContact) · [GitHub](https://github.com/recursive-ai-oss/onecontact-csharp) · [Docs](https://recursiveai.org/onecontact/docs/) · [Download example (.zip)](https://recursiveai.org/onecontact/cookbook/parse-url/parse-url.zip)

Turn a URL into a normalized value and read its host, path and query. Normalization removes fragments and recognized tracking parameters. Beyond the URL components available through .NET’s `System.Uri`, OneContact provides contact-oriented canonicalization, a versioned comparison key and Public Suffix List domain boundaries.

```shell
dotnet add package RecursiveAI.OneContact
```

Requires [.NET 10](https://dotnet.microsoft.com/download/dotnet/10.0) (net10.0); .NET 9 and earlier aren’t supported.

```csharp
using RecursiveAI.OneContact;

var url = WebAddress.Parse(
    "https://EXAMPLE.com/shop#top");
Console.WriteLine(url.Canonical);
Console.WriteLine(url.Host);
```

```text
https://example.com/shop
example.com
```

Unzip [the example](https://recursiveai.org/onecontact/cookbook/parse-url/parse-url.zip), then `dotnet run`.

## Full program

The download includes a fuller example with invented input embedded in `Program.cs`:

```csharp
using RecursiveAI.OneContact;

var url = WebAddress.Parse(
    "HTTPS://Example.com:443/shop?id=7&utm_source=news#top");
Console.WriteLine(url.Canonical);
Console.WriteLine($"Host: {url.Host}");
Console.WriteLine($"Path: {url.Path}");
Console.WriteLine($"Query: {url.Query}");
```

`dotnet run` prints:

```text
https://example.com/shop?id=7
Host: example.com
Path: /shop
Query: id=7
```

Rejected URL text makes `TryParse` return false; `Parse` instead throws `ContactParseException`.

## Variations

Accept a URL without an explicit scheme:

```csharp
using RecursiveAI.OneContact;

if (WebAddress.TryParse("example.com:8080/shop", out var url))
    Console.WriteLine(url.Canonical);
else
    Console.WriteLine("Invalid URL");
```

```text
https://example.com:8080/shop
```

## Related recipes

- [Extract contact information from HTML in C#](https://recursiveai.org/onecontact/cookbook/extract-contacts-from-html/)
- [Get the domain from a URL in C#](https://recursiveai.org/onecontact/cookbook/get-domain-from-url/)
- [Parse a postal address in C#](https://recursiveai.org/onecontact/cookbook/parse-postal-address/)
- [Format a postal address by country in C#](https://recursiveai.org/onecontact/cookbook/format-postal-address/)

## The short answer

Call `WebAddress.Parse` and read `Host`, `Path` and `Query` from the resulting value. Use `Canonical` when you want OneContact’s normalized contact URL. The full program prints `https://example.com/shop?id=7`: the hostname is lowercased, the default HTTPS port disappears, and the tracking parameter and fragment are removed.

This is useful for cleaning website fields in a contact database. It is not a lossless round trip of the original URL. Keep the original input separately when your application needs to reproduce exactly what someone entered. The [web address documentation](https://recursiveai.org/onecontact/docs/web/) defines the normalization and comparison rules.

## How do I parse a URL in C#?

The full program supplies one complete URL and prints the parsed components. `Host` excludes the scheme and path. `Path` is the path portion, and `Query` is the query content without its leading question mark. `Port` is nullable, so a URL with no retained explicit port does not need a made-up numeric default in your data model.

For form input or imported rows, use `TryParse` rather than treating every rejection as an exception. The variation shows the boolean overload. Missing schemes are assumed to be HTTPS; a host followed by a port remains a host-and-port input. This is convenient for website fields where people commonly enter a bare hostname.

OneContact follows the WHATWG URL parsing model, including internationalized domain processing and IP hosts. Parsing accepts non-website schemes too. Check `IsWebsite` if your field is meant to hold only HTTP and HTTPS website addresses; a syntactically accepted URL is not automatically suitable for a clickable website field.

## How do I get query string parameters from a URL in C#?

`Query` gives you the retained query string, not a dictionary of individually decoded parameters. In this example it is exactly `id=7`. Decide whether you need the contact-normalized query or the original query before doing further processing: OneContact intentionally removes its documented list of tracking parameter names, including the `utm_source` used above.

Use .NET’s `HttpUtility.ParseQueryString` to read the retained query, including repeated values:

```csharp
using RecursiveAI.OneContact;
using System.Web;

var url = WebAddress.Parse(
    "https://example.com/shop?id=7&tag=red&tag=blue");
var query = HttpUtility.ParseQueryString(url.Query ?? "");
Console.WriteLine(query["id"]);
Console.WriteLine(string.Join(", ", query.GetValues("tag") ?? []));
```

```text
7
red, blue
```

Do not split a query and assume every name occurs only once. Applications can give repeated parameters their own meaning, and decoding rules belong to the application consuming the query. OneContact’s task here is URL parsing and canonicalization, not interpreting another website’s search or checkout API. Credentials, path case and query parameters outside the documented removal list remain in the canonical form.

## How do I normalize a URL in C#?

Use `Canonical` for the cleaned URL and `Key` for OneContact’s more aggressive comparison form. Those outputs serve different purposes. The key can collapse subdomains to a registrable domain, lowercase path letters and normalize default documents; the canonical URL preserves more of the address’s actual structure.

For a website field that users will navigate to, store the canonical URL rather than substituting its key. Keep a versioned comparison key separately if you need contact matching. A parser does not fetch the URL, resolve its hostname or establish that a destination is reachable. A successful parse answers a syntax-and-normalization question, not a network availability question.
