Migração de dados de Associação e Perfis de usuário do provedor universal para a Identidade do ASP.NET (C#)
por Pranav Rastogi, Rick Anderson, Robert McMurray, Suhas Joshi
Este tutorial descreve as etapas necessárias para migrar dados de usuário e função e dados de perfil de usuário criados usando Provedores Universais de um aplicativo existente para o modelo de identidade do ASP.NET. A abordagem mencionada aqui para migrar dados de perfil do usuário também pode ser usada em um aplicativo com associação SQL.
Com o lançamento do Visual Studio 2013, a equipe de ASP.NET introduziu um novo sistema de identidade do ASP.NET e você pode ler mais sobre essa versão aqui. Seguindo o artigo para migrar aplicativos Web da Associação do SQL para o novo sistema de identidade, este artigo ilustra as etapas para migrar aplicativos existentes que seguem o modelo Provedores para gerenciamento de usuários e funções para o novo modelo de identidade. O foco deste tutorial será principalmente migrar os dados de perfil do usuário para conectá-los perfeitamente ao novo sistema. A migração de informações de usuário e função é semelhante para a associação do SQL. A abordagem seguida para migrar dados de perfil também pode ser usada em um aplicativo com associação SQL.
Por exemplo, começaremos com um aplicativo Web criado usando o Visual Studio 2012 que usa o modelo Provedores. Em seguida, adicionaremos código para gerenciamento de perfil, registraremos um usuário, adicionaremos dados de perfil para os usuários, migraremos o esquema de banco de dados e, em seguida, alteraremos o aplicativo para usar o sistema de identidade para gerenciamento de usuários e funções. Como um teste de migração, os usuários criados usando Provedores Universais devem ser capazes de fazer logon e novos usuários devem ser capazes de se registrar.
Observação
Você pode encontrar o exemplo completo em https://github.com/suhasj/UniversalProviders-Identity-Migrations.
Resumo da migração de dados de perfil
Antes de começar com as migrações, vamos examinar a experiência de armazenar dados de perfil no modelo Provedores. Os dados de perfil para usuários de aplicativos podem ser armazenados de várias maneiras, sendo o mais comum entre eles o uso dos provedores de perfil embutidos enviados junto com o Provedores Universais. As etapas incluem
- Adicione uma classe que tenha propriedades usadas para armazenar dados de perfil.
- Adicione uma classe que estende 'ProfileBase' e implementa métodos para obter os dados de perfil acima para o usuário.
- Habilite o uso de provedores de perfil padrão no arquivo web.config e defina a classe declarada na etapa 2 a ser usada no acesso a informações de perfil.
As informações de perfil são armazenadas como dados xml e binários serializados na tabela 'Perfis' no banco de dados.
Depois de migrar o aplicativo para usar o novo sistema de identidade do ASP.NET, as informações de perfil são desserializadas e armazenadas como propriedades na classe de usuário. Cada propriedade pode então ser mapeada em colunas na tabela de usuário. A vantagem aqui é que as propriedades podem ser trabalhadas diretamente usando a classe de usuário, além de não precisar serializar/desserializar informações de dados todas as vezes ao acessá-las.
Introdução
Crie um novo aplicativo ASP.NET 4.5 Web Forms no Visual Studio 2012. O exemplo atual usa o modelo de Web Forms, mas você também pode usar o Aplicativo MVC.
Criar uma nova pasta 'Models' para armazenar informações de perfil
Por exemplo, vamos armazenar a data de nascimento, cidade, altura e peso do usuário no perfil. A altura e o peso são armazenados como uma classe personalizada chamada 'PersonalStats'. Para armazenar e recuperar o perfil, precisamos de uma classe que estenda 'ProfileBase'. Vamos criar uma nova classe 'AppProfile' para obter e armazenar informações de perfil.
public class ProfileInfo { public ProfileInfo() { UserStats = new PersonalStats(); } public DateTime? DateOfBirth { get; set; } public PersonalStats UserStats { get; set; } public string City { get; set; } } public class PersonalStats { public int? Weight { get; set; } public int? Height { get; set; } } public class AppProfile : ProfileBase { public ProfileInfo ProfileInfo { get { return (ProfileInfo)GetPropertyValue("ProfileInfo"); } } public static AppProfile GetProfile() { return (AppProfile)HttpContext.Current.Profile; } public static AppProfile GetProfile(string userName) { return (AppProfile)Create(userName); } }
Habilite o perfil no arquivo web.config . Insira o nome de classe a ser usado para armazenar/recuperar informações do usuário criadas na etapa 3.
<profile defaultProvider="DefaultProfileProvider" enabled="true" inherits="UniversalProviders_ProfileMigrations.Models.AppProfile"> <providers> ..... </providers> </profile>
Adicione uma página de formulários da Web na pasta 'Conta' para obter os dados do perfil do usuário e armazená-los. Clique com o botão direito do mouse no projeto e selecione "Adicionar novo Item". Adicione uma nova página de webforms com master página 'AddProfileData.aspx'. Copie o seguinte na seção 'MainContent':
<h2> Add Profile Data for <%# User.Identity.Name %></h2> <asp:Label Text="" ID="Result" runat="server" /> <div> Date of Birth: <asp:TextBox runat="server" ID="DateOfBirth"/> </div> <div> Weight: <asp:TextBox runat="server" ID="Weight"/> </div> <div> Height: <asp:TextBox runat="server" ID="Height"/> </div> <div> City: <asp:TextBox runat="server" ID="City"/> </div> <div> <asp:Button Text="Add Profile" ID="Add" OnClick="Add_Click" runat="server" /> </div>
Adicione o seguinte código no code-behind:
protected void Add_Click(object sender, EventArgs e) { AppProfile profile = AppProfile.GetProfile(User.Identity.Name); profile.ProfileInfo.DateOfBirth = DateTime.Parse(DateOfBirth.Text); profile.ProfileInfo.UserStats.Weight = Int32.Parse(Weight.Text); profile.ProfileInfo.UserStats.Height = Int32.Parse(Height.Text); profile.ProfileInfo.City = City.Text; profile.Save(); }
Adicione o namespace no qual a classe AppProfile é definida para remover os erros de compilação.
Execute o aplicativo e crie um novo usuário com o nome de usuário 'olduser'. Navegue até a página 'AddProfileData' e adicione informações de perfil para o usuário.
Você pode verificar se os dados são armazenados como xml serializados na tabela 'Perfis' usando a janela servidor Explorer. No Visual Studio, no menu 'Exibir', escolha 'Servidor Explorer'. Deve haver uma conexão de dados para o banco de dados definido no arquivo web.config . Clicar na conexão de dados mostra subcategorias diferentes. Expanda 'Tabelas' para mostrar as diferentes tabelas em seu banco de dados, clique com o botão direito do mouse em 'Perfis' e escolha 'Mostrar Dados da Tabela' para exibir os dados de perfil armazenados na tabela Perfis.
Migrando esquema de banco de dados
Para que o banco de dados existente funcione com o sistema de identidade, precisamos atualizar o esquema no banco de dados de identidade para dar suporte aos campos que adicionamos ao banco de dados original. Isso pode ser feito usando scripts SQL para criar novas tabelas e copiar as informações existentes. Na janela 'Servidor Explorer', expanda a 'DefaultConnection' para exibir as tabelas. Clique com o botão direito do mouse em Tabelas e selecione 'Nova Consulta'
Cole o script SQL de https://raw.github.com/suhasj/UniversalProviders-Identity-Migrations/master/Migration.txt e execute-o. Se o 'DefaultConnection' for atualizado, poderemos ver que as novas tabelas são adicionadas. Você pode marcar os dados dentro das tabelas para ver se as informações foram migradas.
Migrando o aplicativo para usar o ASP.NET Identity
Instale os pacotes Nuget necessários para ASP.NET Identity:
- Microsoft.AspNet.Identity.EntityFramework
- Microsoft.AspNet.Identity.Owin
- Microsoft.Owin.Host.SystemWeb
- Microsoft.Owin.Security.Facebook
- Microsoft.Owin.Security.Google
- Microsoft.Owin.Security.MicrosoftAccount
- Microsoft.Owin.Security.Twitter
Mais informações sobre como gerenciar pacotes Nuget podem ser encontradas aqui
Para trabalhar com dados existentes na tabela, precisamos criar classes de modelo que são mapeadas de volta para as tabelas e conectá-las no sistema de identidade. Como parte do contrato de identidade, as classes de modelo devem implementar as interfaces definidas na dll Identity.Core ou podem estender a implementação existente dessas interfaces disponíveis em Microsoft.AspNet.Identity.EntityFramework. Usaremos as classes existentes para função, logons de usuário e declarações de usuário. Precisamos usar um usuário personalizado para nosso exemplo. Clique com o botão direito do mouse no projeto e crie uma nova pasta 'IdentityModels'. Adicione uma nova classe 'User', conforme mostrado abaixo:
using Microsoft.AspNet.Identity.EntityFramework; using System; using System.Collections.Generic; using System.Linq; using System.Web; using UniversalProviders_ProfileMigrations.Models; namespace UniversalProviders_Identity_Migrations { public class User : IdentityUser { public User() { CreateDate = DateTime.UtcNow; IsApproved = false; LastLoginDate = DateTime.UtcNow; LastActivityDate = DateTime.UtcNow; LastPasswordChangedDate = DateTime.UtcNow; Profile = new ProfileInfo(); } public System.Guid ApplicationId { get; set; } public bool IsAnonymous { get; set; } public System.DateTime? LastActivityDate { get; set; } public string Email { get; set; } public string PasswordQuestion { get; set; } public string PasswordAnswer { get; set; } public bool IsApproved { get; set; } public bool IsLockedOut { get; set; } public System.DateTime? CreateDate { get; set; } public System.DateTime? LastLoginDate { get; set; } public System.DateTime? LastPasswordChangedDate { get; set; } public System.DateTime? LastLockoutDate { get; set; } public int FailedPasswordAttemptCount { get; set; } public System.DateTime? FailedPasswordAttemptWindowStart { get; set; } public int FailedPasswordAnswerAttemptCount { get; set; } public System.DateTime? FailedPasswordAnswerAttemptWindowStart { get; set; } public string Comment { get; set; } public ProfileInfo Profile { get; set; } } }
Observe que o 'ProfileInfo' agora é uma propriedade na classe de usuário. Portanto, podemos usar a classe de usuário para trabalhar diretamente com dados de perfil.
Copie os arquivos nas pastas IdentityModels e IdentityAccount da origem do download ( https://github.com/suhasj/UniversalProviders-Identity-Migrations/tree/master/UniversalProviders-Identity-Migrations ). Elas têm as classes de modelo restantes e as novas páginas necessárias para o gerenciamento de usuários e funções usando as APIs de identidade do ASP.NET. A abordagem usada é semelhante à Associação do SQL e a explicação detalhada pode ser encontrada aqui.
Não há suporte para alguns comandos se o aplicativo usar o SQLite como seu armazenamento de dados de identidade. Devido a limitações no mecanismo de banco de dados,
Alter
os comandos geram a seguinte exceção:"System.NotSupportedException: o SQLite não dá suporte a essa operação de migração."
Como alternativa, execute migrações do Code First no banco de dados para alterar as tabelas.
Copiando dados de perfil para as novas tabelas
Conforme mencionado anteriormente, precisamos desserializar os dados xml nas tabelas Perfis e armazená-los nas colunas da tabela AspNetUsers. As novas colunas foram criadas na tabela de usuários na etapa anterior para que tudo o que resta seja preencher essas colunas com os dados necessários. Para fazer isso, usaremos um aplicativo de console que é executado uma vez para preencher as colunas recém-criadas na tabela de usuários.
Crie um novo aplicativo de console na solução de saída.
Instale a versão mais recente do pacote do Entity Framework.
Adicione o aplicativo Web criado acima como uma referência ao aplicativo de console. Para fazer isso, clique com o botão direito do mouse em Projeto, depois em 'Adicionar Referências', em solução, clique no projeto e clique em OK.
Copie o código abaixo na classe Program.cs. Essa lógica lê os dados de perfil de cada usuário, serializa-os como objeto 'ProfileInfo' e os armazena de volta no banco de dados.
public class Program { var dbContext = new ApplicationDbContext(); foreach (var profile in dbContext.Profiles) { var stringId = profile.UserId.ToString(); var user = dbContext.Users.Where(x => x.Id == stringId).FirstOrDefault(); Console.WriteLine("Adding Profile for user:" + user.UserName); var serializer = new XmlSerializer(typeof(ProfileInfo)); var stringReader = new StringReader(profile.PropertyValueStrings); var profileData = serializer.Deserialize(stringReader) as ProfileInfo; if (profileData == null) { Console.WriteLine("Profile data deserialization error for user:" + user.UserName); } else { user.Profile = profileData; } } dbContext.SaveChanges(); }
Alguns dos modelos usados são definidos na pasta 'IdentityModels' do projeto de aplicativo Web, portanto, você deve incluir os namespaces correspondentes.
O código acima funciona no arquivo de banco de dados na pasta App_Data do projeto de aplicativo Web criado nas etapas anteriores. Para fazer referência a isso, atualize a cadeia de conexão no arquivo app.config do aplicativo de console com a cadeia de conexão no web.config do aplicativo Web. Forneça também o caminho físico completo na propriedade 'AttachDbFilename'.
Abra um prompt de comando e navegue até a pasta bin do aplicativo de console acima. Execute o executável e examine a saída do log, conforme mostrado na imagem a seguir.
Abra a tabela 'AspNetUsers' no servidor Explorer e verifique os dados nas novas colunas que contêm as propriedades. Eles devem ser atualizados com os valores de propriedade correspondentes.
Verificar a funcionalidade
Use as páginas de associação recém-adicionadas que são implementadas usando ASP.NET Identity para fazer logon de um usuário do banco de dados antigo. O usuário deve ser capaz de fazer logon usando as mesmas credenciais. Experimente as outras funcionalidades, como adicionar o OAuth, criar um novo usuário, alterar uma senha, adicionar funções, adicionar usuários a funções etc.
Os dados de perfil para o usuário antigo e os novos usuários devem ser recuperados e armazenados na tabela de usuários. A tabela antiga não deve mais ser referenciada.
Conclusão
O artigo descreveu o processo de migração de aplicativos Web que usavam o modelo de provedor para associação ao ASP.NET Identity. O artigo também descreve a migração de dados de perfil para que os usuários sejam conectados ao sistema de identidade. Deixe os comentários abaixo para perguntas e problemas encontrados ao migrar seu aplicativo.
Obrigado a Rick Anderson e Robert McMurray por revisarem o artigo.