committed by
GitHub
36 changed files with 2081 additions and 715 deletions
File diff suppressed because it is too large
@ -0,0 +1,138 @@ |
|||||
|
using DotNetCore.CAP.Internal; |
||||
|
using DotNetCore.CAP.Transport; |
||||
|
using System; |
||||
|
using System.Collections.Concurrent; |
||||
|
using System.Collections.Generic; |
||||
|
using System.Text; |
||||
|
using System.Threading; |
||||
|
using System.Reflection; |
||||
|
using Volo.Abp.DependencyInjection; |
||||
|
using Volo.Abp.EventBus; |
||||
|
using Volo.Abp.EventBus.Distributed; |
||||
|
using Volo.Abp.Threading; |
||||
|
using System.Linq; |
||||
|
using DotNetCore.CAP; |
||||
|
using Microsoft.Extensions.Options; |
||||
|
|
||||
|
namespace LINGYUN.Abp.EventBus.CAP |
||||
|
{ |
||||
|
internal class CustomDistributedEventSubscriber : ICustomDistributedEventSubscriber, ISingletonDependency |
||||
|
{ |
||||
|
protected CapOptions CapOptions { get; } |
||||
|
protected IConsumerClientFactory ConsumerClientFactory { get; } |
||||
|
|
||||
|
protected ConcurrentDictionary<Type, List<IEventHandlerFactory>> HandlerFactories { get; } |
||||
|
protected ConcurrentDictionary<string, CancellationTokenSource> EventStopingTokens { get; } |
||||
|
public CustomDistributedEventSubscriber( |
||||
|
IOptions<CapOptions> options, |
||||
|
IConsumerClientFactory consumerClientFactory) |
||||
|
{ |
||||
|
CapOptions = options.Value; |
||||
|
ConsumerClientFactory = consumerClientFactory; |
||||
|
|
||||
|
HandlerFactories = new ConcurrentDictionary<Type, List<IEventHandlerFactory>>(); |
||||
|
EventStopingTokens = new ConcurrentDictionary<string, CancellationTokenSource>(); |
||||
|
} |
||||
|
|
||||
|
public void Subscribe(Type eventType, IEventHandlerFactory factory) |
||||
|
{ |
||||
|
GetOrCreateHandlerFactories(eventType) |
||||
|
.Locking(factories => |
||||
|
{ |
||||
|
if (!factories.Contains(factory)) |
||||
|
{ |
||||
|
factories.Add(factory); |
||||
|
// TODO 客户端订阅
|
||||
|
} |
||||
|
}); |
||||
|
} |
||||
|
|
||||
|
public void UnSubscribe(Type eventType, IEventHandlerFactory factory) |
||||
|
{ |
||||
|
GetOrCreateHandlerFactories(eventType) |
||||
|
.Locking(factories => |
||||
|
{ |
||||
|
if (factories.Contains(factory)) |
||||
|
{ |
||||
|
factories.Remove(factory); |
||||
|
// TODO 客户端退订
|
||||
|
} |
||||
|
}); |
||||
|
} |
||||
|
|
||||
|
private List<IEventHandlerFactory> GetOrCreateHandlerFactories(Type eventType) |
||||
|
{ |
||||
|
return HandlerFactories.GetOrAdd( |
||||
|
eventType, |
||||
|
type => |
||||
|
{ |
||||
|
var eventName = EventNameAttribute.GetNameOrDefault(type); |
||||
|
EventStopingTokens[eventName] = new CancellationTokenSource(); |
||||
|
return new List<IEventHandlerFactory>(); |
||||
|
} |
||||
|
); |
||||
|
} |
||||
|
|
||||
|
private IEnumerable<ConsumerExecutorDescriptor> GetHandlerDescription(Type eventType, Type typeInfo) |
||||
|
{ |
||||
|
var serviceTypeInfo = typeof(IDistributedEventHandler<>) |
||||
|
.MakeGenericType(eventType); |
||||
|
var method = typeInfo |
||||
|
.GetMethod( |
||||
|
nameof(IDistributedEventHandler<object>.HandleEventAsync), |
||||
|
new[] { eventType } |
||||
|
); |
||||
|
var eventName = EventNameAttribute.GetNameOrDefault(eventType); |
||||
|
var topicAttr = method.GetCustomAttributes<TopicAttribute>(true); |
||||
|
var topicAttributes = topicAttr.ToList(); |
||||
|
|
||||
|
topicAttributes.Add(new CapSubscribeAttribute(eventName)); |
||||
|
|
||||
|
foreach (var attr in topicAttributes) |
||||
|
{ |
||||
|
SetSubscribeAttribute(attr); |
||||
|
|
||||
|
var parameters = method.GetParameters() |
||||
|
.Select(parameter => new ParameterDescriptor |
||||
|
{ |
||||
|
Name = parameter.Name, |
||||
|
ParameterType = parameter.ParameterType, |
||||
|
IsFromCap = parameter.GetCustomAttributes(typeof(FromCapAttribute)).Any() |
||||
|
}).ToList(); |
||||
|
|
||||
|
yield return InitDescriptor(attr, method, typeInfo.GetTypeInfo(), serviceTypeInfo.GetTypeInfo(), parameters); |
||||
|
} |
||||
|
} |
||||
|
|
||||
|
private void SetSubscribeAttribute(TopicAttribute attribute) |
||||
|
{ |
||||
|
if (attribute.Group == null) |
||||
|
{ |
||||
|
attribute.Group = CapOptions.DefaultGroup + "." + CapOptions.Version; |
||||
|
} |
||||
|
else |
||||
|
{ |
||||
|
attribute.Group = attribute.Group + "." + CapOptions.Version; |
||||
|
} |
||||
|
} |
||||
|
|
||||
|
private ConsumerExecutorDescriptor InitDescriptor( |
||||
|
TopicAttribute attr, |
||||
|
MethodInfo methodInfo, |
||||
|
TypeInfo implType, |
||||
|
TypeInfo serviceTypeInfo, |
||||
|
IList<ParameterDescriptor> parameters) |
||||
|
{ |
||||
|
var descriptor = new ConsumerExecutorDescriptor |
||||
|
{ |
||||
|
Attribute = attr, |
||||
|
MethodInfo = methodInfo, |
||||
|
ImplTypeInfo = implType, |
||||
|
ServiceTypeInfo = serviceTypeInfo, |
||||
|
Parameters = parameters |
||||
|
}; |
||||
|
|
||||
|
return descriptor; |
||||
|
} |
||||
|
} |
||||
|
} |
||||
@ -0,0 +1,24 @@ |
|||||
|
using System; |
||||
|
using Volo.Abp.EventBus; |
||||
|
|
||||
|
namespace LINGYUN.Abp.EventBus.CAP |
||||
|
{ |
||||
|
/// <summary>
|
||||
|
/// 自定义事件订阅者
|
||||
|
/// </summary>
|
||||
|
public interface ICustomDistributedEventSubscriber |
||||
|
{ |
||||
|
/// <summary>
|
||||
|
/// 订阅事件
|
||||
|
/// </summary>
|
||||
|
/// <param name="eventType"></param>
|
||||
|
/// <param name="factory"></param>
|
||||
|
void Subscribe(Type eventType, IEventHandlerFactory factory); |
||||
|
/// <summary>
|
||||
|
/// 取消订阅
|
||||
|
/// </summary>
|
||||
|
/// <param name="eventType"></param>
|
||||
|
/// <param name="factory"></param>
|
||||
|
void UnSubscribe(Type eventType, IEventHandlerFactory factory); |
||||
|
} |
||||
|
} |
||||
@ -0,0 +1,37 @@ |
|||||
|
<Project Sdk="Microsoft.NET.Sdk"> |
||||
|
|
||||
|
<PropertyGroup> |
||||
|
<TargetFramework>netstandard2.0</TargetFramework> |
||||
|
<RootNamespace /> |
||||
|
<PackageRequireLicenseAcceptance>false</PackageRequireLicenseAcceptance> |
||||
|
<Version>3.0.0</Version> |
||||
|
<Description>腾讯位置服务</Description> |
||||
|
<GeneratePackageOnBuild>true</GeneratePackageOnBuild> |
||||
|
</PropertyGroup> |
||||
|
|
||||
|
<PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Debug|AnyCPU'"> |
||||
|
<OutputPath>D:\LocalNuget</OutputPath> |
||||
|
</PropertyGroup> |
||||
|
|
||||
|
<ItemGroup> |
||||
|
<None Remove="LINGYUN\Abp\Location\Tencent\Localization\Resources\en.json" /> |
||||
|
<None Remove="LINGYUN\Abp\Location\Tencent\Localization\Resources\zh-Hans.json" /> |
||||
|
</ItemGroup> |
||||
|
|
||||
|
<ItemGroup> |
||||
|
<EmbeddedResource Include="LINGYUN\Abp\Location\Tencent\Localization\Resources\en.json" /> |
||||
|
<EmbeddedResource Include="LINGYUN\Abp\Location\Tencent\Localization\Resources\zh-Hans.json" /> |
||||
|
</ItemGroup> |
||||
|
|
||||
|
<ItemGroup> |
||||
|
<PackageReference Include="Microsoft.Extensions.Http.Polly" Version="3.1.2" /> |
||||
|
<PackageReference Include="Volo.Abp.Localization" Version="3.0.0" /> |
||||
|
<PackageReference Include="Volo.Abp.Json" Version="3.0.0" /> |
||||
|
<PackageReference Include="Volo.Abp.Threading" Version="3.0.0" /> |
||||
|
</ItemGroup> |
||||
|
|
||||
|
<ItemGroup> |
||||
|
<ProjectReference Include="..\LINGYUN.Abp.Location\LINGYUN.Abp.Location.csproj" /> |
||||
|
</ItemGroup> |
||||
|
|
||||
|
</Project> |
||||
@ -0,0 +1,36 @@ |
|||||
|
using LINYUN.Abp.Location.Tencent.Localization; |
||||
|
using Microsoft.Extensions.DependencyInjection; |
||||
|
using Polly; |
||||
|
using System; |
||||
|
using Volo.Abp.Localization; |
||||
|
using Volo.Abp.Modularity; |
||||
|
using Volo.Abp.VirtualFileSystem; |
||||
|
|
||||
|
namespace LINGYUN.Abp.Location.Tencent |
||||
|
{ |
||||
|
[DependsOn(typeof(AbpLocationModule))] |
||||
|
public class AbpTencentLocationModule : AbpModule |
||||
|
{ |
||||
|
public override void ConfigureServices(ServiceConfigurationContext context) |
||||
|
{ |
||||
|
var configuration = context.Services.GetConfiguration(); |
||||
|
Configure<TencentLocationOptions>(configuration.GetSection("Location:Tencent")); |
||||
|
|
||||
|
context.Services.AddHttpClient(TencentLocationHttpConsts.HttpClientName) |
||||
|
.AddTransientHttpErrorPolicy(builder => |
||||
|
builder.WaitAndRetryAsync(3, i => TimeSpan.FromSeconds(Math.Pow(2, i)))); |
||||
|
|
||||
|
Configure<AbpVirtualFileSystemOptions>(options => |
||||
|
{ |
||||
|
options.FileSets.AddEmbedded<AbpTencentLocationModule>(); |
||||
|
}); |
||||
|
|
||||
|
Configure<AbpLocalizationOptions>(options => |
||||
|
{ |
||||
|
options.Resources |
||||
|
.Add<TencentLocationResource>("en") |
||||
|
.AddVirtualJson("/LINGYUN/Abp/Location/Tencent/Localization/Resources"); |
||||
|
}); |
||||
|
} |
||||
|
} |
||||
|
} |
||||
@ -0,0 +1,11 @@ |
|||||
|
{ |
||||
|
"culture": "en", |
||||
|
"texts": { |
||||
|
"ResolveLocationFailed": "Parse address error, error message :{0}", |
||||
|
"Message:RETURN_0": "OK", |
||||
|
"Message:RETURN_110": "The request parameter information is incorrect", |
||||
|
"Message:RETURN_306": "Key format error", |
||||
|
"Message:RETURN_310": "Check the string if the request has retention information", |
||||
|
"Message:RETURN_311": "The source of the request is not authorized" |
||||
|
} |
||||
|
} |
||||
@ -0,0 +1,11 @@ |
|||||
|
{ |
||||
|
"culture": "zh-Hans", |
||||
|
"texts": { |
||||
|
"ResolveLocationFailed": "解析地址出错,错误信息:{0}", |
||||
|
"Message:RETURN_0": "正常", |
||||
|
"Message:RETURN_110": "请求参数信息有误", |
||||
|
"Message:RETURN_306": "Key格式错误", |
||||
|
"Message:RETURN_310": "请求有护持信息请检查字符串", |
||||
|
"Message:RETURN_311": "请求来源未被授权" |
||||
|
} |
||||
|
} |
||||
@ -0,0 +1,9 @@ |
|||||
|
using Volo.Abp.Localization; |
||||
|
|
||||
|
namespace LINYUN.Abp.Location.Tencent.Localization |
||||
|
{ |
||||
|
[LocalizationResourceName("TencentLocation")] |
||||
|
public class TencentLocationResource |
||||
|
{ |
||||
|
} |
||||
|
} |
||||
@ -0,0 +1,41 @@ |
|||||
|
using Newtonsoft.Json; |
||||
|
|
||||
|
namespace LINGYUN.Abp.Location.Tencent.Model |
||||
|
{ |
||||
|
/// <summary>
|
||||
|
/// 地址部件,address不满足需求时可自行拼接
|
||||
|
/// </summary>
|
||||
|
public class AddressComponent |
||||
|
{ |
||||
|
/// <summary>
|
||||
|
/// 国家
|
||||
|
/// </summary>
|
||||
|
[JsonProperty("nation")] |
||||
|
public string Nation { get; set; } |
||||
|
/// <summary>
|
||||
|
/// 省
|
||||
|
/// </summary>
|
||||
|
[JsonProperty("province")] |
||||
|
public string Province { get; set; } |
||||
|
/// <summary>
|
||||
|
/// 市
|
||||
|
/// </summary>
|
||||
|
[JsonProperty("city")] |
||||
|
public string City { get; set; } |
||||
|
/// <summary>
|
||||
|
/// 区,可能为空字串
|
||||
|
/// </summary>
|
||||
|
[JsonProperty("district")] |
||||
|
public string District { get; set; } |
||||
|
/// <summary>
|
||||
|
/// 街道,可能为空字串
|
||||
|
/// </summary>
|
||||
|
[JsonProperty("street")] |
||||
|
public string Street { get; set; } |
||||
|
/// <summary>
|
||||
|
/// 门牌,可能为空字串
|
||||
|
/// </summary>
|
||||
|
[JsonProperty("street_number")] |
||||
|
public string StreetNumber { get; set; } |
||||
|
} |
||||
|
} |
||||
@ -0,0 +1,53 @@ |
|||||
|
using Newtonsoft.Json; |
||||
|
|
||||
|
namespace LINGYUN.Abp.Location.Tencent.Model |
||||
|
{ |
||||
|
/// <summary>
|
||||
|
/// 行政区划信息
|
||||
|
/// </summary>
|
||||
|
public class AddressInfo |
||||
|
{ |
||||
|
[JsonProperty("adcode")] |
||||
|
public string AdCode { get; set; } |
||||
|
/// <summary>
|
||||
|
/// 城市代码
|
||||
|
/// </summary>
|
||||
|
[JsonProperty("city_code")] |
||||
|
public string CityCode { get; set; } |
||||
|
/// <summary>
|
||||
|
/// 行政区划代码
|
||||
|
/// </summary>
|
||||
|
[JsonProperty("nation_code")] |
||||
|
public string NationCode { get; set; } |
||||
|
/// <summary>
|
||||
|
/// 行政区划名称
|
||||
|
/// </summary>
|
||||
|
[JsonProperty("name")] |
||||
|
public string Name { get; set; } |
||||
|
/// <summary>
|
||||
|
/// 国家
|
||||
|
/// </summary>
|
||||
|
[JsonProperty("nation")] |
||||
|
public string Nation { get; set; } |
||||
|
/// <summary>
|
||||
|
/// 省/直辖市
|
||||
|
/// </summary>
|
||||
|
[JsonProperty("province")] |
||||
|
public string Province { get; set; } |
||||
|
/// <summary>
|
||||
|
/// 市/地级区 及同级行政区划
|
||||
|
/// </summary>
|
||||
|
[JsonProperty("city")] |
||||
|
public string City { get; set; } |
||||
|
/// <summary>
|
||||
|
/// 区/县级市 及同级行政区划
|
||||
|
/// </summary>
|
||||
|
[JsonProperty("district")] |
||||
|
public string District { get; set; } |
||||
|
/// <summary>
|
||||
|
/// 行政区划中心点坐标
|
||||
|
/// </summary>
|
||||
|
[JsonProperty("location")] |
||||
|
public Location Location { get; set; } = new Location(); |
||||
|
} |
||||
|
} |
||||
@ -0,0 +1,56 @@ |
|||||
|
using Newtonsoft.Json; |
||||
|
|
||||
|
namespace LINGYUN.Abp.Location.Tencent.Model |
||||
|
{ |
||||
|
/// <summary>
|
||||
|
/// 坐标相对位置参考
|
||||
|
/// </summary>
|
||||
|
public class AddressReference |
||||
|
{ |
||||
|
/// <summary>
|
||||
|
/// 商圈
|
||||
|
/// </summary>
|
||||
|
[JsonProperty("business_area")] |
||||
|
public Area BusinessArea { get; set; } = new Area(); |
||||
|
/// <summary>
|
||||
|
/// 知名区域,如商圈或人们普遍认为有较高知名度的区域
|
||||
|
/// </summary>
|
||||
|
[JsonProperty("famous_area")] |
||||
|
public Area FamousArea { get; set; } = new Area(); |
||||
|
/// <summary>
|
||||
|
/// 乡镇街道
|
||||
|
/// </summary>
|
||||
|
[JsonProperty("town")] |
||||
|
public Area Town { get; set; } = new Area(); |
||||
|
/// <summary>
|
||||
|
/// 一级地标,可识别性较强、规模较大的地点、小区等
|
||||
|
/// </summary>
|
||||
|
[JsonProperty("landmark_l1")] |
||||
|
public Area Landmark1 { get; set; } = new Area(); |
||||
|
/// <summary>
|
||||
|
/// 二级地标,较一级地标更为精确,规模更小
|
||||
|
/// </summary>
|
||||
|
[JsonProperty("landmark_l2")] |
||||
|
public Area Landmark2 { get; set; } = new Area(); |
||||
|
/// <summary>
|
||||
|
/// 街道
|
||||
|
/// </summary>
|
||||
|
[JsonProperty("street")] |
||||
|
public Area Street { get; set; } = new Area(); |
||||
|
/// <summary>
|
||||
|
/// 门牌
|
||||
|
/// </summary>
|
||||
|
[JsonProperty("street_number")] |
||||
|
public Area StreetNumber { get; set; } = new Area(); |
||||
|
/// <summary>
|
||||
|
/// 交叉路口
|
||||
|
/// </summary>
|
||||
|
[JsonProperty("crossroad")] |
||||
|
public Area CrossRoad { get; set; } = new Area(); |
||||
|
/// <summary>
|
||||
|
/// 水系
|
||||
|
/// </summary>
|
||||
|
[JsonProperty("water")] |
||||
|
public Area Water { get; set; } = new Area(); |
||||
|
} |
||||
|
} |
||||
@ -0,0 +1,37 @@ |
|||||
|
using Newtonsoft.Json; |
||||
|
|
||||
|
namespace LINGYUN.Abp.Location.Tencent.Model |
||||
|
{ |
||||
|
/// <summary>
|
||||
|
/// 区域信息
|
||||
|
/// </summary>
|
||||
|
public class Area |
||||
|
{ |
||||
|
/// <summary>
|
||||
|
/// 地点唯一标识
|
||||
|
/// </summary>
|
||||
|
[JsonProperty("id")] |
||||
|
public string Id { get; set; } |
||||
|
/// <summary>
|
||||
|
/// 名称/标题
|
||||
|
/// </summary>
|
||||
|
[JsonProperty("title")] |
||||
|
public string Title { get; set; } |
||||
|
/// <summary>
|
||||
|
/// 坐标
|
||||
|
/// </summary>
|
||||
|
[JsonProperty("location")] |
||||
|
public Location Location { get; set; } = new Location(); |
||||
|
/// <summary>
|
||||
|
/// 此参考位置到输入坐标的直线距离
|
||||
|
/// </summary>
|
||||
|
[JsonProperty("_distance")] |
||||
|
public string Distance { get; set; } |
||||
|
/// <summary>
|
||||
|
/// 此参考位置到输入坐标的方位关系,
|
||||
|
/// 如:北、南、内
|
||||
|
/// </summary>
|
||||
|
[JsonProperty("_dir_desc")] |
||||
|
public string DirDescription { get; set; } |
||||
|
} |
||||
|
} |
||||
@ -0,0 +1,21 @@ |
|||||
|
using Newtonsoft.Json; |
||||
|
|
||||
|
namespace LINGYUN.Abp.Location.Tencent.Model |
||||
|
{ |
||||
|
/// <summary>
|
||||
|
/// 位置描述
|
||||
|
/// </summary>
|
||||
|
public class FormattedAddress |
||||
|
{ |
||||
|
/// <summary>
|
||||
|
/// 经过腾讯地图优化过的描述方式,更具人性化特点
|
||||
|
/// </summary>
|
||||
|
[JsonProperty("recommend")] |
||||
|
public string ReCommend { get; set; } |
||||
|
/// <summary>
|
||||
|
/// 大致位置,可用于对位置的粗略描述
|
||||
|
/// </summary>
|
||||
|
[JsonProperty("rough")] |
||||
|
public string Rough { get; set; } |
||||
|
} |
||||
|
} |
||||
@ -0,0 +1,21 @@ |
|||||
|
using Newtonsoft.Json; |
||||
|
|
||||
|
namespace LINGYUN.Abp.Location.Tencent.Model |
||||
|
{ |
||||
|
/// <summary>
|
||||
|
/// 行政区划中心点坐标
|
||||
|
/// </summary>
|
||||
|
public class Location |
||||
|
{ |
||||
|
/// <summary>
|
||||
|
/// 纬度
|
||||
|
/// </summary>
|
||||
|
[JsonProperty("lat")] |
||||
|
public double Lat { get; set; } |
||||
|
/// <summary>
|
||||
|
/// 经度
|
||||
|
/// </summary>
|
||||
|
[JsonProperty("lng")] |
||||
|
public double Lng { get; set; } |
||||
|
} |
||||
|
} |
||||
@ -0,0 +1,46 @@ |
|||||
|
using Newtonsoft.Json; |
||||
|
|
||||
|
namespace LINGYUN.Abp.Location.Tencent.Model |
||||
|
{ |
||||
|
/// <summary>
|
||||
|
/// POI对象
|
||||
|
/// </summary>
|
||||
|
public class Poi |
||||
|
{ |
||||
|
/// <summary>
|
||||
|
/// 地点唯一标识
|
||||
|
/// </summary>
|
||||
|
[JsonProperty("id")] |
||||
|
public string Id { get; set; } |
||||
|
/// <summary>
|
||||
|
/// 名称/标题
|
||||
|
/// </summary>
|
||||
|
[JsonProperty("title")] |
||||
|
public string Title { get; set; } |
||||
|
/// <summary>
|
||||
|
/// 地址
|
||||
|
/// </summary>
|
||||
|
[JsonProperty("address")] |
||||
|
public string Address { get; set; } |
||||
|
/// <summary>
|
||||
|
/// POI分类
|
||||
|
/// </summary>
|
||||
|
[JsonProperty("category")] |
||||
|
public string CateGory { get; set; } |
||||
|
/// <summary>
|
||||
|
/// 坐标
|
||||
|
/// </summary>
|
||||
|
[JsonProperty("location")] |
||||
|
public Location Location { get; set; } = new Location(); |
||||
|
/// <summary>
|
||||
|
/// 该POI到逆地址解析传入的坐标的直线距离
|
||||
|
/// </summary>
|
||||
|
[JsonProperty("_distance")] |
||||
|
public string Distance { get; set; } |
||||
|
/// <summary>
|
||||
|
/// 行政区划信息
|
||||
|
/// </summary>
|
||||
|
[JsonProperty("ad_info")] |
||||
|
public AddressInfo AddressInfo { get; set; } = new AddressInfo(); |
||||
|
} |
||||
|
} |
||||
@ -0,0 +1,44 @@ |
|||||
|
using Newtonsoft.Json; |
||||
|
|
||||
|
namespace LINGYUN.Abp.Location.Tencent.Model |
||||
|
{ |
||||
|
public class TencentGeocode |
||||
|
{ |
||||
|
/// <summary>
|
||||
|
/// 解析到的坐标
|
||||
|
/// </summary>
|
||||
|
[JsonProperty("location")] |
||||
|
public Location Location { get; set; } = new Location(); |
||||
|
/// <summary>
|
||||
|
/// 解析后的地址部件
|
||||
|
/// </summary>
|
||||
|
[JsonProperty("address_components")] |
||||
|
public AddressComponent AddressComponent { get; set; } = new AddressComponent(); |
||||
|
/// <summary>
|
||||
|
/// 行政区划信息
|
||||
|
/// </summary>
|
||||
|
[JsonProperty("ad_info")] |
||||
|
public GeocodeAddressInfo AddressInfo { get; set; } = new GeocodeAddressInfo(); |
||||
|
/// <summary>
|
||||
|
/// 可信度参考:值范围 1 <低可信> - 10 <高可信>
|
||||
|
/// </summary>
|
||||
|
[JsonProperty("reliability")] |
||||
|
public int Reliability { get; set; } |
||||
|
/// <summary>
|
||||
|
/// 解析精度级别,分为11个级别,一般>=9即可采用(定位到点,精度较高) 也可根据实际业务需求自行调整
|
||||
|
/// </summary>
|
||||
|
[JsonProperty("level")] |
||||
|
public int Level { get; set; } |
||||
|
} |
||||
|
/// <summary>
|
||||
|
/// 行政区划信息
|
||||
|
/// </summary>
|
||||
|
public class GeocodeAddressInfo |
||||
|
{ |
||||
|
/// <summary>
|
||||
|
/// 行政区划代码
|
||||
|
/// </summary>
|
||||
|
[JsonProperty("adcode")] |
||||
|
public string AdCode { get; set; } |
||||
|
} |
||||
|
} |
||||
@ -0,0 +1,26 @@ |
|||||
|
using Newtonsoft.Json; |
||||
|
|
||||
|
namespace LINGYUN.Abp.Location.Tencent.Model |
||||
|
{ |
||||
|
/// <summary>
|
||||
|
/// IP定位结果
|
||||
|
/// </summary>
|
||||
|
public class TencentIPGeocode |
||||
|
{ |
||||
|
/// <summary>
|
||||
|
/// 用于定位的IP地址
|
||||
|
/// </summary>
|
||||
|
[JsonProperty("ip")] |
||||
|
public string IpAddress { get; set; } |
||||
|
/// <summary>
|
||||
|
/// 定位坐标
|
||||
|
/// </summary>
|
||||
|
[JsonProperty("location")] |
||||
|
public Location Location { get; set; } = new Location(); |
||||
|
/// <summary>
|
||||
|
/// 定位行政区划信息
|
||||
|
/// </summary>
|
||||
|
[JsonProperty("ad_info")] |
||||
|
public AddressInfo AddressInfo { get; set; } = new AddressInfo(); |
||||
|
} |
||||
|
} |
||||
@ -0,0 +1,46 @@ |
|||||
|
using Newtonsoft.Json; |
||||
|
|
||||
|
namespace LINGYUN.Abp.Location.Tencent.Model |
||||
|
{ |
||||
|
/// <summary>
|
||||
|
/// 逆地址解析结果
|
||||
|
/// </summary>
|
||||
|
public class TencentReGeocode |
||||
|
{ |
||||
|
/// <summary>
|
||||
|
/// 地址描述
|
||||
|
/// </summary>
|
||||
|
[JsonProperty("address")] |
||||
|
public string Address { get; set; } |
||||
|
/// <summary>
|
||||
|
/// 位置描述
|
||||
|
/// </summary>
|
||||
|
[JsonProperty("formatted_addresses")] |
||||
|
public FormattedAddress FormattedAddress { get; set; } = new FormattedAddress(); |
||||
|
/// <summary>
|
||||
|
/// 地址部件,address不满足需求时可自行拼接
|
||||
|
/// </summary>
|
||||
|
[JsonProperty("address_component")] |
||||
|
public AddressComponent AddressComponent { get; set; } = new AddressComponent(); |
||||
|
/// <summary>
|
||||
|
/// 行政区划信息
|
||||
|
/// </summary>
|
||||
|
[JsonProperty("ad_info")] |
||||
|
public AddressInfo AddressInfo { get; set; } = new AddressInfo(); |
||||
|
/// <summary>
|
||||
|
/// 坐标相对位置参考
|
||||
|
/// </summary>
|
||||
|
[JsonProperty("address_reference")] |
||||
|
public AddressReference AddressReference { get; set; } = new AddressReference(); |
||||
|
/// <summary>
|
||||
|
/// 查询的周边poi的总数
|
||||
|
/// </summary>
|
||||
|
[JsonProperty("poi_count")] |
||||
|
public int PoiCount { get; set; } |
||||
|
/// <summary>
|
||||
|
/// POI数组,对象中每个子项为一个POI对象
|
||||
|
/// </summary>
|
||||
|
[JsonProperty("pois")] |
||||
|
public Poi[] Pois { get; set; } = new Poi[0]; |
||||
|
} |
||||
|
} |
||||
@ -0,0 +1,14 @@ |
|||||
|
using LINGYUN.Abp.Location.Tencent.Model; |
||||
|
using Newtonsoft.Json; |
||||
|
|
||||
|
namespace LINGYUN.Abp.Location.Tencent.Response |
||||
|
{ |
||||
|
public class TencentGeocodeResponse : TencentLocationResponse |
||||
|
{ |
||||
|
/// <summary>
|
||||
|
/// 地址解析结果
|
||||
|
/// </summary>
|
||||
|
[JsonProperty("result")] |
||||
|
public TencentGeocode Result { get; set; } = new TencentGeocode(); |
||||
|
} |
||||
|
} |
||||
@ -0,0 +1,14 @@ |
|||||
|
using LINGYUN.Abp.Location.Tencent.Model; |
||||
|
using Newtonsoft.Json; |
||||
|
|
||||
|
namespace LINGYUN.Abp.Location.Tencent.Response |
||||
|
{ |
||||
|
public class TencentIPGeocodeResponse : TencentLocationResponse |
||||
|
{ |
||||
|
/// <summary>
|
||||
|
/// IP定位结果
|
||||
|
/// </summary>
|
||||
|
[JsonProperty("result")] |
||||
|
public TencentIPGeocode Result { get; set; } = new TencentIPGeocode(); |
||||
|
} |
||||
|
} |
||||
@ -0,0 +1,52 @@ |
|||||
|
using LINYUN.Abp.Location.Tencent.Localization; |
||||
|
using Newtonsoft.Json; |
||||
|
using Volo.Abp; |
||||
|
using Volo.Abp.Localization; |
||||
|
|
||||
|
namespace LINGYUN.Abp.Location.Tencent.Response |
||||
|
{ |
||||
|
public abstract class TencentLocationResponse |
||||
|
{ |
||||
|
/// <summary>
|
||||
|
/// 状态码,0为正常,
|
||||
|
/// 310请求参数信息有误,
|
||||
|
/// 311Key格式错误,
|
||||
|
/// 306请求有护持信息请检查字符串,
|
||||
|
/// 110请求来源未被授权
|
||||
|
/// </summary>
|
||||
|
[JsonProperty("status")] |
||||
|
public int Status { get; set; } |
||||
|
/// <summary>
|
||||
|
/// 状态说明
|
||||
|
/// </summary>
|
||||
|
[JsonProperty("message")] |
||||
|
public string Message { get; set; } |
||||
|
/// <summary>
|
||||
|
/// 本次请求的唯一标识
|
||||
|
/// </summary>
|
||||
|
[JsonProperty("request_id")] |
||||
|
public string RequestId { get; set; } |
||||
|
/// <summary>
|
||||
|
/// 是否请求成功
|
||||
|
/// </summary>
|
||||
|
public bool IsSuccessed => Status.Equals(0); |
||||
|
|
||||
|
public ILocalizableString GetErrorMessage() |
||||
|
{ |
||||
|
switch (Status) |
||||
|
{ |
||||
|
case 0: |
||||
|
return LocalizableString.Create<TencentLocationResource>("Message:RETURN_0"); |
||||
|
case 110: |
||||
|
return LocalizableString.Create<TencentLocationResource>("Message:RETURN_110"); |
||||
|
case 306: |
||||
|
return LocalizableString.Create<TencentLocationResource>("Message:RETURN_306"); |
||||
|
case 310: |
||||
|
return LocalizableString.Create<TencentLocationResource>("Message:RETURN_310"); |
||||
|
case 311: |
||||
|
return LocalizableString.Create<TencentLocationResource>("Message:RETURN_311"); |
||||
|
default: throw new AbpException(Message); |
||||
|
} |
||||
|
} |
||||
|
} |
||||
|
} |
||||
@ -0,0 +1,14 @@ |
|||||
|
using LINGYUN.Abp.Location.Tencent.Model; |
||||
|
using Newtonsoft.Json; |
||||
|
|
||||
|
namespace LINGYUN.Abp.Location.Tencent.Response |
||||
|
{ |
||||
|
public class TencentReGeocodeResponse : TencentLocationResponse |
||||
|
{ |
||||
|
/// <summary>
|
||||
|
/// 逆地址解析结果
|
||||
|
/// </summary>
|
||||
|
[JsonProperty("result")] |
||||
|
public TencentReGeocode Result { get; set; } = new TencentReGeocode(); |
||||
|
} |
||||
|
} |
||||
@ -0,0 +1,211 @@ |
|||||
|
using LINGYUN.Abp.Location.Tencent.Response; |
||||
|
using LINGYUN.Abp.Location.Tencent.Utils; |
||||
|
using LINYUN.Abp.Location.Tencent.Localization; |
||||
|
using Microsoft.Extensions.DependencyInjection; |
||||
|
using Microsoft.Extensions.Localization; |
||||
|
using Microsoft.Extensions.Options; |
||||
|
using System; |
||||
|
using System.Collections.Generic; |
||||
|
using System.Linq; |
||||
|
using System.Net.Http; |
||||
|
using System.Text; |
||||
|
using System.Threading; |
||||
|
using System.Threading.Tasks; |
||||
|
using Volo.Abp; |
||||
|
using Volo.Abp.DependencyInjection; |
||||
|
using Volo.Abp.Json; |
||||
|
using Volo.Abp.Threading; |
||||
|
|
||||
|
namespace LINGYUN.Abp.Location.Tencent |
||||
|
{ |
||||
|
public class TencentLocationHttpClient : ITransientDependency |
||||
|
{ |
||||
|
protected TencentLocationOptions Options { get; } |
||||
|
protected IJsonSerializer JsonSerializer { get; } |
||||
|
protected IServiceProvider ServiceProvider { get; } |
||||
|
protected IHttpClientFactory HttpClientFactory { get; } |
||||
|
protected ICancellationTokenProvider CancellationTokenProvider { get; } |
||||
|
|
||||
|
public TencentLocationHttpClient( |
||||
|
IOptions<TencentLocationOptions> options, |
||||
|
IJsonSerializer jsonSerializer, |
||||
|
IServiceProvider serviceProvider, |
||||
|
IHttpClientFactory httpClientFactory, |
||||
|
ICancellationTokenProvider cancellationTokenProvider) |
||||
|
{ |
||||
|
Options = options.Value; |
||||
|
JsonSerializer = jsonSerializer; |
||||
|
ServiceProvider = serviceProvider; |
||||
|
HttpClientFactory = httpClientFactory; |
||||
|
CancellationTokenProvider = cancellationTokenProvider; |
||||
|
} |
||||
|
|
||||
|
public virtual async Task<IPGecodeLocation> IPGeocodeAsync(string ipAddress) |
||||
|
{ |
||||
|
var requestParamters = new Dictionary<string, string> |
||||
|
{ |
||||
|
{ "callback", Options.Callback }, |
||||
|
{ "ip", ipAddress }, |
||||
|
{ "key", Options.AccessKey }, |
||||
|
{ "output", Options.Output } |
||||
|
}; |
||||
|
var tencentMapUrl = "https://apis.map.qq.com"; |
||||
|
var tencentMapPath = "/ws/location/v1/ip"; |
||||
|
if (!Options.SecretKey.IsNullOrWhiteSpace()) |
||||
|
{ |
||||
|
var sig = TencentSecretKeyCaculater.CalcSecretKey(tencentMapPath, Options.SecretKey, requestParamters); |
||||
|
requestParamters.Add("sig", sig); |
||||
|
} |
||||
|
var tencentLocationResponse = await GetTencentMapResponseAsync<TencentIPGeocodeResponse>(tencentMapUrl, tencentMapPath, requestParamters); |
||||
|
|
||||
|
var location = new IPGecodeLocation |
||||
|
{ |
||||
|
IpAddress = tencentLocationResponse.Result.IpAddress, |
||||
|
AdCode = tencentLocationResponse.Result.AddressInfo.AdCode, |
||||
|
City = tencentLocationResponse.Result.AddressInfo.City, |
||||
|
Country = tencentLocationResponse.Result.AddressInfo.Nation, |
||||
|
District = tencentLocationResponse.Result.AddressInfo.District, |
||||
|
Location = new Location |
||||
|
{ |
||||
|
Latitude = tencentLocationResponse.Result.Location.Lat, |
||||
|
Longitude = tencentLocationResponse.Result.Location.Lng |
||||
|
}, |
||||
|
Province = tencentLocationResponse.Result.AddressInfo.Province |
||||
|
}; |
||||
|
location.AddAdditional("TencentLocation", tencentLocationResponse.Result); |
||||
|
|
||||
|
return location; |
||||
|
} |
||||
|
|
||||
|
public virtual async Task<GecodeLocation> GeocodeAsync(string address, string city = null) |
||||
|
{ |
||||
|
var requestParamters = new Dictionary<string, string> |
||||
|
{ |
||||
|
{ "address", address }, |
||||
|
{ "callback", Options.Callback }, |
||||
|
{ "key", Options.AccessKey }, |
||||
|
{ "output", Options.Output } |
||||
|
}; |
||||
|
if (!city.IsNullOrWhiteSpace()) |
||||
|
{ |
||||
|
requestParamters.Add("region", city); |
||||
|
} |
||||
|
var tencentMapUrl = "https://apis.map.qq.com"; |
||||
|
var tencentMapPath = "/ws/geocoder/v1"; |
||||
|
if (!Options.SecretKey.IsNullOrWhiteSpace()) |
||||
|
{ |
||||
|
var sig = TencentSecretKeyCaculater.CalcSecretKey(tencentMapPath, Options.SecretKey, requestParamters); |
||||
|
requestParamters.Add("sig", sig); |
||||
|
} |
||||
|
var tencentLocationResponse = await GetTencentMapResponseAsync<TencentGeocodeResponse>(tencentMapUrl, tencentMapPath, requestParamters); |
||||
|
var location = new GecodeLocation |
||||
|
{ |
||||
|
Confidence = tencentLocationResponse.Result.Reliability, |
||||
|
Latitude = tencentLocationResponse.Result.Location.Lat, |
||||
|
Longitude = tencentLocationResponse.Result.Location.Lng, |
||||
|
Level = tencentLocationResponse.Result.Level.ToString() |
||||
|
}; |
||||
|
location.AddAdditional("TencentLocation", tencentLocationResponse.Result); |
||||
|
|
||||
|
return location; |
||||
|
} |
||||
|
|
||||
|
public virtual async Task<ReGeocodeLocation> ReGeocodeAsync(double lat, double lng, int radius = 1000) |
||||
|
{ |
||||
|
var requestParamters = new Dictionary<string, string> |
||||
|
{ |
||||
|
{ "callback", Options.Callback }, |
||||
|
{ "get_poi", Options.GetPoi }, |
||||
|
{ "key", Options.AccessKey }, |
||||
|
{ "location", $"{lat},{lng}" }, |
||||
|
{ "output", Options.Output }, |
||||
|
{ "poi_options", "radius=" + radius.ToString() } |
||||
|
}; |
||||
|
var tencentMapUrl = "https://apis.map.qq.com"; |
||||
|
var tencentMapPath = "/ws/geocoder/v1"; |
||||
|
if (!Options.SecretKey.IsNullOrWhiteSpace()) |
||||
|
{ |
||||
|
var sig = TencentSecretKeyCaculater.CalcSecretKey(tencentMapPath, Options.SecretKey, requestParamters); |
||||
|
requestParamters.Add("sig", sig); |
||||
|
} |
||||
|
var tencentLocationResponse = await GetTencentMapResponseAsync<TencentReGeocodeResponse>(tencentMapUrl, tencentMapPath, requestParamters); |
||||
|
var location = new ReGeocodeLocation |
||||
|
{ |
||||
|
Street = tencentLocationResponse.Result.AddressComponent.Street, |
||||
|
AdCode = tencentLocationResponse.Result.AddressInfo?.NationCode, |
||||
|
Address = tencentLocationResponse.Result.Address, |
||||
|
City = tencentLocationResponse.Result.AddressComponent.City, |
||||
|
Country = tencentLocationResponse.Result.AddressComponent.Nation, |
||||
|
District = tencentLocationResponse.Result.AddressComponent.District, |
||||
|
Number = tencentLocationResponse.Result.AddressComponent.StreetNumber, |
||||
|
Province = tencentLocationResponse.Result.AddressComponent.Province, |
||||
|
Town = tencentLocationResponse.Result.AddressReference.Town.Title, |
||||
|
Pois = tencentLocationResponse.Result.Pois.Select(p => new Poi |
||||
|
{ |
||||
|
Address = p.Address, |
||||
|
Name = p.Title, |
||||
|
Tag = p.Id, |
||||
|
Type = p.CateGory |
||||
|
}).ToList() |
||||
|
}; |
||||
|
location.AddAdditional("TencentLocation", tencentLocationResponse.Result); |
||||
|
|
||||
|
return location; |
||||
|
} |
||||
|
|
||||
|
protected virtual async Task<string> MakeRequestAndGetResultAsync(string url) |
||||
|
{ |
||||
|
var client = HttpClientFactory.CreateClient(TencentLocationHttpConsts.HttpClientName); |
||||
|
var requestMessage = new HttpRequestMessage(HttpMethod.Get, url); |
||||
|
|
||||
|
var response = await client.SendAsync(requestMessage, GetCancellationToken()); |
||||
|
if (!response.IsSuccessStatusCode) |
||||
|
{ |
||||
|
throw new AbpException($"Tencent http request service returns error! HttpStatusCode: {response.StatusCode}, ReasonPhrase: {response.ReasonPhrase}"); |
||||
|
} |
||||
|
var resultContent = await response.Content.ReadAsStringAsync(); |
||||
|
|
||||
|
return resultContent; |
||||
|
} |
||||
|
|
||||
|
protected virtual CancellationToken GetCancellationToken() |
||||
|
{ |
||||
|
return CancellationTokenProvider.Token; |
||||
|
} |
||||
|
|
||||
|
protected virtual async Task<TResponse> GetTencentMapResponseAsync<TResponse>(string url, string path, IDictionary<string, string> paramters) |
||||
|
where TResponse : TencentLocationResponse |
||||
|
{ |
||||
|
var requestUrl = BuildRequestUrl(url, path, paramters); |
||||
|
var responseContent = await MakeRequestAndGetResultAsync(requestUrl); |
||||
|
var tencentLocationResponse = JsonSerializer.Deserialize<TResponse>(responseContent); |
||||
|
if (!tencentLocationResponse.IsSuccessed) |
||||
|
{ |
||||
|
if (Options.VisableErrorToClient) |
||||
|
{ |
||||
|
var localizerFactory = ServiceProvider.GetRequiredService<IStringLocalizerFactory>(); |
||||
|
var localizerErrorMessage = tencentLocationResponse.GetErrorMessage().Localize(localizerFactory); |
||||
|
var localizer = ServiceProvider.GetRequiredService<IStringLocalizer<TencentLocationResource>>(); |
||||
|
localizerErrorMessage = localizer["ResolveLocationFailed", localizerErrorMessage]; |
||||
|
throw new UserFriendlyException(localizerErrorMessage); |
||||
|
} |
||||
|
throw new AbpException($"Resolution address failed:{tencentLocationResponse.Message}!"); |
||||
|
} |
||||
|
return tencentLocationResponse; |
||||
|
} |
||||
|
|
||||
|
protected virtual string BuildRequestUrl(string uri, string path, IDictionary<string, string> paramters) |
||||
|
{ |
||||
|
var requestUrlBuilder = new StringBuilder(128); |
||||
|
requestUrlBuilder.Append(uri); |
||||
|
requestUrlBuilder.Append(path).Append("?"); |
||||
|
foreach (var paramter in paramters) |
||||
|
{ |
||||
|
requestUrlBuilder.AppendFormat("{0}={1}", paramter.Key, paramter.Value); |
||||
|
requestUrlBuilder.Append("&"); |
||||
|
} |
||||
|
requestUrlBuilder.Remove(requestUrlBuilder.Length - 1, 1); |
||||
|
return requestUrlBuilder.ToString(); |
||||
|
} |
||||
|
} |
||||
|
} |
||||
@ -0,0 +1,7 @@ |
|||||
|
namespace LINGYUN.Abp.Location.Tencent |
||||
|
{ |
||||
|
public class TencentLocationHttpConsts |
||||
|
{ |
||||
|
public const string HttpClientName = "TencentLocation"; |
||||
|
} |
||||
|
} |
||||
@ -0,0 +1,12 @@ |
|||||
|
namespace LINGYUN.Abp.Location.Tencent |
||||
|
{ |
||||
|
public class TencentLocationOptions |
||||
|
{ |
||||
|
public string AccessKey { get; set; } |
||||
|
public string SecretKey { get; set; } |
||||
|
public string GetPoi { get; set; } = "1"; |
||||
|
public string Output { get; set; } = "JSON"; |
||||
|
public string Callback { get; set; } |
||||
|
public bool VisableErrorToClient { get; set; } = false; |
||||
|
} |
||||
|
} |
||||
@ -0,0 +1,33 @@ |
|||||
|
using Microsoft.Extensions.DependencyInjection; |
||||
|
using System.Threading.Tasks; |
||||
|
using Volo.Abp.DependencyInjection; |
||||
|
|
||||
|
namespace LINGYUN.Abp.Location.Tencent |
||||
|
{ |
||||
|
[Dependency(ServiceLifetime.Transient)] |
||||
|
[ExposeServices(typeof(ILocationResolveProvider))] |
||||
|
public class TencentLocationResolveProvider : ILocationResolveProvider |
||||
|
{ |
||||
|
protected TencentLocationHttpClient TencentLocationHttpClient { get; } |
||||
|
|
||||
|
public TencentLocationResolveProvider(TencentLocationHttpClient tencentLocationHttpClient) |
||||
|
{ |
||||
|
TencentLocationHttpClient = tencentLocationHttpClient; |
||||
|
} |
||||
|
|
||||
|
public virtual async Task<IPGecodeLocation> IPGeocodeAsync(string ipAddress) |
||||
|
{ |
||||
|
return await TencentLocationHttpClient.IPGeocodeAsync(ipAddress); |
||||
|
} |
||||
|
|
||||
|
public virtual async Task<ReGeocodeLocation> ReGeocodeAsync(double lat, double lng, int radius = 50) |
||||
|
{ |
||||
|
return await TencentLocationHttpClient.ReGeocodeAsync(lat, lng, radius); |
||||
|
} |
||||
|
|
||||
|
public virtual async Task<GecodeLocation> GeocodeAsync(string address, string city = null) |
||||
|
{ |
||||
|
return await TencentLocationHttpClient.GeocodeAsync(address, city); |
||||
|
} |
||||
|
} |
||||
|
} |
||||
@ -0,0 +1,47 @@ |
|||||
|
using System; |
||||
|
using System.Collections.Generic; |
||||
|
using System.Text; |
||||
|
|
||||
|
namespace LINGYUN.Abp.Location.Tencent.Utils |
||||
|
{ |
||||
|
public class TencentSecretKeyCaculater |
||||
|
{ |
||||
|
private static string MD5(string password) |
||||
|
{ |
||||
|
try |
||||
|
{ |
||||
|
System.Security.Cryptography.HashAlgorithm hash = System.Security.Cryptography.MD5.Create(); |
||||
|
byte[] hash_out = hash.ComputeHash(Encoding.UTF8.GetBytes(password)); |
||||
|
|
||||
|
var md5_str = BitConverter.ToString(hash_out).Replace("-", ""); |
||||
|
return md5_str.ToLower(); |
||||
|
} |
||||
|
catch |
||||
|
{ |
||||
|
throw; |
||||
|
} |
||||
|
} |
||||
|
|
||||
|
private static string HttpBuildQuery(IDictionary<string, string> querystring_arrays) |
||||
|
{ |
||||
|
|
||||
|
StringBuilder sb = new StringBuilder(); |
||||
|
foreach (var item in querystring_arrays) |
||||
|
{ |
||||
|
sb.Append(item.Key); |
||||
|
sb.Append("="); |
||||
|
sb.Append(item.Value); |
||||
|
sb.Append("&"); |
||||
|
} |
||||
|
sb.Remove(sb.Length - 1, 1); |
||||
|
return sb.ToString(); |
||||
|
} |
||||
|
|
||||
|
public static string CalcSecretKey(string url, string secretKey, IDictionary<string, string> querystring_arrays) |
||||
|
{ |
||||
|
var queryString = HttpBuildQuery(querystring_arrays); |
||||
|
|
||||
|
return MD5(url + "?" + queryString + secretKey); |
||||
|
} |
||||
|
} |
||||
|
} |
||||
@ -0,0 +1,43 @@ |
|||||
|
using System.Collections.Generic; |
||||
|
|
||||
|
namespace LINGYUN.Abp.Location |
||||
|
{ |
||||
|
public class IPGecodeLocation |
||||
|
{ |
||||
|
/// <summary>
|
||||
|
/// IP地址
|
||||
|
/// </summary>
|
||||
|
public string IpAddress { get; set; } |
||||
|
/// <summary>
|
||||
|
/// 定位坐标
|
||||
|
/// </summary>
|
||||
|
public Location Location { get; set; } = new Location(); |
||||
|
/// <summary>
|
||||
|
/// 国家
|
||||
|
/// </summary>
|
||||
|
public string Country { get; set; } |
||||
|
/// <summary>
|
||||
|
/// 城市
|
||||
|
/// </summary>
|
||||
|
public string City { get; set; } |
||||
|
/// <summary>
|
||||
|
/// 省份
|
||||
|
/// </summary>
|
||||
|
public string Province { get; set; } |
||||
|
/// <summary>
|
||||
|
/// 区县
|
||||
|
/// </summary>
|
||||
|
public string District { get; set; } |
||||
|
/// <summary>
|
||||
|
/// adcode
|
||||
|
/// </summary>
|
||||
|
public string AdCode { get; set; } |
||||
|
|
||||
|
public IDictionary<string, object> Additionals { get; } = new Dictionary<string, object>(); |
||||
|
|
||||
|
public void AddAdditional(string key, object value) |
||||
|
{ |
||||
|
Additionals.Add(key, value); |
||||
|
} |
||||
|
} |
||||
|
} |
||||
Loading…
Reference in new issue