entity framework - pricing - Código Primero e Identidad con Azure Table Storage
table storage how to use dotnet (4)
Estoy trabajando en una pequeña aplicación web y acabo de llegar al punto de desarrollo donde necesito comenzar a tomar decisiones de base de datos. Mi plan original era utilizar EF Code First con MSSQL en Azure porque simplemente simplifica el proceso de trabajar con una base de datos. Sin embargo, al investigar las capacidades de alojamiento de mi base de datos en Azure, descubrí el almacenamiento de tablas de Azure que me abrió el mundo de NoSQL.
Si bien Internet está lleno de charlas sobre las características de NoSQL, una de las razones más importantes que he logrado reunir es que NoSQL almacena objetos completos como uno en una base de datos sin dividir los datos en varias tablas, lo que es bueno para el rendimiento. Si bien esto suena atractivo, EF Code First ha eliminado este problema de manera efectiva al juntar objetos y separarlos en una base de datos SQL sin que el desarrollador tenga que preocuparse por las consultas.
Mi problema principal, sin embargo, es que no puedo encontrar ninguna documentación para usar cosas como EF Code First y ASP.NET Identity con las bases de datos NoSQL. Como mi aplicación actualmente utiliza Identity, me gustaría evitar tener que cambiar a otra cosa.
P: ¿Es posible usar Code First y / o Identity con Azure Tables?
Edición: Un poco sobre mi aplicación Como una simplificación extrema, mi aplicación permite a mis usuarios crear perfiles personalizados mezclando y combinando tipos de datos preconfigurados. Por ejemplo, un usuario puede agregar cualquier número de objetos de Cotización a su perfil y luego definir el valor de la cotización (es decir, "Sé tú mismo; todos los demás ya están ocupados"). O pueden usar un objeto de película para definir una colección de sus películas favoritas (es decir, "Título: Incepción, Año: 2010"). En promedio, un usuario puede tener fácilmente 50 o más de estas propiedades en su página; no hay limitación en el número de propiedades que pueden tener.
Utilizando este ejemplo, puedo ver fácilmente cómo lo implementaría utilizando Code First (Profile tiene una lista de objetos de Cotización y una lista de objetos de Película). Todavía no estoy seguro de cómo se asignaría esto a una base de datos NoSQL como Azure Tables. Entonces, con las necesidades de mi aplicación, no estoy seguro de si cambiar de Code First a NoSQL sea una decisión razonable con las características y la funcionalidad que perdería.
Con el núcleo del marco de la entidad más reciente, ahora puede conectarse a la tabla de almacenamiento de Azure utilizando EF: EntityFramework.AzureTableStorage 7.0.0-beta1
Ver mi post si desea configurar su Dbcontext.
Usándolo, puedes implementar tu clase UserManager
.
De manera realista, no puede usar el Código de EF primero con Azure Table Storage. Dicho esto, el trabajo con el almacenamiento de tablas generalmente se realiza utilizando un enfoque similar al código primero, es decir, crea sus clases y ellas crean las tablas sobre la marcha.
Tenga en cuenta que con el almacenamiento de tablas no hay relaciones ni nada de eso. El almacenamiento de tablas es incluso más simple que otras soluciones NoSQL, ya que no puede almacenar objetos complejos en una sola "fila" de tablas.
Probablemente podría crear un proveedor de identidad .net que use solo almacenamiento de tablas y / o blobs, pero no puedo encontrar ningún ejemplo por ahí. Estoy seguro de que solía haber un proyecto de codeplex pero ahora no puedo encontrarlo.
Lo que Gert Arnold quiere decir es usar tanto SQL Azure como Table Storage (EF solo con la parte sql azure). De esta manera, puede usar cada uno para lo que es mejor en el almacenamiento de la mesa al almacenar grandes cantidades de datos simplemente estructurados, y el azul de las partes de los datos que son más complejos (es decir, requiere relaciones)
Para cualquier referencia futura. Hay un proyecto github que usa Identity with Azure Table storage. El pez accidental de James Randall . No estoy seguro si los roles ya están implementados.
Por lo tanto, tendremos una muestra de orientación exactamente en este escenario, utilizando el almacenamiento de AzureTable como una implementación sin SQL de un UserStore. Básicamente, implementas un IUserStore utilizando las API de almacenamiento de Azure. Aquí hay una implementación básica que implementa los métodos de inicio de sesión / contraseña, pero no todo:
public class AzureRole : TableEntity, IRole {
public string Id { get; set; }
public string Name { get; set; }
}
public class AzureLogin : TableEntity {
public AzureLogin() {
PartitionKey = Constants.IdentityPartitionKey;
RowKey = Guid.NewGuid().ToString();
}
public AzureLogin(string ownerId, UserLoginInfo info) : this() {
UserId = ownerId;
LoginProvider = info.LoginProvider;
ProviderKey = info.ProviderKey;
}
public string UserId { get; set; }
public string ProviderKey { get; set; }
public string LoginProvider { get; set; }
}
public class AzureUser : TableEntity, IUser {
public AzureUser() {
PartitionKey = Constants.IdentityPartitionKey;
RowKey = Guid.NewGuid().ToString();
Id = RowKey;
Roles = new List<string>();
Claims = new List<Claim>();
Logins = new List<AzureLogin>();
}
public AzureUser(string userName) : this() {
UserName = userName;
}
public string Id { get; set; }
public string UserName { get; set; }
public string PasswordHash { get; set; }
public string SecurityStamp { get; set; }
public IList<string> Roles { get; set; }
public IList<AzureLogin> Logins { get; set; }
public IList<Claim> Claims { get; set; }
}
public static class Constants {
public const string IdentityPartitionKey = "ASP.NET Identity";
}
public class AzureStore : IUserStore<AzureUser>, IUserClaimStore<AzureUser>, IUserLoginStore<AzureUser>, IUserRoleStore<AzureUser>, IUserPasswordStore<AzureUser> {
public AzureStore() {
// Retrieve the storage account from the connection string.
CloudStorageAccount storageAccount = CloudStorageAccount.Parse(CloudConfigurationManager.GetSetting("StorageConnectionString"));
// CreateAsync the table client.
CloudTableClient tableClient = storageAccount.CreateCloudTableClient();
// CreateAsync the table if it doesn''t exist.
CloudTable table = tableClient.GetTableReference("Identity");
table.CreateIfNotExists();
Table = table;
BatchOperation = new TableBatchOperation();
}
public TableBatchOperation BatchOperation { get; set; }
public CloudTable Table { get; set; }
public void Dispose() {
}
public Task<IList<Claim>> GetClaimsAsync(AzureUser user) {
return Task.FromResult(user.Claims);
}
public Task AddClaimAsync(AzureUser user, System.Security.Claims.Claim claim) {
return Task.FromResult(0);
}
public Task RemoveClaimAsync(AzureUser user, System.Security.Claims.Claim claim) {
return Task.FromResult(0);
}
Task IUserStore<AzureUser>.CreateAsync(AzureUser user) {
TableOperation op = TableOperation.Insert(user);
var result = Table.Execute(op);
return Task.FromResult(0);
}
Task IUserStore<AzureUser>.UpdateAsync(AzureUser user) {
TableOperation op = TableOperation.Replace(user);
var result = Table.Execute(op);
return Task.FromResult(0);
}
public Task<AzureUser> FindByIdAsync(string userId) {
TableOperation op = TableOperation.Retrieve<AzureUser>(Constants.IdentityPartitionKey, userId);
var result = Table.Execute(op);
return Task.FromResult<AzureUser>(result.Result as AzureUser);
}
public Task<AzureUser> FindByNameAsync(string userName) {
TableQuery<AzureUser> query = new TableQuery<AzureUser>().Where(TableQuery.GenerateFilterCondition("UserName", QueryComparisons.Equal, userName));
return Task.FromResult(Table.ExecuteQuery(query).FirstOrDefault());
}
public Task AddLoginAsync(AzureUser user, UserLoginInfo login) {
TableOperation op = TableOperation.Insert(new AzureLogin(user.Id, login));
var result = Table.Execute(op);
return Task.FromResult(0);
}
public Task RemoveLoginAsync(AzureUser user, UserLoginInfo login) {
var al = Find(login);
if (al != null) {
TableOperation op = TableOperation.Delete(al);
var result = Table.Execute(op);
}
return Task.FromResult(0);
}
public Task<IList<UserLoginInfo>> GetLoginsAsync(AzureUser user) {
TableQuery<AzureLogin> query = new TableQuery<AzureLogin>()
.Where(TableQuery.GenerateFilterCondition("UserId", QueryComparisons.Equal, user.Id))
.Select(new string[] { "LoginProvider", "ProviderKey" });
var results = Table.ExecuteQuery(query);
IList<UserLoginInfo> logins = new List<UserLoginInfo>();
foreach (var al in results) {
logins.Add(new UserLoginInfo(al.LoginProvider, al.ProviderKey));
}
return Task.FromResult(logins);
}
private AzureLogin Find(UserLoginInfo login) {
TableQuery<AzureLogin> query = new TableQuery<AzureLogin>()
.Where(TableQuery.CombineFilters(
TableQuery.GenerateFilterCondition("LoginProvider", QueryComparisons.Equal, login.LoginProvider),
TableOperators.And,
TableQuery.GenerateFilterCondition("ProviderKey", QueryComparisons.Equal, login.ProviderKey)))
.Select(new string[] { "UserId" });
return Table.ExecuteQuery(query).FirstOrDefault();
}
public Task<AzureUser> FindAsync(UserLoginInfo login) {
var al = Find(login);
if (al != null) {
return FindByIdAsync(al.UserId);
}
return Task.FromResult<AzureUser>(null);
}
public Task AddToRoleAsync(AzureUser user, string role) {
return Task.FromResult(0);
}
public Task RemoveFromRoleAsync(AzureUser user, string role) {
return Task.FromResult(0);
}
public Task<IList<string>> GetRolesAsync(AzureUser user) {
return Task.FromResult(user.Roles);
}
public Task<bool> IsInRoleAsync(AzureUser user, string role) {
return Task.FromResult(false);
}
public Task DeleteAsync(AzureUser user) {
throw new NotImplementedException();
}
public Task<string> GetPasswordHashAsync(AzureUser user) {
return Task.FromResult(user.PasswordHash);
}
public Task<bool> HasPasswordAsync(AzureUser user) {
return Task.FromResult(user.PasswordHash != null);
}
public Task SetPasswordHashAsync(AzureUser user, string passwordHash) {
user.PasswordHash = passwordHash;
return Task.FromResult(0);
}
}