/// <summary> /// Replaces existing query parameter(s) or appends to the end. If value is a collection type (array, IEnumerable, etc.), /// multiple parameters are added, i.e. x=1&x=2. If any of the same name already exist, they are overwritten one by one /// (preserving order) and any remaining are appended to the end. If fewer values are specified than already exist, /// remaining existing values are removed. /// </summary> /// <param name="name">Name of the parameter.</param> /// <param name="value">Value of the parameter. If it's a collection, multiple parameters of the same name are added/replaced.</param> /// <param name="isEncoded">If true, assume value(s) already URL-encoded.</param> /// <param name="nullValueHandling">Describes how to handle null values.</param> public void AddOrReplace(string name, object value, bool isEncoded = false, NullValueHandling nullValueHandling = NullValueHandling.Remove) { if (!Contains(name)) { Add(name, value, isEncoded, nullValueHandling); } // This covers some complex edge cases involving multiple values of the same name. // example: x has values at positions 2 and 4 in the query string, then we set x to // an array of 4 values. We want to replace the values at positions 2 and 4 with the // first 2 values of the new array, then append the remaining 2 values to the end. //var parameters = this.Where(p => p.Name == name).ToArray(); var values = new Queue <object>(SplitCollection(value)); var old = _values.ToArray(); _values.Clear(); foreach (var item in old) { if (item.Name != name) { _values.Add(item); continue; } if (!values.Any()) { continue; // remove, effectively } var val = values.Dequeue(); if (val == null && nullValueHandling == NullValueHandling.Ignore) { _values.Add(item); } else if (val == null && nullValueHandling == NullValueHandling.Remove) { continue; } else { Add(name, val, isEncoded, nullValueHandling); } } // add the rest to the end while (values.Any()) { Add(name, values.Dequeue(), isEncoded, nullValueHandling); } }