包含的属性返回它包含的对象

问题描述 投票:0回答:2

我正在使用ASP.NET Core 2.1中的WebAPI进行我的副项目。我正在使用Entity Framework Core 2.1。

我有一个用户:

public class User : Account
{
    public UInt64 UserEmail { get; protected set; }
    public UserImage UserImage { get; set; }
    public virtual ICollection<Recipe> Recipes { get; set; }

    public User() { }

    public User(string nick, UInt64 login, byte[] salt, byte[] passwordHash,
        string restoreKey, UInt64 userEmail) : base(nick, login, salt, passwordHash, restoreKey)
    {
        UserEmail = userEmail;
        Role = "user";
    }

    public void Update(UInt64 login, UInt64 userEmail)
    {
        Login = login;
        UserEmail = userEmail;
        UpdatedAt = DateTime.UtcNow;
    }

    public void UpdatePassword(byte[] newPassword)
    {
        PasswordHash = newPassword;
        UpdatedAt = DateTime.UtcNow;
    }
}

和UserImage:

public class UserImage : Image
{
    public int? UserRef { get; set; }

    public virtual User User { get; set; }

    public UserImage() : base() { }

    public UserImage(string content) : base(content) { }
}

在我的DbContext中,我有这样的事情:

modelBuilder.Entity<User>()
            .HasOne(x => x.UserImage)
            .WithOne(y => y.User)
            .HasForeignKey<UserImage>(y => y.UserRef)
            .IsRequired(false);

我的服务中有一个方法返回一个用户的图像:

public async Task<User> GetAsync(int id)
    {
        var user = await _context.Users.GetById(id)
            .Include(x => x.UserImage)
            .SingleOrDefaultAsync();

        if (user == null)
            throw new CorruptedOperationException("Invalid id");

        return user;
    }

问题是,当我使用Postman获取用户时,我得到了那种响应:

{
"userEmail": 2606810040825320252,
"userImage": {
    "userRef": 16,
    "user": {
        "userEmail": 2606810040825320252,
        "recipes": null,
        "nick": "MadBear123",
        "login": 10458175107962595193,
        "salt": "Fv/S1pnpu1u0RA6RxE1wfwCmqhbkb0Fu0W2sOuFgv//PHyizyPtmuaX8OtYkCgSJPlKMGmE2qFgg2rgs70Ee9bbMU26iVhtIApqV/Zxac54P9EXBvgkAXede3YHzSPzHkvGz3WchUUDIQqHF+EmdvPT9KuYR1Djgywxh0bDbSJk=",
        "passwordHash": "Yk5S3jutaKJpwSQoRH0nk2At3nYL/Wzi+8QGRFOZuByi54o+YJHuhPYRMMSG3Vmimv1UMRWe+VA8ym2xQxoEJA==",
        "role": "user",
        "restoreKey": "Vub!@g17@kcP",
        "id": 16,
        "createdAt": "2018-10-14T11:11:43.9902857",
        "updatedAt": "2018-10-14T11:11:43.990384"
    },
    "imageContent": "/9j/4AAQSkZJRgABAQEASABIAAD/4QAiRXhpZgAATU0AKgAAAAgAAQESAAMAAAABAAEAAAAAAAD/2wBDAAIBAQIBAQICAgICAgICAwUDAwMDAwYEBAMFBwYHBwcGBwcICQsJCAgKCAcHCg0KCgsMDAwMBwkODw0MDgsMDAz/2wBDAQICAgMDAwYDAwYMCAcIDAwMDAwMDAwMDAwMDAwMDAwMDAwMDAwMDAwMDAwMDAwMDAwMDAwMDAwMDAwMDAwMDAz/wAARCAAgACADASIAAhEBAxEB/8QAHwAAAQUBAQEBAQEAAAAAAAAAAAECAwQFBgcICQoL/8QAtRAAAgEDAwIEAwUFBAQAAAF9AQIDAAQRBRIhMUEGE1FhByJxFDKBkaEII0KxwRVS0fAkM2JyggkKFhcYGRolJicoKSo0NTY3ODk6Q0RFRkdISUpTVFVWV1hZWmNkZWZnaGlqc3R1dnd4eXqDhIWGh4iJipKTlJWWl5iZmqKjpKWmp6ipqrKztLW2t7i5usLDxMXGx8jJytLT1NXW19jZ2uHi4+Tl5ufo6erx8vP09fb3+Pn6/8QAHwEAAwEBAQEBAQEBAQAAAAAAAAECAwQFBgcICQoL/8QAtREAAgECBAQDBAcFBAQAAQJ3AAECAxEEBSExBhJBUQdhcRMiMoEIFEKRobHBCSMzUvAVYnLRChYkNOEl8RcYGRomJygpKjU2Nzg5OkNERUZHSElKU1RVVldYWVpjZGVmZ2hpanN0dXZ3eHl6goOEhYaHiImKkpOUlZaXmJmaoqOkpaanqKmqsrO0tba3uLm6wsPExcbHyMnK0tPU1dbX2Nna4uPk5ebn6Onq8vP09fb3+Pn6/9oADAMBAAIRAxEAPwDjZ/jPZ6rHocDfFz4iNI19b3BU+FdFjYiEho2/5A6l8Mi53Eg4bIbkj3Sx/bi0/T/2dde0CP8AaL1xdvhK+i+w3EeiQCeR4r7bA2NMj3rtnLhScEyLtJZRt+a/2fH8S/Ha5t77wn4x+Hfiqy0q8neCHRrW8vL2dTpuq3bhbeOOWbcqQNshdDNI8kaRqzAkYXiT9tDxF8DLbxlp+peE9b8davp8b6fdaB4ZsL9LqKFZJI57m9lubJhp6o6JGYZojch2w8UIwzEpSneEd9OtjOPJDV7el/yP2V+Hv7VvhvxLrhcftfaTHYl5CkWpXfhhHwJJFCsBBG4OAp6Y57cVjfAL9rHwj4Y/Zx+HMM37YXwb0KSPw7pkLWep3OjF4X+zQp5J/wBJjbcGIXB5yQOtfLn7FH/BbZpPA0eqN8N/EXgLVoI7u5utD8f6nqVrDeRxh5B/Z15baNLFdyNiSMwlIpt6/LG6q7pa0T/gtFefD79kf4e3uo6h8CdBsdA8N2S2clz8ablL7Xo47GMFhpy6FJM8i5IKhSySoACzqm6fehG1rtFq0pXvZH4L/sdftNWH7OOo61f65pt94g0W7sWsY9OsPEUmky3N23EMjT2zrcxLFG9w6tGrK0gjjcFJHFdR8ef2620zXZtY+EPi/wCLWh3HisTy+JLbxFqqXVxb3MgdHe0voPLdoZI3QFJIw6vACXkDkD550T4a61qHmC3jhZmwCd3T9K0JPgT4vZvlsvM3DGVfj9a6oymlaK179TCXI37z07dD6k+B3/BT/VPF+ixt8dvGnxw+JMvhXVDqnhfQtP8AEUVnZ3FxPb/Zp5r69niuLhsQBo4lEbGP7ROysm+RJfIf21v2pNU/a++KknjTVJLiBZ4I9IhtL3xFNq1zp0NuCY4fOu5ZLuaNVkAEk5JJ3ruYoSeb8IfslfEDxEFa2t7W3C95p9nqewNaXxW/Z48caV4b0e21OOzm/s8zKskV2824OwY/KVG0jpkZJGAeAMaSjVlG8l87av5mcalGMrRa9L6L0Wx//9k=",
    "id": 10,
    "createdAt": "2018-10-16T05:45:42.4644513",
    "updatedAt": "2018-10-16T05:45:42.4645292"
},
"recipes": null,
"nick": "MadBear123",
"login": 10458175107962595193,
"salt": "Fv/S1pnpu1u0RA6RxE1wfwCmqhbkb0Fu0W2sOuFgv//PHyizyPtmuaX8OtYkCgSJPlKMGmE2qFgg2rgs70Ee9bbMU26iVhtIApqV/Zxac54P9EXBvgkAXede3YHzSPzHkvGz3WchUUDIQqHF+EmdvPT9KuYR1Djgywxh0bDbSJk=",
"passwordHash": "Yk5S3jutaKJpwSQoRH0nk2At3nYL/Wzi+8QGRFOZuByi54o+YJHuhPYRMMSG3Vmimv1UMRWe+VA8ym2xQxoEJA==",
"role": "user",
"restoreKey": "Vub!@g17@kcP",
"id": 16,
"createdAt": "2018-10-14T11:11:43.9902857",
"updatedAt": "2018-10-14T11:11:43.990384"

}

