网站首页 网站源码
using System;
using System.Collections.Generic;
using System.IO;
using System.Linq;
using System.Text.Json;
using System.Text.Json.Serialization;
using AutoMapper;
using Dpz.Core.EnumLibrary;
using Dpz.Core.Infrastructure;
using Dpz.Core.Public.Entity;
namespace Dpz.Core.Public.ViewModel;
/// <summary>
/// 评论 出参
/// </summary>
public class CommentViewModel : IHaveCustomMapping
{
public string Id { get; set; }
/// <summary>
/// 评论类型
/// </summary>
public CommentNode Node { get; set; }
/// <summary>
/// 关联
/// </summary>
public string Relation { get; set; }
/// <summary>
/// 回复时间
/// </summary>
public DateTime PublishTime { get; set; }
/// <summary>
/// 评论人 (多态)分为匿名评论和成员评论
/// </summary>
[JsonConverter(typeof(CommenterConverter))]
public VmCommenter Commenter { get; set; }
/// <summary>
/// 回复内容
/// </summary>
public string CommentText { get; set; }
/// <summary>
/// 回复ID
/// </summary>
public List<string> Replies { get; set; }
/// <summary>
/// 是否删除
/// </summary>
public bool? IsDelete { get; set; }
/// <summary>
/// 回复
/// </summary>
public List<CommentChildren> Children { get; set; }
private IMapper _mapper = new Mapper(new MapperConfiguration(x =>
{
x.CreateMap<MembleCommenter, VmMemberCommenter>();
x.CreateMap<GuestCommenter, VmGuestCommenter>();
}));
public void CreateMappings(MapperConfigurationExpression cfg)
{
cfg.CreateMap<Comment, CommentViewModel>().ConvertUsing((entity, _) =>
{
if (entity.IsDelete == true)
{
entity.Commenter = new GuestCommenter
{
Email = "",
NickName = "该用户发言已被删除",
Site = ""
};
entity.CommentText = "该用户发言因某些原因已被删除";
}
var viewModel = new CommentViewModel
{
Id = entity.Id.ToString(),
Node = entity.Node,
Relation = entity.Relation,
PublishTime = entity.PublishTime.ToLocalTime(),
CommentText = entity.CommentText,
Replies = entity.Replies == null
? new List<string>()
: entity.Replies.Select(x => x.ToString()).ToList(),
IsDelete = entity.IsDelete,
Children = new List<CommentChildren>(),
Commenter = entity.Commenter switch
{
MembleCommenter membleCommenter => _mapper.Map<VmMemberCommenter>(membleCommenter),
GuestCommenter guestCommenter => _mapper.Map<VmGuestCommenter>(guestCommenter),
_ => null
}
};
return viewModel;
});
}
}
public class CommentChildren : IHaveCustomMapping
{
public string Id { get; set; }
/// <summary>
/// 回复时间
/// </summary>
public DateTime PublishTime { get; set; }
/// <summary>
/// 评论人
/// </summary>
[JsonConverter(typeof(CommenterConverter))]
public VmCommenter Commenter { get; set; }
/// <summary>
/// 回复内容
/// </summary>
public string CommentText { get; set; }
/// <summary>
/// 回复ID
/// </summary>
public List<string> Replies { get; set; }
/// <summary>
/// 是否删除
/// </summary>
public bool? IsDelete { get; set; }
private IMapper _mapper = new Mapper(new MapperConfiguration(x =>
{
x.CreateMap<MembleCommenter, VmMemberCommenter>();
x.CreateMap<GuestCommenter, VmGuestCommenter>();
}));
public void CreateMappings(MapperConfigurationExpression cfg)
{
cfg.CreateMap<Comment, CommentChildren>().ConvertUsing((entity, _) =>
{
if (entity.IsDelete == true)
{
entity.Commenter = new GuestCommenter
{
Email = "",
NickName = "该用户发言已被删除",
Site = ""
};
entity.CommentText = "该用户发言因某些原因已被删除";
}
var viewModel = new CommentChildren
{
Id = entity.Id.ToString(),
PublishTime = entity.PublishTime.ToLocalTime(),
CommentText = entity.CommentText,
Replies = entity.Replies.Select(x => x.ToString()).ToList(),
IsDelete = entity.IsDelete,
Commenter = entity.Commenter switch
{
MembleCommenter membleCommenter => _mapper.Map<VmMemberCommenter>(membleCommenter),
GuestCommenter guestCommenter => _mapper.Map<VmGuestCommenter>(guestCommenter),
_ => null
}
};
return viewModel;
});
}
}
public abstract class VmCommenter
{
/// <summary>
/// 昵称
/// </summary>
public string NickName { get; set; }
}
/// <summary>
/// 登录会员评论
/// </summary>
public class VmMemberCommenter : VmCommenter, IMapFrom<MembleCommenter>
{
/// <summary>
/// 头像
/// </summary>
public string Avatar { get; set; }
/// <summary>
/// 身份标识
/// </summary>
public string Identity { get; set; }
}
/// <summary>
/// 匿名评论
/// </summary>
public class VmGuestCommenter : VmCommenter, IMapFrom<GuestCommenter>
{
/// <summary>
/// 邮箱
/// </summary>
public string Email { get; set; } = "";
/// <summary>
/// 网站
/// </summary>
public string Site { get; set; }
public string EmailMd5 { get; private set; }
public void GenerateEmailMd5()
{
EmailMd5 = Email.GenerateHashMd5();
Email = "";
}
}
public class CommenterConverter : JsonConverter<VmCommenter>
{
public override VmCommenter Read(ref Utf8JsonReader reader, Type typeToConvert, JsonSerializerOptions options)
{
if (reader.TokenType == JsonTokenType.Null) return null;
if (reader.TokenType != JsonTokenType.StartObject)
throw new JsonException("JsonTokenType.StartObject not found.");
if (!reader.Read() || reader.TokenType != JsonTokenType.PropertyName
|| reader.GetString() != "$type")
throw new JsonException("Property $type not found.");
if (!reader.Read() || reader.TokenType != JsonTokenType.String)
throw new JsonException("Value at $type is invalid.");
var typeStr = reader.GetString();
var type = typeStr switch
{
"GuestCommenter" => typeof(VmGuestCommenter),
"MemberCommenter" => typeof(VmMemberCommenter),
_ => typeof(Commenter)
};
using var output = new MemoryStream();
ReadObject(ref reader, output, options);
var result = JsonSerializer.Deserialize(output.ToArray(), type, options);
return result as VmCommenter;
}
private void ReadObject(ref Utf8JsonReader reader, Stream output, JsonSerializerOptions options)
{
using var writer = new Utf8JsonWriter(output, new JsonWriterOptions
{
Encoder = options.Encoder,
Indented = options.WriteIndented
});
writer.WriteStartObject();
var objectIntend = 0;
while (reader.Read())
{
switch (reader.TokenType)
{
case JsonTokenType.None:
case JsonTokenType.Null:
writer.WriteNullValue();
break;
case JsonTokenType.StartObject:
writer.WriteStartObject();
objectIntend++;
break;
case JsonTokenType.EndObject:
writer.WriteEndObject();
if (objectIntend == 0)
{
writer.Flush();
return;
}
objectIntend--;
break;
case JsonTokenType.StartArray:
writer.WriteStartArray();
break;
case JsonTokenType.EndArray:
writer.WriteEndArray();
break;
case JsonTokenType.PropertyName:
writer.WritePropertyName(reader.GetString() ?? "");
break;
case JsonTokenType.Comment:
writer.WriteCommentValue(reader.GetComment());
break;
case JsonTokenType.String:
writer.WriteStringValue(reader.GetString());
break;
case JsonTokenType.Number:
writer.WriteNumberValue(reader.GetInt32());
break;
case JsonTokenType.True:
case JsonTokenType.False:
writer.WriteBooleanValue(reader.GetBoolean());
break;
default:
throw new ArgumentOutOfRangeException();
}
}
}
public override void Write(Utf8JsonWriter writer, VmCommenter value, JsonSerializerOptions options)
{
writer.WriteStartObject();
var valueType = value.GetType();
//var valueAssemblyName = valueType.Assembly.GetName();
writer.WriteString("$type", $"{valueType.Name.Replace("Vm", "")}");
var json = JsonSerializer.Serialize(value, value.GetType(), options);
using (var document = JsonDocument.Parse(json, new JsonDocumentOptions
{
AllowTrailingCommas = options.AllowTrailingCommas,
MaxDepth = options.MaxDepth
}))
{
foreach (var jsonProperty in document.RootElement.EnumerateObject())
jsonProperty.WriteTo(writer);
}
writer.WriteEndObject();
}
}
上述代码定义了一个用于处理评论的视图模型(ViewModel)及其相关类,主要用于将评论数据从实体模型转换为适合前端展示的格式。以下是代码的主要功能和结构的详细解释:
CommentViewModel
类功能: 该类表示评论的视图模型,包含了评论的各种属性和相关信息。
属性:
Id
: 评论的唯一标识符。Node
: 评论的类型(使用 CommentNode
枚举)。Relation
: 评论关联的对象(如文章、帖子等)。PublishTime
: 评论的发布时间。Commenter
: 评论者的信息,使用多态处理(可以是匿名评论或会员评论)。CommentText
: 评论的内容。Replies
: 评论的回复ID列表。IsDelete
: 评论是否被删除的标志。Children
: 评论的子评论(回复)。映射: 使用 AutoMapper 将 Comment
实体映射到 CommentViewModel
。在映射过程中,如果评论被标记为删除,则会用默认的删除信息替代评论者和评论内容。
CommentChildren
类CommentViewModel
类似。CommentViewModel
类似的属性,如 Id
, PublishTime
, Commenter
, CommentText
, Replies
, IsDelete
。Comment
实体映射到 CommentChildren
。VmCommenter
抽象类NickName
属性。VmMemberCommenter
和 VmGuestCommenter
类VmCommenter
。VmMemberCommenter
还包含 Avatar
和 Identity
属性。VmGuestCommenter
包含 Email
和 Site
属性,并提供了一个方法 GenerateEmailMd5
用于生成邮箱的 MD5 哈希值。CommenterConverter
类VmCommenter
类型的对象。Read
: 从 JSON 中读取评论者信息,并根据 $type
属性确定具体的评论者类型(会员或匿名)。Write
: 将 VmCommenter
对象序列化为 JSON,包含 $type
属性以指示具体类型。整体上,这段代码的目的是将评论数据从后端实体模型转换为适合前端展示的视图模型,支持多态处理评论者类型,并提供了自定义的 JSON 序列化和反序列化逻辑。通过使用 AutoMapper 和自定义 JSON 转换器,代码实现了灵活且可扩展的评论处理机制。