Skip to content

Rule URL Resolving

For cases where additional logic is required to determine the URL for a rule, the Cake.Issue addin provides the BaseRuleDescription and BaseRuleUrlResolver classes for simplifying implementation of providing URLs linking to site providing information about issues.

Implementing RuleUrlResolver

In the issue provider a concrete class inheriting from BaseRuleDescription should be implemented containing all properties required to determine the URL to a rule.

The following class adds two properties Category and RuleId to the description, to handle rules following a pattern like ABC123, where ABC is the Category, and 123 is the RuleId:

/// <summary>
/// Class describing rules for my issue provider.
/// </summary>
public class MyRuleDescription : BaseRuleDescription
{
    /// <summary>
    /// Gets or sets the category of the rule.
    /// </summary>
    public string Category { get; set; }

    /// <summary>
    /// Gets or sets the identifier of the rule.
    /// </summary>
    public int RuleId { get; set; }
}

A class inheriting from BaseRuleUrlResolver needs to be implemented containing an implementation of TryGetRuleDescription for parsing rule urls to the concrete BaseRuleDescription class. Additionally different resolvers need to be registered which return the actual URL based on the rule description.

/// <summary>
/// Class for retrieving an URL linking to a site describing a rule.
/// </summary>
internal class MyRuleUrlResolver : BaseRuleUrlResolver<MyRuleDescription>
{
    /// <inheritdoc/>
    protected override bool TryGetRuleDescription(
        string rule,
        MyRuleDescription ruleDescription)
    {
        // Take the first 3 characters as category 
        ruleDescription.Category = rule[..3];
        // Take everything afterwards as the ID
        ruleDescription.RuleId = int.Parse(rule.Substring(3));

        return true;
    }

    /// <summary>
    /// Initializes a new instance of the
    /// <see cref="MyRuleUrlResolver"/> class.
    /// </summary>
    private MyRuleUrlResolver()
    {
        // Add resolver for different issue categories.
        this.AddUrlResolver(x =>
            x.Category
                .Equals(
                    "FOO",
                    StringComparison.InvariantCultureIgnoreCase) ?
                new Uri("https://www.google.com/search?q=%22" + x.Rule) :
                null);
        this.AddUrlResolver(x =>
            x.Category
                .Equals(
                    "BAR",
                    StringComparison.InvariantCultureIgnoreCase) ?
                new Uri("https://www.bing.com/search?q=%22" + x.Rule) :
                null);
    }
}
/// <summary>
/// Class for retrieving an URL linking to a site describing a rule.
/// </summary>
internal class MyRuleUrlResolver : BaseRuleUrlResolver<MyRuleDescription>
{
    /// <inheritdoc/>
    protected override bool TryGetRuleDescription(
        string rule,
        MyRuleDescription ruleDescription)
    {
        // Take the first 3 characters as category 
        ruleDescription.Category = rule[..3];
        // Take everything afterwards as the ID
        ruleDescription.RuleId = int.Parse(rule.Substring(3));

        return true;
    }

    /// <summary>
    /// Initializes a new instance of the
    /// <see cref="MyRuleUrlResolver"/> class.
    /// </summary>
    private MyRuleUrlResolver()
    {
        // Add resolver for different issue categories.
        this.AddUrlResolver(x =>
            x.Category
                .Equals(
                    "FOO",
                    StringComparison.InvariantCultureIgnoreCase) ?
                new Uri("https://www.google.com/search?q=%22" + x.Rule) :
                null);
        this.AddUrlResolver(x =>
            x.Category
                .Equals(
                    "BAR",
                    StringComparison.InvariantCultureIgnoreCase) ?
                new Uri("https://www.bing.com/search?q=%22" + x.Rule) :
                null);
    }
}

To use the URL resolver the ResolveRuleUrl method can be called from the issue provider:

var resolver = new MyRuleUrlResolver();
var url = resolver.ResolveRuleUrl(rule)

Support custom URL resolvers

The AddUrlResolver method can also be called from a Cake alias to allow users of the addin to register custom resolvers. For this the URL resolver class needs to be implemented as a singleton:

/// <summary>
/// Class for retrieving an URL linking to a site describing a rule.
/// </summary>
internal class MyRuleUrlResolver : BaseRuleUrlResolver<MyRuleDescription>
{
    private static readonly Lazy<MyRuleUrlResolver> InstanceValue =
        new Lazy<MyRuleUrlResolver>(() => new MyRuleUrlResolver());

    /// <summary>
    /// Gets the instance of the rule resolver.
    /// </summary>
    public static MyRuleUrlResolver Instance => InstanceValue.Value;

    /// <inheritdoc/>
    protected override bool TryGetRuleDescription(
        string rule,
        MyRuleDescription ruleDescription)
    {
        // Take the first 3 characters as category 
        ruleDescription.Category = rule[..3];
        // Take everything afterwards as the ID
        ruleDescription.RuleId = int.Parse(rule.Substring(3));

        return true;
    }

    /// <summary>
    /// Initializes a new instance of the
    /// <see cref="MyRuleUrlResolver"/> class.
    /// </summary>
    private MyRuleUrlResolver()
    {
        // Add resolver for different issue categories.
        this.AddUrlResolver(x =>
            x.Category
                .Equals(
                    "FOO",
                    StringComparison.InvariantCultureIgnoreCase) ?
                new Uri("https://www.google.com/search?q=%22" + x.Rule) :
                null);
        this.AddUrlResolver(x =>
            x.Category
                .Equals(
                    "BAR",
                    StringComparison.InvariantCultureIgnoreCase) ?
                new Uri("https://www.bing.com/search?q=%22" + x.Rule) :
                null);
    }
}
/// <summary>
/// Class for retrieving an URL linking to a site describing a rule.
/// </summary>
internal class MyRuleUrlResolver : BaseRuleUrlResolver<MyRuleDescription>
{
    private static readonly Lazy<MyRuleUrlResolver> InstanceValue =
        new Lazy<MyRuleUrlResolver>(() => new MyRuleUrlResolver());

    /// <summary>
    /// Gets the instance of the rule resolver.
    /// </summary>
    public static MyRuleUrlResolver Instance => InstanceValue.Value;

    /// <inheritdoc/>
    protected override bool TryGetRuleDescription(
        string rule,
        MyRuleDescription ruleDescription)
    {
        // Take the first 3 characters as category 
        ruleDescription.Category = rule[..3];
        // Take everything afterwards as the ID
        ruleDescription.RuleId = int.Parse(rule.Substring(3));

        return true;
    }

    /// <summary>
    /// Initializes a new instance of the
    /// <see cref="MyRuleUrlResolver"/> class.
    /// </summary>
    private MyRuleUrlResolver()
    {
        // Add resolver for different issue categories.
        this.AddUrlResolver(x =>
            x.Category
                .Equals(
                    "FOO",
                    StringComparison.InvariantCultureIgnoreCase) ?
                new Uri("https://www.google.com/search?q=%22" + x.Rule) :
                null);
        this.AddUrlResolver(x =>
            x.Category
                .Equals(
                    "BAR",
                    StringComparison.InvariantCultureIgnoreCase) ?
                new Uri("https://www.bing.com/search?q=%22" + x.Rule) :
                null);
    }
}
/// <summary>
/// Class for retrieving an URL linking to a site describing a rule.
/// </summary>
internal class MyRuleUrlResolver : BaseRuleUrlResolver<MyRuleDescription>
{
    private static readonly Lazy<MyRuleUrlResolver> InstanceValue =
        new Lazy<MyRuleUrlResolver>(() => new MyRuleUrlResolver());

    /// <summary>
    /// Gets the instance of the rule resolver.
    /// </summary>
    public static MyRuleUrlResolver Instance => InstanceValue.Value;

    /// <inheritdoc/>
    protected override bool TryGetRuleDescription(
        string rule,
        MyRuleDescription ruleDescription)
    {
        // Take the first 3 characters as category 
        ruleDescription.Category = rule[..3];
        // Take everything afterwards as the ID
        ruleDescription.RuleId = int.Parse(rule.Substring(3));

        return true;
    }

    /// <summary>
    /// Initializes a new instance of the
    /// <see cref="MyRuleUrlResolver"/> class.
    /// </summary>
    private MyRuleUrlResolver()
    {
        // Add resolver for different issue categories.
        this.AddUrlResolver(x =>
            x.Category
                .Equals(
                    "FOO",
                    StringComparison.InvariantCultureIgnoreCase) ?
                new Uri("https://www.google.com/search?q=%22" + x.Rule) :
                null);
        this.AddUrlResolver(x =>
            x.Category
                .Equals(
                    "BAR",
                    StringComparison.InvariantCultureIgnoreCase) ?
                new Uri("https://www.bing.com/search?q=%22" + x.Rule) :
                null);
    }
}