Giter VIP home page Giter VIP logo

luoyunchong / lin-cms-dotnetcore Goto Github PK

View Code? Open in Web Editor NEW
796.0 24.0 189.0 14.96 MB

😃A simple and practical CMS implemented by .NET + FreeSql;前后端分离、Docker部署、OAtuh2授权登录、自动化部署DevOps、自动同步至Gitee、代码生成器、仿掘金专栏

Home Page: https://vvlog.igeekfan.cn/#/index

License: MIT License

C# 99.03% Dockerfile 0.40% Batchfile 0.13% PowerShell 0.08% HTML 0.13% Shell 0.24%
lin-cms dotnetcore-cms restful swagger freesql identityserver4 mysql azure-devops automapper serilog

lin-cms-dotnetcore's Introduction

Hi 👋, I'm IGeekFan(天上月) ,我是一名 C#/ASP.NET Core/JavaScript开发者

🍳 推荐项目

📈 Github Statistics

🏆 欢迎微信搜索:dotNET搬砖队

lin-cms-dotnetcore's People

Contributors

dependabot[bot] avatar luoyunchong avatar

Stargazers

 avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar

Watchers

 avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar

lin-cms-dotnetcore's Issues

文件上传服务中文件记录存在,更新记录Path未成功

重现步骤(可选):

  1. 上传单个文件
  2. 将lin_file表中记录的path进行修改
  3. 第二次继续上传相同文件
    期望的结果是什么?
    在第二次上传相同文件时,实际应该将相同文件记录的记录进行Path更新
    实际的结果是什么?
    在执行以下更新语句时,返回影响行数为0
var row= await _fileRepository.UpdateDiy.Set(a => a.Path, path).ExecuteAffrowsAsync();

PgSql 自动创建数据库简单示例

描述你希望的支持的新功能?
PgSql 自动创建数据库简单示例:

     public static FreeSqlBuilder CreateDatabaseIfNotExistsPgSql(this FreeSqlBuilder @this,
        string connectionString = "")
    {
        if (connectionString == "")
        {
            connectionString = GetConnectionString(@this);
        }

        NpgsqlConnectionStringBuilder builder = new NpgsqlConnectionStringBuilder(connectionString);
        
        string createDatabaseSql =
            $"DROP DATABASE IF EXISTS \"{builder.Database}\"; CREATE DATABASE \"{builder.Database}\" WITH OWNER = \"{builder.Username}\"";
       
        using NpgsqlConnection cnn = new NpgsqlConnection(
            $"Host={builder.Host};Port={builder.Port};Username={builder.Username};Password={builder.Password};Pooling=true");
        cnn.Open();
        using (NpgsqlCommand cmd = cnn.CreateCommand())
        {
            cmd.CommandText = createDatabaseSql;
            cmd.ExecuteNonQuery();
        }

        return @this;
    }

你期望的 API 是怎样的?

修改密码逻辑错误,修改密码不成功

重现步骤(可选):
后台登录->个人设置->修改密码 ,代码位置LinCms.Application.Cms.Users:VerifyUserPasswordAsync与ChangePasswordAsync方法
期望的结果是什么?
修改密码成功
实际的结果是什么?
输入正确密码提示密码错误,输入错误密码提示修改成功后,数据未发生改变
已解决方案
代码位置
LinCms.Application.Cms.Users UserService 中ChangePasswordAsync方法
public async Task ChangePasswordAsync(ChangePasswordDto passwordDto)
{
long currentUserId = _currentUser.Id ?? 0;

        bool valid = await _userIdentityService.VerifyUserPasswordAsync(currentUserId, passwordDto.OldPassword);
        if (!valid)
        {
            throw new LinCmsException("旧密码不正确");
        }

        await _userIdentityService.ChangePasswordAsync(currentUserId, passwordDto.NewPassword);
    }

