using System.Threading;
using AngleSharp.Dom;
using Dpz.Core.Infrastructure.Entity;
using EasyCaching.Serialization.SystemTextJson.Configurations;
using Medallion.Threading;
using Medallion.Threading.Redis;
using Microsoft.Extensions.DependencyInjection;
using StackExchange.Redis;
namespace Dpz.Core.Service;
public static class ServiceExtensions
{
/// <summary>
/// 根据当前页索引pageIndex及每页记录数pageSize获取要分页的ViewModel数据对象。
/// </summary>
/// <typeparam name="TSource">原类型</typeparam>
/// <typeparam name="TDestination">目标类型</typeparam>
/// <param name="source">包含所有要分页数据的IMongoQueryable对象。</param>
/// <param name="pageIndex">当前页索引。</param>
/// <param name="pageSize">每页显示的记录数。</param>
/// <returns></returns>
public static IPagedList<TDestination> ToPagedList<TSource, TDestination>(this IMongoQueryable<TSource> source,
int pageIndex, int pageSize) where TDestination : IMapFrom<TSource>, IHaveCustomMapping, new()
{
if (pageIndex < 1)
pageIndex = 1;
var itemIndex = (pageIndex - 1) * pageSize;
var totalItemCount = source.Count();
while (totalItemCount <= itemIndex && pageIndex > 1)
{
itemIndex = (--pageIndex - 1) * pageSize;
}
var pageOfItems = source.Skip(itemIndex).Take(pageSize);
var data = ServiceMapper.GetInstance().Mapper.Map<List<TDestination>>(pageOfItems.ToList());
return new PagedList<TDestination>(data, pageIndex, pageSize, totalItemCount);
}
/// <summary>
/// 根据当前页索引pageIndex及每页记录数pageSize获取要分页的ViewModel数据对象。
/// </summary>
/// <typeparam name="TSource">原类型</typeparam>
/// <typeparam name="TDestination">目标类型</typeparam>
/// <param name="source">包含所有要分页数据的IMongoQueryable对象。</param>
/// <param name="pageIndex">当前页索引。</param>
/// <param name="pageSize">每页显示的记录数。</param>
/// <returns></returns>
public static async Task<IPagedList<TDestination>> ToPagedListAsync<TSource, TDestination>(
this IMongoQueryable<TSource> source, int pageIndex, int pageSize)
where TDestination : IMapFrom<TSource>, new()
{
if (pageIndex < 1)
pageIndex = 1;
var itemIndex = (pageIndex - 1) * pageSize;
var totalItemCount = source.Count();
while (totalItemCount <= itemIndex && pageIndex > 1)
{
itemIndex = (--pageIndex - 1) * pageSize;
}
var pageOfItems = source.Skip(itemIndex).Take(pageSize);
var data = ServiceMapper.GetInstance().Mapper.Map<List<TDestination>>(await pageOfItems.ToListAsync());
return new PagedList<TDestination>(data, pageIndex, pageSize, totalItemCount);
}
public static async Task<IPagedList<TDestination>> ToPagedListAsync<TSource, TDestination>(
this IMongoQueryable<TSource> source, int pageIndex, int pageSize, Func<TSource, TDestination> func)
where TSource : IBaseEntity, new()
where TDestination : new()
{
if (pageIndex < 1)
pageIndex = 1;
var itemIndex = (pageIndex - 1) * pageSize;
var totalItemCount = source.Count();
while (totalItemCount <= itemIndex && pageIndex > 1)
{
itemIndex = (--pageIndex - 1) * pageSize;
}
var pageOfItems = source.Skip(itemIndex).Take(pageSize);
var data = await pageOfItems.ToListAsync();
return new PagedList<TDestination>(data.Select(func), pageIndex, pageSize, totalItemCount);
}
public static async Task<IPagedList<TDestination>> ToPagedListAsync<TSource, TDestination>(
this IFindFluent<TSource, TSource> source, int pageIndex, int pageSize)
where TSource : IBaseEntity, new()
where TDestination : new()
{
if (pageIndex < 1)
pageIndex = 1;
var itemIndex = (pageIndex - 1) * pageSize;
var totalItemCount = checked((int)await source.CountDocumentsAsync());
while (totalItemCount <= itemIndex && pageIndex > 1)
{
itemIndex = (--pageIndex - 1) * pageSize;
}
var pageOfItems = source.Skip(itemIndex).Limit(pageSize);
var data = ServiceMapper.GetInstance().Mapper.Map<List<TDestination>>(await pageOfItems.ToListAsync());
return new PagedList<TDestination>(data, pageIndex, pageSize, totalItemCount);
}
public static async Task<IPagedList<TViewModel>> ToPagedListByModelAsync<TEntity, TViewModel>(
this IRepository<TEntity> repository,
TViewModel viewModel, int pageIndex, int pageSize)
where TEntity : IBaseEntity, new()
where TViewModel : IMapFrom<TEntity>, new()
{
var expression = viewModel.GenerateExpressTree();
var source = await repository.SearchFor(expression)
.ToPagedListAsync<TEntity, TViewModel>(pageIndex, pageSize);
return source;
}
public static async Task<IPagedList<TModel>> ToPagedListAsync<TModel>(this IMongoQueryable<TModel> source,
int pageIndex, int pageSize)
where TModel : IBaseEntity, new()
{
if (pageIndex < 1)
pageIndex = 1;
var itemIndex = (pageIndex - 1) * pageSize;
var totalItemCount = source.Count();
while (totalItemCount <= itemIndex && pageIndex > 1)
{
itemIndex = (--pageIndex - 1) * pageSize;
}
var pageOfItems = source.Skip(itemIndex).Take(pageSize);
var data = await pageOfItems.ToListAsync();
return new PagedList<TModel>(data, pageIndex, pageSize, totalItemCount);
}
/// <summary>
///
/// </summary>
/// <param name="source"></param>
/// <param name="pageIndex"></param>
/// <param name="pageSize"></param>
/// <param name="totalItem">总数</param>
/// <typeparam name="T"></typeparam>
/// <returns></returns>
public static IPagedList<T> ToPagedList<T>(this IEnumerable<T> source, int pageIndex, int pageSize,
int totalItem)
{
return new PagedList<T>(source, pageIndex, pageSize, totalItem);
}
/// <summary>
/// 获取img标签图片地址
/// </summary>
/// <param name="elements"></param>
/// <returns></returns>
public static List<string> GetElementsImageUrls(this IHtmlCollection<IElement> elements)
{
return elements.Select(x => x.Attributes["src"])
.Where(x => x != null)
.Select(x => x!.Value)
.Where(x => x.Any())
.ToList();
}
/// <summary>
/// Mapper to TDestination
/// </summary>
/// <param name="source"></param>
/// <typeparam name="TSource"></typeparam>
/// <typeparam name="TDestination"></typeparam>
/// <returns></returns>
public static async Task<IList<TDestination>> ToListAsync<TSource, TDestination>(
this IMongoQueryable<TSource> source)
where TSource : IBaseEntity, new()
where TDestination : IMapFrom<TSource>, new()
{
var data = await source.ToListAsync();
return ServiceMapper.GetInstance().Mapper.Map<List<TDestination>>(data);
}
public const string ServiceCacheProviderName = "hybrid-cache";
public static void AddBusinessServices(this IServiceCollection services,IConfiguration configuration)
{
services.AddTransient<IUnitOfWork,UnitOfWork>();
services.AddScoped(typeof(IRepository<>),typeof(Repository<>));
#if DEBUG
services.AddScoped<Func<IRepository<Music>>>(x =>
{
var config = x.GetService<IConfiguration>();
var connectionString = config?.GetConnectionString("mongodb-test");
return () => new Repository<Music>(connectionString);
});
#endif
services.AddSingleton<IMapper>(_ => ServiceMapper.Instance.Mapper);
const string cacheName = "redis";
const string memoryCacheName = "dpangzi-memory";
const string serializerName = "dpangzi-message-pack";
var redisConnectionStr = configuration.GetConnectionString(cacheName) ?? "";
services.AddEasyCaching(options =>
{
options.UseInMemory(memoryCacheName);
options
.UseRedis(config =>
{
config.DBConfig.Configuration = redisConnectionStr;
config.DBConfig.Database = 2;
}, cacheName)
.WithMessagePack(cacheName);
options.UseHybrid(config =>
{
config.TopicName = "service-cache";
config.EnableLogging = true;
config.LocalCacheProviderName = memoryCacheName;
config.DistributedCacheProviderName = cacheName;
}, ServiceCacheProviderName)
.WithRedisBus(config =>
{
config.Configuration = redisConnectionStr;
config.Database = 3;
config.SerializerName = serializerName;
})
.WithMessagePack(serializerName);
});
// 分布式锁
services.AddSingleton<IDistributedLockProvider>(_ =>
{
var connectionMultiplexer = ConnectionMultiplexer.Connect(redisConnectionStr);
var database = connectionMultiplexer.GetDatabase();
return new RedisDistributedSynchronizationProvider(database);
});
}
}