繁体   English   中英

ASP.NET MVC身份与MySql注册错误

[英]Asp.NET MVC Identity with MySql register error

我第一次使用Identity进行用户注册。 我需要注册,但是这使我犯了一个错误,并且我不知道可以将经过测试并且正在运行的项目用作模型,但是有一些区别,我们使用的是MySql:

<add name="blabla" providerName="MySql.Data.MySqlClient" connectionString="Server=localhost;Database=blabla;Uid=root;Pwd=1234;" />   

在没有身份的情况下执行测试,因此配置正确。

错误行是:

var result = await UserManager.CreateAsync(user, model.Password);

整个堆栈跟踪可以在以下链接中找到: http : //pastie.org/10208626

视图模型:

public class RegisterViewModel
        {
            [Required]
            [EmailAddress]
            [Display(Name = "E-mail")]
            public string Email { get; set; }

            [EmailAddress]
            [Display(Name = "Confirmar E-mail")]
            [System.ComponentModel.DataAnnotations.Compare("Email", ErrorMessageResourceType = typeof(Language), ErrorMessageResourceName = "EmailsDoNotMatch")]
            public string ConfirmEmail { get; set; }

            [Required]
            [StringLength(100, ErrorMessageResourceType = typeof(Language), ErrorMessageResourceName = "ThePasswordMustBeASixCharactersLong", MinimumLength = 6)]
            [DataType(DataType.Password)]
            [Display(Name = "Senha")]
            public string Password { get; set; }

            [DataType(DataType.Password)]
            [Display(Name = "Confirmar Senha")]
            [System.ComponentModel.DataAnnotations.Compare("Password", ErrorMessageResourceType = typeof(Language), ErrorMessageResourceName = "PasswordsDoNotMatch")]
            public string ConfirmPassword { get; set; }

            [Required]
            [Display(Name = "Name", ResourceType = typeof(Language))]
            public string Nome { get; set; }

            [Required]
            [Display(Name = "UserType", ResourceType = typeof(Language))]
            public TipoUsuario TipoDeUsuario { get; set; }

            [Required]
            [Display(Name = "CelPhone", ResourceType = typeof(Language))]
            public string Celular { get; set; }

            [Display(Name = "Phone", ResourceType = typeof(Language))]
            public long Telefone { get; set; }

            [Required]
            [Display(Name = "RG", ResourceType = typeof(Language))]
            public string RG { get; set; }

            [Cpf]
            [Required]
            [Display(Name = "CPF", ResourceType = typeof(Language))]
            public string CPF { get; set; }

            [Required]
            [Display(Name = "Gender", ResourceType = typeof(Language))]
            public char Sexo { get; set; }
        }

模型:

