Network programming in .NET

.NET provides a layered, extensible, and managed implementation of Internet services that can be quickly and easily integrated into your apps. Your network apps can build on pluggable protocols to automatically take advantage of various Internet protocols, or they can use a managed implementation of cross-platform socket interfaces to work with the network on the socket level.

Internet apps

Internet apps can be classified broadly into two kinds: client apps that request information and server apps that respond to information requests from clients. The classic Internet client-server app is the World Wide Web, where people use browsers to access documents and other data stored on web servers worldwide.

Apps are not limited to just one of these roles; for instance, the familiar middle-tier app server responds to requests from clients by requesting data from another server, in which case it is acting as both a server and a client.

The client app requests by identifying the requested Internet resource and the communication protocol to use for the request and response. If necessary, the client also provides any additional data required to complete the request, such as proxy location or authentication information (user name, password, and so on). Once the request is formed, the request can be sent to the server.

Identifying resources

.NET uses a uniform resource identifier (URI) to identify the requested Internet resource and communication protocol. The URI consists of at least three, and possibly four, fragments: the scheme identifier, which identifies the communications protocol for the request and response; the server identifier, which consists of either a domain name system (DNS) hostname or a TCP address that uniquely identifies the server on the Internet; the path identifier, which locates the requested information on the server; and an optional query string, which passes information from the client to the server.

The System.Uri type is used as a representation of a uniform resource identifier (URI) and easy access to the parts of the URI. To create a Uri instance you can pass it a string:

const string uriString =

Uri canonicalUri = new(uriString);
// Sample output:
//     /en-us/dotnet/path?key=value
//     #bookmark

The Uri class automatically performs validation and canonicalization per RCF 3986. These validation and canonicalization rules are used to ensure that a URI is well-formed and that the URI is in a canonical form. However, this modifies some URIs in a way that might break their end-users.

To bypass these validation rules, set UriCreationOptions.DangerousDisablePathAndQueryCanonicalization to true, which means no validation and no transformation of the input will take place past the authority. As a side effect, Uri instances created with this option don't support Uri.Fragments and this property will always be empty. Moreover, Uri.GetComponents may not be used for UriComponents.Path or UriComponents.Query and will throw InvalidOperationException.

const string uriString =

UriCreationOptions creationOptions = new()
    DangerousDisablePathAndQueryCanonicalization = true

Uri uri = new(uriString, creationOptions);
// Sample output:
//     https://localhost:5001/path%4A?query%4A#/foo
//     /path%4A
//     ?query%4A#/foo
//     /path%4A?query%4A#/foo

Uri canonicalUri = new(uriString);
// Sample output:
//     /pathJ?queryJ
//     #/foo


Disabling canonicalization also means that reserved characters will not be escaped (for example, space characters will not be changed to %20), which may corrupt the HTTP request and makes the application subject to request smuggling. Only set this option if you have ensured that the URI string is already sanitized.

See also