76 changed files with 2866 additions and 58 deletions
@ -0,0 +1,16 @@ |
|||||
|
<Project Sdk="Microsoft.NET.Sdk"> |
||||
|
|
||||
|
<PropertyGroup> |
||||
|
<TargetFramework>netcoreapp3.1</TargetFramework> |
||||
|
<RootNamespace /> |
||||
|
</PropertyGroup> |
||||
|
|
||||
|
<ItemGroup> |
||||
|
<PackageReference Include="Volo.Abp.AspNetCore.SignalR" Version="2.8.0" /> |
||||
|
</ItemGroup> |
||||
|
|
||||
|
<ItemGroup> |
||||
|
<ProjectReference Include="..\LINGYUN.Abp.IM\LINGYUN.Abp.IM.csproj" /> |
||||
|
</ItemGroup> |
||||
|
|
||||
|
</Project> |
||||
@ -0,0 +1,11 @@ |
|||||
|
using Volo.Abp.AspNetCore.SignalR; |
||||
|
using Volo.Abp.Modularity; |
||||
|
|
||||
|
namespace LINGYUN.Abp.IM.SignalR |
||||
|
{ |
||||
|
[DependsOn(typeof(AbpAspNetCoreSignalRModule))] |
||||
|
public class AbpIMSignalRModule : AbpModule |
||||
|
{ |
||||
|
|
||||
|
} |
||||
|
} |
||||
@ -0,0 +1,66 @@ |
|||||
|
using Microsoft.AspNetCore.Http; |
||||
|
using Microsoft.Extensions.Logging; |
||||
|
using System; |
||||
|
using System.Threading.Tasks; |
||||
|
using Volo.Abp.AspNetCore.SignalR; |
||||
|
|
||||
|
namespace LINGYUN.Abp.IM.SignalR |
||||
|
{ |
||||
|
public abstract class OnlineClientHubBase : AbpHub |
||||
|
{ |
||||
|
private IOnlineClientManager _onlineClientManager; |
||||
|
protected IOnlineClientManager OnlineClientManager => LazyGetRequiredService(ref _onlineClientManager); |
||||
|
|
||||
|
private IHttpContextAccessor _httpContextAccessor; |
||||
|
protected IHttpContextAccessor HttpContextAccessor => LazyGetRequiredService(ref _httpContextAccessor); |
||||
|
|
||||
|
public override async Task OnConnectedAsync() |
||||
|
{ |
||||
|
await base.OnConnectedAsync(); |
||||
|
IOnlineClient onlineClient = CreateClientForCurrentConnection(); |
||||
|
Logger.LogDebug("A client is connected: " + onlineClient?.ToString()); |
||||
|
OnlineClientManager.Add(onlineClient); |
||||
|
} |
||||
|
|
||||
|
public override async Task OnDisconnectedAsync(Exception exception) |
||||
|
{ |
||||
|
await base.OnDisconnectedAsync(exception); |
||||
|
Logger.LogDebug("A client is disconnected: " + base.Context.ConnectionId); |
||||
|
try |
||||
|
{ |
||||
|
OnlineClientManager.Remove(Context.ConnectionId); |
||||
|
} |
||||
|
catch (Exception ex) |
||||
|
{ |
||||
|
base.Logger.LogWarning(ex.ToString(), ex); |
||||
|
} |
||||
|
} |
||||
|
|
||||
|
protected virtual IOnlineClient CreateClientForCurrentConnection() |
||||
|
{ |
||||
|
return new OnlineClient(Context.ConnectionId, GetIpAddressOfClient(), |
||||
|
CurrentTenant.Id, CurrentUser.Id) |
||||
|
{ |
||||
|
ConnectTime = Clock.Now |
||||
|
}; |
||||
|
} |
||||
|
|
||||
|
protected virtual string GetIpAddressOfClient() |
||||
|
{ |
||||
|
return HttpContextAccessor.HttpContext?.Connection?.RemoteIpAddress?.ToString(); |
||||
|
} |
||||
|
|
||||
|
protected virtual string GetClientIpAddress(HttpContext httpContext) |
||||
|
{ |
||||
|
try |
||||
|
{ |
||||
|
return HttpContextAccessor.HttpContext?.Connection?.RemoteIpAddress?.ToString(); |
||||
|
} |
||||
|
catch (Exception ex) |
||||
|
{ |
||||
|
Logger.LogException(ex, LogLevel.Warning); |
||||
|
return null; |
||||
|
} |
||||
|
} |
||||
|
} |
||||
|
} |
||||
@ -0,0 +1,12 @@ |
|||||
|
<Project Sdk="Microsoft.NET.Sdk"> |
||||
|
|
||||
|
<PropertyGroup> |
||||
|
<TargetFramework>netstandard2.0</TargetFramework> |
||||
|
<RootNamespace /> |
||||
|
</PropertyGroup> |
||||
|
|
||||
|
<ItemGroup> |
||||
|
<PackageReference Include="Volo.Abp.Core" Version="2.8.0" /> |
||||
|
</ItemGroup> |
||||
|
|
||||
|
</Project> |
||||
@ -0,0 +1,22 @@ |
|||||
|
using System; |
||||
|
using System.Collections.Generic; |
||||
|
|
||||
|
namespace LINGYUN.Abp.IM |
||||
|
{ |
||||
|
public interface IOnlineClient |
||||
|
{ |
||||
|
string ConnectionId { get; } |
||||
|
|
||||
|
string IpAddress { get; } |
||||
|
|
||||
|
Guid? TenantId { get; } |
||||
|
|
||||
|
Guid? UserId { get; } |
||||
|
|
||||
|
DateTime ConnectTime { get; } |
||||
|
|
||||
|
object this[string key] { get; set; } |
||||
|
|
||||
|
Dictionary<string, object> Properties { get; } |
||||
|
} |
||||
|
} |
||||
@ -0,0 +1,27 @@ |
|||||
|
using JetBrains.Annotations; |
||||
|
using System; |
||||
|
using System.Collections.Generic; |
||||
|
|
||||
|
namespace LINGYUN.Abp.IM |
||||
|
{ |
||||
|
public interface IOnlineClientManager |
||||
|
{ |
||||
|
event EventHandler<OnlineClientEventArgs> ClientConnected; |
||||
|
|
||||
|
event EventHandler<OnlineClientEventArgs> ClientDisconnected; |
||||
|
|
||||
|
event EventHandler<OnlineUserEventArgs> UserConnected; |
||||
|
|
||||
|
event EventHandler<OnlineUserEventArgs> UserDisconnected; |
||||
|
|
||||
|
void Add(IOnlineClient client); |
||||
|
|
||||
|
bool Remove(string connectionId); |
||||
|
|
||||
|
IOnlineClient GetByConnectionIdOrNull(string connectionId); |
||||
|
|
||||
|
IReadOnlyList<IOnlineClient> GetAllClients(); |
||||
|
|
||||
|
IReadOnlyList<IOnlineClient> GetAllByContext([NotNull] OnlineClientContext context); |
||||
|
} |
||||
|
} |
||||
@ -0,0 +1,19 @@ |
|||||
|
using System.Collections.Generic; |
||||
|
|
||||
|
namespace LINGYUN.Abp.IM |
||||
|
{ |
||||
|
public interface IOnlineClientStore |
||||
|
{ |
||||
|
void Add(IOnlineClient client); |
||||
|
|
||||
|
bool Remove(string connectionId); |
||||
|
|
||||
|
bool TryRemove(string connectionId, out IOnlineClient client); |
||||
|
|
||||
|
bool TryGet(string connectionId, out IOnlineClient client); |
||||
|
|
||||
|
bool Contains(string connectionId); |
||||
|
|
||||
|
IReadOnlyList<IOnlineClient> GetAll(); |
||||
|
} |
||||
|
} |
||||
@ -0,0 +1,47 @@ |
|||||
|
using System.Collections.Concurrent; |
||||
|
using System.Collections.Generic; |
||||
|
using System.Collections.Immutable; |
||||
|
using Volo.Abp.DependencyInjection; |
||||
|
|
||||
|
namespace LINGYUN.Abp.IM |
||||
|
{ |
||||
|
public class InMemoryOnlineClientStore : IOnlineClientStore, ISingletonDependency |
||||
|
{ |
||||
|
protected ConcurrentDictionary<string, IOnlineClient> Clients { get; } |
||||
|
|
||||
|
public InMemoryOnlineClientStore() |
||||
|
{ |
||||
|
Clients = new ConcurrentDictionary<string, IOnlineClient>(); |
||||
|
} |
||||
|
|
||||
|
public void Add(IOnlineClient client) |
||||
|
{ |
||||
|
Clients.AddOrUpdate(client.ConnectionId, client, (s, o) => client); |
||||
|
} |
||||
|
|
||||
|
public bool Remove(string connectionId) |
||||
|
{ |
||||
|
return TryRemove(connectionId, out _); |
||||
|
} |
||||
|
|
||||
|
public bool TryRemove(string connectionId, out IOnlineClient client) |
||||
|
{ |
||||
|
return Clients.TryRemove(connectionId, out client); |
||||
|
} |
||||
|
|
||||
|
public bool TryGet(string connectionId, out IOnlineClient client) |
||||
|
{ |
||||
|
return Clients.TryGetValue(connectionId, out client); |
||||
|
} |
||||
|
|
||||
|
public bool Contains(string connectionId) |
||||
|
{ |
||||
|
return Clients.ContainsKey(connectionId); |
||||
|
} |
||||
|
|
||||
|
public IReadOnlyList<IOnlineClient> GetAll() |
||||
|
{ |
||||
|
return Clients.Values.ToImmutableList(); |
||||
|
} |
||||
|
} |
||||
|
} |
||||
@ -0,0 +1,66 @@ |
|||||
|
using System; |
||||
|
using System.Collections.Generic; |
||||
|
|
||||
|
namespace LINGYUN.Abp.IM |
||||
|
{ |
||||
|
[Serializable] |
||||
|
public class OnlineClient : IOnlineClient |
||||
|
{ |
||||
|
public object this[string key] |
||||
|
{ |
||||
|
get { return Properties[key]; } |
||||
|
set { Properties[key] = value; } |
||||
|
} |
||||
|
|
||||
|
public string ConnectionId { get; set; } |
||||
|
|
||||
|
public string IpAddress { get; set; } |
||||
|
|
||||
|
public Guid? TenantId { get; set; } |
||||
|
|
||||
|
public Guid? UserId { get; set; } |
||||
|
|
||||
|
public DateTime ConnectTime { get; set; } |
||||
|
|
||||
|
private Dictionary<string, object> _properties; |
||||
|
public Dictionary<string, object> Properties |
||||
|
{ |
||||
|
get { return _properties; } |
||||
|
set |
||||
|
{ |
||||
|
if (value == null) |
||||
|
{ |
||||
|
throw new ArgumentNullException(nameof(value)); |
||||
|
} |
||||
|
|
||||
|
_properties = value; |
||||
|
} |
||||
|
} |
||||
|
|
||||
|
public OnlineClient() |
||||
|
{ |
||||
|
ConnectTime = DateTime.Now; |
||||
|
} |
||||
|
|
||||
|
public OnlineClient(string connectionId, string ipAddress, Guid? tenantId, Guid? userId) |
||||
|
: this() |
||||
|
{ |
||||
|
ConnectionId = connectionId; |
||||
|
IpAddress = ipAddress; |
||||
|
TenantId = tenantId; |
||||
|
UserId = userId; |
||||
|
|
||||
|
Properties = new Dictionary<string, object>(); |
||||
|
} |
||||
|
|
||||
|
public override string ToString() |
||||
|
{ |
||||
|
return string.Concat( |
||||
|
"-- ConnectionId:", ConnectionId, |
||||
|
"-- Connection Time:", ConnectTime, |
||||
|
"-- IpAddress:", IpAddress ?? "::1", |
||||
|
"-- UserId:", UserId.HasValue ? UserId.Value.ToString() : "None", |
||||
|
"-- TenantId:", TenantId.HasValue ? TenantId.Value.ToString() : "None"); |
||||
|
} |
||||
|
} |
||||
|
} |
||||
@ -0,0 +1,20 @@ |
|||||
|
using System; |
||||
|
|
||||
|
namespace LINGYUN.Abp.IM |
||||
|
{ |
||||
|
public class OnlineClientContext |
||||
|
{ |
||||
|
public string ConnectionId { get; } |
||||
|
|
||||
|
public Guid? TenantId { get; } |
||||
|
|
||||
|
public Guid UserId { get; } |
||||
|
|
||||
|
public OnlineClientContext(string connectionId, Guid userId, Guid? tenantId) |
||||
|
{ |
||||
|
UserId = userId; |
||||
|
TenantId = tenantId; |
||||
|
ConnectionId = connectionId; |
||||
|
} |
||||
|
} |
||||
|
} |
||||
@ -0,0 +1,14 @@ |
|||||
|
using System; |
||||
|
|
||||
|
namespace LINGYUN.Abp.IM |
||||
|
{ |
||||
|
public class OnlineClientEventArgs : EventArgs |
||||
|
{ |
||||
|
public IOnlineClient Client { get; } |
||||
|
|
||||
|
public OnlineClientEventArgs(IOnlineClient client) |
||||
|
{ |
||||
|
Client = client; |
||||
|
} |
||||
|
} |
||||
|
} |
||||
@ -0,0 +1,15 @@ |
|||||
|
using JetBrains.Annotations; |
||||
|
|
||||
|
namespace LINGYUN.Abp.IM |
||||
|
{ |
||||
|
public static class OnlineClientExtensions |
||||
|
{ |
||||
|
[CanBeNull] |
||||
|
public static OnlineClientContext ToClientContextOrNull(this IOnlineClient onlineClient) |
||||
|
{ |
||||
|
return onlineClient.UserId.HasValue |
||||
|
? new OnlineClientContext(onlineClient.ConnectionId, onlineClient.UserId.Value, onlineClient.TenantId) |
||||
|
: null; |
||||
|
} |
||||
|
} |
||||
|
} |
||||
@ -0,0 +1,108 @@ |
|||||
|
using JetBrains.Annotations; |
||||
|
using System; |
||||
|
using System.Collections.Generic; |
||||
|
using System.Collections.Immutable; |
||||
|
using System.Linq; |
||||
|
using Volo.Abp; |
||||
|
using Volo.Abp.DependencyInjection; |
||||
|
|
||||
|
namespace LINGYUN.Abp.IM |
||||
|
{ |
||||
|
public class OnlineClientManager : IOnlineClientManager, ISingletonDependency |
||||
|
{ |
||||
|
public event EventHandler<OnlineClientEventArgs> ClientConnected; |
||||
|
public event EventHandler<OnlineClientEventArgs> ClientDisconnected; |
||||
|
|
||||
|
public event EventHandler<OnlineUserEventArgs> UserConnected; |
||||
|
public event EventHandler<OnlineUserEventArgs> UserDisconnected; |
||||
|
|
||||
|
protected IOnlineClientStore Store { get; } |
||||
|
|
||||
|
protected readonly object SyncObj = new object(); |
||||
|
|
||||
|
public OnlineClientManager(IOnlineClientStore store) |
||||
|
{ |
||||
|
Store = store; |
||||
|
} |
||||
|
|
||||
|
public virtual void Add(IOnlineClient client) |
||||
|
{ |
||||
|
lock (SyncObj) |
||||
|
{ |
||||
|
var userWasAlreadyOnline = false; |
||||
|
var context = client.ToClientContextOrNull(); |
||||
|
|
||||
|
if (context != null) |
||||
|
{ |
||||
|
userWasAlreadyOnline = this.IsOnline(context); |
||||
|
} |
||||
|
|
||||
|
Store.Add(client); |
||||
|
|
||||
|
ClientConnected?.Invoke(this, new OnlineClientEventArgs(client)); |
||||
|
|
||||
|
if (context != null && !userWasAlreadyOnline) |
||||
|
{ |
||||
|
UserConnected?.Invoke(this, new OnlineUserEventArgs(context, client)); |
||||
|
} |
||||
|
} |
||||
|
} |
||||
|
|
||||
|
public virtual bool Remove(string connectionId) |
||||
|
{ |
||||
|
lock (SyncObj) |
||||
|
{ |
||||
|
var result = Store.TryRemove(connectionId, out IOnlineClient client); |
||||
|
if (result) |
||||
|
{ |
||||
|
if (UserDisconnected != null) |
||||
|
{ |
||||
|
var context = client.ToClientContextOrNull(); |
||||
|
|
||||
|
if (context != null && !this.IsOnline(context)) |
||||
|
{ |
||||
|
UserDisconnected.Invoke(this, new OnlineUserEventArgs(context, client)); |
||||
|
} |
||||
|
} |
||||
|
|
||||
|
ClientDisconnected?.Invoke(this, new OnlineClientEventArgs(client)); |
||||
|
} |
||||
|
|
||||
|
return result; |
||||
|
} |
||||
|
} |
||||
|
|
||||
|
public virtual IOnlineClient GetByConnectionIdOrNull(string connectionId) |
||||
|
{ |
||||
|
lock (SyncObj) |
||||
|
{ |
||||
|
if (Store.TryGet(connectionId, out IOnlineClient client)) |
||||
|
{ |
||||
|
return client; |
||||
|
} |
||||
|
else |
||||
|
{ |
||||
|
return null; |
||||
|
} |
||||
|
} |
||||
|
} |
||||
|
|
||||
|
public virtual IReadOnlyList<IOnlineClient> GetAllClients() |
||||
|
{ |
||||
|
lock (SyncObj) |
||||
|
{ |
||||
|
return Store.GetAll(); |
||||
|
} |
||||
|
} |
||||
|
|
||||
|
[NotNull] |
||||
|
public virtual IReadOnlyList<IOnlineClient> GetAllByContext([NotNull] OnlineClientContext context) |
||||
|
{ |
||||
|
Check.NotNull(context, nameof(context)); |
||||
|
|
||||
|
return GetAllClients() |
||||
|
.Where(c => c.UserId == context.UserId && c.TenantId == context.TenantId) |
||||
|
.ToImmutableList(); |
||||
|
} |
||||
|
} |
||||
|
} |
||||
@ -0,0 +1,26 @@ |
|||||
|
using JetBrains.Annotations; |
||||
|
using System.Linq; |
||||
|
using Volo.Abp; |
||||
|
|
||||
|
namespace LINGYUN.Abp.IM |
||||
|
{ |
||||
|
public static class OnlineClientManagerExtensions |
||||
|
{ |
||||
|
public static bool IsOnline( |
||||
|
[NotNull] this IOnlineClientManager onlineClientManager, |
||||
|
[NotNull] OnlineClientContext context) |
||||
|
{ |
||||
|
return onlineClientManager.GetAllByContext(context).Any(); |
||||
|
} |
||||
|
|
||||
|
public static bool Remove( |
||||
|
[NotNull] this IOnlineClientManager onlineClientManager, |
||||
|
[NotNull] IOnlineClient client) |
||||
|
{ |
||||
|
Check.NotNull(onlineClientManager, nameof(onlineClientManager)); |
||||
|
Check.NotNull(client, nameof(client)); |
||||
|
|
||||
|
return onlineClientManager.Remove(client.ConnectionId); |
||||
|
} |
||||
|
} |
||||
|
} |
||||
@ -0,0 +1,13 @@ |
|||||
|
namespace LINGYUN.Abp.IM |
||||
|
{ |
||||
|
public class OnlineUserEventArgs : OnlineClientEventArgs |
||||
|
{ |
||||
|
public OnlineClientContext Context { get; } |
||||
|
|
||||
|
public OnlineUserEventArgs(OnlineClientContext context, IOnlineClient client) |
||||
|
: base(client) |
||||
|
{ |
||||
|
Context = context; |
||||
|
} |
||||
|
} |
||||
|
} |
||||
@ -0,0 +1,29 @@ |
|||||
|
<Project Sdk="Microsoft.NET.Sdk"> |
||||
|
|
||||
|
<PropertyGroup> |
||||
|
<TargetFramework>netstandard2.0</TargetFramework> |
||||
|
<RootNamespace /> |
||||
|
</PropertyGroup> |
||||
|
|
||||
|
<ItemGroup> |
||||
|
<None Remove="LINGYUN\Abp\Location\Amap\Localization\Resources\en.json" /> |
||||
|
<None Remove="LINGYUN\Abp\Location\Amap\Localization\Resources\zh-Hans.json" /> |
||||
|
</ItemGroup> |
||||
|
|
||||
|
<ItemGroup> |
||||
|
<EmbeddedResource Include="LINGYUN\Abp\Location\Amap\Localization\Resources\en.json" /> |
||||
|
<EmbeddedResource Include="LINGYUN\Abp\Location\Amap\Localization\Resources\zh-Hans.json" /> |
||||
|
</ItemGroup> |
||||
|
|
||||
|
<ItemGroup> |
||||
|
<PackageReference Include="Microsoft.Extensions.Http.Polly" Version="3.1.2" /> |
||||
|
<PackageReference Include="Volo.Abp.Json" Version="2.8.0" /> |
||||
|
<PackageReference Include="Volo.Abp.Localization" Version="2.8.0" /> |
||||
|
<PackageReference Include="Volo.Abp.Threading" Version="2.8.0" /> |
||||
|
</ItemGroup> |
||||
|
|
||||
|
<ItemGroup> |
||||
|
<ProjectReference Include="..\LINGYUN.Abp.Location\LINGYUN.Abp.Location.csproj" /> |
||||
|
</ItemGroup> |
||||
|
|
||||
|
</Project> |
||||
@ -0,0 +1,42 @@ |
|||||
|
using LINYUN.Abp.Location.Amap.Localization; |
||||
|
using Microsoft.Extensions.DependencyInjection; |
||||
|
using Polly; |
||||
|
using System; |
||||
|
using Volo.Abp.Json; |
||||
|
using Volo.Abp.Localization; |
||||
|
using Volo.Abp.Modularity; |
||||
|
using Volo.Abp.Threading; |
||||
|
using Volo.Abp.VirtualFileSystem; |
||||
|
|
||||
|
namespace LINGYUN.Abp.Location.Amap |
||||
|
{ |
||||
|
[DependsOn( |
||||
|
typeof(AbpLocationModule), |
||||
|
typeof(AbpJsonModule), |
||||
|
typeof(AbpThreadingModule), |
||||
|
typeof(AbpLocalizationModule))] |
||||
|
public class AbpAmapLocationModule : AbpModule |
||||
|
{ |
||||
|
public override void ConfigureServices(ServiceConfigurationContext context) |
||||
|
{ |
||||
|
var configuration = context.Services.GetConfiguration(); |
||||
|
Configure<AmapLocationOptions>(configuration.GetSection("Location:Amap")); |
||||
|
|
||||
|
Configure<AbpVirtualFileSystemOptions>(options => |
||||
|
{ |
||||
|
options.FileSets.AddEmbedded<AbpAmapLocationModule>(); |
||||
|
}); |
||||
|
|
||||
|
Configure<AbpLocalizationOptions>(options => |
||||
|
{ |
||||
|
options.Resources |
||||
|
.Add<AmapLocationResource>("en") |
||||
|
.AddVirtualJson("/LINGYUN/Abp/Location/Amap/Localization/Resources"); |
||||
|
}); |
||||
|
|
||||
|
context.Services.AddHttpClient(AmapHttpConsts.HttpClientName) |
||||
|
.AddTransientHttpErrorPolicy(builder => |
||||
|
builder.WaitAndRetryAsync(3, i => TimeSpan.FromSeconds(Math.Pow(2, i)))); |
||||
|
} |
||||
|
} |
||||
|
} |
||||
@ -0,0 +1,104 @@ |
|||||
|
using Newtonsoft.Json; |
||||
|
|
||||
|
namespace LINGYUN.Abp.Location.Amap |
||||
|
{ |
||||
|
/// <summary>
|
||||
|
/// 高德地图的返回参数格式真的奇葩
|
||||
|
/// 弃用了
|
||||
|
/// </summary>
|
||||
|
public class AmapGeocode |
||||
|
{ |
||||
|
/// <summary>
|
||||
|
/// 结构化地址信息
|
||||
|
/// 省份+城市+区县+城镇+乡村+街道+门牌号码
|
||||
|
/// </summary>
|
||||
|
[JsonProperty("formatted_address")] |
||||
|
public string Address { get; set; } |
||||
|
|
||||
|
/// <summary>
|
||||
|
/// 国家
|
||||
|
/// 国内地址默认返回中国
|
||||
|
/// </summary>
|
||||
|
[JsonProperty("country")] |
||||
|
public string Country { get; set; } |
||||
|
|
||||
|
/// <summary>
|
||||
|
/// 地址所在的省份名
|
||||
|
/// 例如:北京市。此处需要注意的是,中国的四大直辖市也算作省级单位。
|
||||
|
/// </summary>
|
||||
|
[JsonProperty("province")] |
||||
|
public string Province { get; set; } |
||||
|
|
||||
|
/// <summary>
|
||||
|
/// 地址所在的城市名
|
||||
|
/// 例如:北京市
|
||||
|
/// </summary>
|
||||
|
[JsonProperty("city")] |
||||
|
public string City { get; set; } |
||||
|
|
||||
|
/// <summary>
|
||||
|
/// 城市编码
|
||||
|
/// 例如:010
|
||||
|
/// </summary>
|
||||
|
[JsonProperty("citycode")] |
||||
|
public string CityCode { get; set; } |
||||
|
|
||||
|
/// <summary>
|
||||
|
/// 地址所在的区
|
||||
|
/// 例如:朝阳区
|
||||
|
/// </summary>
|
||||
|
[JsonProperty("district")] |
||||
|
public string District { get; set; } |
||||
|
|
||||
|
/// <summary>
|
||||
|
/// 坐标点所在乡镇/街道(此街道为社区街道,不是道路信息)
|
||||
|
/// 例如:燕园街道
|
||||
|
/// </summary>
|
||||
|
public string[] TownShip { get; set; } = new string[0]; |
||||
|
|
||||
|
/// <summary>
|
||||
|
/// 社区信息列表
|
||||
|
/// </summary>
|
||||
|
public NeighBorHood NeighBorHood { get; set; } = new NeighBorHood(); |
||||
|
|
||||
|
/// <summary>
|
||||
|
/// 楼信息列表
|
||||
|
/// </summary>
|
||||
|
public Building Building { get; set; } = new Building(); |
||||
|
|
||||
|
/// <summary>
|
||||
|
/// 街道
|
||||
|
/// 例如:阜通东大街
|
||||
|
/// </summary>
|
||||
|
[JsonProperty("street")] |
||||
|
public string[] Street { get; set; } = new string[0]; |
||||
|
|
||||
|
/// <summary>
|
||||
|
/// 门牌
|
||||
|
/// 例如:6号
|
||||
|
/// </summary>
|
||||
|
[JsonProperty("number")] |
||||
|
public string[] Number { get; set; } = new string[0]; |
||||
|
|
||||
|
/// <summary>
|
||||
|
/// 区域编码
|
||||
|
/// 例如:110101
|
||||
|
/// </summary>
|
||||
|
[JsonProperty("adcode")] |
||||
|
public string Adcode { get; set; } |
||||
|
|
||||
|
/// <summary>
|
||||
|
/// 坐标点
|
||||
|
/// 经度,纬度
|
||||
|
/// </summary>
|
||||
|
[JsonProperty("location")] |
||||
|
public string Location { get; set; } |
||||
|
|
||||
|
/// <summary>
|
||||
|
/// 匹配级别
|
||||
|
/// 例如:朝阳区
|
||||
|
/// </summary>
|
||||
|
[JsonProperty("level")] |
||||
|
public string Level { get; set; } |
||||
|
} |
||||
|
} |
||||
@ -0,0 +1,7 @@ |
|||||
|
namespace LINGYUN.Abp.Location.Amap |
||||
|
{ |
||||
|
public class AmapHttpConsts |
||||
|
{ |
||||
|
public const string HttpClientName = "AmapLocationHttpClient"; |
||||
|
} |
||||
|
} |
||||
@ -0,0 +1,206 @@ |
|||||
|
using LINYUN.Abp.Location.Amap.Localization; |
||||
|
using Microsoft.Extensions.DependencyInjection; |
||||
|
using Microsoft.Extensions.Localization; |
||||
|
using Microsoft.Extensions.Options; |
||||
|
using System; |
||||
|
using System.Net.Http; |
||||
|
using System.Text; |
||||
|
using System.Threading; |
||||
|
using System.Threading.Tasks; |
||||
|
using Volo.Abp; |
||||
|
using Volo.Abp.Json; |
||||
|
using Volo.Abp.Threading; |
||||
|
using Volo.Abp.DependencyInjection; |
||||
|
using System.Linq; |
||||
|
using System.Collections.Generic; |
||||
|
|
||||
|
namespace LINGYUN.Abp.Location.Amap |
||||
|
{ |
||||
|
public class AmapHttpRequestClient : ITransientDependency |
||||
|
{ |
||||
|
protected AmapLocationOptions Options { get; } |
||||
|
|
||||
|
protected IServiceProvider ServiceProvider { get; } |
||||
|
|
||||
|
protected IJsonSerializer JsonSerializer { get; } |
||||
|
|
||||
|
protected IHttpClientFactory HttpClientFactory { get; } |
||||
|
|
||||
|
protected ICancellationTokenProvider CancellationTokenProvider { get; } |
||||
|
|
||||
|
public AmapHttpRequestClient( |
||||
|
IJsonSerializer jsonSerializer, |
||||
|
IServiceProvider serviceProvider, |
||||
|
IOptions<AmapLocationOptions> options, |
||||
|
IHttpClientFactory httpClientFactory, |
||||
|
ICancellationTokenProvider cancellationTokenProvider) |
||||
|
{ |
||||
|
Options = options.Value; |
||||
|
JsonSerializer = jsonSerializer; |
||||
|
ServiceProvider = serviceProvider; |
||||
|
HttpClientFactory = httpClientFactory; |
||||
|
CancellationTokenProvider = cancellationTokenProvider; |
||||
|
} |
||||
|
|
||||
|
public virtual async Task<GecodeLocation> PositiveAsync(AmapPositiveHttpRequestParamter requestParamter) |
||||
|
{ |
||||
|
var client = HttpClientFactory.CreateClient(AmapHttpConsts.HttpClientName); |
||||
|
var requestUrlBuilder = new StringBuilder(128); |
||||
|
requestUrlBuilder.Append("http://restapi.amap.com/v3/geocode/geo"); |
||||
|
requestUrlBuilder.AppendFormat("?key={0}", Options.ApiKey); |
||||
|
requestUrlBuilder.AppendFormat("&address={0}", requestParamter.Address); |
||||
|
if (!requestParamter.City.IsNullOrWhiteSpace()) |
||||
|
{ |
||||
|
requestUrlBuilder.AppendFormat("&city={0}", requestParamter.City); |
||||
|
} |
||||
|
if (!requestParamter.Output.IsNullOrWhiteSpace()) |
||||
|
{ |
||||
|
requestUrlBuilder.AppendFormat("&output={0}", requestParamter.Output); |
||||
|
} |
||||
|
if (!requestParamter.Sig.IsNullOrWhiteSpace()) |
||||
|
{ |
||||
|
requestUrlBuilder.AppendFormat("&sig={0}", requestParamter.Sig); |
||||
|
} |
||||
|
requestUrlBuilder.AppendFormat("&batch={0}", requestParamter.Batch); |
||||
|
|
||||
|
var requestMessage = new HttpRequestMessage(HttpMethod.Get, requestUrlBuilder.ToString()); |
||||
|
|
||||
|
var response = await client.SendAsync(requestMessage, GetCancellationToken()); |
||||
|
|
||||
|
if (!response.IsSuccessStatusCode) |
||||
|
{ |
||||
|
throw new AbpException($"Amap request service returns error! HttpStatusCode: {response.StatusCode}, ReasonPhrase: {response.ReasonPhrase}"); |
||||
|
} |
||||
|
|
||||
|
var resultContent = await response.Content.ReadAsStringAsync(); |
||||
|
var amapResponse = JsonSerializer.Deserialize<AmapPositiveHttpResponse>(resultContent); |
||||
|
|
||||
|
if (!amapResponse.IsSuccess()) |
||||
|
{ |
||||
|
var localizerFactory = ServiceProvider.GetRequiredService<IStringLocalizerFactory>(); |
||||
|
var localizerError = amapResponse.GetErrorMessage().Localize(localizerFactory); |
||||
|
if (Options.VisableErrorToClient) |
||||
|
{ |
||||
|
var localizer = ServiceProvider.GetRequiredService<IStringLocalizer<AmapLocationResource>>(); |
||||
|
localizerError = localizer["ResolveLocationFailed", localizerError]; |
||||
|
throw new UserFriendlyException(localizerError); |
||||
|
} |
||||
|
throw new AbpException($"Resolution address failed:{localizerError}!"); |
||||
|
} |
||||
|
if(amapResponse.Count <= 0) |
||||
|
{ |
||||
|
var localizer = ServiceProvider.GetRequiredService<IStringLocalizer<AmapLocationResource>>(); |
||||
|
var localizerError = localizer["ResolveLocationZero"]; |
||||
|
if (Options.VisableErrorToClient) |
||||
|
{ |
||||
|
throw new UserFriendlyException(localizerError); |
||||
|
} |
||||
|
throw new AbpException(localizerError); |
||||
|
} |
||||
|
|
||||
|
var locations = amapResponse.Geocodes[0].Location.Split(","); |
||||
|
var postiveLocation = new GecodeLocation |
||||
|
{ |
||||
|
Longitude = double.Parse(locations[0]), |
||||
|
Latitude = double.Parse(locations[1]), |
||||
|
Level = amapResponse.Geocodes[0].Level |
||||
|
}; |
||||
|
postiveLocation.AddAdditional("Geocodes", amapResponse.Geocodes); |
||||
|
|
||||
|
return postiveLocation; |
||||
|
} |
||||
|
|
||||
|
public virtual async Task<ReGeocodeLocation> InverseAsync(AmapInverseHttpRequestParamter requestParamter) |
||||
|
{ |
||||
|
if(requestParamter.Locations.Length > 20) |
||||
|
{ |
||||
|
var localizer = ServiceProvider.GetRequiredService<IStringLocalizer<AmapLocationResource>>(); |
||||
|
var localizerError = localizer["SupportsResolveAddress", 20]; |
||||
|
localizerError = localizer["ResolveLocationFailed", localizerError]; |
||||
|
if (Options.VisableErrorToClient) |
||||
|
{ |
||||
|
throw new UserFriendlyException(localizerError); |
||||
|
} |
||||
|
throw new AbpException($"Resolution address failed:{localizerError}!"); |
||||
|
} |
||||
|
var client = HttpClientFactory.CreateClient(AmapHttpConsts.HttpClientName); |
||||
|
var requestUrlBuilder = new StringBuilder(128); |
||||
|
requestUrlBuilder.Append("http://restapi.amap.com/v3/geocode/regeo"); |
||||
|
requestUrlBuilder.AppendFormat("?key={0}", Options.ApiKey); |
||||
|
requestUrlBuilder.AppendFormat("&batch={0}", requestParamter.Batch); |
||||
|
requestUrlBuilder.AppendFormat("&output={0}", requestParamter.Output); |
||||
|
requestUrlBuilder.AppendFormat("&radius={0}", requestParamter.Radius); |
||||
|
requestUrlBuilder.AppendFormat("&extensions={0}", requestParamter.Extensions); |
||||
|
requestUrlBuilder.AppendFormat("&homeorcorp={0}", requestParamter.HomeOrCorp); |
||||
|
requestUrlBuilder.AppendFormat("&location="); |
||||
|
for(int i = 0; i < requestParamter.Locations.Length; i++) |
||||
|
{ |
||||
|
requestUrlBuilder.AppendFormat("{0},{1}", Math.Round(requestParamter.Locations[i].Longitude, 6), |
||||
|
Math.Round(requestParamter.Locations[i].Latitude, 6)); |
||||
|
if (i < requestParamter.Locations.Length - 1) |
||||
|
{ |
||||
|
requestUrlBuilder.Append("|"); |
||||
|
} |
||||
|
} |
||||
|
if (!requestParamter.PoiType.IsNullOrWhiteSpace()) |
||||
|
{ |
||||
|
requestUrlBuilder.AppendFormat("&poitype={0}", requestParamter.PoiType); |
||||
|
} |
||||
|
if (!requestParamter.PoiType.IsNullOrWhiteSpace()) |
||||
|
{ |
||||
|
requestUrlBuilder.AppendFormat("&poitype={0}", requestParamter.PoiType); |
||||
|
} |
||||
|
if (!requestParamter.Sig.IsNullOrWhiteSpace()) |
||||
|
{ |
||||
|
requestUrlBuilder.AppendFormat("&sig={0}", requestParamter.Sig); |
||||
|
} |
||||
|
if (requestParamter.RoadLevel.HasValue) |
||||
|
{ |
||||
|
requestUrlBuilder.AppendFormat("&roadlevel={0}", requestParamter.RoadLevel); |
||||
|
} |
||||
|
|
||||
|
var requestMessage = new HttpRequestMessage(HttpMethod.Get, requestUrlBuilder.ToString()); |
||||
|
|
||||
|
var response = await client.SendAsync(requestMessage, GetCancellationToken()); |
||||
|
|
||||
|
if (!response.IsSuccessStatusCode) |
||||
|
{ |
||||
|
throw new AbpException($"Amap request service returns error! HttpStatusCode: {response.StatusCode}, ReasonPhrase: {response.ReasonPhrase}"); |
||||
|
} |
||||
|
|
||||
|
var resultContent = await response.Content.ReadAsStringAsync(); |
||||
|
var amapResponse = JsonSerializer.Deserialize<AmapInverseLocationResponse>(resultContent); |
||||
|
|
||||
|
if (!amapResponse.IsSuccess()) |
||||
|
{ |
||||
|
var localizerFactory = ServiceProvider.GetRequiredService<IStringLocalizerFactory>(); |
||||
|
var localizerError = amapResponse.GetErrorMessage().Localize(localizerFactory); |
||||
|
if (Options.VisableErrorToClient) |
||||
|
{ |
||||
|
var localizer = ServiceProvider.GetRequiredService<IStringLocalizer<AmapLocationResource>>(); |
||||
|
localizerError = localizer["ResolveLocationFailed", localizerError]; |
||||
|
throw new UserFriendlyException(localizerError); |
||||
|
} |
||||
|
throw new AbpException($"Resolution address failed:{localizerError}!"); |
||||
|
} |
||||
|
var inverseLocation = new ReGeocodeLocation |
||||
|
{ |
||||
|
Street = amapResponse.Regeocode.AddressComponent.StreetNumber.Street, |
||||
|
AdCode = amapResponse.Regeocode.AddressComponent.AdCode, |
||||
|
Address = amapResponse.Regeocode.Address, |
||||
|
City = amapResponse.Regeocode.AddressComponent.City.JoinAsString(","), |
||||
|
Country = amapResponse.Regeocode.AddressComponent.Country, |
||||
|
District = amapResponse.Regeocode.AddressComponent.District, |
||||
|
Number = amapResponse.Regeocode.AddressComponent.StreetNumber.Number, |
||||
|
Province = amapResponse.Regeocode.AddressComponent.Province, |
||||
|
Town = amapResponse.Regeocode.AddressComponent.TownShip.JoinAsString(" ") |
||||
|
}; |
||||
|
return inverseLocation; |
||||
|
} |
||||
|
|
||||
|
protected virtual CancellationToken GetCancellationToken() |
||||
|
{ |
||||
|
return CancellationTokenProvider.Token; |
||||
|
} |
||||
|
} |
||||
|
} |
||||
@ -0,0 +1,121 @@ |
|||||
|
using LINYUN.Abp.Location.Amap.Localization; |
||||
|
using Volo.Abp; |
||||
|
using Volo.Abp.Localization; |
||||
|
|
||||
|
namespace LINGYUN.Abp.Location.Amap |
||||
|
{ |
||||
|
public abstract class AmapHttpResponse |
||||
|
{ |
||||
|
/// <summary>
|
||||
|
/// 返回结果状态值
|
||||
|
/// </summary>
|
||||
|
/// <remarks>
|
||||
|
/// 返回值为 0 或 1,0 表示请求失败;1 表示请求成功。
|
||||
|
/// </remarks>
|
||||
|
public int Status { get; set; } |
||||
|
/// <summary>
|
||||
|
/// 返回状态说明
|
||||
|
/// </summary>
|
||||
|
/// <remarks>
|
||||
|
/// 当 status 为 0 时,info 会返回具体错误原因,否则返回“OK”。
|
||||
|
/// </remarks>
|
||||
|
public string Info { get; set; } |
||||
|
|
||||
|
/// <summary>
|
||||
|
/// 返回状态码
|
||||
|
/// </summary>
|
||||
|
public string InfoCode { get; set; } |
||||
|
|
||||
|
public bool IsSuccess() |
||||
|
{ |
||||
|
return Status == 1; |
||||
|
} |
||||
|
|
||||
|
public ILocalizableString GetErrorMessage() |
||||
|
{ |
||||
|
switch (Info) |
||||
|
{ |
||||
|
case "OK": |
||||
|
return LocalizableString.Create<AmapLocationResource>("OK"); |
||||
|
case "INVALID_USER_KEY": |
||||
|
return LocalizableString.Create<AmapLocationResource>("INVALID_USER_KEY"); |
||||
|
case "SERVICE_NOT_AVAILABLE": |
||||
|
return LocalizableString.Create<AmapLocationResource>("SERVICE_NOT_AVAILABLE"); |
||||
|
case "DAILY_QUERY_OVER_LIMIT": |
||||
|
return LocalizableString.Create<AmapLocationResource>("DAILY_QUERY_OVER_LIMIT"); |
||||
|
case "ACCESS_TOO_FREQUENT": |
||||
|
return LocalizableString.Create<AmapLocationResource>("ACCESS_TOO_FREQUENT"); |
||||
|
case "INVALID_USER_IP": |
||||
|
return LocalizableString.Create<AmapLocationResource>("INVALID_USER_IP"); |
||||
|
case "INVALID_USER_DOMAIN": |
||||
|
return LocalizableString.Create<AmapLocationResource>("INVALID_USER_DOMAIN"); |
||||
|
case "INVALID_USER_SIGNATURE": |
||||
|
return LocalizableString.Create<AmapLocationResource>("INVALID_USER_SIGNATURE"); |
||||
|
case "INVALID_USER_SCODE": |
||||
|
return LocalizableString.Create<AmapLocationResource>("INVALID_USER_SCODE"); |
||||
|
case "USERKEY_PLAT_NOMATCH": |
||||
|
return LocalizableString.Create<AmapLocationResource>("USERKEY_PLAT_NOMATCH"); |
||||
|
case "IP_QUERY_OVER_LIMIT": |
||||
|
return LocalizableString.Create<AmapLocationResource>("IP_QUERY_OVER_LIMIT"); |
||||
|
case "NOT_SUPPORT_HTTPS": |
||||
|
return LocalizableString.Create<AmapLocationResource>("NOT_SUPPORT_HTTPS"); |
||||
|
case "INSUFFICIENT_PRIVILEGES": |
||||
|
return LocalizableString.Create<AmapLocationResource>("INSUFFICIENT_PRIVILEGES"); |
||||
|
case "USER_KEY_RECYCLED": |
||||
|
return LocalizableString.Create<AmapLocationResource>("USER_KEY_RECYCLED"); |
||||
|
case "QPS_HAS_EXCEEDED_THE_LIMIT": |
||||
|
return LocalizableString.Create<AmapLocationResource>("QPS_HAS_EXCEEDED_THE_LIMIT"); |
||||
|
case "GATEWAY_TIMEOUT": |
||||
|
return LocalizableString.Create<AmapLocationResource>("GATEWAY_TIMEOUT"); |
||||
|
case "SERVER_IS_BUSY": |
||||
|
return LocalizableString.Create<AmapLocationResource>("SERVER_IS_BUSY"); |
||||
|
case "RESOURCE_UNAVAILABLE": |
||||
|
return LocalizableString.Create<AmapLocationResource>("RESOURCE_UNAVAILABLE"); |
||||
|
case "CQPS_HAS_EXCEEDED_THE_LIMIT": |
||||
|
return LocalizableString.Create<AmapLocationResource>("CQPS_HAS_EXCEEDED_THE_LIMIT"); |
||||
|
case "CKQPS_HAS_EXCEEDED_THE_LIMIT": |
||||
|
return LocalizableString.Create<AmapLocationResource>("CKQPS_HAS_EXCEEDED_THE_LIMIT"); |
||||
|
case "CIQPS_HAS_EXCEEDED_THE_LIMIT": |
||||
|
return LocalizableString.Create<AmapLocationResource>("CIQPS_HAS_EXCEEDED_THE_LIMIT"); |
||||
|
case "CIKQPS_HAS_EXCEEDED_THE_LIMIT": |
||||
|
return LocalizableString.Create<AmapLocationResource>("CIKQPS_HAS_EXCEEDED_THE_LIMIT"); |
||||
|
case "KQPS_HAS_EXCEEDED_THE_LIMIT": |
||||
|
return LocalizableString.Create<AmapLocationResource>("KQPS_HAS_EXCEEDED_THE_LIMIT"); |
||||
|
case "ABROAD_DAILY_QUERY_OVER_LIMIT": |
||||
|
return LocalizableString.Create<AmapLocationResource>("ABROAD_DAILY_QUERY_OVER_LIMIT"); |
||||
|
case "INVALID_PARAMS": |
||||
|
return LocalizableString.Create<AmapLocationResource>("INVALID_PARAMS"); |
||||
|
case "MISSING_REQUIRED_PARAMS": |
||||
|
return LocalizableString.Create<AmapLocationResource>("MISSING_REQUIRED_PARAMS"); |
||||
|
case "ILLEGAL_REQUEST": |
||||
|
return LocalizableString.Create<AmapLocationResource>("ILLEGAL_REQUEST"); |
||||
|
case "UNKNOWN_ERROR": |
||||
|
return LocalizableString.Create<AmapLocationResource>("UNKNOWN_ERROR"); |
||||
|
case "INSUFFICIENT_ABROAD_PRIVILEGES": |
||||
|
return LocalizableString.Create<AmapLocationResource>("INSUFFICIENT_ABROAD_PRIVILEGES"); |
||||
|
case "ILLEGAL_CONTENT": |
||||
|
return LocalizableString.Create<AmapLocationResource>("ILLEGAL_CONTENT"); |
||||
|
case "OUT_OF_SERVICE": |
||||
|
return LocalizableString.Create<AmapLocationResource>("OUT_OF_SERVICE"); |
||||
|
case "NO_ROADS_NEARBY": |
||||
|
return LocalizableString.Create<AmapLocationResource>("NO_ROADS_NEARBY"); |
||||
|
case "ROUTE_FAIL": |
||||
|
return LocalizableString.Create<AmapLocationResource>("ROUTE_FAIL"); |
||||
|
case "OVER_DIRECTION_RANGE": |
||||
|
return LocalizableString.Create<AmapLocationResource>("OVER_DIRECTION_RANGE"); |
||||
|
case "ENGINE_RESPONSE_DATA_ERROR": |
||||
|
return LocalizableString.Create<AmapLocationResource>("ENGINE_RESPONSE_DATA_ERROR"); |
||||
|
case "QUOTA_PLAN_RUN_OUT": |
||||
|
return LocalizableString.Create<AmapLocationResource>("QUOTA_PLAN_RUN_OUT"); |
||||
|
case "GEOFENCE_MAX_COUNT_REACHED": |
||||
|
return LocalizableString.Create<AmapLocationResource>("GEOFENCE_MAX_COUNT_REACHED"); |
||||
|
case "SERVICE_EXPIRED": |
||||
|
return LocalizableString.Create<AmapLocationResource>("SERVICE_EXPIRED"); |
||||
|
case "ABROAD_QUOTA_PLAN_RUN_OUT": |
||||
|
return LocalizableString.Create<AmapLocationResource>("ABROAD_QUOTA_PLAN_RUN_OUT"); |
||||
|
default: |
||||
|
throw new AbpException($"{Info} - no error code define!"); |
||||
|
} |
||||
|
} |
||||
|
} |
||||
|
} |
||||
@ -0,0 +1,72 @@ |
|||||
|
namespace LINGYUN.Abp.Location.Amap |
||||
|
{ |
||||
|
public class AmapInverseHttpRequestParamter |
||||
|
{ |
||||
|
/// <summary>
|
||||
|
/// 经纬度坐标
|
||||
|
///
|
||||
|
/// 传入内容规则:经度在前,纬度在后,经纬度间以“,”分割,经纬度小数点后不要超过 6 位。
|
||||
|
/// 如果需要解析多个经纬度的话,请用"|"进行间隔,并且将 batch 参数设置为 true,最多支持传入 20 对坐标点。
|
||||
|
/// 每对点坐标之间用"|"分割。
|
||||
|
/// </summary>
|
||||
|
public Location[] Locations { get; set; } = new Location[0]; |
||||
|
/// <summary>
|
||||
|
/// 返回附近POI类型
|
||||
|
/// 以下内容需要 extensions 参数为 all 时才生效。
|
||||
|
/// 逆地理编码在进行坐标解析之后不仅可以返回地址描述,也可以返回经纬度附近符合限定要求的POI内容(在 extensions 字段值为 all 时才会返回POI内容)。
|
||||
|
/// 设置 POI 类型参数相当于为上述操作限定要求。
|
||||
|
///
|
||||
|
/// 参数仅支持传入POI TYPECODE,可以传入多个POI TYPECODE,相互之间用“|”分隔。
|
||||
|
/// 该参数在 batch 取值为 true 时不生效。获取 POI TYPECODE
|
||||
|
/// </summary>
|
||||
|
public string PoiType { get; set; } |
||||
|
/// <summary>
|
||||
|
/// 搜索半径
|
||||
|
/// radius取值范围在0~3000,默认是1000。单位:米
|
||||
|
/// </summary>
|
||||
|
public short Radius { get; set; } = 1000; |
||||
|
/// <summary>
|
||||
|
/// 返回结果控制
|
||||
|
/// extensions 参数默认取值是 base,也就是返回基本地址信息;
|
||||
|
/// extensions 参数取值为 all 时会返回基本地址信息、附近 POI 内容、道路信息以及道路交叉口信息。
|
||||
|
/// </summary>
|
||||
|
public string Extensions { get; set; } = "base"; |
||||
|
/// <summary>
|
||||
|
/// 批量查询控制
|
||||
|
/// batch 参数设置为 true 时进行批量查询操作,最多支持 20 个经纬度点进行批量地址查询操作。
|
||||
|
/// batch 参数设置为 false 时进行单点查询,此时即使传入多个经纬度也只返回第一个经纬度的地址解析查询结果。
|
||||
|
/// </summary>
|
||||
|
public bool Batch { get; set; } = false; |
||||
|
/// <summary>
|
||||
|
/// 道路等级
|
||||
|
///
|
||||
|
/// 以下内容需要 extensions 参数为 all 时才生效。
|
||||
|
/// 可选值:0,1
|
||||
|
/// 当roadlevel=0时,显示所有道路
|
||||
|
/// 当roadlevel = 1时,过滤非主干道路,仅输出主干道路数据
|
||||
|
/// </summary>
|
||||
|
public sbyte? RoadLevel { get; set; } |
||||
|
/// <summary>
|
||||
|
/// 数字签名
|
||||
|
/// </summary>
|
||||
|
public string Sig { get; set; } |
||||
|
/// <summary>
|
||||
|
/// 返回数据格式类型
|
||||
|
/// 可选输入内容包括:JSON,XML。设置 JSON 返回结果数据将会以JSON结构构成;
|
||||
|
/// 如果设置 XML 返回结果数据将以 XML 结构构成。
|
||||
|
/// </summary>
|
||||
|
public string Output { get; set; } = "JSON"; |
||||
|
/// <summary>
|
||||
|
/// 是否优化POI返回顺序
|
||||
|
/// 以下内容需要 extensions 参数为 all 时才生效。
|
||||
|
/// homeorcorp 参数的设置可以影响召回 POI 内容的排序策略,目前提供三个可选参数:
|
||||
|
///
|
||||
|
/// 0:不对召回的排序策略进行干扰。
|
||||
|
///
|
||||
|
/// 1:综合大数据分析将居家相关的 POI 内容优先返回,即优化返回结果中 pois 字段的poi顺序。
|
||||
|
///
|
||||
|
/// 2:综合大数据分析将公司相关的 POI 内容优先返回,即优化返回结果中 pois 字段的poi顺序。
|
||||
|
/// </summary>
|
||||
|
public sbyte HomeOrCorp { get; set; } = 0; |
||||
|
} |
||||
|
} |
||||
@ -0,0 +1,14 @@ |
|||||
|
namespace LINGYUN.Abp.Location.Amap |
||||
|
{ |
||||
|
/// <summary>
|
||||
|
/// 逆地址解析结果
|
||||
|
/// </summary>
|
||||
|
public class AmapInverseLocationResponse : AmapHttpResponse |
||||
|
{ |
||||
|
public AmapRegeocode Regeocode { get; set; } |
||||
|
public AmapInverseLocationResponse() |
||||
|
{ |
||||
|
Regeocode = new AmapRegeocode(); |
||||
|
} |
||||
|
} |
||||
|
} |
||||
@ -0,0 +1,8 @@ |
|||||
|
namespace LINGYUN.Abp.Location.Amap |
||||
|
{ |
||||
|
public class AmapLocationOptions |
||||
|
{ |
||||
|
public string ApiKey { get; set; } |
||||
|
public bool VisableErrorToClient { get; set; } = false; |
||||
|
} |
||||
|
} |
||||
@ -0,0 +1,41 @@ |
|||||
|
using Microsoft.Extensions.DependencyInjection; |
||||
|
using System.Threading.Tasks; |
||||
|
using Volo.Abp.DependencyInjection; |
||||
|
|
||||
|
namespace LINGYUN.Abp.Location.Amap |
||||
|
{ |
||||
|
[Dependency(ServiceLifetime.Transient)] |
||||
|
[ExposeServices(typeof(ILocationResolveProvider))] |
||||
|
public class AmapLocationResolveProvider : ILocationResolveProvider |
||||
|
{ |
||||
|
protected AmapHttpRequestClient AmapHttpRequestClient { get; } |
||||
|
|
||||
|
public AmapLocationResolveProvider(AmapHttpRequestClient amapHttpRequestClient) |
||||
|
{ |
||||
|
AmapHttpRequestClient = amapHttpRequestClient; |
||||
|
} |
||||
|
|
||||
|
public async Task<ReGeocodeLocation> ReGeocodeAsync(double lat, double lng, int radius = 50) |
||||
|
{ |
||||
|
var inverseRequestPramter = new AmapInverseHttpRequestParamter(); |
||||
|
inverseRequestPramter.Locations = new Location[1] |
||||
|
{ |
||||
|
new Location |
||||
|
{ |
||||
|
Latitude = lat, |
||||
|
Longitude = lng |
||||
|
} |
||||
|
}; |
||||
|
return await AmapHttpRequestClient.InverseAsync(inverseRequestPramter); |
||||
|
} |
||||
|
|
||||
|
public async Task<GecodeLocation> GeocodeAsync(string address, string city) |
||||
|
{ |
||||
|
var positiceRequestParamter = new AmapPositiveHttpRequestParamter |
||||
|
{ |
||||
|
Address = address |
||||
|
}; |
||||
|
return await AmapHttpRequestClient.PositiveAsync(positiceRequestParamter); |
||||
|
} |
||||
|
} |
||||
|
} |
||||
@ -0,0 +1,45 @@ |
|||||
|
using JetBrains.Annotations; |
||||
|
|
||||
|
namespace LINGYUN.Abp.Location.Amap |
||||
|
{ |
||||
|
/// <summary>
|
||||
|
/// 高德地图正地址解析请求参数
|
||||
|
/// </summary>
|
||||
|
public class AmapPositiveHttpRequestParamter |
||||
|
{ |
||||
|
/// <summary>
|
||||
|
/// 结构化的地址
|
||||
|
/// 规则遵循:国家、省份、城市、区县、城镇、乡村、街道、门牌号码、屋邨、大厦,如:北京市朝阳区阜通东大街6号。
|
||||
|
/// 如果需要解析多个地址的话,请用"|"进行间隔,并且将 batch 参数设置为 true,最多支持 10 个地址进进行"|"分割形式的请求
|
||||
|
/// </summary>
|
||||
|
[NotNull] |
||||
|
public string Address { get; set; } |
||||
|
/// <summary>
|
||||
|
/// 城市
|
||||
|
/// 可选输入内容包括:指定城市的中文(如北京)、指定城市的中文全拼(beijing)、citycode(010)、adcode(110000),不支持县级市。
|
||||
|
/// 当指定城市查询内容为空时,会进行全国范围内的地址转换检索。
|
||||
|
/// </summary>
|
||||
|
[CanBeNull] |
||||
|
public string City { get; set; } |
||||
|
/// <summary>
|
||||
|
/// 批量查询控制
|
||||
|
/// batch 参数设置为 true 时进行批量查询操作,最多支持 10 个地址进行批量查询。
|
||||
|
/// batch 参数设置为 false 时进行单点查询,此时即使传入多个地址也只返回第一个地址的解析查询结果
|
||||
|
/// </summary>
|
||||
|
[CanBeNull] |
||||
|
public bool Batch { get; set; } = false; |
||||
|
/// <summary>
|
||||
|
/// 数字签名
|
||||
|
/// </summary>
|
||||
|
[CanBeNull] |
||||
|
|
||||
|
public string Sig { get; set; } |
||||
|
/// <summary>
|
||||
|
/// 返回数据格式类型
|
||||
|
/// 可选输入内容包括:JSON,XML。设置 JSON 返回结果数据将会以JSON结构构成;
|
||||
|
/// 如果设置 XML 返回结果数据将以 XML 结构构成。
|
||||
|
/// </summary>
|
||||
|
[CanBeNull] |
||||
|
public string Output { get; set; } = "JSON"; |
||||
|
} |
||||
|
} |
||||
@ -0,0 +1,29 @@ |
|||||
|
using Newtonsoft.Json; |
||||
|
|
||||
|
namespace LINGYUN.Abp.Location.Amap |
||||
|
{ |
||||
|
/// <summary>
|
||||
|
/// 正地址解析结果
|
||||
|
/// </summary>
|
||||
|
public class AmapPositiveHttpResponse : AmapHttpResponse |
||||
|
{ |
||||
|
/// <summary>
|
||||
|
/// 返回结果数目
|
||||
|
/// </summary>
|
||||
|
/// <remarks>
|
||||
|
/// 返回结果的个数。
|
||||
|
/// </remarks>
|
||||
|
public int Count { get; set; } |
||||
|
|
||||
|
/// <summary>
|
||||
|
/// 地理编码信息列表
|
||||
|
/// </summary>
|
||||
|
[JsonProperty("geocodes")] |
||||
|
public AmapGeocode[] Geocodes { get; set; } |
||||
|
|
||||
|
public AmapPositiveHttpResponse() |
||||
|
{ |
||||
|
Geocodes = new AmapGeocode[0]; |
||||
|
} |
||||
|
} |
||||
|
} |
||||
@ -0,0 +1,366 @@ |
|||||
|
using Newtonsoft.Json; |
||||
|
using System.Collections.Generic; |
||||
|
|
||||
|
namespace LINGYUN.Abp.Location.Amap |
||||
|
{ |
||||
|
public class AmapRegeocode |
||||
|
{ |
||||
|
/// <summary>
|
||||
|
/// 结构化地址信息
|
||||
|
/// 省份+城市+区县+城镇+乡村+街道+门牌号码
|
||||
|
/// </summary>
|
||||
|
[JsonProperty("formatted_address")] |
||||
|
public string Address { get; set; } |
||||
|
/// <summary>
|
||||
|
/// 地址元素列表
|
||||
|
/// </summary>
|
||||
|
public AddressComponent AddressComponent { get; set; } |
||||
|
/// <summary>
|
||||
|
/// 道路信息列表
|
||||
|
/// 请求参数 extensions 为 all 时返回
|
||||
|
/// </summary>
|
||||
|
public Road[] Roads { get; set; } |
||||
|
/// <summary>
|
||||
|
/// 道路交叉口列表
|
||||
|
/// 请求参数 extensions 为 all 时返回
|
||||
|
/// </summary>
|
||||
|
public Roadinter[] Roadinters { get; set; } |
||||
|
/// <summary>
|
||||
|
/// poi信息列表
|
||||
|
/// 请求参数 extensions 为 all 时返回
|
||||
|
/// </summary>
|
||||
|
public Poi[] Pois { get; set; } |
||||
|
/// <summary>
|
||||
|
/// aoi信息列表
|
||||
|
/// 请求参数 extensions 为 all 时返回
|
||||
|
/// </summary>
|
||||
|
public Aoi[] Aois { get; set; } |
||||
|
public AmapRegeocode() |
||||
|
{ |
||||
|
AddressComponent = new AddressComponent(); |
||||
|
Roads = new Road[0]; |
||||
|
Roadinters = new Roadinter[0]; |
||||
|
Pois = new Poi[0]; |
||||
|
Aois = new Aoi[0]; |
||||
|
} |
||||
|
} |
||||
|
|
||||
|
public class AddressComponent |
||||
|
{ |
||||
|
/// <summary>
|
||||
|
/// 国家
|
||||
|
/// </summary>
|
||||
|
public string Country { get; set; } |
||||
|
/// <summary>
|
||||
|
/// 坐标点所在省名称
|
||||
|
/// 例如:北京市
|
||||
|
/// </summary>
|
||||
|
public string Province { get; set; } |
||||
|
|
||||
|
/// <summary>
|
||||
|
/// 坐标点所在城市名称
|
||||
|
/// 请注意:当城市是省直辖县时返回为空,以及城市为北京、上海、天津、重庆四个直辖市时,该字段返回为空
|
||||
|
/// </summary>
|
||||
|
public string[] City { get; set; } |
||||
|
|
||||
|
/// <summary>
|
||||
|
/// 城市编码
|
||||
|
/// 例如:010
|
||||
|
/// </summary>
|
||||
|
public string CityCode { get; set; } |
||||
|
|
||||
|
/// <summary>
|
||||
|
/// 坐标点所在区
|
||||
|
/// 例如:海淀区
|
||||
|
/// </summary>
|
||||
|
public string District { get; set; } |
||||
|
|
||||
|
/// <summary>
|
||||
|
/// 行政区编码
|
||||
|
/// 例如:110108
|
||||
|
/// </summary>
|
||||
|
public string AdCode { get; set; } |
||||
|
|
||||
|
/// <summary>
|
||||
|
/// 坐标点所在乡镇/街道(此街道为社区街道,不是道路信息)
|
||||
|
/// 例如:燕园街道
|
||||
|
/// </summary>
|
||||
|
public string[] TownShip { get; set; } |
||||
|
|
||||
|
/// <summary>
|
||||
|
/// 乡镇街道编码
|
||||
|
/// 例如:110101001000
|
||||
|
/// </summary>
|
||||
|
public string TownCode { get; set; } |
||||
|
/// <summary>
|
||||
|
/// 社区信息列表
|
||||
|
/// </summary>
|
||||
|
public NeighBorHood NeighBorHood { get; set; } |
||||
|
/// <summary>
|
||||
|
/// 楼信息列表
|
||||
|
/// </summary>
|
||||
|
public Building Building { get; set; } |
||||
|
/// <summary>
|
||||
|
/// 门牌信息列表
|
||||
|
/// </summary>
|
||||
|
public StreetNumber StreetNumber { get; set; } |
||||
|
/// <summary>
|
||||
|
/// 所属海域信息
|
||||
|
/// 例如:渤海
|
||||
|
/// </summary>
|
||||
|
public string SeaArea { get; set; } |
||||
|
/// <summary>
|
||||
|
/// 经纬度所属商圈列表
|
||||
|
/// </summary>
|
||||
|
public List<BusinessArea> BusinessAreas { get; set; } |
||||
|
public AddressComponent() |
||||
|
{ |
||||
|
NeighBorHood = new NeighBorHood(); |
||||
|
Building = new Building(); |
||||
|
StreetNumber = new StreetNumber(); |
||||
|
BusinessAreas = new List<BusinessArea>(); |
||||
|
} |
||||
|
} |
||||
|
|
||||
|
/// <summary>
|
||||
|
/// 社区信息
|
||||
|
/// </summary>
|
||||
|
public class NeighBorHood |
||||
|
{ |
||||
|
/// <summary>
|
||||
|
/// 社区名称
|
||||
|
/// 例如:北京大学
|
||||
|
/// </summary>
|
||||
|
public string[] Name { get; set; } = new string[0]; |
||||
|
|
||||
|
/// <summary>
|
||||
|
/// POI类型
|
||||
|
/// 例如:科教文化服务;学校;高等院校
|
||||
|
/// </summary>
|
||||
|
public string[] Type { get; set; } = new string[0]; |
||||
|
} |
||||
|
/// <summary>
|
||||
|
/// 楼信息
|
||||
|
/// </summary>
|
||||
|
public class Building |
||||
|
{ |
||||
|
/// <summary>
|
||||
|
/// 建筑名称
|
||||
|
/// 例如:万达广场
|
||||
|
/// </summary>
|
||||
|
public string[] Name { get; set; } = new string[0]; |
||||
|
|
||||
|
/// <summary>
|
||||
|
/// 类型
|
||||
|
/// 例如:科教文化服务;学校;高等院校
|
||||
|
/// </summary>
|
||||
|
public string[] Type { get; set; } = new string[0]; |
||||
|
} |
||||
|
/// <summary>
|
||||
|
/// 街道信息
|
||||
|
/// </summary>
|
||||
|
public class StreetNumber |
||||
|
{ |
||||
|
/// <summary>
|
||||
|
/// 街道名称
|
||||
|
/// 例如:中关村北二条
|
||||
|
/// </summary>
|
||||
|
public string Street { get; set; } |
||||
|
|
||||
|
/// <summary>
|
||||
|
/// 门牌号
|
||||
|
/// 例如:3号
|
||||
|
/// </summary>
|
||||
|
public string Number { get; set; } |
||||
|
|
||||
|
/// <summary>
|
||||
|
/// 坐标点
|
||||
|
/// 经纬度坐标点:经度,纬度
|
||||
|
/// </summary>
|
||||
|
public string Location { get; set; } |
||||
|
|
||||
|
/// <summary>
|
||||
|
/// 方向
|
||||
|
/// 坐标点所处街道方位
|
||||
|
/// </summary>
|
||||
|
public string Direction { get; set; } |
||||
|
|
||||
|
/// <summary>
|
||||
|
/// 门牌地址到请求坐标的距离
|
||||
|
/// 单位:米
|
||||
|
/// </summary>
|
||||
|
public string Distance { get; set; } |
||||
|
} |
||||
|
|
||||
|
/// <summary>
|
||||
|
/// 商圈信息
|
||||
|
/// </summary>
|
||||
|
public class BusinessArea |
||||
|
{ |
||||
|
/// <summary>
|
||||
|
/// 商圈中心点经纬度
|
||||
|
/// 经纬度坐标点:经度,纬度
|
||||
|
/// </summary>
|
||||
|
public string Location { get; set; } |
||||
|
|
||||
|
/// <summary>
|
||||
|
/// 商圈名称
|
||||
|
/// 例如:颐和园
|
||||
|
/// </summary>
|
||||
|
public string Name { get; set; } |
||||
|
|
||||
|
/// <summary>
|
||||
|
/// 商圈所在区域的adcode
|
||||
|
/// 例如:朝阳区/海淀区
|
||||
|
/// </summary>
|
||||
|
public string Id { get; set; } |
||||
|
} |
||||
|
|
||||
|
/// <summary>
|
||||
|
/// 道路信息
|
||||
|
/// </summary>
|
||||
|
public class Road |
||||
|
{ |
||||
|
/// <summary>
|
||||
|
/// 道路Id
|
||||
|
/// </summary>
|
||||
|
public string Id { get; set; } |
||||
|
/// <summary>
|
||||
|
/// 道路名称
|
||||
|
/// </summary>
|
||||
|
public string Name { get; set; } |
||||
|
/// <summary>
|
||||
|
/// 道路到请求的坐标距离
|
||||
|
/// 单位:米
|
||||
|
/// </summary>
|
||||
|
public string Distance { get; set; } |
||||
|
/// <summary>
|
||||
|
/// 方位
|
||||
|
/// 输入点和此路的相对方位
|
||||
|
/// </summary>
|
||||
|
public string Direction { get; set; } |
||||
|
/// <summary>
|
||||
|
/// 坐标点
|
||||
|
/// 经纬度坐标点:经度,纬度
|
||||
|
/// </summary>
|
||||
|
public string Location { get; set; } |
||||
|
} |
||||
|
|
||||
|
/// <summary>
|
||||
|
/// 道路交叉口
|
||||
|
/// </summary>
|
||||
|
public class Roadinter |
||||
|
{ |
||||
|
/// <summary>
|
||||
|
/// 交叉路口到请求坐标的距离
|
||||
|
/// 单位:米
|
||||
|
/// </summary>
|
||||
|
public string Distance { get; set; } |
||||
|
/// <summary>
|
||||
|
/// 方位
|
||||
|
/// 输入点相对路口的方位
|
||||
|
/// </summary>
|
||||
|
public string Direction { get; set; } |
||||
|
/// <summary>
|
||||
|
/// 路口经纬度
|
||||
|
/// </summary>
|
||||
|
public string Location { get; set; } |
||||
|
/// <summary>
|
||||
|
/// 第一条道路id
|
||||
|
/// </summary>
|
||||
|
[JsonProperty("first_id")] |
||||
|
public string FirstId { get; set; } |
||||
|
/// <summary>
|
||||
|
/// 第一条道路名称
|
||||
|
/// </summary>
|
||||
|
[JsonProperty("first_name")] |
||||
|
public string FirstName { get; set; } |
||||
|
/// <summary>
|
||||
|
/// 第二条道路id
|
||||
|
/// </summary>
|
||||
|
[JsonProperty("second_id")] |
||||
|
public string SecondId { get; set; } |
||||
|
/// <summary>
|
||||
|
/// 第二条道路名称
|
||||
|
/// </summary>
|
||||
|
[JsonProperty("second_name")] |
||||
|
public string SecondName { get; set; } |
||||
|
} |
||||
|
|
||||
|
/// <summary>
|
||||
|
/// poi信息
|
||||
|
/// </summary>
|
||||
|
public class Poi |
||||
|
{ |
||||
|
/// <summary>
|
||||
|
/// Poi信息
|
||||
|
/// </summary>
|
||||
|
public string Id { get; set; } |
||||
|
/// <summary>
|
||||
|
/// poi点名称
|
||||
|
/// </summary>
|
||||
|
public string Name { get; set; } |
||||
|
/// <summary>
|
||||
|
/// poi类型
|
||||
|
/// </summary>
|
||||
|
public string Type { get; set; } |
||||
|
/// <summary>
|
||||
|
/// 电话
|
||||
|
/// </summary>
|
||||
|
public string Tel { get; set; } |
||||
|
/// <summary>
|
||||
|
/// 该POI的中心点到请求坐标的距离
|
||||
|
/// 单位:米
|
||||
|
/// </summary>
|
||||
|
public string Distance { get; set; } |
||||
|
/// <summary>
|
||||
|
/// 方向
|
||||
|
/// 为输入点相对建筑物的方位
|
||||
|
/// </summary>
|
||||
|
public string Direction { get; set; } |
||||
|
/// <summary>
|
||||
|
/// poi地址信息
|
||||
|
/// </summary>
|
||||
|
public string Address { get; set; } |
||||
|
/// <summary>
|
||||
|
/// 坐标点
|
||||
|
/// </summary>
|
||||
|
public string Location { get; set; } |
||||
|
/// <summary>
|
||||
|
/// poi所在商圈名称
|
||||
|
/// </summary>
|
||||
|
public string BusinessArea { get; set; } |
||||
|
} |
||||
|
/// <summary>
|
||||
|
/// aoi信息
|
||||
|
/// </summary>
|
||||
|
public class Aoi |
||||
|
{ |
||||
|
/// <summary>
|
||||
|
/// 所属 aoi的id
|
||||
|
/// </summary>
|
||||
|
public string Id { get; set; } |
||||
|
/// <summary>
|
||||
|
/// 所属 aoi 名称
|
||||
|
/// </summary>
|
||||
|
public string Name { get; set; } |
||||
|
/// <summary>
|
||||
|
/// 所属 aoi 所在区域编码
|
||||
|
/// </summary>
|
||||
|
public string AdCode { get; set; } |
||||
|
/// <summary>
|
||||
|
/// 所属 aoi 中心点坐标
|
||||
|
/// </summary>
|
||||
|
public string Location { get; set; } |
||||
|
/// <summary>
|
||||
|
/// 所属aoi点面积
|
||||
|
/// 单位:平方米
|
||||
|
/// </summary>
|
||||
|
public string Area { get; set; } |
||||
|
/// <summary>
|
||||
|
/// 输入经纬度是否在aoi面之中
|
||||
|
/// 0,代表在aoi内 其余整数代表距离AOI的距离
|
||||
|
/// </summary>
|
||||
|
public string Distance { get; set; } |
||||
|
} |
||||
|
} |
||||
@ -0,0 +1,9 @@ |
|||||
|
using Volo.Abp.Localization; |
||||
|
|
||||
|
namespace LINYUN.Abp.Location.Amap.Localization |
||||
|
{ |
||||
|
[LocalizationResourceName("AmapLocation")] |
||||
|
public class AmapLocationResource |
||||
|
{ |
||||
|
} |
||||
|
} |
||||
@ -0,0 +1,47 @@ |
|||||
|
{ |
||||
|
"culture": "en", |
||||
|
"texts": { |
||||
|
"ResolveLocationFailed": "Resolution address failed:{0}", |
||||
|
"ResolveLocationZero": "Resolution address count is 0", |
||||
|
"SupportsResolveAddress": "Support up to {0} address resolution!", |
||||
|
"OK": "OK", |
||||
|
"INVALID_USER_KEY": "invalid or expired key ", |
||||
|
"SERVICE_NOT_AVAILABLE": "no permission to use the appropriate service or request interface path misspelled ", |
||||
|
"DAILY_QUERY_OVER_LIMIT": "access exceeded daily visits ", |
||||
|
"ACCESS_TOO_FREQUENT": "too many visits per unit time ", |
||||
|
"INVALID_USER_IP": "IP whitelist error, the server IP that sent the request is not in IP whitelist ", |
||||
|
"INVALID_USER_DOMAIN": "invalid binding ", |
||||
|
"INVALID_USER_SIGNATURE": "digital signature not verified ", |
||||
|
"INVALID_USER_SCODE": "MD5 security code failed validation ", |
||||
|
"USERKEY_PLAT_NOMATCH": "the requested key does not match the binding platform ", |
||||
|
"IP_QUERY_OVER_LIMIT": "IP access overlimit ", |
||||
|
"NOT_SUPPORT_HTTPS": "the service does not support HTTPS requests ", |
||||
|
"INSUFFICIENT_PRIVILEGES": "insufficient privileges, service request denied ", |
||||
|
"User_key_recycle ": "Key has been deleted ", |
||||
|
"QPS_HAS_EXCEEDED_THE_LIMIT": "cloud services QPS overrun,", |
||||
|
"GATEWAY_TIMEOUT": "subject to single-machine QPS current limit ", |
||||
|
"SERVER_IS_BUSY": "server load is too high ", |
||||
|
"RESOURCE_UNAVAILABLE": "the requested resource is not available ", |
||||
|
"CQPS_HAS_EXCEEDED_THE_LIMIT": "the use of a service always QPS overrun,", |
||||
|
"CKQPS_HAS_EXCEEDED_THE_LIMIT": "a Key using a service interface QPS beyond the limit", |
||||
|
"CIQPS_HAS_EXCEEDED_THE_LIMIT": "from the same IP access, the use of a service QPS beyond the limit.", |
||||
|
"CIKQPS_HAS_EXCEEDED_THE_LIMIT": "a Key from the same IP access, the use of a service QPS beyond the limit.", |
||||
|
"KQPS_HAS_EXCEEDED_THE_LIMIT": "a Key QPS beyond the limit.", |
||||
|
"ABROAD_DAILY_QUERY_OVER_LIMIT": "the QPS for a Key exceeds the limit ", |
||||
|
"INVALID_PARAMS": "request parameter invalid ", |
||||
|
"MISSING_REQUIRED_PARAMS": "missing required parameters ", |
||||
|
"ILLEGAL_REQUEST": "request protocol is illegal ", |
||||
|
"UNKNOWN_ERROR": "other unknown errors ", |
||||
|
"INSUFFICIENT_ABROAD_PRIVILEGES": "the query coordinates or planning points (starting, ending, passing points) are located overseas, but do not have overseas map privileges ", |
||||
|
"ILLEGAL_CONTENT": "illegal content exists in the query information ", |
||||
|
"OUT_OF_SERVICE": "the planned point (including the starting point, ending point and passing point) is not within the mainland of China", |
||||
|
"NO_ROADS_NEARBY": "no way can be found near the starting point (starting point, ending point, passing point) ", |
||||
|
"ROUTE_FAIL": "route calculation failed, usually due to road connectivity ", |
||||
|
"OVER_DIRECTION_RANGE": "the starting and ending points are too long.", |
||||
|
"ENGINE_RESPONSE_DATA_ERROR": "service response failed ", |
||||
|
"QUOTA_PLAN_RUN_OUT": "balance exhausted ", |
||||
|
"Geofence_max_count_reach ": " maximum number of fences ", |
||||
|
"SERVICE_EXPIRED": "expired service purchased ", |
||||
|
"ABROAD_QUOTA_PLAN_RUN_OUT": "overseas service balance exhausted" |
||||
|
} |
||||
|
} |
||||
@ -0,0 +1,47 @@ |
|||||
|
{ |
||||
|
"culture": "zh-Hans", |
||||
|
"texts": { |
||||
|
"ResolveLocationFailed": "解析地址失败:{0}", |
||||
|
"ResolveLocationZero": "解析地址数为0", |
||||
|
"SupportsResolveAddress": "最多支持 {0} 个地址解析!", |
||||
|
"OK": "调用成功!", |
||||
|
"INVALID_USER_KEY": "key不正确或过期", |
||||
|
"SERVICE_NOT_AVAILABLE": "没有权限使用相应的服务或者请求接口的路径拼写错误", |
||||
|
"DAILY_QUERY_OVER_LIMIT": "访问已超出日访问量", |
||||
|
"ACCESS_TOO_FREQUENT": "单位时间内访问过于频繁", |
||||
|
"INVALID_USER_IP": "IP白名单出错,发送请求的服务器IP不在IP白名单内", |
||||
|
"INVALID_USER_DOMAIN": "绑定域名无效", |
||||
|
"INVALID_USER_SIGNATURE": "数字签名未通过验证", |
||||
|
"INVALID_USER_SCODE": "MD5安全码未通过验证", |
||||
|
"USERKEY_PLAT_NOMATCH": "请求key与绑定平台不符", |
||||
|
"IP_QUERY_OVER_LIMIT": "IP访问超限", |
||||
|
"NOT_SUPPORT_HTTPS": "服务不支持https请求", |
||||
|
"INSUFFICIENT_PRIVILEGES": "权限不足,服务请求被拒绝", |
||||
|
"USER_KEY_RECYCLED": "Key被删除", |
||||
|
"QPS_HAS_EXCEEDED_THE_LIMIT": "云图服务QPS超限", |
||||
|
"GATEWAY_TIMEOUT": "受单机QPS限流限制", |
||||
|
"SERVER_IS_BUSY": "服务器负载过高", |
||||
|
"RESOURCE_UNAVAILABLE": "所请求的资源不可用", |
||||
|
"CQPS_HAS_EXCEEDED_THE_LIMIT": "使用的某个服务总QPS超限", |
||||
|
"CKQPS_HAS_EXCEEDED_THE_LIMIT": "某个Key使用某个服务接口QPS超出限制", |
||||
|
"CIQPS_HAS_EXCEEDED_THE_LIMIT": "来自于同一IP的访问,使用某个服务QPS超出限制", |
||||
|
"CIKQPS_HAS_EXCEEDED_THE_LIMIT": "某个Key,来自于同一IP的访问,使用某个服务QPS超出限制", |
||||
|
"KQPS_HAS_EXCEEDED_THE_LIMIT": "某个Key的QPS超出限制", |
||||
|
"ABROAD_DAILY_QUERY_OVER_LIMIT": "某个Key的QPS超出限制", |
||||
|
"INVALID_PARAMS": "请求参数非法", |
||||
|
"MISSING_REQUIRED_PARAMS": "缺少必填参数", |
||||
|
"ILLEGAL_REQUEST": "请求协议非法", |
||||
|
"UNKNOWN_ERROR": "其他未知错误", |
||||
|
"INSUFFICIENT_ABROAD_PRIVILEGES": "查询坐标或规划点(包括起点、终点、途经点)在海外,但没有海外地图权限", |
||||
|
"ILLEGAL_CONTENT": "查询信息存在非法内容", |
||||
|
"OUT_OF_SERVICE": "规划点(包括起点、终点、途经点)不在中国陆地范围内", |
||||
|
"NO_ROADS_NEARBY": "划点(起点、终点、途经点)附近搜不到路", |
||||
|
"ROUTE_FAIL": "路线计算失败,通常是由于道路连通关系导致", |
||||
|
"OVER_DIRECTION_RANGE": "起点终点距离过长.", |
||||
|
"ENGINE_RESPONSE_DATA_ERROR": "服务响应失败.", |
||||
|
"QUOTA_PLAN_RUN_OUT": "余额耗尽", |
||||
|
"GEOFENCE_MAX_COUNT_REACHED": "围栏个数达到上限", |
||||
|
"SERVICE_EXPIRED": "购买服务到期", |
||||
|
"ABROAD_QUOTA_PLAN_RUN_OUT": "海外服务余额耗尽" |
||||
|
} |
||||
|
} |
||||
@ -0,0 +1,39 @@ |
|||||
|
using LINYUN.Abp.Location.Baidu.Localization; |
||||
|
using Microsoft.Extensions.DependencyInjection; |
||||
|
using Polly; |
||||
|
using System; |
||||
|
using Volo.Abp.Json; |
||||
|
using Volo.Abp.Localization; |
||||
|
using Volo.Abp.Modularity; |
||||
|
using Volo.Abp.VirtualFileSystem; |
||||
|
|
||||
|
namespace LINGYUN.Abp.Location.Baidu |
||||
|
{ |
||||
|
[DependsOn( |
||||
|
typeof(AbpLocationModule), |
||||
|
typeof(AbpJsonModule))] |
||||
|
public class AbpBaiduLocationModule : AbpModule |
||||
|
{ |
||||
|
public override void ConfigureServices(ServiceConfigurationContext context) |
||||
|
{ |
||||
|
var configuration = context.Services.GetConfiguration(); |
||||
|
Configure<BaiduLocationOptions>(configuration.GetSection("Location:Baidu")); |
||||
|
|
||||
|
context.Services.AddHttpClient(BaiduLocationHttpConsts.HttpClientName) |
||||
|
.AddTransientHttpErrorPolicy(builder => |
||||
|
builder.WaitAndRetryAsync(3, i => TimeSpan.FromSeconds(Math.Pow(2, i)))); |
||||
|
|
||||
|
Configure<AbpVirtualFileSystemOptions>(options => |
||||
|
{ |
||||
|
options.FileSets.AddEmbedded<AbpBaiduLocationModule>(); |
||||
|
}); |
||||
|
|
||||
|
Configure<AbpLocalizationOptions>(options => |
||||
|
{ |
||||
|
options.Resources |
||||
|
.Add<BaiduLocationResource>("en") |
||||
|
.AddVirtualJson("/LINGYUN/Abp/Location/Baidu/Localization/Resources"); |
||||
|
}); |
||||
|
} |
||||
|
} |
||||
|
} |
||||
@ -0,0 +1,194 @@ |
|||||
|
using LINGYUN.Abp.Location.Baidu.Response; |
||||
|
using LINGYUN.Abp.Location.Baidu.Utils; |
||||
|
using LINYUN.Abp.Location.Baidu.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.Baidu |
||||
|
{ |
||||
|
public class BaiduLocationHttpClient : ITransientDependency |
||||
|
{ |
||||
|
protected BaiduLocationOptions Options { get; } |
||||
|
protected IJsonSerializer JsonSerializer { get; } |
||||
|
protected IServiceProvider ServiceProvider { get; } |
||||
|
protected IHttpClientFactory HttpClientFactory { get; } |
||||
|
protected ICancellationTokenProvider CancellationTokenProvider { get; } |
||||
|
|
||||
|
public BaiduLocationHttpClient( |
||||
|
IOptions<BaiduLocationOptions> options, |
||||
|
IJsonSerializer jsonSerializer, |
||||
|
IServiceProvider serviceProvider, |
||||
|
IHttpClientFactory httpClientFactory, |
||||
|
ICancellationTokenProvider cancellationTokenProvider) |
||||
|
{ |
||||
|
Options = options.Value; |
||||
|
JsonSerializer = jsonSerializer; |
||||
|
ServiceProvider = serviceProvider; |
||||
|
HttpClientFactory = httpClientFactory; |
||||
|
CancellationTokenProvider = cancellationTokenProvider; |
||||
|
} |
||||
|
|
||||
|
public virtual async Task<GecodeLocation> GeocodeAsync(string address, string city = null) |
||||
|
{ |
||||
|
var requestParamters = new Dictionary<string, string> |
||||
|
{ |
||||
|
{ "address", address }, |
||||
|
{ "ak", Options.AccessKey }, |
||||
|
{ "output", Options.Output }, |
||||
|
{ "ret_coordtype", Options.ReturnCoordType } |
||||
|
}; |
||||
|
if (!city.IsNullOrWhiteSpace()) |
||||
|
{ |
||||
|
requestParamters.Add("city", city); |
||||
|
} |
||||
|
var baiduMapUrl = "http://api.map.baidu.com"; |
||||
|
var baiduMapPath = "/geocoding/v3"; |
||||
|
if (Options.CaculateAKSN) |
||||
|
{ |
||||
|
// TODO: 百度的文档不明不白,sn的算法在遇到特殊字符会验证失败,有待完善
|
||||
|
var sn = BaiduAKSNCaculater.CaculateAKSN(Options.AccessSecret, baiduMapPath, requestParamters); |
||||
|
requestParamters.Add("sn", sn); |
||||
|
} |
||||
|
var requestUrl = BuildRequestUrl(baiduMapUrl, baiduMapPath, requestParamters); |
||||
|
var responseContent = await MakeRequestAndGetResultAsync(requestUrl); |
||||
|
var baiduLocationResponse = JsonSerializer.Deserialize<BaiduGeocodeResponse>(responseContent); |
||||
|
if (!baiduLocationResponse.IsSuccess()) |
||||
|
{ |
||||
|
var localizerFactory = ServiceProvider.GetRequiredService<IStringLocalizerFactory>(); |
||||
|
var localizerErrorMessage = baiduLocationResponse.GetErrorMessage().Localize(localizerFactory); |
||||
|
var localizerErrorDescription = baiduLocationResponse.GetErrorMessage().Localize(localizerFactory); |
||||
|
var localizer = ServiceProvider.GetRequiredService<IStringLocalizer<BaiduLocationResource>>(); |
||||
|
localizerErrorMessage = localizer["ResolveLocationFailed", localizerErrorMessage, localizerErrorDescription]; |
||||
|
if (Options.VisableErrorToClient) |
||||
|
{ |
||||
|
throw new UserFriendlyException(localizerErrorMessage); |
||||
|
} |
||||
|
throw new AbpException($"Resolution address failed:{localizerErrorMessage}!"); |
||||
|
} |
||||
|
var location = new GecodeLocation |
||||
|
{ |
||||
|
Confidence = baiduLocationResponse.Result.Confidence, |
||||
|
Latitude = baiduLocationResponse.Result.Location.Lat, |
||||
|
Longitude = baiduLocationResponse.Result.Location.Lng, |
||||
|
Level = baiduLocationResponse.Result.Level |
||||
|
}; |
||||
|
location.AddAdditional("BaiduLocation", baiduLocationResponse.Result); |
||||
|
|
||||
|
return location; |
||||
|
} |
||||
|
|
||||
|
public virtual async Task<ReGeocodeLocation> ReGeocodeAsync(double lat, double lng, int radius = 1000) |
||||
|
{ |
||||
|
var requestParamters = new Dictionary<string, string> |
||||
|
{ |
||||
|
{ "ak", Options.AccessKey }, |
||||
|
{ "output", Options.Output }, |
||||
|
{ "radius", radius.ToString() }, |
||||
|
{ "language", Options.Language }, |
||||
|
{ "coordtype", Options.CoordType }, |
||||
|
{ "extensions_poi", Options.ExtensionsPoi }, |
||||
|
{ "ret_coordtype", Options.ReturnCoordType }, |
||||
|
{ "location", string.Format("{0},{1}", lat, lng) }, |
||||
|
{ "extensions_road", Options.ExtensionsRoad ? "true" : "false" }, |
||||
|
{ "extensions_town", Options.ExtensionsTown ? "true" : "false" }, |
||||
|
}; |
||||
|
var baiduMapUrl = "http://api.map.baidu.com"; |
||||
|
var baiduMapPath = "/reverse_geocoding/v3"; |
||||
|
if (Options.CaculateAKSN) |
||||
|
{ |
||||
|
// TODO: 百度的文档不明不白,sn的算法在遇到特殊字符会验证失败,有待完善
|
||||
|
var sn = BaiduAKSNCaculater.CaculateAKSN(Options.AccessSecret, baiduMapPath, requestParamters); |
||||
|
requestParamters.Add("sn", sn); |
||||
|
} |
||||
|
requestParamters["location"] = string.Format("{0}%2C{1}", lat, lng); |
||||
|
var requestUrl = BuildRequestUrl(baiduMapUrl, baiduMapPath, requestParamters); |
||||
|
var responseContent = await MakeRequestAndGetResultAsync(requestUrl); |
||||
|
var baiduLocationResponse = JsonSerializer.Deserialize<BaiduReGeocodeResponse>(responseContent); |
||||
|
if (!baiduLocationResponse.IsSuccess()) |
||||
|
{ |
||||
|
var localizerFactory = ServiceProvider.GetRequiredService<IStringLocalizerFactory>(); |
||||
|
var localizerErrorMessage = baiduLocationResponse.GetErrorMessage().Localize(localizerFactory); |
||||
|
var localizerErrorDescription = baiduLocationResponse.GetErrorMessage().Localize(localizerFactory); |
||||
|
var localizer = ServiceProvider.GetRequiredService<IStringLocalizer<BaiduLocationResource>>(); |
||||
|
localizerErrorMessage = localizer["ResolveLocationFailed", localizerErrorMessage, localizerErrorDescription]; |
||||
|
if (Options.VisableErrorToClient) |
||||
|
{ |
||||
|
throw new UserFriendlyException(localizerErrorMessage); |
||||
|
} |
||||
|
throw new AbpException($"Resolution address failed:{localizerErrorMessage}!"); |
||||
|
} |
||||
|
var location = new ReGeocodeLocation |
||||
|
{ |
||||
|
Street = baiduLocationResponse.Result.AddressComponent.Street, |
||||
|
AdCode = baiduLocationResponse.Result.AddressComponent.AdCode.ToString(), |
||||
|
Address = baiduLocationResponse.Result.Address, |
||||
|
City = baiduLocationResponse.Result.AddressComponent.City, |
||||
|
Country = baiduLocationResponse.Result.AddressComponent.Country, |
||||
|
District = baiduLocationResponse.Result.AddressComponent.District, |
||||
|
Number = baiduLocationResponse.Result.AddressComponent.StreetNumber, |
||||
|
Province = baiduLocationResponse.Result.AddressComponent.Province, |
||||
|
Town = baiduLocationResponse.Result.AddressComponent.Town, |
||||
|
Pois = baiduLocationResponse.Result.Pois.Select(p => new Poi |
||||
|
{ |
||||
|
Address = p.Address, |
||||
|
Name = p.Name, |
||||
|
Tag = p.Tag, |
||||
|
Type = p.PoiType |
||||
|
}).ToList(), |
||||
|
Roads = baiduLocationResponse.Result.Roads.Select(r => new Road |
||||
|
{ |
||||
|
Name = r.Name |
||||
|
}).ToList() |
||||
|
}; |
||||
|
location.AddAdditional("BaiduLocation", baiduLocationResponse.Result); |
||||
|
|
||||
|
return location; |
||||
|
} |
||||
|
|
||||
|
protected virtual async Task<string> MakeRequestAndGetResultAsync(string url) |
||||
|
{ |
||||
|
var client = HttpClientFactory.CreateClient(BaiduLocationHttpConsts.HttpClientName); |
||||
|
var requestMessage = new HttpRequestMessage(HttpMethod.Get, url); |
||||
|
|
||||
|
var response = await client.SendAsync(requestMessage, GetCancellationToken()); |
||||
|
if (!response.IsSuccessStatusCode) |
||||
|
{ |
||||
|
throw new AbpException($"Baidu 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 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.Baidu |
||||
|
{ |
||||
|
public class BaiduLocationHttpConsts |
||||
|
{ |
||||
|
public const string HttpClientName = "BaiduLocation"; |
||||
|
} |
||||
|
} |
||||
@ -0,0 +1,65 @@ |
|||||
|
using System; |
||||
|
|
||||
|
namespace LINGYUN.Abp.Location.Baidu |
||||
|
{ |
||||
|
public class BaiduLocationOptions |
||||
|
{ |
||||
|
/// <summary>
|
||||
|
/// 用户申请注册的key
|
||||
|
/// </summary>
|
||||
|
public string AccessKey { get; set; } |
||||
|
/// <summary>
|
||||
|
/// 用户申请注册的AccessSecret
|
||||
|
/// </summary>
|
||||
|
public string AccessSecret { get; set; } |
||||
|
/// <summary>
|
||||
|
/// 坐标的类型,目前支持的坐标类型包括:
|
||||
|
/// bd09ll(百度经纬度坐标)
|
||||
|
/// bd09mc(百度米制坐标)
|
||||
|
/// gcj02ll(国测局经纬度坐标,仅限中国)
|
||||
|
/// wgs84ll( GPS经纬度)
|
||||
|
/// </summary>
|
||||
|
public string CoordType { get; set; } = "bd09ll"; |
||||
|
/// <summary>
|
||||
|
/// 可选参数,添加后返回国测局经纬度坐标或百度米制
|
||||
|
/// gcj02ll(国测局坐标)
|
||||
|
/// bd09mc(百度墨卡托坐标)
|
||||
|
/// </summary>
|
||||
|
public string ReturnCoordType { get; set; } = "bd09ll"; |
||||
|
/// <summary>
|
||||
|
/// 计算sn
|
||||
|
/// </summary>
|
||||
|
public bool CaculateAKSN => !AccessSecret.IsNullOrWhiteSpace(); |
||||
|
/// <summary>
|
||||
|
/// extensions_poi=0,不召回pois数据。
|
||||
|
/// extensions_poi=1,返回pois数据,
|
||||
|
/// 默认显示周边1000米内的poi。
|
||||
|
/// </summary>
|
||||
|
public string ExtensionsPoi { get; set; } = "0"; |
||||
|
/// <summary>
|
||||
|
/// 当取值为true时,召回坐标周围最近的3条道路数据。
|
||||
|
/// 区别于行政区划中的street参数(street参数为行政区划中的街道,和普通道路不对应)
|
||||
|
/// </summary>
|
||||
|
public bool ExtensionsRoad { get; set; } = false; |
||||
|
/// <summary>
|
||||
|
/// 当取值为true时,行政区划返回乡镇级数据(仅国内召回乡镇数据)。
|
||||
|
/// 默认不访问。
|
||||
|
/// </summary>
|
||||
|
public bool ExtensionsTown { get; set; } = false; |
||||
|
/// <summary>
|
||||
|
/// 指定召回的新政区划语言类型。
|
||||
|
/// el gu en vi ca it iw sv eu ar cs gl id es en-GB ru sr nl pt tr tl lv en-AU lt th ro
|
||||
|
/// fil ta fr bg hr bn de hu fa hi pt-BR fi da ja te pt-PT ml ko kn sk zh-CN pl uk sl mr
|
||||
|
/// local
|
||||
|
/// </summary>
|
||||
|
public string Language { get; set; } = "zh-CN"; |
||||
|
/// <summary>
|
||||
|
/// 输出格式为json或者xml
|
||||
|
/// </summary>
|
||||
|
public string Output { get; set; } = "json"; |
||||
|
/// <summary>
|
||||
|
/// 展示错误给客户端
|
||||
|
/// </summary>
|
||||
|
public bool VisableErrorToClient { get; set; } = false; |
||||
|
} |
||||
|
} |
||||
@ -0,0 +1,28 @@ |
|||||
|
using Microsoft.Extensions.DependencyInjection; |
||||
|
using System.Threading.Tasks; |
||||
|
using Volo.Abp.DependencyInjection; |
||||
|
|
||||
|
namespace LINGYUN.Abp.Location.Baidu |
||||
|
{ |
||||
|
[Dependency(ServiceLifetime.Transient)] |
||||
|
[ExposeServices(typeof(ILocationResolveProvider))] |
||||
|
public class BaiduLocationResolveProvider : ILocationResolveProvider |
||||
|
{ |
||||
|
protected BaiduLocationHttpClient BaiduLocationHttpClient { get; } |
||||
|
|
||||
|
public BaiduLocationResolveProvider(BaiduLocationHttpClient baiduHttpRequestClient) |
||||
|
{ |
||||
|
BaiduLocationHttpClient = baiduHttpRequestClient; |
||||
|
} |
||||
|
|
||||
|
public async Task<ReGeocodeLocation> ReGeocodeAsync(double lat, double lng, int radius = 50) |
||||
|
{ |
||||
|
return await BaiduLocationHttpClient.ReGeocodeAsync(lat, lng, radius); |
||||
|
} |
||||
|
|
||||
|
public async Task<GecodeLocation> GeocodeAsync(string address, string city = null) |
||||
|
{ |
||||
|
return await BaiduLocationHttpClient.GeocodeAsync(address, city); |
||||
|
} |
||||
|
} |
||||
|
} |
||||
@ -1,15 +0,0 @@ |
|||||
using Newtonsoft.Json; |
|
||||
using System; |
|
||||
using System.Collections.Generic; |
|
||||
using System.Text; |
|
||||
|
|
||||
namespace LINGYUN.Abp.Location.Baidu.Http |
|
||||
{ |
|
||||
public class BaiduInverseLocationResponse : BaiduLocationResponse |
|
||||
{ |
|
||||
[JsonProperty("formatted_address")] |
|
||||
public string Address { get; set; } |
|
||||
|
|
||||
|
|
||||
} |
|
||||
} |
|
||||
@ -1,11 +0,0 @@ |
|||||
using System; |
|
||||
using System.Collections.Generic; |
|
||||
using System.Text; |
|
||||
|
|
||||
namespace LINGYUN.Abp.Location.Baidu.Http |
|
||||
{ |
|
||||
public class BaiduLocationHttpClient |
|
||||
{ |
|
||||
|
|
||||
} |
|
||||
} |
|
||||
@ -1,14 +0,0 @@ |
|||||
namespace LINGYUN.Abp.Location.Baidu.Http |
|
||||
{ |
|
||||
public abstract class BaiduLocationResponse |
|
||||
{ |
|
||||
public int Status { get; set; } |
|
||||
|
|
||||
public Location Location { get; set; } |
|
||||
|
|
||||
public bool IsSuccess() |
|
||||
{ |
|
||||
return Status == 0; |
|
||||
} |
|
||||
} |
|
||||
} |
|
||||
@ -0,0 +1,9 @@ |
|||||
|
using Volo.Abp.Localization; |
||||
|
|
||||
|
namespace LINYUN.Abp.Location.Baidu.Localization |
||||
|
{ |
||||
|
[LocalizationResourceName("BaiduLocation")] |
||||
|
public class BaiduLocationResource |
||||
|
{ |
||||
|
} |
||||
|
} |
||||
@ -0,0 +1,52 @@ |
|||||
|
{ |
||||
|
"culture": "en", |
||||
|
"texts": { |
||||
|
"ResolveLocationFailed": "Parse address error, error message :{0}, error description :{1}", |
||||
|
"Message:RETURN_0": "OK ", |
||||
|
"Description:RETURN_0": "OK", |
||||
|
"Message:RETURN_1": "server internal error ", |
||||
|
"Description:RETURN_1": "this service response timeout or system error, please leave your contact information ", |
||||
|
"Message:RETURN_10": "upload content over 8M", |
||||
|
"Description:RETURN_10": "Post upload data cannot exceed 8M", |
||||
|
"Message:RETURN_101": "AK parameter does not exist ", |
||||
|
"Description:RETURN_101": "request message does not carry AK parameter ", |
||||
|
"Message:RETURN_102": "MCODE parameter does not exist, MCODE parameter of mobile type is required ", |
||||
|
"Description:RETURN_102": "McOde parameter is required for Mobile type application request. This error code represents that the server did not resolve to McOde ", |
||||
|
"Message:RETURN_200": "APP does not exist, AK is wrong please check and try again ", |
||||
|
"Description:RETURN_200": "according to the requested AK, the corresponding APP cannot be found ", |
||||
|
"Message:RETURN_201": "APP is disabled by user, please unblock it in the console ", |
||||
|
"Description:RETURN_201": "APP was disabled by the user, please unblock it on the console ", |
||||
|
"Message:RETURN_202": "APP deleted by administrator ", |
||||
|
"Description:RETURN_202": "malicious APP deleted by administrator ", |
||||
|
"Message:RETURN_203": "APP type error ", |
||||
|
"Description:RETURN_203": "the current API console supports Server(type 1), Mobile(type 2), and the new console is divided into Mobile_Android(type 21), Mobile_IPhone (type 22), and Browser (type 3). Other types are considered as APP type errors ", |
||||
|
"Message:RETURN_210": "APP IP validation failed ", |
||||
|
"Description:RETURN_210": "when applying for SERVER type application, select IP validation, need to fill in the IP white list, if the current request IP address is not in the IP white list or is not 0.0.0.0/0, IP validation will be considered a failure ", |
||||
|
"Message:RETURN_211": "APP SN validation failed ", |
||||
|
"Description:RETURN_211": "the SERVER type APP has two check methods: IP check and SN check. When the SN requested by the user is not equal to the SN calculated by the SERVER, the SN check fails ", |
||||
|
"Message:RETURN_220": "APP Referer validation failed ", |
||||
|
"Description:RETURN_220": "the browser-type APP will verify whether the referer field is saved and cut into the referer whitelist, otherwise it will return the error code ", |
||||
|
"Message:RETURN_230": "APP Mcode check failed ", |
||||
|
"Description:RETURN_230": "the server can parse to McOde, but it is not consistent with the database, please bring the correct McOde ", |
||||
|
"Message:RETURN_240": "APP service is disabled ", |
||||
|
"Description:RETURN_240": "the user disabled a service when creating or setting an APP in the API console. If the user needs to open the permission, he can enter the API console and check the corresponding service for AK ", |
||||
|
"Message:RETURN_250": "user does not exist ", |
||||
|
"Description:RETURN_250": "according to the requested user_id, the user's information cannot be found in the database, please bring the correct user_id", |
||||
|
"Message:RETURN_251": "user deleted by himself ", |
||||
|
"Description:RETURN_251": "the user is in an inactive state ", |
||||
|
"Message:RETURN_252": "user deleted by administrator ", |
||||
|
"Description:RETURN_252": "malicious user added to blacklist ", |
||||
|
"Message:RETURN_260": "service does not exist ", |
||||
|
"Description:RETURN_260": "the server could not resolve the service name requested by the user ", |
||||
|
"Message:RETURN_261": "service disabled ", |
||||
|
"Description:RETURN_261": "the service has been offline. Please confirm at the console whether you have access to the service.", |
||||
|
"Message:RETURN_301": "permanent quota overruns, restricted access ", |
||||
|
"Description:RETURN_301": "quota exceeded. If you want to increase quota, please contact baidu map ", |
||||
|
"Message:RETURN_302": "day quota exceeded, restricted access ", |
||||
|
"Description:RETURN_302": "quota exceeded. If you want to increase quota, please contact baidu map ", |
||||
|
"Message:RETURN_401": "the current concurrency amount has exceeded the agreed concurrency quota, restricting access ", |
||||
|
"Description: RETURN_401": "concurrency control exceeded, please control the amount of concurrency or contact baidu map", |
||||
|
"Message:RETURN_402": "the current concurrency amount has exceeded the agreed concurrency quota, and the total concurrency amount of the service has exceeded the set total concurrency quota, restricting access ", |
||||
|
"Description:RETURN_402": "concurrency control exceeded, please control the amount of concurrency or contact baidu map" |
||||
|
} |
||||
|
} |
||||
@ -0,0 +1,52 @@ |
|||||
|
{ |
||||
|
"culture": "zh-Hans", |
||||
|
"texts": { |
||||
|
"ResolveLocationFailed": "解析地址出错,错误信息:{0},错误说明:{1}", |
||||
|
"Message:RETURN_0": "正常", |
||||
|
"Description:RETURN_0": "服务请求正常召回", |
||||
|
"Message:RETURN_1": "服务器内部错误", |
||||
|
"Description:RETURN_1": "该服务响应超时或系统内部错误,请留下联系方式", |
||||
|
"Message:RETURN_10": "上传内容超过8M", |
||||
|
"Description:RETURN_10": "Post上传数据不能超过8M", |
||||
|
"Message:RETURN_101": "AK参数不存在", |
||||
|
"Description:RETURN_101": "请求消息没有携带AK参数", |
||||
|
"Message:RETURN_102": "MCODE参数不存在,mobile类型mcode参数必需", |
||||
|
"Description:RETURN_102": "对于Mobile类型的应用请求需要携带mcode参数,该错误码代表服务器没有解析到mcode", |
||||
|
"Message:RETURN_200": "APP不存在,AK有误请检查再重试", |
||||
|
"Description:RETURN_200": "根据请求的AK,找不到对应的APP", |
||||
|
"Message:RETURN_201": "APP被用户自己禁用,请在控制台解禁", |
||||
|
"Description:RETURN_201": "APP被用户自己禁用,请在控制台解禁", |
||||
|
"Message:RETURN_202": "APP被管理员删除", |
||||
|
"Description:RETURN_202": "恶意APP被管理员删除", |
||||
|
"Message:RETURN_203": "APP类型错误", |
||||
|
"Description:RETURN_203": "当前API控制台支持Server(类型1), Mobile(类型2, 新版控制台区分为Mobile_Android(类型21)及Mobile_IPhone(类型22))及Browser(类型3),除此之外其他类型认为是APP类型错误", |
||||
|
"Message:RETURN_210": "APP IP校验失败", |
||||
|
"Description:RETURN_210": "在申请SERVER类型应用的时候选择IP校验,需要填写IP白名单,如果当前请求的IP地址不在IP白名单或者不是0.0.0.0/0就认为IP校验失败", |
||||
|
"Message:RETURN_211": "APP SN校验失败", |
||||
|
"Description:RETURN_211": "SERVER类型APP有两种校验方式IP校验和SN校验,当用户请求的SN和服务端计算出来的SN不相等的时候提示SN校验失败", |
||||
|
"Message:RETURN_220": "APP Referer校验失败", |
||||
|
"Description:RETURN_220": "浏览器类型的APP会校验referer字段是否存且切在referer白名单里面,否则返回该错误码", |
||||
|
"Message:RETURN_230": "APP Mcode码校验失败", |
||||
|
"Description:RETURN_230": "服务器能解析到mcode,但和数据库中不一致,请携带正确的mcode", |
||||
|
"Message:RETURN_240": "APP 服务被禁用", |
||||
|
"Description:RETURN_240": "用户在API控制台中创建或设置某APP的时候禁用了某项服务,若需开通权限,可进入API控制台为AK勾选对应服务", |
||||
|
"Message:RETURN_250": "用户不存在", |
||||
|
"Description:RETURN_250": "根据请求的user_id, 数据库中找不到该用户的信息,请携带正确的user_id", |
||||
|
"Message:RETURN_251": "用户被自己删除", |
||||
|
"Description:RETURN_251": "该用户处于未激活状态", |
||||
|
"Message:RETURN_252": "用户被管理员删除", |
||||
|
"Description:RETURN_252": "恶意用户被加入黑名单", |
||||
|
"Message:RETURN_260": "服务不存在", |
||||
|
"Description:RETURN_260": "服务器解析不到用户请求的服务名称", |
||||
|
"Message:RETURN_261": "服务被禁用", |
||||
|
"Description:RETURN_261": "该服务已下线,请在控制台确认是否有该服务的权限。", |
||||
|
"Message:RETURN_301": "永久配额超限,限制访问", |
||||
|
"Description:RETURN_301": "配额超限,如果想增加配额请联系百度地图", |
||||
|
"Message:RETURN_302": "当天配额超限,限制访问", |
||||
|
"Description:RETURN_302": "配额超限,如果想增加配额请联系百度地图", |
||||
|
"Message:RETURN_401": "当前并发量已经超过约定并发配额,限制访问", |
||||
|
"Description:RETURN_401": "并发控制超限,请控制并发量或联系百度地图", |
||||
|
"Message:RETURN_402": "当前并发量已经超过约定并发配额,并且服务总并发量也已经超过设定的总并发配额,限制访问", |
||||
|
"Description:RETURN_402": "并发控制超限,请控制并发量或联系百度地图" |
||||
|
} |
||||
|
} |
||||
@ -0,0 +1,79 @@ |
|||||
|
using Newtonsoft.Json; |
||||
|
using System; |
||||
|
using System.Collections.Generic; |
||||
|
using System.Text; |
||||
|
|
||||
|
namespace LINGYUN.Abp.Location.Baidu.Model |
||||
|
{ |
||||
|
public class AddressComponent |
||||
|
{ |
||||
|
/// <summary>
|
||||
|
/// 国家
|
||||
|
/// </summary>
|
||||
|
public string Country { get; set; } |
||||
|
/// <summary>
|
||||
|
/// 国家国家编码
|
||||
|
/// </summary>
|
||||
|
[JsonProperty("country_code")] |
||||
|
public int CountryCode { get; set; } |
||||
|
/// <summary>
|
||||
|
/// 国家英文缩写(三位)
|
||||
|
/// </summary>
|
||||
|
[JsonProperty("country_code_iso")] |
||||
|
public string CountryCodeIso { get; set; } |
||||
|
/// <summary>
|
||||
|
/// 国家英文缩写(两位)
|
||||
|
/// </summary>
|
||||
|
[JsonProperty("country_code_iso2")] |
||||
|
public string CountryCodeIso2 { get; set; } |
||||
|
/// <summary>
|
||||
|
/// 省名
|
||||
|
/// </summary>
|
||||
|
public string Province { get; set; } |
||||
|
/// <summary>
|
||||
|
/// 城市名
|
||||
|
/// </summary>
|
||||
|
public string City { get; set; } |
||||
|
/// <summary>
|
||||
|
/// 城市所在级别(仅国外有参考意义。
|
||||
|
/// 国外行政区划与中国有差异,城市对应的层级不一定为『city』。
|
||||
|
/// country、province、city、district、town分别对应0-4级,若city_level=3,则district层级为该国家的city层级)
|
||||
|
/// </summary>
|
||||
|
[JsonProperty("city_level")] |
||||
|
public int CityLevel { get; set; } |
||||
|
/// <summary>
|
||||
|
/// 区县名
|
||||
|
/// </summary>
|
||||
|
public string District { get; set; } |
||||
|
/// <summary>
|
||||
|
/// 乡镇名
|
||||
|
/// </summary>
|
||||
|
public string Town { get; set; } |
||||
|
/// <summary>
|
||||
|
/// 乡镇id
|
||||
|
/// </summary>
|
||||
|
[JsonProperty("town_code")] |
||||
|
public string TownCode { get; set; } |
||||
|
/// <summary>
|
||||
|
/// 街道名(行政区划中的街道层级)
|
||||
|
/// </summary>
|
||||
|
public string Street { get; set; } |
||||
|
/// <summary>
|
||||
|
/// 街道门牌号
|
||||
|
/// </summary>
|
||||
|
[JsonProperty("street_number")] |
||||
|
public string StreetNumber { get; set; } |
||||
|
/// <summary>
|
||||
|
/// 行政区划代码
|
||||
|
/// </summary>
|
||||
|
public string AdCode { get; set; } |
||||
|
/// <summary>
|
||||
|
/// 相对当前坐标点的方向,当有门牌号的时候返回数据
|
||||
|
/// </summary>
|
||||
|
public string Direction { get; set; } |
||||
|
/// <summary>
|
||||
|
/// 相对当前坐标点的距离,当有门牌号的时候返回数据
|
||||
|
/// </summary>
|
||||
|
public string Distance { get; set; } |
||||
|
} |
||||
|
} |
||||
@ -1,7 +1,8 @@ |
|||||
namespace LINGYUN.Abp.Location.Baidu.Http |
namespace LINGYUN.Abp.Location.Baidu.Model |
||||
{ |
{ |
||||
public class BaiduPositiveLocationResponse : BaiduLocationResponse |
public class BaiduGeocode |
||||
{ |
{ |
||||
|
public BaiduLocation Location { get; set; } = new BaiduLocation(); |
||||
public int Precise { get; set; } |
public int Precise { get; set; } |
||||
public int Confidence { get; set; } |
public int Confidence { get; set; } |
||||
public int Comprehension { get; set; } |
public int Comprehension { get; set; } |
||||
@ -1,6 +1,6 @@ |
|||||
namespace LINGYUN.Abp.Location.Baidu.Http |
namespace LINGYUN.Abp.Location.Baidu.Model |
||||
{ |
{ |
||||
public class Location |
public class BaiduLocation |
||||
{ |
{ |
||||
public double Lat { get; set; } |
public double Lat { get; set; } |
||||
public double Lng { get; set; } |
public double Lng { get; set; } |
||||
@ -0,0 +1,58 @@ |
|||||
|
using Newtonsoft.Json; |
||||
|
|
||||
|
namespace LINGYUN.Abp.Location.Baidu.Model |
||||
|
{ |
||||
|
public class BaiduPoi |
||||
|
{ |
||||
|
/// <summary>
|
||||
|
/// 地址信息
|
||||
|
/// </summary>
|
||||
|
[JsonProperty("addr")] |
||||
|
public string Address { get; set; } |
||||
|
/// <summary>
|
||||
|
/// 名称
|
||||
|
/// </summary>
|
||||
|
public string Name { get; set; } |
||||
|
/// <summary>
|
||||
|
/// 标记
|
||||
|
/// </summary>
|
||||
|
public string Tag { get; set; } |
||||
|
/// <summary>
|
||||
|
/// 和当前坐标点的方向
|
||||
|
/// </summary>
|
||||
|
public string Direction { get; set; } |
||||
|
/// <summary>
|
||||
|
/// 离坐标点距离
|
||||
|
/// </summary>
|
||||
|
public string Distance { get; set; } |
||||
|
/// <summary>
|
||||
|
/// poi坐标{x,y}
|
||||
|
/// </summary>
|
||||
|
public Point Point { get; set; } = new Point(); |
||||
|
|
||||
|
/// <summary>
|
||||
|
/// 坐标类型
|
||||
|
/// </summary>
|
||||
|
public string PoiType { get; set; } |
||||
|
/// <summary>
|
||||
|
/// 电话
|
||||
|
/// </summary>
|
||||
|
[JsonProperty("tel")] |
||||
|
public string TelPhone { get; set; } |
||||
|
/// <summary>
|
||||
|
/// poi唯一标识
|
||||
|
/// </summary>
|
||||
|
public string Uid { get; set; } |
||||
|
/// <summary>
|
||||
|
/// 邮编
|
||||
|
/// </summary>
|
||||
|
[JsonProperty("zip")] |
||||
|
public string Post { get; set; } |
||||
|
/// <summary>
|
||||
|
/// poi对应的主点poi(如,海底捞的主点为上地华联,该字段则为上地华联的poi信息。
|
||||
|
/// 如无,该字段为空),包含子字段和pois基础召回字段相同。
|
||||
|
/// </summary>
|
||||
|
[JsonProperty("parent_poi")] |
||||
|
public BaiduPoi ParentPoi { get; set; } |
||||
|
} |
||||
|
} |
||||
@ -0,0 +1,47 @@ |
|||||
|
using Newtonsoft.Json; |
||||
|
using System.Collections.Generic; |
||||
|
|
||||
|
namespace LINGYUN.Abp.Location.Baidu.Model |
||||
|
{ |
||||
|
public class BaiduReGeocode |
||||
|
{ |
||||
|
/// <summary>
|
||||
|
/// 结构化地址信息
|
||||
|
/// </summary>
|
||||
|
[JsonProperty("formatted_address")] |
||||
|
public string Address { get; set; } |
||||
|
/// <summary>
|
||||
|
/// 坐标所在商圈信息,如 "人民大学,中关村,苏州街"。
|
||||
|
/// 最多返回3个。
|
||||
|
/// </summary>
|
||||
|
public string Business { get; set; } |
||||
|
/// <summary>
|
||||
|
/// 地址元素列表
|
||||
|
/// </summary>
|
||||
|
public AddressComponent AddressComponent { get; set; } |
||||
|
/// <summary>
|
||||
|
/// 周边poi数组
|
||||
|
/// </summary>
|
||||
|
public List<BaiduPoi> Pois { get; set; } |
||||
|
/// <summary>
|
||||
|
/// 周边道路数组
|
||||
|
/// </summary>
|
||||
|
public List<BaiduRoad> Roads { get; set; } |
||||
|
/// <summary>
|
||||
|
/// 周边区域面数组
|
||||
|
/// </summary>
|
||||
|
public List<PoiRegion> PoiRegions { get; set; } |
||||
|
/// <summary>
|
||||
|
/// 当前位置结合POI的语义化结果描述
|
||||
|
/// </summary>
|
||||
|
[JsonProperty("sematic_description")] |
||||
|
public string SematicDescription { get; set; } |
||||
|
public BaiduReGeocode() |
||||
|
{ |
||||
|
AddressComponent = new AddressComponent(); |
||||
|
Pois = new List<BaiduPoi>(); |
||||
|
Roads = new List<BaiduRoad>(); |
||||
|
PoiRegions = new List<PoiRegion>(); |
||||
|
} |
||||
|
} |
||||
|
} |
||||
@ -0,0 +1,14 @@ |
|||||
|
namespace LINGYUN.Abp.Location.Baidu.Model |
||||
|
{ |
||||
|
/// <summary>
|
||||
|
/// 道路
|
||||
|
/// </summary>
|
||||
|
public class BaiduRoad |
||||
|
{ |
||||
|
public string Name { get; set; } |
||||
|
/// <summary>
|
||||
|
/// 传入的坐标点距离道路的大概距离
|
||||
|
/// </summary>
|
||||
|
public string Distance { get; set; } |
||||
|
} |
||||
|
} |
||||
@ -0,0 +1,32 @@ |
|||||
|
using Newtonsoft.Json; |
||||
|
|
||||
|
namespace LINGYUN.Abp.Location.Baidu.Model |
||||
|
{ |
||||
|
/// <summary>
|
||||
|
/// 区域面
|
||||
|
/// </summary>
|
||||
|
public class PoiRegion |
||||
|
{ |
||||
|
/// <summary>
|
||||
|
/// 归属区域面名称
|
||||
|
/// </summary>
|
||||
|
public string Name { get; set; } |
||||
|
/// <summary>
|
||||
|
/// 归属区域面类型
|
||||
|
/// </summary>
|
||||
|
public string Tag { get; set; } |
||||
|
/// <summary>
|
||||
|
/// 请求中的坐标与所归属区域面的相对位置关系
|
||||
|
/// </summary>
|
||||
|
[JsonProperty("direction_desc")] |
||||
|
public string DirectionDesc { get; set; } |
||||
|
/// <summary>
|
||||
|
/// poi唯一标识
|
||||
|
/// </summary>
|
||||
|
public string Uid { get; set; } |
||||
|
/// <summary>
|
||||
|
/// 离坐标点距离
|
||||
|
/// </summary>
|
||||
|
public string Distance { get; set; } |
||||
|
} |
||||
|
} |
||||
@ -0,0 +1,8 @@ |
|||||
|
namespace LINGYUN.Abp.Location.Baidu.Model |
||||
|
{ |
||||
|
public class Point |
||||
|
{ |
||||
|
public float X { get; set; } |
||||
|
public float Y { get; set; } |
||||
|
} |
||||
|
} |
||||
@ -0,0 +1,9 @@ |
|||||
|
using LINGYUN.Abp.Location.Baidu.Model; |
||||
|
|
||||
|
namespace LINGYUN.Abp.Location.Baidu.Response |
||||
|
{ |
||||
|
public class BaiduGeocodeResponse : BaiduLocationResponse |
||||
|
{ |
||||
|
public BaiduGeocode Result { get; set; } = new BaiduGeocode(); |
||||
|
} |
||||
|
} |
||||
@ -0,0 +1,124 @@ |
|||||
|
using LINYUN.Abp.Location.Baidu.Localization; |
||||
|
using Volo.Abp; |
||||
|
using Volo.Abp.Localization; |
||||
|
|
||||
|
namespace LINGYUN.Abp.Location.Baidu.Response |
||||
|
{ |
||||
|
public abstract class BaiduLocationResponse |
||||
|
{ |
||||
|
public int Status { get; set; } |
||||
|
|
||||
|
public bool IsSuccess() |
||||
|
{ |
||||
|
return Status == 0; |
||||
|
} |
||||
|
|
||||
|
public ILocalizableString GetErrorMessage() |
||||
|
{ |
||||
|
switch (Status) |
||||
|
{ |
||||
|
case 0: |
||||
|
return LocalizableString.Create<BaiduLocationResource>("Message:RETURN_0"); |
||||
|
case 1: |
||||
|
return LocalizableString.Create<BaiduLocationResource>("Message:RETURN_1"); |
||||
|
case 10: |
||||
|
return LocalizableString.Create<BaiduLocationResource>("Message:RETURN_10"); |
||||
|
case 101: |
||||
|
return LocalizableString.Create<BaiduLocationResource>("Message:RETURN_101"); |
||||
|
case 102: |
||||
|
return LocalizableString.Create<BaiduLocationResource>("Message:RETURN_102"); |
||||
|
case 200: |
||||
|
return LocalizableString.Create<BaiduLocationResource>("Message:RETURN_200"); |
||||
|
case 201: |
||||
|
return LocalizableString.Create<BaiduLocationResource>("Message:RETURN_201"); |
||||
|
case 202: |
||||
|
return LocalizableString.Create<BaiduLocationResource>("Message:RETURN_202"); |
||||
|
case 203: |
||||
|
return LocalizableString.Create<BaiduLocationResource>("Message:RETURN_203"); |
||||
|
case 210: |
||||
|
return LocalizableString.Create<BaiduLocationResource>("Message:RETURN_210"); |
||||
|
case 211: |
||||
|
return LocalizableString.Create<BaiduLocationResource>("Message:RETURN_211"); |
||||
|
case 220: |
||||
|
return LocalizableString.Create<BaiduLocationResource>("Message:RETURN_220"); |
||||
|
case 230: |
||||
|
return LocalizableString.Create<BaiduLocationResource>("Message:RETURN_230"); |
||||
|
case 240: |
||||
|
return LocalizableString.Create<BaiduLocationResource>("Message:RETURN_240"); |
||||
|
case 250: |
||||
|
return LocalizableString.Create<BaiduLocationResource>("Message:RETURN_250"); |
||||
|
case 251: |
||||
|
return LocalizableString.Create<BaiduLocationResource>("Message:RETURN_251"); |
||||
|
case 252: |
||||
|
return LocalizableString.Create<BaiduLocationResource>("Message:RETURN_252"); |
||||
|
case 260: |
||||
|
return LocalizableString.Create<BaiduLocationResource>("Message:RETURN_260"); |
||||
|
case 261: |
||||
|
return LocalizableString.Create<BaiduLocationResource>("Message:RETURN_261"); |
||||
|
case 301: |
||||
|
return LocalizableString.Create<BaiduLocationResource>("Message:RETURN_301"); |
||||
|
case 302: |
||||
|
return LocalizableString.Create<BaiduLocationResource>("Message:RETURN_302"); |
||||
|
case 401: |
||||
|
return LocalizableString.Create<BaiduLocationResource>("Message:RETURN_401"); |
||||
|
case 402: |
||||
|
return LocalizableString.Create<BaiduLocationResource>("Message:RETURN_402"); |
||||
|
default: throw new AbpException($"{Status} - no error code define!"); |
||||
|
} |
||||
|
} |
||||
|
|
||||
|
public ILocalizableString GetErrorDescription() |
||||
|
{ |
||||
|
switch (Status) |
||||
|
{ |
||||
|
case 0: |
||||
|
return LocalizableString.Create<BaiduLocationResource>("Description:RETURN_0"); |
||||
|
case 1: |
||||
|
return LocalizableString.Create<BaiduLocationResource>("Description:RETURN_1"); |
||||
|
case 10: |
||||
|
return LocalizableString.Create<BaiduLocationResource>("Description:RETURN_10"); |
||||
|
case 101: |
||||
|
return LocalizableString.Create<BaiduLocationResource>("Description:RETURN_101"); |
||||
|
case 102: |
||||
|
return LocalizableString.Create<BaiduLocationResource>("Description:RETURN_102"); |
||||
|
case 200: |
||||
|
return LocalizableString.Create<BaiduLocationResource>("Description:RETURN_200"); |
||||
|
case 201: |
||||
|
return LocalizableString.Create<BaiduLocationResource>("Description:RETURN_201"); |
||||
|
case 202: |
||||
|
return LocalizableString.Create<BaiduLocationResource>("Description:RETURN_202"); |
||||
|
case 203: |
||||
|
return LocalizableString.Create<BaiduLocationResource>("Description:RETURN_203"); |
||||
|
case 210: |
||||
|
return LocalizableString.Create<BaiduLocationResource>("Description:RETURN_210"); |
||||
|
case 211: |
||||
|
return LocalizableString.Create<BaiduLocationResource>("Description:RETURN_211"); |
||||
|
case 220: |
||||
|
return LocalizableString.Create<BaiduLocationResource>("Description:RETURN_220"); |
||||
|
case 230: |
||||
|
return LocalizableString.Create<BaiduLocationResource>("Description:RETURN_230"); |
||||
|
case 240: |
||||
|
return LocalizableString.Create<BaiduLocationResource>("Description:RETURN_240"); |
||||
|
case 250: |
||||
|
return LocalizableString.Create<BaiduLocationResource>("Description:RETURN_250"); |
||||
|
case 251: |
||||
|
return LocalizableString.Create<BaiduLocationResource>("Description:RETURN_251"); |
||||
|
case 252: |
||||
|
return LocalizableString.Create<BaiduLocationResource>("Description:RETURN_252"); |
||||
|
case 260: |
||||
|
return LocalizableString.Create<BaiduLocationResource>("Description:RETURN_260"); |
||||
|
case 261: |
||||
|
return LocalizableString.Create<BaiduLocationResource>("Description:RETURN_261"); |
||||
|
case 301: |
||||
|
return LocalizableString.Create<BaiduLocationResource>("Description:RETURN_301"); |
||||
|
case 302: |
||||
|
return LocalizableString.Create<BaiduLocationResource>("Description:RETURN_302"); |
||||
|
case 401: |
||||
|
return LocalizableString.Create<BaiduLocationResource>("Description:RETURN_401"); |
||||
|
case 402: |
||||
|
return LocalizableString.Create<BaiduLocationResource>("Description:RETURN_402"); |
||||
|
default: throw new AbpException($"{Status} - no error code define!"); |
||||
|
} |
||||
|
} |
||||
|
} |
||||
|
} |
||||
@ -0,0 +1,9 @@ |
|||||
|
using LINGYUN.Abp.Location.Baidu.Model; |
||||
|
|
||||
|
namespace LINGYUN.Abp.Location.Baidu.Response |
||||
|
{ |
||||
|
public class BaiduReGeocodeResponse : BaiduLocationResponse |
||||
|
{ |
||||
|
public BaiduReGeocode Result { get; set; } = new BaiduReGeocode(); |
||||
|
} |
||||
|
} |
||||
@ -0,0 +1,63 @@ |
|||||
|
using System; |
||||
|
using System.Collections.Generic; |
||||
|
using System.Text; |
||||
|
|
||||
|
namespace LINGYUN.Abp.Location.Baidu.Utils |
||||
|
{ |
||||
|
public class BaiduAKSNCaculater |
||||
|
{ |
||||
|
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 UrlEncode(string str) |
||||
|
{ |
||||
|
str = System.Web.HttpUtility.UrlEncode(str); |
||||
|
byte[] buf = Encoding.ASCII.GetBytes(str);//等同于Encoding.ASCII.GetBytes(str)
|
||||
|
for (int i = 0; i < buf.Length; i++) |
||||
|
if (buf[i] == '%') |
||||
|
{ |
||||
|
if (buf[i + 1] >= 'a') buf[i + 1] -= 32; |
||||
|
if (buf[i + 2] >= 'a') buf[i + 2] -= 32; |
||||
|
i += 2; |
||||
|
} |
||||
|
return Encoding.ASCII.GetString(buf);//同上,等同于Encoding.ASCII.GetString(buf)
|
||||
|
} |
||||
|
|
||||
|
private static string HttpBuildQuery(IDictionary<string, string> querystring_arrays) |
||||
|
{ |
||||
|
|
||||
|
StringBuilder sb = new StringBuilder(); |
||||
|
foreach (var item in querystring_arrays) |
||||
|
{ |
||||
|
sb.Append(UrlEncode(item.Key)); |
||||
|
sb.Append("="); |
||||
|
sb.Append(UrlEncode(item.Value)); |
||||
|
sb.Append("&"); |
||||
|
} |
||||
|
sb.Remove(sb.Length - 1, 1); |
||||
|
return sb.ToString(); |
||||
|
} |
||||
|
|
||||
|
public static string CaculateAKSN(string sk, string url, IDictionary<string, string> querystring_arrays) |
||||
|
{ |
||||
|
var queryString = HttpBuildQuery(querystring_arrays); |
||||
|
|
||||
|
var str = UrlEncode(url + "?" + queryString + sk); |
||||
|
|
||||
|
return MD5(str); |
||||
|
} |
||||
|
} |
||||
|
} |
||||
@ -1,9 +1,11 @@ |
|||||
namespace LINGYUN.Abp.Location |
using System.Threading.Tasks; |
||||
|
|
||||
|
namespace LINGYUN.Abp.Location |
||||
{ |
{ |
||||
public interface ILocationResolveProvider |
public interface ILocationResolveProvider |
||||
{ |
{ |
||||
PositiveLocation GetPositiveLocation(string address); |
Task<GecodeLocation> GeocodeAsync(string address, string city = null); |
||||
|
|
||||
InverseLocation GetInverseLocation(double lat, double lng); |
Task<ReGeocodeLocation> ReGeocodeAsync(double lat, double lng, int radius = 50); |
||||
} |
} |
||||
} |
} |
||||
|
|||||
@ -0,0 +1,10 @@ |
|||||
|
namespace LINGYUN.Abp.Location |
||||
|
{ |
||||
|
public class Poi |
||||
|
{ |
||||
|
public string Tag { get; set; } |
||||
|
public string Name { get; set; } |
||||
|
public string Type { get; set; } |
||||
|
public string Address { get; set; } |
||||
|
} |
||||
|
} |
||||
@ -0,0 +1,7 @@ |
|||||
|
namespace LINGYUN.Abp.Location |
||||
|
{ |
||||
|
public class Road |
||||
|
{ |
||||
|
public string Name { get; set; } |
||||
|
} |
||||
|
} |
||||
@ -0,0 +1,8 @@ |
|||||
|
<Project Sdk="Microsoft.NET.Sdk"> |
||||
|
|
||||
|
<PropertyGroup> |
||||
|
<TargetFramework>netstandard2.0</TargetFramework> |
||||
|
<RootNamespace /> |
||||
|
</PropertyGroup> |
||||
|
|
||||
|
</Project> |
||||
@ -0,0 +1,17 @@ |
|||||
|
namespace LINGYUN.Abp.MessageService.Messages |
||||
|
{ |
||||
|
/// <summary>
|
||||
|
/// 读取状态
|
||||
|
/// </summary>
|
||||
|
public enum ReadStatus : sbyte |
||||
|
{ |
||||
|
/// <summary>
|
||||
|
/// 已读
|
||||
|
/// </summary>
|
||||
|
Read = 0, |
||||
|
/// <summary>
|
||||
|
/// 未读
|
||||
|
/// </summary>
|
||||
|
UnRead = 10 |
||||
|
} |
||||
|
} |
||||
@ -0,0 +1,25 @@ |
|||||
|
namespace LINGYUN.Abp.MessageService.Messages |
||||
|
{ |
||||
|
/// <summary>
|
||||
|
/// 消息状态
|
||||
|
/// </summary>
|
||||
|
public enum SendStatus : sbyte |
||||
|
{ |
||||
|
/// <summary>
|
||||
|
/// 已发送
|
||||
|
/// </summary>
|
||||
|
Send = 0, |
||||
|
/// <summary>
|
||||
|
/// 撤回
|
||||
|
/// </summary>
|
||||
|
ReCall = 10, |
||||
|
/// <summary>
|
||||
|
/// 发送失败
|
||||
|
/// </summary>
|
||||
|
Failed = 50, |
||||
|
/// <summary>
|
||||
|
/// 退回
|
||||
|
/// </summary>
|
||||
|
BackTo = 100 |
||||
|
} |
||||
|
} |
||||
@ -0,0 +1,20 @@ |
|||||
|
<Project Sdk="Microsoft.NET.Sdk"> |
||||
|
|
||||
|
<PropertyGroup> |
||||
|
<TargetFramework>netstandard2.0</TargetFramework> |
||||
|
<RootNamespace /> |
||||
|
</PropertyGroup> |
||||
|
|
||||
|
<ItemGroup> |
||||
|
<PackageReference Include="Volo.Abp.Ddd.Domain" Version="2.8.0" /> |
||||
|
</ItemGroup> |
||||
|
|
||||
|
<ItemGroup> |
||||
|
<Folder Include="LINGYUN\Abp\MessageService\Notifications\" /> |
||||
|
</ItemGroup> |
||||
|
|
||||
|
<ItemGroup> |
||||
|
<ProjectReference Include="..\LINGYUN.Abp.MessageService.Domain.Shared\LINGYUN.Abp.MessageService.Domain.Shared.csproj" /> |
||||
|
</ItemGroup> |
||||
|
|
||||
|
</Project> |
||||
@ -0,0 +1,9 @@ |
|||||
|
using Volo.Abp.Modularity; |
||||
|
|
||||
|
namespace LINGYUN.Abp.MessageService |
||||
|
{ |
||||
|
public class AbpMessageServiceDomainModule : AbpModule |
||||
|
{ |
||||
|
|
||||
|
} |
||||
|
} |
||||
@ -0,0 +1,34 @@ |
|||||
|
using System; |
||||
|
using Volo.Abp.Domain.Entities; |
||||
|
using Volo.Abp.MultiTenancy; |
||||
|
|
||||
|
namespace LINGYUN.Abp.MessageService.Messages |
||||
|
{ |
||||
|
public abstract class ChatMessage : Entity<long>, IMultiTenant |
||||
|
{ |
||||
|
/// <summary>
|
||||
|
/// 租户
|
||||
|
/// </summary>
|
||||
|
public virtual Guid? TenantId { get; protected set; } |
||||
|
/// <summary>
|
||||
|
/// 发送用户标识
|
||||
|
/// </summary>
|
||||
|
public virtual Guid SendUserId { get; protected set; } |
||||
|
/// <summary>
|
||||
|
/// 接收用户标识
|
||||
|
/// </summary>
|
||||
|
public virtual Guid ReceiveUserId { get; set; } |
||||
|
/// <summary>
|
||||
|
/// 内容
|
||||
|
/// </summary>
|
||||
|
public virtual string Content { get; protected set; } |
||||
|
/// <summary>
|
||||
|
/// 发送状态
|
||||
|
/// </summary>
|
||||
|
public virtual SendStatus SendStatus { get; protected set; } |
||||
|
/// <summary>
|
||||
|
/// 阅读状态
|
||||
|
/// </summary>
|
||||
|
public virtual ReadStatus ReadStatus { get; protected set; } |
||||
|
} |
||||
|
} |
||||
@ -0,0 +1,13 @@ |
|||||
|
using System; |
||||
|
using Volo.Abp.Domain.Entities.Auditing; |
||||
|
using Volo.Abp.MultiTenancy; |
||||
|
|
||||
|
namespace LINGYUN.Abp.MessageService.Subscriptions |
||||
|
{ |
||||
|
public class Subscribe : CreationAuditedEntity<long>, IMultiTenant |
||||
|
{ |
||||
|
public virtual Guid? TenantId { get; protected set; } |
||||
|
public virtual string EventType { get; protected set; } |
||||
|
public virtual string RoleName { get; protected set; } |
||||
|
} |
||||
|
} |
||||
@ -0,0 +1,12 @@ |
|||||
|
<Project Sdk="Microsoft.NET.Sdk"> |
||||
|
|
||||
|
<PropertyGroup> |
||||
|
<TargetFramework>netcoreapp3.1</TargetFramework> |
||||
|
<RootNamespace /> |
||||
|
</PropertyGroup> |
||||
|
|
||||
|
<ItemGroup> |
||||
|
<ProjectReference Include="..\..\common\LINGYUN.Abp.IM.SignalR\LINGYUN.Abp.IM.SignalR.csproj" /> |
||||
|
</ItemGroup> |
||||
|
|
||||
|
</Project> |
||||
@ -0,0 +1,10 @@ |
|||||
|
using System.Threading.Tasks; |
||||
|
using LINGYUN.Abp.AspNetCore.SignalR; |
||||
|
|
||||
|
namespace LINGYUN.Abp.MessageService.SignalR |
||||
|
{ |
||||
|
public abstract class ChatMessaheHub : OnlineClientHubBase |
||||
|
{ |
||||
|
|
||||
|
} |
||||
|
} |
||||
@ -0,0 +1,38 @@ |
|||||
|
using LINGYUN.Abp.Location; |
||||
|
using Microsoft.AspNetCore.Mvc; |
||||
|
using System.Threading.Tasks; |
||||
|
using Volo.Abp.AspNetCore.Mvc; |
||||
|
|
||||
|
#if DEBUG
|
||||
|
namespace LINGYUN.Platform.Controllers |
||||
|
{ |
||||
|
[Route("Location")] |
||||
|
public class LocationController : AbpController |
||||
|
{ |
||||
|
protected ILocationResolveProvider LocationResolveProvider { get; } |
||||
|
|
||||
|
public LocationController( |
||||
|
ILocationResolveProvider locationResolveProvider) |
||||
|
{ |
||||
|
LocationResolveProvider = locationResolveProvider; |
||||
|
} |
||||
|
|
||||
|
[HttpGet] |
||||
|
[Route("Geocode")] |
||||
|
public async Task<GecodeLocation> GeocodeAsync(string address) |
||||
|
{ |
||||
|
var location = await LocationResolveProvider.GeocodeAsync(address); |
||||
|
return location; |
||||
|
} |
||||
|
|
||||
|
[HttpGet] |
||||
|
[Route("ReGeocode")] |
||||
|
|
||||
|
public async Task<ReGeocodeLocation> ReGeocodeAsync(double lat, double lng) |
||||
|
{ |
||||
|
var location = await LocationResolveProvider.ReGeocodeAsync(lat, lng); |
||||
|
return location; |
||||
|
} |
||||
|
} |
||||
|
} |
||||
|
#endif
|
||||
Loading…
Reference in new issue