LinCms.Application.Cms.Users:ChangePasswordAsync方法
public async Task ChangePasswordAsync(long userId, string newpassword)
{
string encryptPassword = EncryptUtil.Encrypt(newpassword);
var linUserIdentity = await _userIdentityRepository.Where(a => a.CreateUserId == userId).FirstAsync();
linUserIdentity.Credential = encryptPassword;
_ = _userIdentityRepository.Update(linUserIdentity);//.ExecuteUpdatedAsync();
}
上面那个qq第三方登录,SaveQQAsync
应该是。。 IdentityType = LinUserIdentity.QQ,

LinCmsTimeConverter ReadJson DateTime 无法正常转换

https://github.com/luoyunchong/lin-cms-dotnetcore/blob/master/src/LinCms.Core/Extensions/LinCmsTimeConverter.cs

     public override object ReadJson(JsonReader reader, Type objectType, object existingValue, JsonSerializer serializer)
        {
            return ConvertIntDateTime(double.Parse(reader.Value.ToString()));
        }

        public static DateTime ConvertIntDateTime(double milliseconds)
        {
            return new DateTime(1970, 1, 1).AddMilliseconds(milliseconds);
        }

实体类传DateTime,类型为 FormBody,会序列化。存在 异常。

image

使用策略者模式减少switch case 语句

描述你希望的支持的新功能?
这样的switch case 还可以 再优化。

你期望的 API 是怎样的?

使用策略者模式减少switch case 语句

image