public class ApplicationUser : IdentityUser
    {
        public ApplicationUser()
        {
            Clients = new Collection<Client>();
        }

        [Index, MaxLength(60)]
        public override string UserName { get; set; }

        public Guid EmpresaPaiID { get; set; }
        public Guid EnderecoID { get; set; }
        public Guid ServicoID { get; set; }
        public bool Ativo { get; set; }
        public bool CadastroCompleto { get; set; }

        [Display(Name = "Address", ResourceType = typeof(Resources.Language))]
        public virtual Endereco Endereco { get; set; }
        [Display(Name = "Vehicles", ResourceType = typeof(Resources.Language))]
        public virtual ICollection<Veiculo> Veiculos { get; set; }
        [Display(Name = "ServicesPerformed", ResourceType = typeof(Resources.Language))]
        public virtual ICollection<Servico> ServicosVans { get; set; }

        [Display(Name = "Available", ResourceType = typeof(Resources.Language))]
        public bool Disponivel { get; set; }        

        [Required]
        [Display(Name = "Name", ResourceType = typeof(Resources.Language))]
        public string Nome { get; set; }

        [Required]
        [EmailAddress]
        [Display(Name = "UserType", ResourceType = typeof(Resources.Language))]
        public TipoUsuario TipoUsuario { get; set; }

        //[Required]
        //[EmailAddress]
        //[Display(Name = "Email", ResourceType = typeof(Resources.Language))]
        //public string Email { get; set; }

        //[Required]
        //[Display(Name = "Password", ResourceType = typeof(Resources.Language))]
        //[DataType(DataType.Password)]
        //public string Password { get; set; }

        [Required]
        [Display(Name = "CelPhone", ResourceType = typeof(Resources.Language))]
        public override string PhoneNumber { get; set; }

        [Display(Name = "Phone", ResourceType = typeof(Resources.Language))]
        public long Telefone { get; set; }

        [Required]
        [Display(Name = "RG", ResourceType = typeof(Resources.Language))]
        public string RG { get; set; }

        [Cpf]
        [Required]
        [Display(Name = "CPF", ResourceType = typeof(Resources.Language))]
        public string CPF { get; set; }

        [Cnpj]
        [Display(Name = "CNPJ", ResourceType = typeof(Resources.Language))]
        public string CNPJEmpresa { get; set; } //Caso for empresa o tipo de usuário

        [Cnpj]
        [Display(Name = "RentalCNPJ", ResourceType = typeof(Resources.Language))]
        public string CNPJLocadora { get; set; }

        [Required]
        [Display(Name = "Gender", ResourceType = typeof(Resources.Language))]
        public char Sexo { get; set; }        

        public double Latitude { get; set; }

        public double Longitude { get; set; }

        [Display(Name = "PassangerSecurity", ResourceType = typeof(Resources.Language))]
        public bool SeguroPassageiro { get; set; }

        [Display(Name = "RemuneratedActivity", ResourceType = typeof(Resources.Language))]
        public bool AtividadeRemunerada { get; set; }

        [Display(Name = "DriverLicense", ResourceType = typeof(Resources.Language))]
        public long CNH { get; set; }

        [NotMapped]
        [Display(Name = "Photo", ResourceType = typeof(Resources.Language))]
        public HttpPostedFileBase Foto { get; set; }

        public string FotoPath { get; set; }
        public string DocumentoLocadoraVeiculosPath { get; set; }
        public string AtestadoAntecedentesCriminaisPath { get; set; }
        public string BilheteDPVATPath { get; set; }
        public string RegistroLicenciamentoVeiculoPath { get; set; }

        public virtual ICollection<Client> Clients { get; set; }

        [NotMapped]
        public string CurrentClientId { get; set; }

        public async Task<ClaimsIdentity> GenerateUserIdentityAsync(UserManager<ApplicationUser> manager, ClaimsIdentity ext = null)
        {
            // Observe que o authenticationType precisa ser o mesmo que foi definido em CookieAuthenticationOptions.AuthenticationType
            var userIdentity = await manager.CreateIdentityAsync(this, DefaultAuthenticationTypes.ApplicationCookie);

            var claims = new List<Claim>();

            if (!string.IsNullOrEmpty(CurrentClientId))
            {
                claims.Add(new Claim("AspNet.Identity.ClientId", CurrentClientId));
            }

            //  Adicione novos Claims aqui //

            // Adicionando Claims externos capturados no login
            if (ext != null)
            {
                await SetExternalProperties(userIdentity, ext);
            }

            // Gerenciamento de Claims para informaçoes do usuario
            //claims.Add(new Claim("AdmRoles", "True"));

            userIdentity.AddClaims(claims);

            return userIdentity;
        }

        private async Task SetExternalProperties(ClaimsIdentity identity, ClaimsIdentity ext)
        {
            if (ext != null)
            {
                var ignoreClaim = "http://schemas.xmlsoap.org/ws/2005/05/identity/claims";
                // Adicionando Claims Externos no Identity
                foreach (var c in ext.Claims)
                {
                    if (!c.Type.StartsWith(ignoreClaim))
                        if (!identity.HasClaim(c.Type, c.Value))
                            identity.AddClaim(c);
                }
            }
        }
    }

我以为问题可能与用户创建所需的项目数量有关,但是据我所知,这非常完美,ViewModel中所需的所有内容都与Model一致。

我觉得很有趣,也将Migration生成的代码放进去:

