web-dev-qa-db-ja.com

コードファーストとAzureTableStorageを使用したID

私は小さなWebアプリに取り組んでおり、データベースの決定を開始する必要がある開発の段階に到達しました。私の当初の計画は、データベースを操作するプロセスを単純化するだけなので、Azure上のMSSQLでEFコードファーストを使用することでした。しかし、Azureでデータベースホスティング機能を調査したところ、NoSQLの世界を切り開いたAzure TableStorageを発見しました。

インターネットはNoSQLの機能についておしゃべりに満ちていますが、私が収集できた最大の理由の1つは、NoSQLがデータをさまざまなテーブルに分割せずに、オブジェクト全体を1つのデータベースに格納することです。これはパフォーマンスに優れています。これは魅力的に聞こえますが、EF Code Firstは、開発者がクエリについて心配することなく、オブジェクトを自動的にまとめてSQLデータベースに分離することにより、この問題を効果的に排除しました。

ただし、私の主な問題は、EF CodeFirstやASP.NETIdentity withNoSQLデータベースなどを使用するためのドキュメントが見つからないことです。私のアプリは現在Identityを使用しているので、他のものに切り替える必要はありません。

Q:コードファーストやAzureテーブルでのIDを使用することは可能ですか?


編集:私のアプリについて少し非常に単純化したものとして、私のアプリでは、ユーザーが事前構成されたタイプのデータを組み合わせて一致させることにより、カスタムプロファイルを作成できます。たとえば、ユーザーはプロファイルに任意の数のQuoteオブジェクトを追加してから、見積もりの​​値を定義できます(つまり、「自分らしく、他のすべての人はすでに取得されています」)。または、Movieオブジェクトを使用して、お気に入りの映画のコレクションを定義することもできます(つまり、「タイトル:開始、年:2010」)。平均して、ユーザーは自分のページに50以上のそのようなプロパティを簡単に持つことができます。持つことができるプロパティの数に制限はありません。

この例を使用すると、Code Firstを使用して実装する方法を簡単に確認できます(プロファイルにはQuoteオブジェクトのリストとMovieオブジェクトのリストがあります)。これがAzureTablesなどのNoSQLデータベースにどのようにマッピングされるかはまだわかりません。そのため、アプリのニーズに応じて、Code FirstからNoSQLに切り替えることで、失われる可能性のある機能を適切に決定できるかどうかはわかりません。

17
Dragonseer

したがって、UserStoreのno sql実装としてAzureTableストレージを使用して、まさにこのシナリオを対象としたサンプルを用意します。基本的に、Azure StorageAPIを使用して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", 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);
    }
}
18
Hao Kung

現実的には、Azure TableStorageでEFCodeFirstを使用することはできません。つまり、テーブルストレージの操作は、通常、最初にコードを作成するのと同様のアプローチを使用して行われます。つまり、クラスを作成し、その場でテーブルを作成します。

テーブルストレージには、関係などがないことに注意してください。テーブルストレージは、複雑なオブジェクトを単一のテーブル「行」に格納できないという点で、他のNoSQLソリューションよりもさらに単純です。

テーブルやblobストレージのみを使用する.netIDプロバイダーを作成することもできますが、例は見つかりません。以前はコードプレックスプロジェクトがあったと思いますが、現在は見つかりません。

Gert Arnoldが意味するのは、SQL Azureとテーブルストレージの両方を使用することです(EFはSQL Azure部分のみ)。このようにして、それぞれを最高の目的で使用できます-単純に構造化されたデータを大量に格納するテーブルストレージ、より複雑な(つまり関係が必要な)データの部分にはsql Azure

5
Matt Whetton

今後の参考のために。 Identity with AzureTableストレージを使用するgithubプロジェクトがあります。 ジェームズランドールの偶発的な魚 。役割がすでに実装されているかどうかはわかりません。

1
markwilde

最新のエンティティフレームワークコアを使用すると、EFを使用してAzureストレージテーブルに接続できるようになります: EntityFramework.AzureTableStorage 7.0.0-beta1

Dbcontextを構成する場合は、my post を参照してください。

これを使用して、UserManagerクラスを実装できます。

0
Thomas