就像你可以看到我得到一个用户的图像,在这个图像中我得到(再次)这个用户。我想得到这样的回应:

{
"userEmail": 2606810040825320252,
"userImage": {
    "userRef": 16,
    "user": null,
    "imageContent": "/9j/4AAQSkZJRgABAQEASABIAAD/4QAiRXhpZgAATU0AKgAAAAgAAQESAAMAAAABAAEAAAAAAAD/2wBDAAIBAQIBAQICAgICAgICAwUDAwMDAwYEBAMFBwYHBwcGBwcICQsJCAgKCAcHCg0KCgsMDAwMBwkODw0MDgsMDAz/2wBDAQICAgMDAwYDAwYMCAcIDAwMDAwMDAwMDAwMDAwMDAwMDAwMDAwMDAwMDAwMDAwMDAwMDAwMDAwMDAwMDAwMDAz/wAARCAAgACADASIAAhEBAxEB/8QAHwAAAQUBAQEBAQEAAAAAAAAAAAECAwQFBgcICQoL/8QAtRAAAgEDAwIEAwUFBAQAAAF9AQIDAAQRBRIhMUEGE1FhByJxFDKBkaEII0KxwRVS0fAkM2JyggkKFhcYGRolJicoKSo0NTY3ODk6Q0RFRkdISUpTVFVWV1hZWmNkZWZnaGlqc3R1dnd4eXqDhIWGh4iJipKTlJWWl5iZmqKjpKWmp6ipqrKztLW2t7i5usLDxMXGx8jJytLT1NXW19jZ2uHi4+Tl5ufo6erx8vP09fb3+Pn6/8QAHwEAAwEBAQEBAQEBAQAAAAAAAAECAwQFBgcICQoL/8QAtREAAgECBAQDBAcFBAQAAQJ3AAECAxEEBSExBhJBUQdhcRMiMoEIFEKRobHBCSMzUvAVYnLRChYkNOEl8RcYGRomJygpKjU2Nzg5OkNERUZHSElKU1RVVldYWVpjZGVmZ2hpanN0dXZ3eHl6goOEhYaHiImKkpOUlZaXmJmaoqOkpaanqKmqsrO0tba3uLm6wsPExcbHyMnK0tPU1dbX2Nna4uPk5ebn6Onq8vP09fb3+Pn6/9oADAMBAAIRAxEAPwDjZ/jPZ6rHocDfFz4iNI19b3BU+FdFjYiEho2/5A6l8Mi53Eg4bIbkj3Sx/bi0/T/2dde0CP8AaL1xdvhK+i+w3EeiQCeR4r7bA2NMj3rtnLhScEyLtJZRt+a/2fH8S/Ha5t77wn4x+Hfiqy0q8neCHRrW8vL2dTpuq3bhbeOOWbcqQNshdDNI8kaRqzAkYXiT9tDxF8DLbxlp+peE9b8davp8b6fdaB4ZsL9LqKFZJI57m9lubJhp6o6JGYZojch2w8UIwzEpSneEd9OtjOPJDV7el/yP2V+Hv7VvhvxLrhcftfaTHYl5CkWpXfhhHwJJFCsBBG4OAp6Y57cVjfAL9rHwj4Y/Zx+HMM37YXwb0KSPw7pkLWep3OjF4X+zQp5J/wBJjbcGIXB5yQOtfLn7FH/BbZpPA0eqN8N/EXgLVoI7u5utD8f6nqVrDeRxh5B/Z15baNLFdyNiSMwlIpt6/LG6q7pa0T/gtFefD79kf4e3uo6h8CdBsdA8N2S2clz8ablL7Xo47GMFhpy6FJM8i5IKhSySoACzqm6fehG1rtFq0pXvZH4L/sdftNWH7OOo61f65pt94g0W7sWsY9OsPEUmky3N23EMjT2zrcxLFG9w6tGrK0gjjcFJHFdR8ef2620zXZtY+EPi/wCLWh3HisTy+JLbxFqqXVxb3MgdHe0voPLdoZI3QFJIw6vACXkDkD550T4a61qHmC3jhZmwCd3T9K0JPgT4vZvlsvM3DGVfj9a6oymlaK179TCXI37z07dD6k+B3/BT/VPF+ixt8dvGnxw+JMvhXVDqnhfQtP8AEUVnZ3FxPb/Zp5r69niuLhsQBo4lEbGP7ROysm+RJfIf21v2pNU/a++KknjTVJLiBZ4I9IhtL3xFNq1zp0NuCY4fOu5ZLuaNVkAEk5JJ3ruYoSeb8IfslfEDxEFa2t7W3C95p9nqewNaXxW/Z48caV4b0e21OOzm/s8zKskV2824OwY/KVG0jpkZJGAeAMaSjVlG8l87av5mcalGMrRa9L6L0Wx//9k=",
    "id": 10,
    "createdAt": "2018-10-16T05:45:42.4644513",
    "updatedAt": "2018-10-16T05:45:42.4645292"
},
"recipes": null,
"nick": "MadBear123",
"login": 10458175107962595193,
"salt": "Fv/S1pnpu1u0RA6RxE1wfwCmqhbkb0Fu0W2sOuFgv//PHyizyPtmuaX8OtYkCgSJPlKMGmE2qFgg2rgs70Ee9bbMU26iVhtIApqV/Zxac54P9EXBvgkAXede3YHzSPzHkvGz3WchUUDIQqHF+EmdvPT9KuYR1Djgywxh0bDbSJk=",
"passwordHash": "Yk5S3jutaKJpwSQoRH0nk2At3nYL/Wzi+8QGRFOZuByi54o+YJHuhPYRMMSG3Vmimv1UMRWe+VA8ym2xQxoEJA==",
"role": "user",
"restoreKey": "Vub!@g17@kcP",
"id": 16,
"createdAt": "2018-10-14T11:11:43.9902857",
"updatedAt": "2018-10-14T11:11:43.990384"

}

或类似的东西。我尝试使用Include()和(或没有)虚拟方式,但我最终得到了这个。

UPDATE

GetById()的定义:

public static IQueryable<User> GetById(this IQueryable<User> value,int id)
     => value.Where(x => x.Id == id);

你可以在GitHub找到完整的项目。我正在分支MB#20

entity-framework-core asp.net-core-webapi navigation-properties
2个回答
1
投票

对于循环引用,您无法在EF Core中控制它。

对于一般处理,我们在Startup.cs中配置它

.AddJsonOptions(options =>
{
    options.SerializerSettings.ReferenceLoopHandling = Newtonsoft.Json
        .ReferenceLoopHandling.Ignore;
    options.SerializerSettings.ContractResolver =
        new CamelCasePropertyNamesContractResolver();
});

用例:

var user = await _userService.GetAsync(id);
return Ok(user);

对于你的问题,你在user返回之前修改了return Ok(user.ShapeData(fields));,这使得JsonSerialize无法知道它的循环引用。

对于变通方法,在转换为ExpandoObject之前,处理循环引用,如

public static ExpandoObject ShapeData<TSource>(this TSource source, string fields)
{
    if (source == null)
    {
        throw new ArgumentNullException("source");
    }
    var result =JsonConvert.SerializeObject(source, new JsonSerializerSettings{
        ReferenceLoopHandling = ReferenceLoopHandling.Ignore
    } );
    source = JsonConvert.DeserializeObject<TSource>(result);
    var dataShapedObject = new ExpandoObject();

    //your rest code
    return dataShapedObject;
}

更新

对于UserImage中的null,它是由您将属性指定为public string ImageContent { get; protected set; }引起的。

尝试自定义DefaultContractResolver以反序列化受保护的属性。

IncludePrivateStateContractResolver.cs

public class IncludePrivateStateContractResolver : DefaultContractResolver
{
    protected override List<MemberInfo> GetSerializableMembers(Type objectType)
    {
        const BindingFlags BindingFlags = BindingFlags.Instance | BindingFlags.NonPublic | BindingFlags.Public;
        var properties = objectType.GetProperties(BindingFlags);//.Where(p => p.HasSetter() && p.HasGetter());
        var fields = objectType.GetFields(BindingFlags);

        var allMembers = properties.Cast<MemberInfo>().Union(fields);
        return allMembers.ToList();
    }

