I assume all keys int your vals dictionary don't contain { and } character.
To deal with this case, dont use . in the {{.+}} match. . accept any single character except \n (in case your regex code).
Replace . with [^\{\}], which match any character except { and }.
And you should escape { and } in your regex function, because they have special meaning in Regex. Some cases Regex treat them as literal charater, but not in other cases.
To have m.Groups[1], you have to wrap [^\{\}]+ inside ( and ).
Finally, to avoid exception, check if your dictionary keys contain a string found by above Regex function before replace it.
Your code can be like bellow:
string s = "{{hello {{User.Name}}, thanks for your buying in {{Shop}}. This {{Tag}} is not found";
IDictionary<string, string> vals = new Dictionary<string, string>()
{
{"User.Name","Jim" },
{"Shop","NewStore" }
};
string result = Regex.Replace(s, @"\{\{([^\{\}]+)\}\}",
m => vals.ContainsKey(m.Groups[1].Value) ? vals[m.Groups[1].Value] : m.Value);
Console.WriteLine(result);
Output:
{{hello Jim, thanks for your buying in NewStore. This {{Tag}} is not found