How to make Service Fabric Reliable collections case-insensitive?

485 Views Asked by At

I have a Stateful Service Fabric service and create, update or read data using IReliableDictionary created with the following code:

var dictionary = await StateManager.GetOrAddAsync<IReliableDictionary<string, Entry>>(ReliableDictionaryName);

// Read
using (ITransaction tx = StateManager.CreateTransaction())
{
    ConditionalValue<Entry> result = await dictionary.TryGetValueAsync(tx, name);
    return result.HasValue ? result.Value : null;
}

// Create or update
using (ITransaction tx = StateManager.CreateTransaction())
{
    await dictionary.AddOrUpdateAsync(tx, entry.Name, entry, (key, prev) => entry);
    await tx.CommitAsync();
}    

It works, but it is case-sensitive. Is there any way to make Reliable collection store and get data in a case-insensitive way, except for applying .ToLower() to the keys, which is kind of hacky?

1

There are 1 best solutions below

0
On

This behavior you see is mostly a property of how strings are compared by default in C#. Reliable dictionaries use a key's implementation of IEquatable and IComparable to perform lookups. If the default behavior of string doesn't work for you, you can implement a type that performs string comparisons the way you want. Then, use the new type as the key for your reliable dictionary. You could implement implicit operators to convert between raw strings and the custom type to make usage painless. Here's an example:

using System.Runtime.Serialization;

    [DataContract]
    public class CaseInsensitiveString : IEquatable<CaseInsensitiveString>,
                                         IComparable<CaseInsensitiveString>
    {
        #region Constructors

        public CaseInsensitiveString(string value)
        {
            this.Value = value;
        }

        #endregion

        #region Instance Properties

        [DataMember]
        public string Value
        {
            get;
            set;
        }

        #endregion

        #region Instance Methods

        public override bool Equals(object obj)
        {
            if (ReferenceEquals(null,
                                obj))
            {
                return false;
            }

            if (ReferenceEquals(this,
                                obj))
            {
                return true;
            }

            if (obj.GetType() != this.GetType())
            {
                return false;
            }

            return this.Equals((CaseInsensitiveString)obj);
        }

        public override int GetHashCode()
        {
            return this.Value != null
                       ? this.Value.GetHashCode()
                       : 0;
        }

        public int CompareTo(CaseInsensitiveString other)
        {
            return string.Compare(this.Value,
                                  other?.Value,
                                  StringComparison.OrdinalIgnoreCase);
        }

        public bool Equals(CaseInsensitiveString other)
        {
            if (ReferenceEquals(null,
                                other))
            {
                return false;
            }

            if (ReferenceEquals(this,
                                other))
            {
                return true;
            }

            return string.Equals(this.Value,
                                 other.Value,
                                 StringComparison.OrdinalIgnoreCase);
        }

        #endregion

        #region Class Methods

        public static bool operator ==(CaseInsensitiveString left,
                                       CaseInsensitiveString right)
        {
            return Equals(left,
                          right);
        }

        public static implicit operator CaseInsensitiveString(string value)
        {
            return new CaseInsensitiveString(value);
        }

        public static implicit operator string(CaseInsensitiveString caseInsensitiveString)
        {
            return caseInsensitiveString.Value;
        }

        public static bool operator !=(CaseInsensitiveString left,
                                       CaseInsensitiveString right)
        {
            return !Equals(left,
                           right);
        }

        #endregion
    }