    protected override JsonProperty CreateProperty(MemberInfo member, MemberSerialization memberSerialization)
    {
        var prop = base.CreateProperty(member, memberSerialization);

        if (!prop.Writable)
        {
            var property = member as PropertyInfo;
            if (property != null)
            {
                prop.Writable = property.HasSetter();
            }
            else
            {
                var field = member as FieldInfo;
                if (field != null)
                {
                    prop.Writable = true;
                }
            }
        }

        if (!prop.Readable)
        {
            var field = member as FieldInfo;
            if (field != null)
            {
                prop.Readable = true;
            }
        }

        return prop;
    }
}

public static class TypeExtensions
{
    public static bool HasSetter(this PropertyInfo property)
    {
        //In this way we can check for private setters in base classes
        return property.DeclaringType.GetMethods(BindingFlags.Instance | BindingFlags.NonPublic | BindingFlags.Public)
                                     .Any(m => m.Name == "set_" + property.Name);
    }

    public static bool HasGetter(this PropertyInfo property)
    {
        //In this way we can check for private getters in base classes
        return property.DeclaringType.GetMethods(BindingFlags.Instance | BindingFlags.NonPublic | BindingFlags.Public)
                                     .Any(m => m.Name == "get_" + property.Name);
    }
}

用例:

public static ExpandoObject ShapeData<TSource>(this TSource source, string fields)
{
    var soureType = source.GetType();
    if (source == null)
    {
        throw new ArgumentNullException("source");
    }
    var serializeSettings = new JsonSerializerSettings{
        ReferenceLoopHandling = ReferenceLoopHandling.Ignore
    };
    var deserializeSettings = new JsonSerializerSettings{
        ContractResolver = new IncludePrivateStateContractResolver()
    };
    var result =JsonConvert.SerializeObject(source, serializeSettings );
    var castType = JsonConvert.DeserializeObject<TSource>(result, deserializeSettings);
    var dataShapedObject = new ExpandoObject();

-1
投票

我设法解决了我的问题。我将模型属性中的所有私有设置器更改为公共使用的Tao Zhou原始答案。

我的ShapeData方法:

public static ExpandoObject ShapeData<TSource>(this TSource source, string fields)
    {
        if (source == null)
        {
            throw new ArgumentNullException("source");
        }

        var result = JsonConvert.SerializeObject(source, new JsonSerializerSettings
        {
            ReferenceLoopHandling = ReferenceLoopHandling.Ignore
        });
        source = JsonConvert.DeserializeObject<TSource>(result);
        var dataShapedObject = new ExpandoObject();
        // rest of my code
    }

用户:

public class User : Account
{
    public UInt64 UserEmail { get; set; }
    public UserImage UserImage { get; set; }
    public virtual ICollection<Recipe> Recipes { get; set; }
    // rest of the code
}

UserImage:

public class UserImage : Image
{
    public int? UserRef { get; set; }

    public virtual User User { get; set; }

    public UserImage() : base() { }

    public UserImage(string content) : base(content) { }
}

返回数据的示例:

{
"userEmail": 2606810040825320252,
"userImage": {
    "userRef": 16,
    "user": null,
    "imageContent": "/9j/4AAQSkZJRgABAQEASABIAAD/4QAiRXhpZgAATU0AKgAAAAgAAQESAAMAAAABAAEAAAAAAAD/2wBDAAIBAQIBAQICAgICAgICAwUDAwMDAwYEBAMFBwYHBwcGBwcICQsJCAgKCAcHCg0KCgsMDAwMBwkODw0MDgsMDAz/2wBDAQICAgMDAwYDAwYMCAcIDAwMDAwMDAwMDAwMDAwMDAwMDAwMDAwMDAwMDAwMDAwMDAwMDAwMDAwMDAwMDAwMDAz/wAARCAAgACADASIAAhEBAxEB/8QAHwAAAQUBAQEBAQEAAAAAAAAAAAECAwQFBgcICQoL/8QAtRAAAgEDAwIEAwUFBAQAAAF9AQIDAAQRBRIhMUEGE1FhByJxFDKBkaEII0KxwRVS0fAkM2JyggkKFhcYGRolJicoKSo0NTY3ODk6Q0RFRkdISUpTVFVWV1hZWmNkZWZnaGlqc3R1dnd4eXqDhIWGh4iJipKTlJWWl5iZmqKjpKWmp6ipqrKztLW2t7i5usLDxMXGx8jJytLT1NXW19jZ2uHi4+Tl5ufo6erx8vP09fb3+Pn6/8QAHwEAAwEBAQEBAQEBAQAAAAAAAAECAwQFBgcICQoL/8QAtREAAgECBAQDBAcFBAQAAQJ3AAECAxEEBSExBhJBUQdhcRMiMoEIFEKRobHBCSMzUvAVYnLRChYkNOEl8RcYGRomJygpKjU2Nzg5OkNERUZHSElKU1RVVldYWVpjZGVmZ2hpanN0dXZ3eHl6goOEhYaHiImKkpOUlZaXmJmaoqOkpaanqKmqsrO0tba3uLm6wsPExcbHyMnK0tPU1dbX2Nna4uPk5ebn6Onq8vP09fb3+Pn6/9oADAMBAAIRAxEAPwDjZ/jPZ6rHocDfFz4iNI19b3BU+FdFjYiEho2/5A6l8Mi53Eg4bIbkj3Sx/bi0/T/2dde0CP8AaL1xdvhK+i+w3EeiQCeR4r7bA2NMj3rtnLhScEyLtJZRt+a/2fH8S/Ha5t77wn4x+Hfiqy0q8neCHRrW8vL2dTpuq3bhbeOOWbcqQNshdDNI8kaRqzAkYXiT9tDxF8DLbxlp+peE9b8davp8b6fdaB4ZsL9LqKFZJI57m9lubJhp6o6JGYZojch2w8UIwzEpSneEd9OtjOPJDV7el/yP2V+Hv7VvhvxLrhcftfaTHYl5CkWpXfhhHwJJFCsBBG4OAp6Y57cVjfAL9rHwj4Y/Zx+HMM37YXwb0KSPw7pkLWep3OjF4X+zQp5J/wBJjbcGIXB5yQOtfLn7FH/BbZpPA0eqN8N/EXgLVoI7u5utD8f6nqVrDeRxh5B/Z15baNLFdyNiSMwlIpt6/LG6q7pa0T/gtFefD79kf4e3uo6h8CdBsdA8N2S2clz8ablL7Xo47GMFhpy6FJM8i5IKhSySoACzqm6fehG1rtFq0pXvZH4L/sdftNWH7OOo61f65pt94g0W7sWsY9OsPEUmky3N23EMjT2zrcxLFG9w6tGrK0gjjcFJHFdR8ef2620zXZtY+EPi/wCLWh3HisTy+JLbxFqqXVxb3MgdHe0voPLdoZI3QFJIw6vACXkDkD550T4a61qHmC3jhZmwCd3T9K0JPgT4vZvlsvM3DGVfj9a6oymlaK179TCXI37z07dD6k+B3/BT/VPF+ixt8dvGnxw+JMvhXVDqnhfQtP8AEUVnZ3FxPb/Zp5r69niuLhsQBo4lEbGP7ROysm+RJfIf21v2pNU/a++KknjTVJLiBZ4I9IhtL3xFNq1zp0NuCY4fOu5ZLuaNVkAEk5JJ3ruYoSeb8IfslfEDxEFa2t7W3C95p9nqewNaXxW/Z48caV4b0e21OOzm/s8zKskV2824OwY/KVG0jpkZJGAeAMaSjVlG8l87av5mcalGMrRa9L6L0Wx//9k=",
    "id": 10,
    "createdAt": "2018-10-16T05:45:42.4644513",
    "updatedAt": "2018-10-16T05:45:42.4645292"
},
"recipes": null,
"nick": "MadBear123",
"login": 10458175107962595193,
"salt": "Fv/S1pnpu1u0RA6RxE1wfwCmqhbkb0Fu0W2sOuFgv//PHyizyPtmuaX8OtYkCgSJPlKMGmE2qFgg2rgs70Ee9bbMU26iVhtIApqV/Zxac54P9EXBvgkAXede3YHzSPzHkvGz3WchUUDIQqHF+EmdvPT9KuYR1Djgywxh0bDbSJk=",
"passwordHash": "Yk5S3jutaKJpwSQoRH0nk2At3nYL/Wzi+8QGRFOZuByi54o+YJHuhPYRMMSG3Vmimv1UMRWe+VA8ym2xQxoEJA==",
"role": "user",
"restoreKey": "Vub!@g17@kcP",
"id": 16,
"createdAt": "2018-10-14T11:11:43.9902857",
"updatedAt": "2018-10-14T11:11:43.990384"
}
© www.soinside.com 2019 - 2024. All rights reserved.