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.

Comments (9)

  1. Andy says:

    Any chance the "excellent" doc can be put somewhere public?

  2. Brad Abrans says:

    Sorry about the bad whitepaper link… I am working on getting it posted outside the farm now..

  3. Ken Brubaker says:

    Can you make a more generic rule for when to use composite types and simple types. This rule could apply for System.Guid and string for example.

  4. Peter says:

    I’m not so happy with the uri class because:

    I’ve noticed some strange behaviors with the uri class,

    First the constructor has strange behavior (first code snippet)

    Second the EQUALS method and the ==/!= operators behave differently ?

    string partialUrl="../../Styles/Common/Styles.css";

    string anotherUrl="../Styles/Common/Styles.css";

    Uri remoteUri = new Uri("http://pdemeyer01/nbbcms/test.html");

    Uri anUri = new Uri(remoteUri,partialUrl);

    Console.WriteLine(anUri.AbsoluteUri); //prints http://pdemeyer01/../Styles/Common/Styles.css INCORRECT

    anUri = new Uri(remoteUri,anotherUrl );

    Console.WriteLine(anUri.AbsoluteUri); //prints http://pdemeyer01/Styles/Common/Styles.css CORRECT

    Queue aQueue = new Queue();

    Uri NL =new Uri("http://localhost/NBBCMS/WebForm1.aspx?Language=NL");

    Uri UK=new Uri("http://localhost/NBBCMS/WebForm1.aspx?Language=UK");


    if (!aQueue.Contains(UK))

    Console.WriteLine("UK Not in the queue");


    Console.WriteLine("UK Already in Queue"); //prints UK Already in Queue INCORRECT

    if (UK.Equals(NL))

    Console.WriteLine("UK Equals NL"); //prints UK Equals NL INCORRECT

    if (UK!=NL)

    Console.WriteLine("UK != NL"); //prints UK != NL CORRECT

  5. Brad Abrams says:

    From the dev team: You will be glad to know that we have fixed this in the current builds…

    Now it prints:



    UK Not in the queue

    UK != NL

    Note Uri.Equals() will still ignore userinfo and fragment parts.

    For now this is to maintain compatibility with v1.0 when a uri is used to resolve a resource (not to identify it)

    Ignoring a query part was just a plain bug.

  6. Doug McClean says:

    This is off topic, but does anyone have any idea why System.Uri inherits System.MarshalByRefObject? Seems like a very odd choice for such an obviously serializable type, that is marked as serializable, and that appears to be immutable (doesn’t have any set accessors or methods that seem like they should have side effects). Can anyone weigh in on this? Under what circumstances would a serializable type be marshaled by reference, anyway?