我正在开发一个小型的网络应用程序,我刚刚点击开发中需要开始做数据库决策.我原来的计划是在Azure上使用MSsql的EF Code First,因为它只是简化了使用数据库的过程.然而,当我调查Azure上的数据库托管功能时,我发现了Azure Table Storage,它向我开放了Nosql的世界.
当互联网喋喋不休地关于Nosql的功能时,我设法收集的最大的原因之一是Nosql将整个对象作为一个数据库存储在一个数据库中,而不会将数据分解成不同的表格,这对于性能是有好处的.虽然这听起来很吸引人,但EF Code First通过自动将对象和将对象分离成sql数据库而无需开发人员就必须担心查询,从而有效地消除了此问题.
但是,我的主要问题是,我找不到任何文档,如EF Code First和ASP.NET Identity与Nosql数据库.由于我的应用程序目前使用身份,我想避免不必要切换到其他的东西.
问:是否可以在Azure表中使用Code First和/或Identity?
编辑:有关我的应用程序作为一个极端的简化,我的应用程序允许我的用户通过混合和匹配预先配置的数据类型来创建自定义配置文件.例如,用户可以将任意数量的引用对象添加到其个人资料中,然后定义报价的值(即“自己动手,其他所有人已经被使用”).或者他们可以使用Movie对象来定义他们喜欢的电影的集合(即“Title:Inception,Year:2010”).平均来说,用户可以在其页面上轻松拥有50个以上的这样的属性;对他们可以拥有的属性数量没有限制.
使用这个例子,我可以很容易地看到我将如何使用Code First实现它(Profile有一个Quote对象列表和一个Movie对象列表).我还不清楚如何映射到Nosql数据库,如Azure Tables.所以,根据我的应用需求,我不知道从代码优先转换到Nosql是否合理的决定,我会失去的功能和功能.
解决方法
因此,我们将有一个针对这种情况的示例,使用AzureTable存储作为UserStore的no sql实现.基本上,您使用Azure Storage API实现IUserStore.这是实现登录/密码方法但不是所有内容的基本实现:
- 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",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",login.LoginProvider),TableOperators.And,TableQuery.GenerateFilterCondition("ProviderKey",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);
- }
- }