URI Parameters Not Strings

ID

csharp.uri_parameters_not_strings

Severity

low

Remediation Complexity

medium

Remediation Risk

low

Remediation Effort

medium

Resource

Code Smell

Language

CSharp

Tags

api-design, code_smell, uri

Description

Reports parameters whose name ends with Url or Uri and whose declared type is string. The .NET design guidelines recommend exposing URLs through the strongly-typed System.Uri so the parse step lives at the API boundary and malformed input is rejected before it reaches the business logic. MVC actions and Razor Pages handlers are exempt: their parameters are model-bound from route/query text, so the string signature is the framework’s contract. Non-public methods are exempt too, including a member that only implements a same-file interface method whose own declared accessibility (e.g. internal, valid on an interface member since C# 8) is not externally visible — an explicit interface implementation carries no access modifier of its own, so its reachability is the interface member’s to declare.

Rationale

A string parameter labelled Url documents intent but does not enforce it: the function still has to call new Uri(…​) and decide what to do on failure. A Uri parameter shifts that decision to the caller and guarantees the method body sees a parsed value. Side benefit: overload resolution can distinguish URL-bearing methods from arbitrary-string-bearing methods.

public interface IClient
{
    internal string SendGet(string query);
}

public class Client : IClient
{
    public void Fetch(string targetUrl) { }            // FLAW
    public void Post(string callbackUri, byte[] payload) { } // FLAW

    public void Get(Uri targetUrl) { }                  // OK
    public void Send(string body) { }                   // OK, not Url/Uri suffix

    string IClient.SendGet(string subUrl)               // OK, IClient.SendGet is internal
    {
        return subUrl;
    }
}

Remediation

Change the parameter type to System.Uri. If the caller has only a string, let them call new Uri(…​) at the call site, where the parse failure is local.