switch case 代码过多

        [HttpGet("signin-callback")]
        public async Task<IActionResult> Home(string provider, string redirectUrl = "")
        {
            if (string.IsNullOrWhiteSpace(provider))
            {
                return BadRequest();
            }

            if (!await HttpContext.IsProviderSupportedAsync(provider))
            {
                return BadRequest();
            }

            AuthenticateResult authenticateResult = await _contextAccessor.HttpContext.AuthenticateAsync(provider);
            if (!authenticateResult.Succeeded) return Redirect(redirectUrl);
            var openIdClaim = authenticateResult.Principal.FindFirst(ClaimTypes.NameIdentifier);
            if (openIdClaim == null || string.IsNullOrWhiteSpace(openIdClaim.Value))
                return Redirect(redirectUrl);
            long id = 0;
            switch (provider)
            {
                case LinUserIdentity.GitHub:
                    id = await _userCommunityService.SaveGitHubAsync(authenticateResult.Principal, openIdClaim.Value);
                    break;

                case LinUserIdentity.QQ:
                    id = await _userCommunityService.SaveQQAsync(authenticateResult.Principal, openIdClaim.Value);
                    break;

                case LinUserIdentity.Gitee:
                    string access_token = authenticateResult.Properties.GetTokenValue("access_token");
                    string refresh_token = authenticateResult.Properties.GetTokenValue("refresh_token");
                    string token_type = authenticateResult.Properties.GetTokenValue("token_type");
                    string expires_at = authenticateResult.Properties.GetTokenValue("expires_at");
                    id = await _userCommunityService.SaveGiteeAsync(authenticateResult.Principal, openIdClaim.Value);
                    break;
                case LinUserIdentity.WeiXin:

                    break;
                default:
                    _logger.LogError($"未知的privoder:{provider},redirectUrl:{redirectUrl}");
                    throw new LinCmsException($"未知的privoder:{provider}!");
            }
            List<Claim> authClaims = authenticateResult.Principal.Claims.ToList();

            LinUser user = await _userRepository.Select.IncludeMany(r => r.LinGroups)
                .WhereCascade(r => r.IsDeleted == false).Where(r => r.Id == id).FirstAsync();

            if (user == null)
            {
                throw new LinCmsException("第三方登录失败!");
            }
            List<Claim> claims = new List<Claim>()
            {
                new Claim (ClaimTypes.NameIdentifier, user.Id.ToString ()),
                new Claim (ClaimTypes.Email, user.Email?? ""),
                new Claim (ClaimTypes.GivenName, user.Nickname?? ""),
                new Claim (ClaimTypes.Name, user.Username?? ""),
            };

            user.LinGroups?.ForEach(r =>
           {
               claims.Add(new Claim(LinCmsClaimTypes.Groups, r.Id.ToString()));
           });

            //claims.AddRange(authClaims);
            string token = _jsonWebTokenService.Encode(claims);

            //TODO 生成刷新token
            //user.AddRefreshToken(token);
            //await _userRepository.UpdateAsync(user);

            return Redirect($"{redirectUrl}#login-result?token={token}");
        }
    /// <summary>
        /// 第三方账号绑定回调
        /// </summary>
        /// <param name="provider"></param>
        /// <param name="redirectUrl"></param>
        /// <param name="token"></param>
        /// <returns></returns>
        [HttpGet("signin-bind-callback")]
        public async Task<IActionResult> SignInBindCallBack(string provider, string redirectUrl = "", string token = "")
        {
            if (string.IsNullOrWhiteSpace(provider))
            {
                return BadRequest();
            }

            if (!await HttpContext.IsProviderSupportedAsync(provider))
            {
                return BadRequest();
            }

            if (token.IsNullOrEmpty() || !token.StartsWith("Bearer "))
            {
                return Redirect($"{redirectUrl}#bind-result?code={ErrorCode.Fail}&message={HttpUtility.UrlEncode("请先登录")}");
            }
            else
            {
                token = token.Remove(0, 7);
            }

            AuthenticateResult authenticateResult = await _contextAccessor.HttpContext.AuthenticateAsync(provider);
            if (!authenticateResult.Succeeded) return Redirect($"{redirectUrl}#bind-result?code=fail&message={authenticateResult.Failure.Message}");
            var openIdClaim = authenticateResult.Principal.FindFirst(ClaimTypes.NameIdentifier);
            if (openIdClaim == null || string.IsNullOrWhiteSpace(openIdClaim.Value))
                return Redirect($"{redirectUrl}#bind-result?code={ErrorCode.Fail}&message={HttpUtility.UrlEncode("未能获取openId")}");

            JwtPayload jwtPayload = (JwtPayload)_jsonWebTokenService.Decode(token);
            string nameIdentifier = jwtPayload.Claims.FirstOrDefault(r => r.Type == ClaimTypes.NameIdentifier)?.Value;
            if (nameIdentifier.IsNullOrWhiteSpace())
            {
                return Redirect($"{redirectUrl}#bind-result?code={ErrorCode.Fail}&message={HttpUtility.UrlEncode("请先登录")}");
            }
            long userId = long.Parse(nameIdentifier);
            UnifyResponseDto unifyResponseDto;
            switch (provider)
            {
                case LinUserIdentity.GitHub:
                    unifyResponseDto = await _userCommunityService.BindGitHubAsync(authenticateResult.Principal, openIdClaim.Value, userId);
                    break;
                case LinUserIdentity.QQ:
                    unifyResponseDto = await _userCommunityService.BindQQAsync(authenticateResult.Principal, openIdClaim.Value, userId);
                    break;
                case LinUserIdentity.Gitee:
                    unifyResponseDto = await _userCommunityService.BindGiteeAsync(authenticateResult.Principal, openIdClaim.Value, userId);
                    break;
                //case LinUserIdentity.WeiXin:

                //    break;
                default:
                    _logger.LogError($"未知的privoder:{provider},redirectUrl:{redirectUrl}");
                    unifyResponseDto = UnifyResponseDto.Error($"未知的privoder:{provider}!");
                    break;
            }

            return Redirect($"{redirectUrl}#bind-result?code={unifyResponseDto.Code.ToString()}&message={HttpUtility.UrlEncode(unifyResponseDto.Message.ToString())}");
        }
   public async Task<UnifyResponseDto> BindGitHubAsync(ClaimsPrincipal principal, string openId, long userId)
        {
            string name = principal.FindFirst(ClaimTypes.Name)?.Value;
            return await this.BindAsync(LinUserIdentity.GitHub, name, openId, userId);
        }

        public async Task<UnifyResponseDto> BindQQAsync(ClaimsPrincipal principal, string openId, long userId)
        {
            string nickname = principal.FindFirst(ClaimTypes.Name)?.Value;
            return await this.BindAsync(LinUserIdentity.QQ, nickname, openId, userId);
        }

        public async Task<UnifyResponseDto> BindGiteeAsync(ClaimsPrincipal principal, string openId, long userId)
        {
            string name = principal.FindFirst(ClaimTypes.Name)?.Value;
            return await this.BindAsync(LinUserIdentity.Gitee, name, openId, userId);
        }

        private async Task<UnifyResponseDto> BindAsync(string identityType, string name, string openId, long userId)
        {
            LinUserIdentity linUserIdentity = await _userIdentityRepository.Where(r => r.IdentityType == identityType && r.Credential == openId).FirstAsync();
            if (linUserIdentity == null)
            {
                var userIdentity = new LinUserIdentity(identityType, name, openId, DateTime.Now);
                userIdentity.CreateUserId = userId;
                await _userIdentityRepository.InsertAsync(userIdentity);
                return UnifyResponseDto.Success("绑定成功");
            }
            else
            {
                return UnifyResponseDto.Error("绑定失败,该用户已绑定其他账号");
            }
        }
  public async Task<long> SaveGitHubAsync(ClaimsPrincipal principal, string openId)
        {
           xxx
            return userId;
        }

        public async Task<long> SaveQQAsync(ClaimsPrincipal principal, string openId)
        {
           xxx
            return userId;
        }
        public async Task<long> SaveGiteeAsync(ClaimsPrincipal principal, string openId)
        {
            xxx
            return userId;
        }