public partial class OverflowReview : DbMigration
    {
        public override void Up()
        {
            CreateTable(
                "dbo.Bairros",
                c => new
                    {
                        BairroID = c.Guid(nullable: false),
                        CidadeID = c.Guid(nullable: false),
                        Nome = c.String(nullable: false, unicode: false),
                    })
                .PrimaryKey(t => t.BairroID)
                .ForeignKey("dbo.Cidades", t => t.CidadeID, cascadeDelete: true)
                .Index(t => t.CidadeID);

            CreateTable(
                "dbo.Cidades",
                c => new
                    {
                        CidadeID = c.Guid(nullable: false),
                        UF = c.String(nullable: false, maxLength: 128, storeType: "nvarchar"),
                        Nome = c.String(nullable: false, unicode: false),
                    })
                .PrimaryKey(t => t.CidadeID)
                .ForeignKey("dbo.Estados", t => t.UF, cascadeDelete: true)
                .Index(t => t.UF);

            CreateTable(
                "dbo.Estados",
                c => new
                    {
                        UF = c.String(nullable: false, maxLength: 128, storeType: "nvarchar"),
                        Nome = c.String(nullable: false, unicode: false),
                    })
                .PrimaryKey(t => t.UF)
                .Index(t => t.UF);

            CreateTable(
                "dbo.AspNetClaims",
                c => new
                    {
                        Id = c.Guid(nullable: false),
                        Name = c.String(nullable: false, maxLength: 128, storeType: "nvarchar"),
                    })
                .PrimaryKey(t => t.Id);

            CreateTable(
                "dbo.AspNetClients",
                c => new
                    {
                        Id = c.Int(nullable: false, identity: true),
                        ClientKey = c.String(unicode: false),
                        ApplicationUser_Id = c.String(maxLength: 128, storeType: "nvarchar"),
                    })
                .PrimaryKey(t => t.Id)
                .ForeignKey("dbo.AspNetUsers", t => t.ApplicationUser_Id)
                .Index(t => t.ApplicationUser_Id);

            CreateTable(
                "dbo.Coordenadas",
                c => new
                    {
                        CoordenadaID = c.Guid(nullable: false),
                        ServicoID = c.Guid(nullable: false),
                        Latitude = c.Double(nullable: false),
                        Longitude = c.Double(nullable: false),
                        Data = c.DateTime(nullable: false, precision: 0),
                    })
                .PrimaryKey(t => t.CoordenadaID)
                .ForeignKey("dbo.Servicos", t => t.ServicoID, cascadeDelete: true)
                .Index(t => t.ServicoID);

            CreateTable(
                "dbo.Servicos",
                c => new
                    {
                        ServicoID = c.Guid(nullable: false),
                        VeiculoID = c.Guid(nullable: false),
                        MotoristaID = c.Guid(nullable: false),
                        ClienteID = c.Guid(nullable: false),
                        EnderecoInicioID = c.Guid(nullable: false),
                        EnderecoFimID = c.Guid(nullable: false),
                        NumeroPassageiros = c.Int(nullable: false),
                        ValorTotal = c.Long(),
                        PagamentoEfetuado = c.Boolean(nullable: false),
                        Disponivel = c.Boolean(nullable: false),
                        DataInicio = c.DateTime(nullable: false, precision: 0),
                        DataFim = c.DateTime(precision: 0),
                        DataVisualizacao = c.DateTime(precision: 0),
                        ApplicationUser_Id = c.String(maxLength: 128, storeType: "nvarchar"),
                        Cliente_Id = c.String(maxLength: 128, storeType: "nvarchar"),
                        EnderecoFim_EnderecoID = c.Guid(),
                        EnderecoInicio_EnderecoID = c.Guid(),
                        Motorista_Id = c.String(maxLength: 128, storeType: "nvarchar"),
                    })
                .PrimaryKey(t => t.ServicoID)
                .ForeignKey("dbo.AspNetUsers", t => t.ApplicationUser_Id)
                .ForeignKey("dbo.AspNetUsers", t => t.Cliente_Id)
                .ForeignKey("dbo.Enderecos", t => t.EnderecoFim_EnderecoID)
                .ForeignKey("dbo.Enderecos", t => t.EnderecoInicio_EnderecoID)
                .ForeignKey("dbo.AspNetUsers", t => t.Motorista_Id)
                .Index(t => t.ApplicationUser_Id)
                .Index(t => t.Cliente_Id)
                .Index(t => t.EnderecoFim_EnderecoID)
                .Index(t => t.EnderecoInicio_EnderecoID)
                .Index(t => t.Motorista_Id);

            CreateTable(
                "dbo.AspNetUsers",
                c => new
                    {
                        Id = c.String(nullable: false, maxLength: 128, storeType: "nvarchar"),
                        UserName = c.String(nullable: false, maxLength: 60, storeType: "nvarchar"),
                        EmpresaPaiID = c.Guid(nullable: false),
                        EnderecoID = c.Guid(nullable: false),
                        ServicoID = c.Guid(nullable: false),
                        Ativo = c.Boolean(nullable: false),
                        CadastroCompleto = c.Boolean(nullable: false),
                        Disponivel = c.Boolean(nullable: false),
                        Nome = c.String(nullable: false, unicode: false),
                        TipoUsuario = c.Int(nullable: false),
                        PhoneNumber = c.String(nullable: false, unicode: false),
                        Telefone = c.Long(nullable: false),
                        RG = c.String(nullable: false, unicode: false),
                        CPF = c.String(nullable: false, unicode: false),
                        CNPJEmpresa = c.String(unicode: false),
                        CNPJLocadora = c.String(unicode: false),
                        Latitude = c.Double(nullable: false),
                        Longitude = c.Double(nullable: false),
                        SeguroPassageiro = c.Boolean(nullable: false),
                        AtividadeRemunerada = c.Boolean(nullable: false),
                        CNH = c.Long(nullable: false),
                        FotoPath = c.String(unicode: false),
                        DocumentoLocadoraVeiculosPath = c.String(unicode: false),
                        AtestadoAntecedentesCriminaisPath = c.String(unicode: false),
                        BilheteDPVATPath = c.String(unicode: false),
                        RegistroLicenciamentoVeiculoPath = c.String(unicode: false),
                        Email = c.String(maxLength: 256, storeType: "nvarchar"),
                        EmailConfirmed = c.Boolean(nullable: false),
                        PasswordHash = c.String(unicode: false),
                        SecurityStamp = c.String(unicode: false),
                        PhoneNumberConfirmed = c.Boolean(nullable: false),
                        TwoFactorEnabled = c.Boolean(nullable: false),
                        LockoutEndDateUtc = c.DateTime(precision: 0),
                        LockoutEnabled = c.Boolean(nullable: false),
                        AccessFailedCount = c.Int(nullable: false),
                        Veiculo_VeiculoID = c.Guid(),
                    })
                .PrimaryKey(t => t.Id)
                .ForeignKey("dbo.Enderecos", t => t.EnderecoID, cascadeDelete: true)
                .ForeignKey("dbo.Veiculos", t => t.Veiculo_VeiculoID)
                .Index(t => t.UserName)
                .Index(t => t.UserName, unique: true, name: "UserNameIndex")
                .Index(t => t.EnderecoID)
                .Index(t => t.Veiculo_VeiculoID);

            CreateTable(
                "dbo.AspNetUserClaims",
                c => new
                    {
                        Id = c.Int(nullable: false, identity: true),
                        UserId = c.String(nullable: false, maxLength: 128, storeType: "nvarchar"),
                        ClaimType = c.String(unicode: false),
                        ClaimValue = c.String(unicode: false),
                    })
                .PrimaryKey(t => t.Id)
                .ForeignKey("dbo.AspNetUsers", t => t.UserId, cascadeDelete: true)
                .Index(t => t.UserId);

            CreateTable(
                "dbo.Enderecos",
                c => new
                    {
                        EnderecoID = c.Guid(nullable: false),
                        CidadeID = c.Guid(nullable: false),
                        Logradouro = c.String(nullable: false, unicode: false),
                        CEP = c.Int(nullable: false),
                        Bairro_BairroID = c.Guid(),
                        Estado_UF = c.String(maxLength: 128, storeType: "nvarchar"),
                    })
                .PrimaryKey(t => t.EnderecoID)
                .ForeignKey("dbo.Bairros", t => t.Bairro_BairroID)
                .ForeignKey("dbo.Cidades", t => t.CidadeID, cascadeDelete: true)
                .ForeignKey("dbo.Estados", t => t.Estado_UF)
                .Index(t => t.CidadeID)
                .Index(t => t.Bairro_BairroID)
                .Index(t => t.Estado_UF);

            CreateTable(
                "dbo.AspNetUserLogins",
                c => new
                    {
                        LoginProvider = c.String(nullable: false, maxLength: 128, storeType: "nvarchar"),
                        ProviderKey = c.String(nullable: false, maxLength: 128, storeType: "nvarchar"),
                        UserId = c.String(nullable: false, maxLength: 128, storeType: "nvarchar"),
                    })
                .PrimaryKey(t => new { t.LoginProvider, t.ProviderKey, t.UserId })
                .ForeignKey("dbo.AspNetUsers", t => t.UserId, cascadeDelete: true)
                .Index(t => t.UserId);

            CreateTable(
                "dbo.AspNetUserRoles",
                c => new
                    {
                        UserId = c.String(nullable: false, maxLength: 128, storeType: "nvarchar"),
                        RoleId = c.String(nullable: false, maxLength: 128, storeType: "nvarchar"),
                    })
                .PrimaryKey(t => new { t.UserId, t.RoleId })
                .ForeignKey("dbo.AspNetUsers", t => t.UserId, cascadeDelete: true)
                .ForeignKey("dbo.AspNetRoles", t => t.RoleId, cascadeDelete: true)
                .Index(t => t.UserId)
                .Index(t => t.RoleId);

            CreateTable(
                "dbo.Veiculos",
                c => new
                    {
                        VeiculoID = c.Guid(nullable: false),
                        MotoristaID = c.Guid(nullable: false),
                        EnderecoID = c.Guid(nullable: false),
                        EmpresaID = c.Guid(nullable: false),
                        Marca = c.String(nullable: false, unicode: false),
                        Modelo = c.String(nullable: false, unicode: false),
                        Ano = c.Int(nullable: false),
                        Placa = c.String(nullable: false, unicode: false),
                        Cor = c.String(nullable: false, unicode: false),
                        Renavan = c.Long(nullable: false),
                        NumeroPassageiros = c.Int(nullable: false),
                        PesoExtra = c.Double(nullable: false),
                        Carretinha = c.Boolean(nullable: false),
                        Empresa_Id = c.String(maxLength: 128, storeType: "nvarchar"),
                        ApplicationUser_Id = c.String(maxLength: 128, storeType: "nvarchar"),
                        Servico_ServicoID = c.Guid(),
                    })
                .PrimaryKey(t => t.VeiculoID)
                .ForeignKey("dbo.AspNetUsers", t => t.Empresa_Id)
                .ForeignKey("dbo.Enderecos", t => t.EnderecoID, cascadeDelete: true)
                .ForeignKey("dbo.AspNetUsers", t => t.ApplicationUser_Id)
                .ForeignKey("dbo.Servicos", t => t.Servico_ServicoID)
                .Index(t => t.EnderecoID)
                .Index(t => t.Empresa_Id)
                .Index(t => t.ApplicationUser_Id)
                .Index(t => t.Servico_ServicoID);

            CreateTable(
                "dbo.AspNetRoles",
                c => new
                    {
                        Id = c.String(nullable: false, maxLength: 128, storeType: "nvarchar"),
                        Name = c.String(nullable: false, maxLength: 200, storeType: "nvarchar"),
                    })
                .PrimaryKey(t => t.Id)
                .Index(t => t.Name, unique: true, name: "RoleNameIndex");

        }

        public override void Down()
        {
            DropForeignKey("dbo.AspNetUserRoles", "RoleId", "dbo.AspNetRoles");
            DropForeignKey("dbo.Coordenadas", "ServicoID", "dbo.Servicos");
            DropForeignKey("dbo.Veiculos", "Servico_ServicoID", "dbo.Servicos");
            DropForeignKey("dbo.Servicos", "Motorista_Id", "dbo.AspNetUsers");
            DropForeignKey("dbo.Servicos", "EnderecoInicio_EnderecoID", "dbo.Enderecos");
            DropForeignKey("dbo.Servicos", "EnderecoFim_EnderecoID", "dbo.Enderecos");
            DropForeignKey("dbo.Servicos", "Cliente_Id", "dbo.AspNetUsers");
            DropForeignKey("dbo.Veiculos", "ApplicationUser_Id", "dbo.AspNetUsers");
            DropForeignKey("dbo.AspNetUsers", "Veiculo_VeiculoID", "dbo.Veiculos");
            DropForeignKey("dbo.Veiculos", "EnderecoID", "dbo.Enderecos");
            DropForeignKey("dbo.Veiculos", "Empresa_Id", "dbo.AspNetUsers");
            DropForeignKey("dbo.Servicos", "ApplicationUser_Id", "dbo.AspNetUsers");
            DropForeignKey("dbo.AspNetUserRoles", "UserId", "dbo.AspNetUsers");
            DropForeignKey("dbo.AspNetUserLogins", "UserId", "dbo.AspNetUsers");
            DropForeignKey("dbo.AspNetUsers", "EnderecoID", "dbo.Enderecos");
            DropForeignKey("dbo.Enderecos", "Estado_UF", "dbo.Estados");
            DropForeignKey("dbo.Enderecos", "CidadeID", "dbo.Cidades");
            DropForeignKey("dbo.Enderecos", "Bairro_BairroID", "dbo.Bairros");
            DropForeignKey("dbo.AspNetClients", "ApplicationUser_Id", "dbo.AspNetUsers");
            DropForeignKey("dbo.AspNetUserClaims", "UserId", "dbo.AspNetUsers");
            DropForeignKey("dbo.Bairros", "CidadeID", "dbo.Cidades");
            DropForeignKey("dbo.Cidades", "UF", "dbo.Estados");
            DropIndex("dbo.AspNetRoles", "RoleNameIndex");
            DropIndex("dbo.Veiculos", new[] { "Servico_ServicoID" });
            DropIndex("dbo.Veiculos", new[] { "ApplicationUser_Id" });
            DropIndex("dbo.Veiculos", new[] { "Empresa_Id" });
            DropIndex("dbo.Veiculos", new[] { "EnderecoID" });
            DropIndex("dbo.AspNetUserRoles", new[] { "RoleId" });
            DropIndex("dbo.AspNetUserRoles", new[] { "UserId" });
            DropIndex("dbo.AspNetUserLogins", new[] { "UserId" });
            DropIndex("dbo.Enderecos", new[] { "Estado_UF" });
            DropIndex("dbo.Enderecos", new[] { "Bairro_BairroID" });
            DropIndex("dbo.Enderecos", new[] { "CidadeID" });
            DropIndex("dbo.AspNetUserClaims", new[] { "UserId" });
            DropIndex("dbo.AspNetUsers", new[] { "Veiculo_VeiculoID" });
            DropIndex("dbo.AspNetUsers", new[] { "EnderecoID" });
            DropIndex("dbo.AspNetUsers", "UserNameIndex");
            DropIndex("dbo.AspNetUsers", new[] { "UserName" });
            DropIndex("dbo.Servicos", new[] { "Motorista_Id" });
            DropIndex("dbo.Servicos", new[] { "EnderecoInicio_EnderecoID" });
            DropIndex("dbo.Servicos", new[] { "EnderecoFim_EnderecoID" });
            DropIndex("dbo.Servicos", new[] { "Cliente_Id" });
            DropIndex("dbo.Servicos", new[] { "ApplicationUser_Id" });
            DropIndex("dbo.Coordenadas", new[] { "ServicoID" });
            DropIndex("dbo.AspNetClients", new[] { "ApplicationUser_Id" });
            DropIndex("dbo.Estados", new[] { "UF" });
            DropIndex("dbo.Cidades", new[] { "UF" });
            DropIndex("dbo.Bairros", new[] { "CidadeID" });
            DropTable("dbo.AspNetRoles");
            DropTable("dbo.Veiculos");
            DropTable("dbo.AspNetUserRoles");
            DropTable("dbo.AspNetUserLogins");
            DropTable("dbo.Enderecos");
            DropTable("dbo.AspNetUserClaims");
            DropTable("dbo.AspNetUsers");
            DropTable("dbo.Servicos");
            DropTable("dbo.Coordenadas");
            DropTable("dbo.AspNetClients");
            DropTable("dbo.AspNetClaims");
            DropTable("dbo.Estados");
            DropTable("dbo.Cidades");
            DropTable("dbo.Bairros");
        }
    }

您的异常要求查看EntityValidationErrors。 看一下该属性,您将看到实体有什么错误。

如何查看验证错误: https//stackoverflow.com/a/7798264/250849

http://mattrandle.me/viewing-entityvalidationerrors-in-visual-studio/

暂无
暂无

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM