Determining the region from several sources of information
Since you are not actually using a dictionary I find anonymous tuples would be much more readable here. Consider this where you don't even need a List&lt;T&gt; but just a simple array:

var weights = new (int RegionId, int Importance)[]
{
  (regionIdByIp, 5),
  (regionIdByPhone, 3),
  (regionIdByInput, 4)
};


Where you define such a tuple as (int RegionId, int Importance). With it the next query (also written with line breaks) would be much easier to understand.

int mostImportantRegionId = 
    weights
        .Where(x =&gt; x.RegionId &gt; 0)
        .GroupBy(kvp =&gt; kvp.RegionId)
        .OrderByDescending(x =&gt; x.Sum(y =&gt; y.Importance))
        .Select(x =&gt; x.RegionId)
        .FirstOrDefault();


I also think that x.Key != default(int) is a strage condition. If Key is an id then it probably should be greater than 0 so it's better to write x.RegionId &gt; 0 instead.



What you also can do better is the await part. Currently you wait for each task to finish one-by-one. Let's them work in parallel with WaitAll:

var regionIdByIpTask = GetRegionIdByKeywordAsync(regionByIpStr);
var regionIdByPhoneTask = GetRegionIdByKeywordAsync(regionByPhoneStr);
var regionIdByInputTask = GetRegionIdByKeywordAsync(regionByInputStr);

Task.WaitAll(new [] 
{
    regionIdByIpTask,
    regionIdByPhoneTask,
    regionIdByInputTask
};


Now you can build your weights:

var weights = new (int RegionId, int Importance)[]
{
  (regionIdByIpTask.Result, 5),
  (regionIdByPhoneTask.Result, 3),
  (regionIdByInputTask.Result, 4)
};