一种基于权限注解作为数据源完善swagger的方案

感谢开源,我fork后代码改的太多,就没法pr,这里给可能需要的人提供下效果的和思路。

我们想实现的效果是

也许,看到这里,你可能会嗤之以鼻,这个多简单,还用你啰嗦

 /// <summary>
    /// 删除图书
    /// </summary>
/// <remarks>
/// 描述测试 **markdown测试**
///<remarks>
 [HttpDelete("{id}")]
        [LinCmsAuthorize("删除图书", "图书",Desc = "描述测试 **markdown测试**")]
        public async Task<UnifyResponseDto> DeleteAsync(int id)
        {
            await _bookService.DeleteAsync(id);
            return UnifyResponseDto.Success();

        }

这有问题吗?没有问题。
但是,作为一个强迫症,我是无法容忍自己写两遍一样的东西的,那怎么办呢?


首先,修改 LinCmsAuthorizeAttribute, 增加一个可选的 描述字段

    public class LinCmsAuthorizeAttribute : Attribute, IAsyncAuthorizationFilter
    {
        public string Permission { get; }
        public string Module { get; }

        public string? Desc { get; set; }

        public LinCmsAuthorizeAttribute(string permission, string module)

这样,我们就可以删除掉上面的注释了,统统使用注解来完成。

接着,我们给swagger增加一个Filter,使之在找不到注释的时候,使用我们的权限注解,即优先注释。

public class AuthorizeAttrFilter : IOperationFilter
{
    public void Apply(OpenApiOperation operation, OperationFilterContext context)
    {
var swaggerOperationAttribute =context.MethodInfo.GetCustomAttributes(true).OfType<LinCmsAuthorizeAttribute>().FirstOrDefault();
if (swaggerOperationAttribute == null) return;

        if (operation.Summary == null && swaggerOperationAttribute.Permission != null)
            operation.Summary = swaggerOperationAttribute.Permission;

        if (operation.Description == null && swaggerOperationAttribute.Desc != null)
            operation.Description = swaggerOperationAttribute.Desc;
}
}

最后,我们应用这个Filter就可以了。

 options.CustomOperationIds(apiDesc =>
                {
                    var controllerAction = apiDesc.ActionDescriptor as ControllerActionDescriptor;
                    return
                        $"{controllerAction.ControllerName}-{controllerAction.ActionName}-{controllerAction.GetHashCode()}";
                });
// 添加这行,应用之~
 options.OperationFilter<AuthorizeAttrFilter>();

吃水不忘挖井人,希望能起到抛砖引玉的效果

功能模块的设计

功能模块的设计

基础权限模块

  • 用户信息:邮件、用户名(唯一)、昵称、头像、分组、是否激活、手机号、是否是Admin、个性签名
    • 注册/登录
    • 上传头像
    • 修改密码
    • 用户基本信息修改
    • 用户增删改,配置分组
  • 绑定第三方账号
    • GitHub登录
    • QQ 登录
    • Gitee登录
  • 分组信息:是否静态分组(无法删除,无法修改分组编码)、名称可以修改
    • 分组增删改
    • 组别配置权限
  • 文件管理
    • 本地文件上传
    • 七牛云存储
    • 文件去重,秒传
  • 系统日志:请求方法、路径、http返回码、时间、用户昵称、用户id、访问哪个权限、 日志信息
    • 记录系统请求的日志
    • 异常日志
  • 设置管理:name(键),value(值),provider_name(提供名),provider_key(提供者值)
    • 设置新增修改删除
    • 所有设置

比如存某用户选择的是markdown还是富文本。

name="Article.Editor",
value="markdown" 或 "富文本",
provider_name为"User",
provider_key为用户Id

或存储七牛云的某一个配置

name="Qiniu.AK",
value="asfadsfadf23rft66S4XM2GIK7FGmj7czuYkcAyNGDAc" ,
provider_name为"Qiniu"或自己定义的字符串
provider_key为空

cms 管理员维护模块

  • 标签管理:名称、图片,是否启用/禁用,排序、文章数量、用户关注数量。
    • 标签增删改
    • 标签列表,禁用
  • 技术频道:封面图、名称、是否启用/禁用、排序、编码、备注描述、下属标签.一个技术频道对应多个标签
    • 技术频道增删改
    • 列表、禁用
  • 随笔管理:
    • 审核随笔/拉黑
  • 评论管理
    • 后台审核通过/拉黑
    • 管理员删除评论
  • 字典管理
    • 字典类别管理
    • 字典管理:如随笔类型(原创、转载、翻译)

cms 用户端模块

  • 技术频道

    • 首页展示技术频道
    • 选择技术频道后,可再根据标签查询文章
  • 分类专栏管理:发布随笔时可选择单个分类。

    • 分类增删改(随笔数量、图片、名称、排序)
    • 分类列表,仅查看、编辑自己创建的分类专栏
  • 标签:统计每个标签下多少个文章、多少人关注

    • 标签列表
    • 无限加载
    • 最新/最热 根据标签名称模糊查询
    • 已关注的标签
    • 热门标签
  • 随笔

    • 支持markdown,增删改(仅自己的随笔),修正分类专栏中的随笔数量
    • 支持富文本编辑随笔
    • 列表无限加载,按标签查询随笔
    • 点赞随笔
    • 随笔详情页
      • 支持目录导航(滚动时,固定至顶部位置),展示字数统计、预计阅读时长;
      • 作者介绍:头像,昵称,签名,随笔数;
      • 展示文章类型:原创、转载、翻译
      • 作者最近的三个文章
      • 推荐文章
  • 评论

    • 用户关闭评论时,无法对随笔进行评论
    • 评论随笔(内容支持超链接、emoji)
    • 删除自己的评论
    • 点赞评论
    • 回复评论
  • 关注

    • 关注/取消关注用户
    • 关注/取消关注标签
  • 个人主页

    • 随笔
      • 用户专栏分类展示
      • 最新发布的随笔
    • 关注
      • 关注的人
      • 粉丝
      • 关注的标签
  • 设置

    • 个人主页设置
      • 个人资料更新
    • 安全设置
      • 密码修改:快速登录的账号,初次设置时可留空
    • 博客设置
      • 编辑器设置,(可切换markdown/富文本)
    • 代码风格配置(tango、native、monokai、github、solarized-light、vs)
  • 消息

    • 评论:点赞评论、评论随笔、回复评论
    • 喜欢和赞:点赞随笔、点赞评论
    • 关注,谁谁关注了你

脑图分享

http://naotu.baidu.com/file/6532431a2e1f0c37c93c5ffd1dd5b49c?token=87690a9bc64fbae1

分组

分为三种

id  name        info
1	Admin	    系统管理员
2	CmsAdmin	内容管理员
3	User	    普通用户

审计日志

大多数表存在如下8个字段,用于记录行的变化状态,is_deleted为软删除,执行删除操作时,将其状态置为true,默认实体类继承 FullAduitEntity 即可拥有以下8个字段。该设计参考ABP中的实现。FullAduitEntity为泛型,默认id为long类型,FullAduitEntity<Guid>,即可改变主键类型,默认LinUser表主键long,保持create_user_id,delete_user_id,update_user_id都与LinUser的主键相同


id	                bigint
create_user_id  	bigint
create_time	        datetime
is_deleted	        bit
delete_user_id  	bigint
delete_time	        datetime
update_user_id	    bigint
update_time	        datetime


lin-cms 开源地址分享

好像缺了表啥的

重现步骤(可选):
image

期望的结果是什么?
页面无报错
实际的结果是什么?
报错

版本是刚拉的

lin-cms-dotnetcore 计划处理问题

0.3.0系统权限模块更新

  1. lin_permission 权限表,本系统通过反射在系统初次启动时,启动异步任务,将不存在的权限新增到此表中。
  2. lin_group_permission 分组权限表,用于分组与权限表的关联
  3. lin_user_group 用户分组表。用于用户和分组表的关联。可配置一个用户属于多个分组。
  4. lin_user_identity 用户授权信息表,用于存储不同登录类型的用户信息,如用户名、第三方应用快速登录(微信、QQ、GitHub、Gitee)的登录

完整的表结构文档: https://igeekfan.gitee.io/vovo-docs/dotnetcore/lin-cms/table.html

代码不更新了吗?

重现步骤(可选):

期望的结果是什么?

实际的结果是什么?
我看更新日志都懒的写了,最后的日志部分还是升级到.net5.

下个版本开发计划

下个版本开发计划

  • 基于lin-cms-vue的基础,将之前Mock.luo项目中的博客迁移过来
    • 博客随笔发布/编辑/删除
    • 留言板
    • 评论回复、审核、点赞等
    • 前端展示博客效果

UserSubscribeController [FromServices] Self referencing loop detected for property '

重现步骤(可选):

该[FromServices]存在循环依赖

public SubscribeCountDto GetUserSubscribeInfo(long userId, [FromServices] IAuditBaseRepository<UserTag> _userTagRepository)
{

}
[19:07:35 ERR] 异常信息:Self referencing loop detected for property '_orm' with type 'FreeSql.MySql.MySqlProvider`1[IFreeSql]'. Path '_userTagRepository.Orm._originalFsql.Ado._util'. |    at Newtonsoft.Json.Serialization.JsonSerializerInternalWriter.CheckForCircularReference(JsonWriter writer, Object value, JsonProperty property, JsonContract contract, JsonContainerContract containerContract, JsonProperty containerProperty)


   at Newtonsoft.Json.Serialization.JsonSerializerInternalWriter.CalculatePropertyValues(JsonWriter writer, Object value, JsonContainerContract contract, JsonProperty member, JsonProperty property, JsonContract& memberContract, Object& memberValue)


   at Newtonsoft.Json.Serialization.JsonSerializerInternalWriter.SerializeObject(JsonWriter writer, Object value, JsonObjectContract contract, JsonProperty member, JsonContainerContract collectionContract, JsonProperty containerProperty)


   at Newtonsoft.Json.Serialization.JsonSerializerInternalWriter.SerializeObject(JsonWriter writer, Object value, JsonObjectContract contract, JsonProperty member, JsonContainerContract collectionContract, JsonProperty containerProperty)


   at Newtonsoft.Json.Serialization.JsonSerializerInternalWriter.SerializeObject(JsonWriter writer, Object value, JsonObjectContract contract, JsonProperty member, JsonContainerContract collectionContract, JsonProperty containerProperty)


   at Newtonsoft.Json.Serialization.JsonSerializerInternalWriter.SerializeObject(JsonWriter writer, Object value, JsonObjectContract contract, JsonProperty member, JsonContainerContract collectionContract, JsonProperty containerProperty)


   at Newtonsoft.Json.Serialization.JsonSerializerInternalWriter.SerializeObject(JsonWriter writer, Object value, JsonObjectContract contract, JsonProperty member, JsonContainerContract collectionContract, JsonProperty containerProperty)


   at Newtonsoft.Json.Serialization.JsonSerializerInternalWriter.SerializeDictionary(JsonWriter writer, IDictionary values, JsonDictionaryContract contract, JsonProperty member, JsonContainerContract collectionContract, JsonProperty containerProperty)


   at Newtonsoft.Json.Serialization.JsonSerializerInternalWriter.Serialize(JsonWriter jsonWriter, Object value, Type objectType)


   at Newtonsoft.Json.JsonSerializer.SerializeInternal(JsonWriter jsonWriter, Object value, Type objectType)


   at Newtonsoft.Json.JsonConvert.SerializeObjectInternal(Object value, Type type, JsonSerializer jsonSerializer)


   at LinCms.Aop.Filter.LogActionFilterAttribute.OnActionExecuting(ActionExecutingContext context) in /src/src/LinCms.Core/Aop/Filter/LogActionFilterAttribute.cs:line 41


   at Microsoft.AspNetCore.Mvc.Filters.ActionFilterAttribute.OnActionExecutionAsync(ActionExecutingContext context, ActionExecutionDelegate next)


   at Microsoft.AspNetCore.Mvc.Infrastructure.ControllerActionInvoker.<InvokeNextActionFilterAsync>g__Awaited|10_0(ControllerActionInvoker invoker, Task lastTask, State next, Scope scope, Object state, Boolean isCompleted)


   at Microsoft.AspNetCore.Mvc.Infrastructure.ControllerActionInvoker.Rethrow(ActionExecutedContextSealed context)


   at Microsoft.AspNetCore.Mvc.Infrastructure.ControllerActionInvoker.Next(State& next, Scope& scope, Object& state, Boolean& isCompleted)


   at Microsoft.AspNetCore.Mvc.Infrastructure.ControllerActionInvoker.InvokeInnerFilterAsync()


--- End of stack trace from previous location ---


   at Microsoft.AspNetCore.Mvc.Infrastructure.ResourceInvoker.<InvokeNextExceptionFilterAsync>g__Awaited|26_0(ResourceInvoker invoker, Task lastTask, State next, Scope scope, Object state, Boolean isCompleted) |  <s:LinCms.Aop.Filter.LinCmsExceptionFilter>


[19:07:35 INF] Executing JsonResult, writing value of type 'LinCms.Data.UnifyResponseDto'. <s:Microsoft.AspNetCore.Mvc.NewtonsoftJson.NewtonsoftJsonResultExecutor>

Recommend Projects

  • React photo React

    A declarative, efficient, and flexible JavaScript library for building user interfaces.

  • Vue.js photo Vue.js

    🖖 Vue.js is a progressive, incrementally-adoptable JavaScript framework for building UI on the web.

  • Typescript photo Typescript

    TypeScript is a superset of JavaScript that compiles to clean JavaScript output.

  • TensorFlow photo TensorFlow

    An Open Source Machine Learning Framework for Everyone

  • Django photo Django

    The Web framework for perfectionists with deadlines.

  • D3 photo D3

    Bring data to life with SVG, Canvas and HTML. 📊📈🎉

Recommend Topics

  • javascript

    JavaScript (JS) is a lightweight interpreted programming language with first-class functions.

  • web

    Some thing interesting about web. New door for the world.

  • server

    A server is a program made to process requests and deliver data to clients.

  • Machine learning

    Machine learning is a way of modeling and interpreting data that allows a piece of software to respond intelligently.

  • Game

    Some thing interesting about game, make everyone happy.

Recommend Org

  • Facebook photo Facebook

    We are working to build community through open source technology. NB: members must have two-factor auth.

  • Microsoft photo Microsoft

    Open source projects and samples from Microsoft.

  • Google photo Google

    Google ❤️ Open Source for everyone.

  • D3 photo D3

    Data-Driven Documents codes.