1.0.0.1
This commit is contained in:
parent
56e3b1d901
commit
7f5b0651d4
|
|
@ -0,0 +1,52 @@
|
|||
using CloudGaming.Api.Base;
|
||||
using CloudGaming.Code.Cache;
|
||||
using CloudGaming.Code.Game;
|
||||
using CloudGaming.Code.MiddlewareExtend;
|
||||
using CloudGaming.DtoModel.Game;
|
||||
using CloudGaming.GameModel.Db.Db_Game;
|
||||
|
||||
using Microsoft.AspNetCore.Mvc;
|
||||
|
||||
namespace CloudGaming.Api.Controllers
|
||||
{
|
||||
/// <summary>
|
||||
/// 游戏控制器
|
||||
/// </summary>
|
||||
public class GameController : CloudGamingControllerBase
|
||||
{
|
||||
public GameController(IServiceProvider _serviceProvider) : base(_serviceProvider)
|
||||
{
|
||||
}
|
||||
|
||||
|
||||
/// <summary>
|
||||
/// 游戏类型列表
|
||||
/// </summary>
|
||||
/// <returns></returns>
|
||||
[HttpGet]
|
||||
[RedisCache(2, 0, 0)]
|
||||
public async Task<List<GameExtendedAttribute>> GetGameTypeListAsync()
|
||||
{
|
||||
GameBLL gamebll = new GameBLL(this.ServiceProvider);
|
||||
return await gamebll.GetGameTypeListAsync();
|
||||
}
|
||||
|
||||
|
||||
/// <summary>
|
||||
/// 根据游戏类型Id 获取游戏列表
|
||||
/// </summary>
|
||||
/// <param name="typeId"></param>
|
||||
/// <returns></returns>
|
||||
[HttpGet]
|
||||
[RedisCache(2, 5, 0)]
|
||||
public async Task<List<GameListDto>> GetGameListAsync([FromQuery] int typeId)
|
||||
{
|
||||
if (typeId == 0)
|
||||
{
|
||||
return new List<GameListDto>();
|
||||
}
|
||||
GameBLL gamebll = new GameBLL(this.ServiceProvider);
|
||||
return await gamebll.GetGameListAsync(typeId);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
@ -1,5 +1,6 @@
|
|||
using CloudGaming.Api.Base;
|
||||
using CloudGaming.Code.Epg;
|
||||
using CloudGaming.Code.MiddlewareExtend;
|
||||
using CloudGaming.DtoModel.Epg;
|
||||
|
||||
using Microsoft.AspNetCore.JsonPatch.Internal;
|
||||
|
|
@ -18,6 +19,7 @@ public class HomeController : CloudGamingControllerBase
|
|||
/// </summary>
|
||||
/// <returns></returns>
|
||||
[HttpGet]
|
||||
[RedisCache(1, 0, 0)]
|
||||
public async Task<List<EpgCategoryDto>> GetHomeInfo()
|
||||
{
|
||||
EpgBLL epgBLL = new EpgBLL(ServiceProvider);
|
||||
|
|
|
|||
|
|
@ -17,6 +17,7 @@ using CloudGaming.Code.AppExtend.JsonConverHelper;
|
|||
using Microsoft.AspNetCore.Mvc.Infrastructure;
|
||||
using Microsoft.Extensions.Options;
|
||||
using CloudGaming.GameModel.Db.Db_Ext;
|
||||
using CloudGaming.Code.MiddlewareExtend;
|
||||
var builder = WebApplication.CreateBuilder(args);
|
||||
#region 日志
|
||||
// Add services to the container.
|
||||
|
|
@ -37,6 +38,7 @@ builder.Services.AddSingleton(typeof(ILogger<ExceptionMiddleware>), serviceProvi
|
|||
return loggerFactory.CreateLogger<ExceptionMiddleware>();
|
||||
});
|
||||
#endregion
|
||||
builder.Services.AddMemoryCache();
|
||||
builder.Services.AddHttpClient();
|
||||
builder.Services.AddHttpContextAccessor(); //添加httpContext注入访问
|
||||
#region 返回数据解析
|
||||
|
|
@ -168,6 +170,8 @@ app.MapControllers();
|
|||
app.UseStaticFiles();//静态文件访问配置
|
||||
//执行扩展中间件
|
||||
app.UseMiddlewareAll();
|
||||
//缓存中间件
|
||||
app.UseCloudGamingMiddlewareAll();
|
||||
#region 默认请求
|
||||
app.MapGet("/", () => "请求成功").WithName("默认请求");
|
||||
|
||||
|
|
|
|||
|
|
@ -3,6 +3,9 @@ using AgileConfig.Client;
|
|||
using CloudGaming.Code.DataAccess.MultiTenantUtil;
|
||||
|
||||
using HuanMeng.DotNetCore.CacheHelper;
|
||||
using HuanMeng.DotNetCore.Redis;
|
||||
|
||||
using StackExchange.Redis;
|
||||
|
||||
using System.Collections.Concurrent;
|
||||
using System.Collections.Frozen;
|
||||
|
|
@ -136,6 +139,15 @@ namespace CloudGaming.Code.AppExtend
|
|||
tenantInfo.Name = appConfig.Name;
|
||||
return tenantInfo;
|
||||
}
|
||||
/// <summary>
|
||||
/// 获取redis缓存
|
||||
/// </summary>
|
||||
/// <param name="appConfig"></param>
|
||||
/// <returns></returns>
|
||||
public static IDatabase GetRedisDataBase(this AppConfig appConfig)
|
||||
{
|
||||
return RedisConnection.GetRedis(appConfig.RedisConnectionString);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
///
|
||||
|
|
|
|||
|
|
@ -110,6 +110,15 @@ namespace CloudGaming.Code.AppExtend
|
|||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// 获取key
|
||||
/// </summary>
|
||||
public string Key
|
||||
{
|
||||
|
||||
get => $"{Language}_{Channel}_{Version}";
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// 地区
|
||||
/// </summary>
|
||||
|
|
|
|||
|
|
@ -71,7 +71,7 @@ namespace CloudGaming.Code.Cache
|
|||
#endregion
|
||||
|
||||
|
||||
public GameEntityCache? gameEntityCache;
|
||||
private GameEntityCache? gameEntityCache;
|
||||
|
||||
/// <summary>
|
||||
/// 游戏缓存
|
||||
|
|
|
|||
|
|
@ -27,7 +27,8 @@ namespace CloudGaming.Code.Cache.Special
|
|||
|
||||
public override string key => $"{appConfig.Identifier}:game:gameInfo";
|
||||
|
||||
public string locaKey => $"{appConfig.Identifier}:lock:gameInfo";
|
||||
public string locaKey => $"lock:gameInfo";
|
||||
public string RedisKey => $"cache:game:gameInfo";
|
||||
|
||||
public override List<GameInfo> GetDataList()
|
||||
{
|
||||
|
|
@ -71,10 +72,10 @@ namespace CloudGaming.Code.Cache.Special
|
|||
return _dataList;
|
||||
}
|
||||
|
||||
long hashLength = database.HashLength(key);
|
||||
long hashLength = database.HashLength(RedisKey);
|
||||
if (hashLength > 0)
|
||||
{
|
||||
var hashEntries = database.HashGetAll(key);
|
||||
var hashEntries = database.HashGetAll(RedisKey);
|
||||
var list = hashEntries
|
||||
.Where(entry => !string.IsNullOrEmpty(entry.Value))
|
||||
.Select(entry => JsonConvert.DeserializeObject<GameInfo>(entry.Value))
|
||||
|
|
@ -94,7 +95,7 @@ namespace CloudGaming.Code.Cache.Special
|
|||
var serializedGameInfos = tempDataList
|
||||
.Select(info => new HashEntry($"gameInfo:{info.GameId}", JsonConvert.SerializeObject(info)))
|
||||
.ToArray();
|
||||
database.HashSet(key, serializedGameInfos);
|
||||
database.HashSet(RedisKey, serializedGameInfos);
|
||||
|
||||
MemoryCacheHelper.SetCache(key, tempDataList, 60 * 60);
|
||||
_dataList = tempDataList;
|
||||
|
|
|
|||
|
|
@ -29,8 +29,7 @@ namespace CloudGaming.Code.DataAccess.MultiTenantUtil
|
|||
/// <returns></returns>
|
||||
public virtual async Task Invoke(HttpContext context,
|
||||
IServiceProvider _serviceProvider,
|
||||
AppConfig appConfig
|
||||
)
|
||||
AppConfig appConfig )
|
||||
{
|
||||
|
||||
var host = context.Request.Host.Host;
|
||||
|
|
|
|||
|
|
@ -47,8 +47,14 @@ namespace CloudGaming.Code.Epg
|
|||
return null;
|
||||
}
|
||||
|
||||
epgInfo.Title ??= gameInfo.GameName;
|
||||
epgInfo.SubTitle ??= gameInfo.Title2;
|
||||
if (string.IsNullOrEmpty(epgInfo.Title))
|
||||
{
|
||||
epgInfo.Title = gameInfo.GameName;
|
||||
}
|
||||
if (string.IsNullOrEmpty(epgInfo.SubTitle))
|
||||
{
|
||||
epgInfo.SubTitle = gameInfo.Title2;
|
||||
}
|
||||
|
||||
if (epgInfo.ImageUrl == 0 && !string.IsNullOrEmpty(epgCfg.ImageResStyle))
|
||||
{
|
||||
|
|
|
|||
64
src/CloudGaming/Code/CloudGaming.Code/Game/GameBLL.cs
Normal file
64
src/CloudGaming/Code/CloudGaming.Code/Game/GameBLL.cs
Normal file
|
|
@ -0,0 +1,64 @@
|
|||
using CloudGaming.Code.Cache;
|
||||
using CloudGaming.DtoModel.Game;
|
||||
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Linq;
|
||||
using System.Text;
|
||||
using System.Threading.Tasks;
|
||||
|
||||
namespace CloudGaming.Code.Game
|
||||
{
|
||||
/// <summary>
|
||||
/// 游戏逻辑类
|
||||
/// </summary>
|
||||
public class GameBLL : CloudGamingBase
|
||||
{
|
||||
public GameBLL(IServiceProvider serviceProvider) : base(serviceProvider)
|
||||
{
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
///
|
||||
/// </summary>
|
||||
/// <returns></returns>
|
||||
public async Task<List<GameExtendedAttribute>> GetGameTypeListAsync()
|
||||
{
|
||||
var gameList = Cache.GameEntityCache?.DataList ?? new List<GameInfo>();
|
||||
var gameTypes = await Task.Run(() =>
|
||||
{
|
||||
return CloudGamingCacheExtend.GetDataEntityCache<T_Game_Types>(this, it => it.IsOnline)?.DataList
|
||||
.Where(it => gameList.Any(item => item.GameType?.Any(gameType => gameType.Id == it.TypeId) ?? false))
|
||||
.OrderBy(it => it.OrderId)
|
||||
.Select(it => new GameExtendedAttribute
|
||||
{
|
||||
Id = it.TypeId,
|
||||
Name = it.TypeName,
|
||||
OrderId = it.OrderId
|
||||
})
|
||||
.ToList();
|
||||
});
|
||||
|
||||
return gameTypes;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// 根据游戏类型Id 获取游戏列表
|
||||
/// </summary>
|
||||
/// <param name="typeId"></param>
|
||||
/// <returns></returns>
|
||||
public async Task<List<GameListDto>> GetGameListAsync(int typeId)
|
||||
{
|
||||
|
||||
var gameListDto = await Task.Run(() =>
|
||||
{
|
||||
var gameList = Cache.GameEntityCache?.DataList ?? new List<GameInfo>();
|
||||
var x = gameList.Where(it => it.GameType?.Any(item => item.Id == typeId) ?? false).Select(it => new
|
||||
GameListDto(it)).ToList();
|
||||
return x;
|
||||
});
|
||||
return gameListDto;
|
||||
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
@ -0,0 +1,147 @@
|
|||
using Microsoft.AspNetCore.Http.Features;
|
||||
using Microsoft.AspNetCore.Http;
|
||||
using Microsoft.Extensions.Caching.Memory;
|
||||
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Linq;
|
||||
using System.Text;
|
||||
using System.Threading.Tasks;
|
||||
using Microsoft.IdentityModel.Tokens;
|
||||
using System.Collections.Concurrent;
|
||||
|
||||
namespace CloudGaming.Code.MiddlewareExtend
|
||||
{
|
||||
/// <summary>
|
||||
/// 内存缓存
|
||||
/// </summary>
|
||||
public class MemoryCacheMiddleware
|
||||
{
|
||||
private readonly RequestDelegate _next;
|
||||
private readonly IMemoryCache _cache;
|
||||
private static readonly ConcurrentDictionary<Endpoint, MemoryCacheAttribute> _attributeCache = new();
|
||||
/// <summary>
|
||||
///
|
||||
/// </summary>
|
||||
/// <param name="next"></param>
|
||||
/// <param name="cache"></param>
|
||||
public MemoryCacheMiddleware(RequestDelegate next, IMemoryCache cache)
|
||||
{
|
||||
_next = next;
|
||||
_cache = cache;
|
||||
}
|
||||
|
||||
public async Task InvokeAsync(HttpContext context,
|
||||
IServiceProvider _serviceProvider,
|
||||
AppConfig appConfig
|
||||
)
|
||||
{
|
||||
// 检查当前请求是否需要缓存
|
||||
var cacheAttribute = GetCacheAttribute(context);
|
||||
if (cacheAttribute == null)
|
||||
{
|
||||
// 如果没有找到 MemoryCacheAttribute,直接调用下一个中间件
|
||||
await _next(context);
|
||||
return;
|
||||
}
|
||||
|
||||
// 生成缓存键(基于请求路径和查询字符串)
|
||||
var cacheKey = GenerateCacheKey(context.Request, appConfig);
|
||||
|
||||
// 尝试从缓存中获取数据
|
||||
if (_cache.TryGetValue(cacheKey, out string cachedResponse))
|
||||
{
|
||||
context.Response.StatusCode = StatusCodes.Status200OK;
|
||||
// 如果缓存中有数据,则直接返回缓存的响应
|
||||
context.Response.ContentType = "application/json";
|
||||
await context.Response.WriteAsync(cachedResponse);
|
||||
return;
|
||||
}
|
||||
|
||||
// 捕获原始响应流
|
||||
var originalResponseStream = context.Response.Body;
|
||||
|
||||
try
|
||||
{
|
||||
using (var memoryStream = new MemoryStream())
|
||||
{
|
||||
context.Response.Body = memoryStream;
|
||||
|
||||
// 调用下一个中间件
|
||||
await _next(context);
|
||||
|
||||
// 将响应流重新定位到起始位置
|
||||
memoryStream.Position = 0;
|
||||
|
||||
// 读取响应内容
|
||||
var responseBody = await new StreamReader(memoryStream).ReadToEndAsync();
|
||||
|
||||
// 将响应内容缓存
|
||||
_cache.Set(cacheKey, responseBody, cacheAttribute.TimeSpan);
|
||||
|
||||
// 将内容写回原始响应流
|
||||
memoryStream.Position = 0;
|
||||
await memoryStream.CopyToAsync(originalResponseStream);
|
||||
}
|
||||
}
|
||||
finally
|
||||
{
|
||||
// 恢复原始响应流
|
||||
context.Response.Body = originalResponseStream;
|
||||
}
|
||||
}
|
||||
|
||||
private MemoryCacheAttribute GetCacheAttribute(HttpContext context)
|
||||
{
|
||||
var endpoint = context.Features.Get<IEndpointFeature>()?.Endpoint;
|
||||
if (endpoint == null) return null;
|
||||
|
||||
// 使用字典缓存以减少重复获取
|
||||
if (_attributeCache.TryGetValue(endpoint, out var cachedAttribute))
|
||||
{
|
||||
return cachedAttribute;
|
||||
}
|
||||
|
||||
// 获取并缓存 MemoryCacheAttribute
|
||||
var attribute = endpoint.Metadata.GetMetadata<MemoryCacheAttribute>();
|
||||
if (attribute != null)
|
||||
{
|
||||
_attributeCache.TryAdd(endpoint, attribute);
|
||||
}
|
||||
|
||||
return attribute;
|
||||
}
|
||||
|
||||
private string GenerateCacheKey(HttpRequest request, AppConfig appConfig)
|
||||
{
|
||||
var appRequestInfo = new AppRequestConfig(request);
|
||||
// 基于请求路径和查询参数生成缓存键
|
||||
var cacheKey = $"{appConfig.Identifier}:{request.Path.Value.Replace('/', '.').TrimStart('.')}:{(string.IsNullOrEmpty(request.QueryString.Value) ? "default" : request.QueryString)}:{appRequestInfo.Key}";
|
||||
return cacheKey;
|
||||
}
|
||||
}
|
||||
/// <summary>
|
||||
/// 内存缓存特性类
|
||||
/// </summary>
|
||||
[AttributeUsage(AttributeTargets.Method, AllowMultiple = false)]
|
||||
public class MemoryCacheAttribute : Attribute
|
||||
{
|
||||
|
||||
public TimeSpan TimeSpan { get; }
|
||||
public MemoryCacheAttribute(int durationInSeconds)
|
||||
{
|
||||
TimeSpan = TimeSpan.FromSeconds(durationInSeconds);
|
||||
}
|
||||
public MemoryCacheAttribute(int hours, int minutes, int seconds)
|
||||
{
|
||||
|
||||
TimeSpan = new TimeSpan(hours, minutes, seconds);
|
||||
}
|
||||
public MemoryCacheAttribute(int minutes, int seconds)
|
||||
{
|
||||
|
||||
TimeSpan = new TimeSpan(0, minutes, seconds);
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
|
|
@ -0,0 +1,45 @@
|
|||
using HuanMeng.DotNetCore.MiddlewareExtend;
|
||||
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Linq;
|
||||
using System.Text;
|
||||
using System.Threading.Tasks;
|
||||
|
||||
namespace CloudGaming.Code.MiddlewareExtend
|
||||
{
|
||||
/// <summary>
|
||||
///
|
||||
/// </summary>
|
||||
public static class MiddlewareExtends
|
||||
{
|
||||
/// <summary>
|
||||
/// 加载全部中间件
|
||||
/// </summary>
|
||||
/// <param name="builder"></param>
|
||||
/// <returns></returns>
|
||||
public static IApplicationBuilder UseCloudGamingMiddlewareAll(this IApplicationBuilder builder)
|
||||
{
|
||||
return builder
|
||||
.UseCacheMiddleware()
|
||||
.UseRedisCacheMiddleware()
|
||||
;
|
||||
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// 缓存中间件
|
||||
/// </summary>
|
||||
/// <param name="builder"></param>
|
||||
/// <returns></returns>
|
||||
public static IApplicationBuilder UseCacheMiddleware(this IApplicationBuilder builder)
|
||||
{
|
||||
return builder.UseMiddleware<MemoryCacheMiddleware>();
|
||||
}
|
||||
public static IApplicationBuilder UseRedisCacheMiddleware(this IApplicationBuilder builder)
|
||||
{
|
||||
return builder.UseMiddleware<RedisCacheMiddleware>();
|
||||
}
|
||||
|
||||
}
|
||||
}
|
||||
|
|
@ -0,0 +1,124 @@
|
|||
using Microsoft.AspNetCore.Http;
|
||||
using Microsoft.AspNetCore.Http.Features;
|
||||
using Microsoft.Extensions.Caching.Distributed;
|
||||
|
||||
using System;
|
||||
using System.Collections.Concurrent;
|
||||
using System.IO;
|
||||
using System.Text;
|
||||
using System.Threading.Tasks;
|
||||
|
||||
namespace CloudGaming.Code.MiddlewareExtend
|
||||
{
|
||||
/// <summary>
|
||||
/// Redis 缓存中间件
|
||||
/// </summary>
|
||||
public class RedisCacheMiddleware
|
||||
{
|
||||
private readonly RequestDelegate _next;
|
||||
|
||||
private static readonly ConcurrentDictionary<Endpoint, RedisCacheAttribute> _attributeCache = new();
|
||||
|
||||
public RedisCacheMiddleware(RequestDelegate next)
|
||||
{
|
||||
_next = next;
|
||||
|
||||
}
|
||||
|
||||
public async Task InvokeAsync(HttpContext context,
|
||||
IServiceProvider _serviceProvider,
|
||||
AppConfig appConfig
|
||||
)
|
||||
{
|
||||
// 检查当前请求是否需要缓存
|
||||
var cacheAttribute = GetCacheAttribute(context);
|
||||
if (cacheAttribute == null)
|
||||
{
|
||||
await _next(context);
|
||||
return;
|
||||
}
|
||||
var _cache = appConfig.GetRedisDataBase();
|
||||
|
||||
// 生成缓存键(基于请求路径和查询字符串)
|
||||
var cacheKey = GenerateCacheKey(context.Request, appConfig);
|
||||
|
||||
// 尝试从 Redis 缓存中获取数据
|
||||
var cachedResponse = await _cache.StringGetAsync(cacheKey);
|
||||
if (!cachedResponse.IsNullOrEmpty)
|
||||
{
|
||||
context.Response.StatusCode = StatusCodes.Status200OK;
|
||||
context.Response.ContentType = "application/json";
|
||||
await context.Response.WriteAsync(cachedResponse);
|
||||
return;
|
||||
}
|
||||
|
||||
// 捕获原始响应流
|
||||
var originalResponseStream = context.Response.Body;
|
||||
|
||||
try
|
||||
{
|
||||
using (var memoryStream = new MemoryStream())
|
||||
{
|
||||
context.Response.Body = memoryStream;
|
||||
|
||||
// 调用下一个中间件
|
||||
await _next(context);
|
||||
|
||||
// 将响应流重新定位到起始位置
|
||||
memoryStream.Position = 0;
|
||||
|
||||
// 读取响应内容
|
||||
var responseBody = await new StreamReader(memoryStream).ReadToEndAsync();
|
||||
|
||||
await _cache.StringSetAsync(cacheKey, responseBody, cacheAttribute.TimeSpan);
|
||||
|
||||
// 将内容写回原始响应流
|
||||
memoryStream.Position = 0;
|
||||
await memoryStream.CopyToAsync(originalResponseStream);
|
||||
}
|
||||
}
|
||||
finally
|
||||
{
|
||||
context.Response.Body = originalResponseStream;
|
||||
}
|
||||
}
|
||||
|
||||
private RedisCacheAttribute GetCacheAttribute(HttpContext context)
|
||||
{
|
||||
var endpoint = context.Features.Get<IEndpointFeature>()?.Endpoint;
|
||||
if (endpoint == null) return null;
|
||||
|
||||
if (_attributeCache.TryGetValue(endpoint, out var cachedAttribute))
|
||||
{
|
||||
return cachedAttribute;
|
||||
}
|
||||
|
||||
var attribute = endpoint.Metadata.GetMetadata<RedisCacheAttribute>();
|
||||
if (attribute != null)
|
||||
{
|
||||
_attributeCache.TryAdd(endpoint, attribute);
|
||||
}
|
||||
|
||||
return attribute;
|
||||
}
|
||||
|
||||
private string GenerateCacheKey(HttpRequest request, AppConfig appConfig)
|
||||
{
|
||||
var appRequestInfo = new AppRequestConfig(request);
|
||||
var cacheKey = $"cache:api:{request.Path.Value.Replace('/', '.').TrimStart('.')}:{appRequestInfo.Key}:{(string.IsNullOrEmpty(request.QueryString.Value) ? "default" : request.QueryString)}";
|
||||
return cacheKey;
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Redis 缓存特性类
|
||||
/// </summary>
|
||||
[AttributeUsage(AttributeTargets.Method, AllowMultiple = false)]
|
||||
public class RedisCacheAttribute : Attribute
|
||||
{
|
||||
public TimeSpan TimeSpan { get; }
|
||||
public RedisCacheAttribute(int durationInSeconds) => TimeSpan = TimeSpan.FromSeconds(durationInSeconds);
|
||||
public RedisCacheAttribute(int hours, int minutes, int seconds) => TimeSpan = new TimeSpan(hours, minutes, seconds);
|
||||
public RedisCacheAttribute(int minutes, int seconds) => TimeSpan = new TimeSpan(0, minutes, seconds);
|
||||
}
|
||||
}
|
||||
|
|
@ -0,0 +1,40 @@
|
|||
using HuanMeng.DotNetCore.AttributeExtend;
|
||||
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Linq;
|
||||
using System.Text;
|
||||
using System.Threading.Tasks;
|
||||
|
||||
namespace CloudGaming.DtoModel.Game
|
||||
{
|
||||
public class GameInfoDto
|
||||
{
|
||||
/// <summary>
|
||||
/// 游戏Id
|
||||
/// </summary>
|
||||
public virtual string GameId { get; set; } = null!;
|
||||
|
||||
|
||||
/// <summary>
|
||||
/// 游戏icon
|
||||
/// </summary>
|
||||
[Images("ImageIcon")]
|
||||
public virtual int ImageIcon { get; set; }
|
||||
|
||||
/// <summary>
|
||||
///
|
||||
/// </summary>
|
||||
[Images("GameBgImage")]
|
||||
public virtual int GameBgImage { get; set; }
|
||||
/// <summary>
|
||||
/// 游戏标签
|
||||
/// </summary>
|
||||
public List<GameExtendedAttribute> GameTags { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// 游戏列表
|
||||
/// </summary>
|
||||
public List<GameExtendedAttribute> GameType { get; set; }
|
||||
}
|
||||
}
|
||||
|
|
@ -0,0 +1,48 @@
|
|||
using HuanMeng.DotNetCore.AttributeExtend;
|
||||
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Linq;
|
||||
using System.Text;
|
||||
using System.Threading.Tasks;
|
||||
|
||||
namespace CloudGaming.DtoModel.Game
|
||||
{
|
||||
/// <summary>
|
||||
/// 游戏列表数据
|
||||
/// </summary>
|
||||
public class GameListDto
|
||||
{
|
||||
public GameListDto() { }
|
||||
|
||||
/// <summary>
|
||||
///
|
||||
/// </summary>
|
||||
/// <param name="gameInfo"></param>
|
||||
public GameListDto(GameInfo gameInfo)
|
||||
{
|
||||
if (gameInfo != null)
|
||||
{
|
||||
this.GameName = gameInfo.GameName;
|
||||
this.GameId = gameInfo.GameId;
|
||||
this.GameIconImage = gameInfo.GameImageId;
|
||||
|
||||
|
||||
}
|
||||
}
|
||||
/// <summary>
|
||||
/// 游戏Id
|
||||
/// </summary>
|
||||
public string GameId { get; set; }
|
||||
/// <summary>
|
||||
/// 游戏名称
|
||||
/// </summary>
|
||||
public string GameName { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// 游戏icon
|
||||
/// </summary>
|
||||
[Images]
|
||||
public int GameIconImage { get; set; }
|
||||
}
|
||||
}
|
||||
|
|
@ -5,6 +5,7 @@ using System.Collections.Generic;
|
|||
using System.Reflection;
|
||||
using HuanMeng.DotNetCore.AttributeExtend;
|
||||
using System.Linq.Expressions;
|
||||
using Microsoft.IdentityModel.Tokens;
|
||||
|
||||
|
||||
namespace HuanMeng.DotNetCore.Utility;
|
||||
|
|
@ -23,7 +24,7 @@ public static class ObjectExtensions
|
|||
/// <summary>
|
||||
/// 缓存每个属性是否具有 ImagesAttribute 特性。
|
||||
/// </summary>
|
||||
public static readonly ConcurrentDictionary<PropertyInfo, bool> _PropertyCache = new();
|
||||
public static readonly ConcurrentDictionary<PropertyInfo, ImagesAttribute?> _PropertyCache = new();
|
||||
|
||||
/// <summary>
|
||||
/// 判断对象是否为原始类型或字符串类型。
|
||||
|
|
@ -102,8 +103,8 @@ public static class ObjectExtensions
|
|||
// 如果属性是字符串,在其值前添加 "test"
|
||||
if (propertyValue is string stringValue)
|
||||
{
|
||||
keyValuePairs[accessor.PropertyName] = $"test{stringValue}";
|
||||
Console.WriteLine(propertyPath);
|
||||
keyValuePairs[accessor.PropertyName] = stringValue;
|
||||
//Console.WriteLine(propertyPath);
|
||||
continue;
|
||||
}
|
||||
|
||||
|
|
@ -130,8 +131,16 @@ public static class ObjectExtensions
|
|||
// 创建用于访问属性值的委托
|
||||
var getter = CreatePropertyGetter(type, property);
|
||||
// 检查属性是否具有 ImagesAttribute,并将结果存储在缓存中
|
||||
bool hasImagesAttribute = _PropertyCache.GetOrAdd(property, p => p.GetCustomAttribute<ImagesAttribute>() != null);
|
||||
return new PropertyAccessor(property.Name, getter, hasImagesAttribute);
|
||||
var imagesAttribute = _PropertyCache.GetOrAdd(property, p => p.GetCustomAttribute<ImagesAttribute>());
|
||||
if (imagesAttribute != null)
|
||||
{
|
||||
if (!string.IsNullOrEmpty(imagesAttribute.FieldName))
|
||||
{
|
||||
return new PropertyAccessor(imagesAttribute.FieldName, getter, true);
|
||||
}
|
||||
return new PropertyAccessor(property.Name, getter, true);
|
||||
}
|
||||
return new PropertyAccessor(property.Name, getter, false);
|
||||
}).ToArray();
|
||||
}
|
||||
|
||||
|
|
|
|||
Loading…
Reference in New Issue
Block a user