Design Guideline Update: Uri vs. string

ChrisAn blogged about this a few weeks ago and I am happy to announce that Krzysztof Cwalina has a guideline ready for you to comment on! 

System.URI Usage

Use System.Uri to represent URI/URL data. This applies to parameter types, property types, and return value types.

public class Navigator {

public Navigator(Uri initialLocation);

public Uri CurrentLocation { get; }

public Uri NavigateTo(Uri location);

}

Note: System.Uri is a much safer and richer way of representing URIs. Extensive manipulation of URI related data using plain strings has been shown to cause many security and correctness problems. An excellent whitepaper describing the issues in more details is on it's way

Consider providing string-based overloads for most commonly used members with System.Uri parameters.

In cases where the usage pattern of taking a string from a user will be common enough, you should consider adding a convenience overload accepting a string. The string-based overload should be implemented in terms of the Uri-based overload.

public class Navigator {

    public void NavigateTo(Uri location);
    public void NavigateTo(string location) {

      NavigateTo (new Uri (location));

    }
}

Do not automatically overload all Uri-based members with a version that accepts a string.

Generally, Uri-based APIs are preferred. String-based overloads are meant to be helpers for the most common scenarios. Therefore, you should not automatically provide string-based overloads for all variants of the Uri-based members. Be selective and provide such helpers just for the most commonly used variants.

public class Navigator {

    public void NavigateTo(Uri location);

    public void NavigateTo(string location);
    public void NavigateTo(Uri location, NavigationMode mode);
}

1.1.1 URI/URL Data Implementation Rules

Call the Uri-based overloads if available.

Do not store URI/URL data in a string.

When you accept a URI/URL input as a string, you should convert the string to a System.Uri and store the instance of System.Uri.

 

In addition here are the FxCop rules we are thinking about to help enforce this guideline:

If a parameter name contains “uri” or “url” or “urn” and it’s typed as string, the parameter type should be changed to System.Uri, unless there is an overload method where the same parameter is types as Uri.

If a function name contains “uri” or “url” or “urn” and the return type is string, the return type should be changed to System.Uri.

If a property name contains “uri” or “url” or “urn” and it’s typed as string, it should be changed to System.Uri.

If a parameter is typed as System.Uri and the member has an overload where a parameter at the same position is typed as System.String, the member should not do anything with the string except to pass it to Uri.TryParse or Uri.ctor, and call the overload that takes Uri.

If there are two overloads one taking System.Uri and one taking System.String, library code should never call the string-based overload.