first commit
This commit is contained in:
@@ -0,0 +1,39 @@
|
||||
<Project Sdk="Microsoft.NET.Sdk">
|
||||
|
||||
<PropertyGroup>
|
||||
<TargetFramework>netcoreapp2.0</TargetFramework>
|
||||
</PropertyGroup>
|
||||
|
||||
<PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Release|AnyCPU'">
|
||||
<DocumentationFile>bin\Release\netcoreapp2.0\AspNetCore.Identity.MongoDbCore.xml</DocumentationFile>
|
||||
</PropertyGroup>
|
||||
|
||||
<PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Debug|AnyCPU'">
|
||||
<DocumentationFile>bin\Debug\netcoreapp2.0\AspNetCore.Identity.MongoDbCore.xml</DocumentationFile>
|
||||
</PropertyGroup>
|
||||
|
||||
<ItemGroup>
|
||||
<!--<PackageReference Include="Microsoft.AspNetCore.All" Version="2.0.0" />-->
|
||||
<PackageReference Include="Microsoft.AspNetCore.Identity" Version="2.0.0" />
|
||||
<PackageReference Include="Microsoft.Extensions.Identity.Stores" Version="2.0.0" />
|
||||
<PackageReference Include="MongoDB.Driver" Version="2.4.4" />
|
||||
<PackageReference Include="MongoDbGenericRepository" Version="1.3.0" />
|
||||
</ItemGroup>
|
||||
|
||||
<ItemGroup>
|
||||
<Compile Update="Resources.Designer.cs">
|
||||
<DependentUpon>Resources.resx</DependentUpon>
|
||||
<DesignTime>True</DesignTime>
|
||||
<AutoGen>True</AutoGen>
|
||||
</Compile>
|
||||
</ItemGroup>
|
||||
|
||||
<ItemGroup>
|
||||
<EmbeddedResource Update="Resources.resx">
|
||||
<LastGenOutput>Resources.Designer.cs</LastGenOutput>
|
||||
<Generator>ResXFileCodeGenerator</Generator>
|
||||
<CopyToOutputDirectory>Always</CopyToOutputDirectory>
|
||||
</EmbeddedResource>
|
||||
</ItemGroup>
|
||||
|
||||
</Project>
|
||||
@@ -0,0 +1,20 @@
|
||||
<?xml version="1.0"?>
|
||||
<package >
|
||||
<metadata>
|
||||
<id>AspNetCore.Identity.MongoDbCore</id>
|
||||
<version>1.0.3</version>
|
||||
<title>AspNetCore.Identity.MongoDbCore</title>
|
||||
<authors>Alexandre Spieser</authors>
|
||||
<owners>Alexandre Spieser</owners>
|
||||
<licenseUrl>http://www.opensource.org/licenses/mit-license.php</licenseUrl>
|
||||
<projectUrl>https://github.com/alexandre-spieser/AspNetCore.Identity.MongoDbCore</projectUrl>
|
||||
<requireLicenseAcceptance>false</requireLicenseAcceptance>
|
||||
<description>A MongoDb UserStore and RoleStore adapter for Microsoft.AspNetCore.Identity 2.0.</description>
|
||||
<releaseNotes>First release.</releaseNotes>
|
||||
<copyright>Copyright 2017 (c) Alexandre Spieser. All rights reserved.</copyright>
|
||||
<tags>aspnetcore mongo mongodb identity membership</tags>
|
||||
</metadata>
|
||||
<files>
|
||||
<file src="lib\**" target="lib" />
|
||||
</files>
|
||||
</package>
|
||||
@@ -0,0 +1,122 @@
|
||||
using AspNetCore.Identity.MongoDbCore.Interfaces;
|
||||
using AspNetCore.Identity.MongoDbCore.Models;
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Linq;
|
||||
using System.Security.Claims;
|
||||
|
||||
namespace AspNetCore.Identity.MongoDbCore.Extensions
|
||||
{
|
||||
/// <summary>
|
||||
/// The extensions for an object that holds claims.
|
||||
/// </summary>
|
||||
public static class ClaimHolderExtensions
|
||||
{
|
||||
public static MongoClaim ToMongoClaim(this Claim claim)
|
||||
{
|
||||
return new MongoClaim
|
||||
{
|
||||
Type = claim.Type,
|
||||
Value = claim.Value,
|
||||
Issuer = claim.Issuer
|
||||
};
|
||||
}
|
||||
|
||||
public static Claim ToClaim(this MongoClaim claim)
|
||||
{
|
||||
return new Claim(claim.Type, claim.Value, null, claim.Issuer);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Adds a claim to a claim holder, implementing <see cref="IClaimHolder"/>.
|
||||
/// </summary>
|
||||
/// <param name="claimHolder">The object holding claims.</param>
|
||||
/// <param name="claim">The claim you want to add.</param>
|
||||
/// <returns>Returns true if the claim was added.</returns>
|
||||
public static bool AddClaim(this IClaimHolder claimHolder, Claim claim)
|
||||
{
|
||||
if (claim == null)
|
||||
{
|
||||
throw new ArgumentNullException(nameof(claim));
|
||||
}
|
||||
|
||||
// prevent adding duplicate claims
|
||||
if (claimHolder.HasClaim(claim))
|
||||
{
|
||||
return false;
|
||||
}
|
||||
|
||||
claimHolder.Claims.Add(claim.ToMongoClaim());
|
||||
return true;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Replaces a claim on a claim holder, implementing <see cref="IClaimHolder"/>.
|
||||
/// </summary>
|
||||
/// <param name="claimHolder">The object holding claims.</param>
|
||||
/// <param name="claim">The claim you want to replace.</param>
|
||||
/// <param name="newClaim">The new claim you want to set.</param>
|
||||
/// <returns>Returns true if the claim was replaced.</returns>
|
||||
public static bool ReplaceClaim(this IClaimHolder claimHolder, Claim claim, Claim newClaim)
|
||||
{
|
||||
var replaced = false;
|
||||
claimHolder.Claims.Where(uc => uc.Value == claim.Value && uc.Type == claim.Type).ToList()
|
||||
.ForEach(oldClaim => {
|
||||
oldClaim.Type = newClaim.Type;
|
||||
oldClaim.Value = newClaim.Value;
|
||||
oldClaim.Issuer = newClaim.Issuer;
|
||||
replaced |= true;
|
||||
});
|
||||
return replaced;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Checks if an object implementing <see cref="IClaimHolder"/> has a claim.
|
||||
/// </summary>
|
||||
/// <param name="claimHolder">The object holding claims.</param>
|
||||
/// <param name="claim">The claim you want to replace.</param>
|
||||
/// <returns>Returns true if the claim is present, false otherwise.</returns>
|
||||
public static bool HasClaim(this IClaimHolder claimHolder, Claim claim)
|
||||
{
|
||||
if(claimHolder.Claims == null)
|
||||
{
|
||||
claimHolder.Claims = new List<MongoClaim>();
|
||||
}
|
||||
return claimHolder.Claims.Any(e => e.Value == claim.Value && e.Type == claim.Type);
|
||||
}
|
||||
|
||||
public static bool RemoveClaim(this IClaimHolder claimHolder, Claim claim)
|
||||
{
|
||||
if (claim == null)
|
||||
{
|
||||
throw new ArgumentNullException(nameof(claim));
|
||||
}
|
||||
var exists = claimHolder.Claims
|
||||
.FirstOrDefault(e => e.Value == claim.Value
|
||||
&& e.Type == claim.Type);
|
||||
if (exists != null)
|
||||
{
|
||||
claimHolder.Claims.Remove(exists);
|
||||
return true;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
public static bool RemoveClaims(this IClaimHolder claimHolder, IEnumerable<Claim> claims)
|
||||
{
|
||||
var someClaimsRemoved = false;
|
||||
foreach (var claim in claims)
|
||||
{
|
||||
var matchedClaims = claimHolder.Claims.Where(uc => uc.Value == claim.Value && uc.Type == claim.Type)
|
||||
.ToList();
|
||||
|
||||
foreach (var c in matchedClaims)
|
||||
{
|
||||
claimHolder.Claims.Remove(c);
|
||||
someClaimsRemoved |= true;
|
||||
}
|
||||
}
|
||||
return someClaimsRemoved;
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,94 @@
|
||||
using AspNetCore.Identity.MongoDbCore.Infrastructure;
|
||||
using AspNetCore.Identity.MongoDbCore.Models;
|
||||
using Microsoft.AspNetCore.Identity;
|
||||
using Microsoft.Extensions.DependencyInjection;
|
||||
using MongoDbGenericRepository;
|
||||
using System;
|
||||
|
||||
namespace AspNetCore.Identity.MongoDbCore.Extensions
|
||||
{
|
||||
public class MongoDbSettings
|
||||
{
|
||||
public string ConnectionString { get; set; }
|
||||
public string DatabaseName { get; set; }
|
||||
}
|
||||
|
||||
public class MongoDbIdentityConfiguration
|
||||
{
|
||||
public MongoDbSettings MongoDbSettings { get; set; }
|
||||
public Action<IdentityOptions> IdentityOptionsAction { get; set; }
|
||||
}
|
||||
|
||||
public static class ServiceCollectionExtension
|
||||
{
|
||||
public static void ConfigureMongoDbIdentity<TUser, TKey>(
|
||||
this IServiceCollection services,
|
||||
MongoDbIdentityConfiguration mongoDbIdentityConfiguration,
|
||||
IMongoRepository mongoRepository = null)
|
||||
where TUser : MongoIdentityUser<TKey>, new()
|
||||
where TKey : IEquatable<TKey>
|
||||
{
|
||||
services.AddSingleton<MongoDbSettings>(mongoDbIdentityConfiguration.MongoDbSettings);
|
||||
services.AddSingleton<IMongoRepository>(provider =>
|
||||
{
|
||||
var options = provider.GetService<MongoDbSettings>();
|
||||
return mongoRepository ?? new MongoRepository(options.ConnectionString, options.DatabaseName);
|
||||
});
|
||||
|
||||
CommonMongoDbSetup<TUser, MongoIdentityRole<TKey>, TKey>(services, mongoDbIdentityConfiguration);
|
||||
}
|
||||
|
||||
public static void ConfigureMongoDbIdentity<TUser>(this IServiceCollection services, MongoDbIdentityConfiguration mongoDbIdentityConfiguration)
|
||||
where TUser : MongoIdentityUser, new()
|
||||
{
|
||||
services.AddSingleton<MongoDbSettings>(mongoDbIdentityConfiguration.MongoDbSettings);
|
||||
services.AddSingleton<IMongoRepository>(provider =>
|
||||
{
|
||||
var options = provider.GetService<MongoDbSettings>();
|
||||
return new MongoRepository(options.ConnectionString, options.DatabaseName);
|
||||
});
|
||||
|
||||
CommonMongoDbSetup<TUser, MongoIdentityRole, Guid>(services, mongoDbIdentityConfiguration);
|
||||
}
|
||||
|
||||
|
||||
public static void ConfigureMongoDbIdentity<TUser, TRole, TKey>(this IServiceCollection services, MongoDbIdentityConfiguration mongoDbIdentityConfiguration,
|
||||
IMongoDbContext mongoDbContext = null)
|
||||
where TUser : MongoIdentityUser<TKey>, new()
|
||||
where TRole : MongoIdentityRole<TKey>, new()
|
||||
where TKey : IEquatable<TKey>
|
||||
{
|
||||
services.AddSingleton<MongoDbSettings>(mongoDbIdentityConfiguration.MongoDbSettings);
|
||||
services.AddSingleton<IMongoRepository>(provider =>
|
||||
{
|
||||
var options = provider.GetService<MongoDbSettings>();
|
||||
return mongoDbContext == null ? new MongoRepository(options.ConnectionString, options.DatabaseName) : new MongoRepository(mongoDbContext);
|
||||
});
|
||||
|
||||
CommonMongoDbSetup<TUser, TRole, TKey>(services, mongoDbIdentityConfiguration);
|
||||
}
|
||||
|
||||
private static void CommonMongoDbSetup<TUser, TRole, TKey>(this IServiceCollection services, MongoDbIdentityConfiguration mongoDbIdentityConfiguration)
|
||||
where TUser : MongoIdentityUser<TKey>, new()
|
||||
where TRole : MongoIdentityRole<TKey>, new()
|
||||
where TKey : IEquatable<TKey>
|
||||
{
|
||||
services.AddScoped<IUserStore<TUser>>(provider =>
|
||||
{
|
||||
var userStore = new MongoUserStore<TUser, TRole, IMongoDbContext, TKey>(provider.GetService<IMongoRepository>().Context);
|
||||
return userStore;
|
||||
});
|
||||
|
||||
services.AddScoped<IRoleStore<TRole>>(provider =>
|
||||
{
|
||||
return new MongoRoleStore<TRole, IMongoDbContext, TKey>(provider.GetService<IMongoRepository>().Context);
|
||||
});
|
||||
|
||||
services.AddIdentity<TUser, TRole>()
|
||||
.AddDefaultTokenProviders();
|
||||
|
||||
services.Configure<IdentityOptions>(mongoDbIdentityConfiguration.IdentityOptionsAction);
|
||||
}
|
||||
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,9 @@
|
||||
using System;
|
||||
|
||||
namespace AspNetCore.Identity.MongoDbCore
|
||||
{
|
||||
public static class GlobalVariables
|
||||
{
|
||||
public static Random Random = new Random();
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,35 @@
|
||||
using MongoDbGenericRepository;
|
||||
|
||||
namespace AspNetCore.Identity.MongoDbCore.Infrastructure
|
||||
{
|
||||
public interface IMongoRepository : IBaseMongoRepository
|
||||
{
|
||||
void DropCollection<TDocument>();
|
||||
void DropCollection<TDocument>(string partitionKey);
|
||||
IMongoDbContext Context { get; }
|
||||
}
|
||||
|
||||
|
||||
public class MongoRepository : BaseMongoRepository, IMongoRepository
|
||||
{
|
||||
public MongoRepository(string connectionString, string databaseName) : base(connectionString, databaseName)
|
||||
{
|
||||
}
|
||||
|
||||
public MongoRepository(IMongoDbContext mongoDbContext) : base(mongoDbContext)
|
||||
{
|
||||
}
|
||||
|
||||
public void DropCollection<TDocument>()
|
||||
{
|
||||
MongoDbContext.DropCollection<TDocument>();
|
||||
}
|
||||
|
||||
public void DropCollection<TDocument>(string partitionKey)
|
||||
{
|
||||
MongoDbContext.DropCollection<TDocument>(partitionKey);
|
||||
}
|
||||
|
||||
public IMongoDbContext Context => MongoDbContext;
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,13 @@
|
||||
using AspNetCore.Identity.MongoDbCore.Models;
|
||||
using System.Collections.Generic;
|
||||
|
||||
namespace AspNetCore.Identity.MongoDbCore.Interfaces
|
||||
{
|
||||
/// <summary>
|
||||
/// The interface for an object that holds claims.
|
||||
/// </summary>
|
||||
public interface IClaimHolder
|
||||
{
|
||||
List<MongoClaim> Claims { get; set; }
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,84 @@
|
||||
using AspNetCore.Identity.MongoDbCore.Interfaces;
|
||||
using Microsoft.AspNetCore.Identity;
|
||||
using MongoDbGenericRepository.Models;
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Security.Claims;
|
||||
|
||||
namespace AspNetCore.Identity.MongoDbCore.Models
|
||||
{
|
||||
public class MongoDbIdentityRole : MongoIdentityRole<string>
|
||||
{
|
||||
public MongoDbIdentityRole() : base()
|
||||
{
|
||||
}
|
||||
|
||||
public MongoDbIdentityRole(string roleName) : base(roleName)
|
||||
{
|
||||
}
|
||||
}
|
||||
|
||||
public class MongoIdentityRole : MongoIdentityRole<Guid>
|
||||
{
|
||||
public MongoIdentityRole() : base()
|
||||
{
|
||||
}
|
||||
|
||||
public MongoIdentityRole(string roleName) : base(roleName)
|
||||
{
|
||||
}
|
||||
}
|
||||
|
||||
public class MongoIdentityRole<TKey> : IdentityRole<TKey>, IDocument<TKey>, IClaimHolder
|
||||
where TKey : IEquatable<TKey>
|
||||
{
|
||||
|
||||
private void InitializeFields()
|
||||
{
|
||||
Version = 1;
|
||||
Claims = new List<MongoClaim>();
|
||||
Guid guidValue = Guid.NewGuid();
|
||||
var idTypeName = typeof(TKey).Name;
|
||||
switch (idTypeName)
|
||||
{
|
||||
case "Guid":
|
||||
Id = (TKey)(object)guidValue;
|
||||
break;
|
||||
case "Int32":
|
||||
Id = (TKey)(object)GlobalVariables.Random.Next(1, int.MaxValue);
|
||||
break;
|
||||
case "String":
|
||||
Id = (TKey)(object)guidValue.ToString();
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
public MongoIdentityRole()
|
||||
{
|
||||
InitializeFields();
|
||||
}
|
||||
|
||||
public MongoIdentityRole(string roleName)
|
||||
{
|
||||
Name = roleName;
|
||||
InitializeFields();
|
||||
}
|
||||
|
||||
public MongoIdentityRole(string name, TKey key)
|
||||
{
|
||||
InitializeFields();
|
||||
Id = key;
|
||||
Name = Name;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// The version of the role schema
|
||||
/// </summary>
|
||||
public int Version { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// The claims associated to the role
|
||||
/// </summary>
|
||||
public List<MongoClaim> Claims { get; set; }
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,398 @@
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using MongoDbGenericRepository.Models;
|
||||
using System.Linq;
|
||||
using MongoDB.Driver;
|
||||
using AspNetCore.Identity.MongoDbCore.Interfaces;
|
||||
using Microsoft.AspNetCore.Identity;
|
||||
|
||||
namespace AspNetCore.Identity.MongoDbCore.Models
|
||||
{
|
||||
public class Token
|
||||
{
|
||||
/// <summary>
|
||||
/// Gets or sets the LoginProvider this token is from.
|
||||
/// </summary>
|
||||
public string LoginProvider { get; set; }
|
||||
/// <summary>
|
||||
/// Gets or sets the name of the token.
|
||||
public string Name { get; set; }
|
||||
/// <summary>
|
||||
/// Gets or sets the token value.
|
||||
/// </summary>
|
||||
public string Value { get; set; }
|
||||
}
|
||||
|
||||
public class MongoClaim {
|
||||
public string Type { get; set; }
|
||||
public string Value { get; set; }
|
||||
public string Issuer { get; set; }
|
||||
}
|
||||
|
||||
public class UserRole
|
||||
{
|
||||
public object UserId { get; set; }
|
||||
public object RoleId { get; set; }
|
||||
}
|
||||
|
||||
public class MongoDbIdentityUser : MongoIdentityUser<string>
|
||||
{
|
||||
public MongoDbIdentityUser() : base()
|
||||
{
|
||||
}
|
||||
|
||||
public MongoDbIdentityUser(string userName) : base(userName)
|
||||
{
|
||||
}
|
||||
|
||||
public MongoDbIdentityUser(string userName, string email) : base(userName, email)
|
||||
{
|
||||
}
|
||||
}
|
||||
|
||||
public class MongoIdentityUser : MongoIdentityUser<Guid>
|
||||
{
|
||||
public MongoIdentityUser() : base()
|
||||
{
|
||||
}
|
||||
|
||||
public MongoIdentityUser(string userName) : base(userName)
|
||||
{
|
||||
}
|
||||
|
||||
public MongoIdentityUser(string userName, string email) : base(userName, email)
|
||||
{
|
||||
}
|
||||
}
|
||||
|
||||
public class MongoIdentityUser<TKey> : IdentityUser<TKey>, IDocument<TKey>, IClaimHolder
|
||||
where TKey : IEquatable<TKey>
|
||||
{
|
||||
|
||||
public int Version { get; set; }
|
||||
|
||||
public DateTime CreatedOn { get; private set; }
|
||||
public DateTime? LockoutEndDate { get; private set; }
|
||||
public DateTime? DeletedOn { get; private set; }
|
||||
public List<MongoClaim> Claims { get; set; }
|
||||
public List<TKey> Roles { get; set; }
|
||||
public List<UserLoginInfo> Logins { get; set; }
|
||||
public List<Token> Tokens { get; set; }
|
||||
|
||||
private void InitializeFields()
|
||||
{
|
||||
Claims = new List<MongoClaim>();
|
||||
Logins = new List<UserLoginInfo>();
|
||||
Roles = new List<TKey>();
|
||||
Tokens = new List<Token>();
|
||||
Guid guidValue = Guid.NewGuid();
|
||||
|
||||
var idTypeName = typeof(TKey).Name;
|
||||
switch (idTypeName)
|
||||
{
|
||||
case "Guid":
|
||||
Id = (TKey)(object)guidValue;
|
||||
break;
|
||||
case "Int32":
|
||||
Id = (TKey)(object)GlobalVariables.Random.Next(1, int.MaxValue);
|
||||
break;
|
||||
case "String":
|
||||
Id = (TKey)(object)guidValue.ToString();
|
||||
break;
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
public MongoIdentityUser()
|
||||
{
|
||||
CreatedOn = DateTime.UtcNow;
|
||||
SetVersion(1);
|
||||
InitializeFields();
|
||||
}
|
||||
|
||||
public MongoIdentityUser(string userName, string email) : this(userName)
|
||||
{
|
||||
if (email != null)
|
||||
{
|
||||
Email = email.ToLowerInvariant().Trim();
|
||||
}
|
||||
}
|
||||
|
||||
public MongoIdentityUser(string userName)
|
||||
{
|
||||
UserName = userName ?? throw new ArgumentNullException(nameof(userName));
|
||||
CreatedOn = DateTime.UtcNow;
|
||||
|
||||
SetVersion(1);
|
||||
InitializeFields();
|
||||
Roles = new List<TKey>();
|
||||
}
|
||||
|
||||
public virtual MongoIdentityUser<TKey> SetId(TKey key)
|
||||
{
|
||||
Id = key;
|
||||
return this;
|
||||
}
|
||||
|
||||
public virtual MongoIdentityUser<TKey> SetVersion(int version)
|
||||
{
|
||||
Version = 1;
|
||||
return this;
|
||||
}
|
||||
|
||||
public virtual void EnableTwoFactorAuthentication()
|
||||
{
|
||||
TwoFactorEnabled = true;
|
||||
}
|
||||
|
||||
public virtual void DisableTwoFactorAuthentication()
|
||||
{
|
||||
TwoFactorEnabled = false;
|
||||
}
|
||||
|
||||
public virtual void EnableLockout()
|
||||
{
|
||||
LockoutEnabled = true;
|
||||
}
|
||||
|
||||
public virtual void DisableLockout()
|
||||
{
|
||||
LockoutEnabled = false;
|
||||
}
|
||||
|
||||
public virtual void SetEmail(string email)
|
||||
{
|
||||
Email = email ?? throw new ArgumentNullException(nameof(email));
|
||||
}
|
||||
|
||||
public virtual void SetNormalizedUserName(string normalizedUserName)
|
||||
{
|
||||
NormalizedUserName = normalizedUserName ?? throw new ArgumentNullException(nameof(normalizedUserName));
|
||||
}
|
||||
|
||||
public virtual void SetPhoneNumber(string phoneNumber)
|
||||
{
|
||||
PhoneNumber = phoneNumber;
|
||||
}
|
||||
|
||||
public virtual void SetPasswordHash(string passwordHash)
|
||||
{
|
||||
PasswordHash = passwordHash;
|
||||
}
|
||||
|
||||
public virtual void SetSecurityStamp(string securityStamp)
|
||||
{
|
||||
SecurityStamp = securityStamp;
|
||||
}
|
||||
|
||||
public virtual void SetAccessFailedCount(int accessFailedCount)
|
||||
{
|
||||
AccessFailedCount = accessFailedCount;
|
||||
}
|
||||
|
||||
public virtual void ResetAccessFailedCount()
|
||||
{
|
||||
AccessFailedCount = 0;
|
||||
}
|
||||
|
||||
public virtual void LockUntil(DateTime lockoutEndDate)
|
||||
{
|
||||
LockoutEndDate = lockoutEndDate;
|
||||
}
|
||||
|
||||
public void Delete()
|
||||
{
|
||||
if (DeletedOn != null)
|
||||
{
|
||||
throw new InvalidOperationException($"User '{Id}' has already been deleted.");
|
||||
}
|
||||
|
||||
DeletedOn = DateTime.UtcNow;
|
||||
}
|
||||
|
||||
#region Role Management
|
||||
|
||||
public virtual IdentityUserRole<TKey> GetUserRole(TKey roleId)
|
||||
{
|
||||
var foundRoleId = Roles.FirstOrDefault(e => e.Equals(roleId));
|
||||
if (!foundRoleId.Equals(default(TKey)))
|
||||
{
|
||||
return new IdentityUserRole<TKey>
|
||||
{
|
||||
UserId = Id,
|
||||
RoleId = foundRoleId
|
||||
};
|
||||
}
|
||||
return default(IdentityUserRole<TKey>);
|
||||
}
|
||||
|
||||
public virtual bool RemoveRole(TKey roleId)
|
||||
{
|
||||
var roleClaim = Roles.FirstOrDefault(e => e.Equals(roleId));
|
||||
if (!roleClaim.Equals(default(TKey)))
|
||||
{
|
||||
Roles.Remove(roleId);
|
||||
return true;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
public virtual bool AddRole(TKey roleId)
|
||||
{
|
||||
if (!Roles.Contains(roleId))
|
||||
{
|
||||
Roles.Add(roleId);
|
||||
return true;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
#endregion
|
||||
|
||||
#region Login Management
|
||||
|
||||
public virtual bool AddLogin(UserLoginInfo mongoUserLogin)
|
||||
{
|
||||
if (mongoUserLogin == null)
|
||||
{
|
||||
throw new ArgumentNullException(nameof(mongoUserLogin));
|
||||
}
|
||||
if (HasLogin(mongoUserLogin))
|
||||
{
|
||||
return false;
|
||||
}
|
||||
Logins.Add(mongoUserLogin);
|
||||
return true;
|
||||
}
|
||||
|
||||
public virtual bool HasLogin(UserLoginInfo login)
|
||||
{
|
||||
return Logins.Any(e => e.LoginProvider == login.LoginProvider && e.ProviderKey == e.ProviderKey);
|
||||
}
|
||||
|
||||
public virtual void RemoveLogin(UserLoginInfo mongoUserLogin)
|
||||
{
|
||||
if (mongoUserLogin == null)
|
||||
{
|
||||
throw new ArgumentNullException(nameof(mongoUserLogin));
|
||||
}
|
||||
|
||||
Logins.Remove(mongoUserLogin);
|
||||
}
|
||||
|
||||
public virtual IdentityUserLogin<TKey> GetUserLogin(string loginProvider, string providerKey)
|
||||
{
|
||||
|
||||
var login = Logins.FirstOrDefault(e => e.LoginProvider == loginProvider && e.ProviderKey == providerKey);
|
||||
if (login != null)
|
||||
{
|
||||
return new IdentityUserLogin<TKey>
|
||||
{
|
||||
UserId = Id,
|
||||
LoginProvider = login.LoginProvider,
|
||||
ProviderDisplayName = login.ProviderDisplayName,
|
||||
ProviderKey = login.ProviderKey
|
||||
};
|
||||
}
|
||||
return default(IdentityUserLogin<TKey>);
|
||||
}
|
||||
|
||||
#endregion
|
||||
|
||||
#region Token Management
|
||||
|
||||
|
||||
/// <summary>
|
||||
/// Replaces a claim on a claim holder, implementing <see cref="IClaimHolder"/>.
|
||||
/// </summary>
|
||||
/// <param name="claimHolder">The object holding claims.</param>
|
||||
/// <param name="claim">The claim you want to replace.</param>
|
||||
/// <param name="newClaim">The new claim you want to set.</param>
|
||||
/// <returns>Returns true if the claim was replaced.</returns>
|
||||
public bool SetToken(IdentityUserToken<TKey> tokenToset, string value)
|
||||
{
|
||||
var token = Tokens.FirstOrDefault(e => e.LoginProvider == tokenToset.LoginProvider && e.Name == tokenToset.Name);
|
||||
if (token != null)
|
||||
{
|
||||
token.Value = value;
|
||||
return true;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
public IdentityUserToken<TKey> GetToken(string loginProvider, string name)
|
||||
{
|
||||
var token = Tokens.FirstOrDefault(e => e.LoginProvider == loginProvider && e.Name == name);
|
||||
if (token != null)
|
||||
{
|
||||
return new IdentityUserToken<TKey>
|
||||
{
|
||||
UserId = Id,
|
||||
LoginProvider = token.LoginProvider,
|
||||
Name = token.Name,
|
||||
Value = token.Value
|
||||
};
|
||||
}
|
||||
return default(IdentityUserToken<TKey>);
|
||||
}
|
||||
|
||||
public bool HasToken(IdentityUserToken<TKey> token)
|
||||
{
|
||||
return Tokens.Any(e => e.LoginProvider == token.LoginProvider
|
||||
&& e.Name == token.Name
|
||||
&& e.Value == token.Value);
|
||||
}
|
||||
|
||||
public bool AddOrSet(IdentityUserToken<TKey> token)
|
||||
{
|
||||
var exists = GetToken(token.LoginProvider, token.Name);
|
||||
if (exists != null && exists.Value != token.Value)
|
||||
{
|
||||
return SetToken(exists, token.Value);
|
||||
}
|
||||
if (exists == null)
|
||||
{
|
||||
Tokens.Add(new Token
|
||||
{
|
||||
LoginProvider = token.LoginProvider,
|
||||
Name = token.Name,
|
||||
Value = token.Value
|
||||
});
|
||||
return true;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
public bool AddUserToken<TUserToken>(TUserToken token) where TUserToken : IdentityUserToken<TKey>
|
||||
{
|
||||
if (HasToken(token))
|
||||
{
|
||||
return false;
|
||||
}
|
||||
|
||||
Tokens.Add(new Token
|
||||
{
|
||||
LoginProvider = token.LoginProvider,
|
||||
Name = token.Name,
|
||||
Value = token.Value
|
||||
});
|
||||
return true;
|
||||
}
|
||||
|
||||
public bool RemoveUserToken<TUserToken>(TUserToken token) where TUserToken : IdentityUserToken<TKey>
|
||||
{
|
||||
var exists = Tokens.FirstOrDefault(e => e.LoginProvider == token.LoginProvider && e.Name == token.Name);
|
||||
if (exists == null)
|
||||
{
|
||||
return false;
|
||||
}
|
||||
Tokens.Remove(exists);
|
||||
return true;
|
||||
}
|
||||
|
||||
#endregion Token Management
|
||||
|
||||
|
||||
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,49 @@
|
||||
using AspNetCore.Identity.MongoDbCore.Models;
|
||||
using MongoDB.Bson.Serialization.Conventions;
|
||||
using System;
|
||||
using System.Threading;
|
||||
|
||||
namespace AspNetCore.Identity.MongoDbCore
|
||||
{
|
||||
internal static class MongoConfig
|
||||
{
|
||||
private static bool _initialized = false;
|
||||
private static object _initializationLock = new object();
|
||||
private static object _initializationTarget;
|
||||
|
||||
public static void EnsureConfigured()
|
||||
{
|
||||
EnsureConfiguredImpl();
|
||||
}
|
||||
|
||||
private static void EnsureConfiguredImpl()
|
||||
{
|
||||
LazyInitializer.EnsureInitialized(ref _initializationTarget, ref _initialized, ref _initializationLock, () =>
|
||||
{
|
||||
Configure();
|
||||
return null;
|
||||
});
|
||||
}
|
||||
|
||||
private static void Configure()
|
||||
{
|
||||
RegisterConventions();
|
||||
}
|
||||
|
||||
private static void RegisterConventions()
|
||||
{
|
||||
var pack = new ConventionPack
|
||||
{
|
||||
new IgnoreIfNullConvention(false),
|
||||
new CamelCaseElementNameConvention(),
|
||||
};
|
||||
|
||||
ConventionRegistry.Register("AspNetCore.Identity.MongoDB", pack, IsConventionApplicable);
|
||||
}
|
||||
|
||||
private static bool IsConventionApplicable(Type type)
|
||||
{
|
||||
return type == typeof(MongoIdentityUser<>);
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,89 @@
|
||||
using AspNetCore.Identity.MongoDbCore.Infrastructure;
|
||||
using AspNetCore.Identity.MongoDbCore.Models;
|
||||
using MongoDB.Driver;
|
||||
using MongoDbGenericRepository;
|
||||
using System;
|
||||
|
||||
namespace AspNetCore.Identity.MongoDbCore
|
||||
{
|
||||
|
||||
public class MongoIdentityDbContext : MongoDbContext
|
||||
{
|
||||
|
||||
public MongoIdentityDbContext(string connectionString, string databaseName) : base(connectionString, databaseName)
|
||||
{
|
||||
}
|
||||
|
||||
public IMongoRepository MongoRepository { get; }
|
||||
|
||||
public IMongoCollection<MongoIdentityUser> Users
|
||||
{
|
||||
get
|
||||
{
|
||||
return GetCollection<MongoIdentityUser>();
|
||||
}
|
||||
}
|
||||
|
||||
public IMongoCollection<MongoIdentityRole> Roles
|
||||
{
|
||||
get
|
||||
{
|
||||
return GetCollection<MongoIdentityRole>();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
public class MongoIdentityDbContext<TUser> : MongoDbContext
|
||||
where TUser : MongoIdentityUser
|
||||
{
|
||||
|
||||
public MongoIdentityDbContext(string connectionString, string databaseName) : base(connectionString, databaseName)
|
||||
{
|
||||
}
|
||||
|
||||
public IMongoRepository MongoRepository { get; }
|
||||
|
||||
public IMongoCollection<TUser> Users
|
||||
{
|
||||
get
|
||||
{
|
||||
return GetCollection<TUser>();
|
||||
}
|
||||
}
|
||||
|
||||
public IMongoCollection<MongoIdentityRole> Roles
|
||||
{
|
||||
get
|
||||
{
|
||||
return GetCollection<MongoIdentityRole>();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
public class MongoIdentityDbContext<TUser, TRole, TKey> : MongoDbContext
|
||||
where TUser : MongoIdentityUser<TKey>
|
||||
where TRole : MongoIdentityRole<TKey>
|
||||
where TKey : IEquatable<TKey>
|
||||
{
|
||||
|
||||
public MongoIdentityDbContext(string connectionString, string databaseName) : base(connectionString, databaseName)
|
||||
{
|
||||
}
|
||||
|
||||
public IMongoCollection<TUser> Users
|
||||
{
|
||||
get
|
||||
{
|
||||
return GetCollection<TUser>();
|
||||
}
|
||||
}
|
||||
|
||||
public IMongoCollection<TRole> Roles
|
||||
{
|
||||
get
|
||||
{
|
||||
return GetCollection<TRole>();
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,59 @@
|
||||
using System;
|
||||
using Microsoft.AspNetCore.Http;
|
||||
using Microsoft.Extensions.DependencyInjection;
|
||||
using Microsoft.Extensions.DependencyInjection.Extensions;
|
||||
using Microsoft.Extensions.Options;
|
||||
using Microsoft.AspNetCore.Identity;
|
||||
|
||||
namespace AspNetCore.Identity.MongoDbCore
|
||||
{
|
||||
/// <summary>
|
||||
/// Represents the password hashing options
|
||||
/// </summary>
|
||||
public sealed class PasswordHasherOptionsAccessor : IOptions<PasswordHasherOptions>
|
||||
{
|
||||
/// <summary>
|
||||
/// Gets options which use the IdentityV3 compat mode, and set the iteration count to 200000 PBKDF2-SHA256 iterations
|
||||
/// (roughly 200ms of work)
|
||||
/// </summary>
|
||||
public PasswordHasherOptions Value { get; } = new PasswordHasherOptions
|
||||
{
|
||||
CompatibilityMode = PasswordHasherCompatibilityMode.IdentityV3,
|
||||
IterationCount = 200000
|
||||
};
|
||||
}
|
||||
|
||||
public static class MongoIdentityServiceCollectionExtensions
|
||||
{
|
||||
public static IdentityBuilder AddIdentity<TUser>(this IServiceCollection services)
|
||||
where TUser : class => services.AddIdentity<TUser>(null);
|
||||
|
||||
public static IdentityBuilder AddIdentity<TUser>(this IServiceCollection services, Action<IdentityOptions> setupAction)
|
||||
where TUser : class
|
||||
{
|
||||
// Hosting doesn't add IHttpContextAccessor by default
|
||||
services.TryAddSingleton<IHttpContextAccessor, HttpContextAccessor>();
|
||||
|
||||
// Identity services
|
||||
services.TryAddScoped<IUserValidator<TUser>, UserValidator<TUser>>();
|
||||
services.TryAddScoped<IPasswordValidator<TUser>, PasswordValidator<TUser>>();
|
||||
|
||||
services.TryAddScoped<IPasswordHasher<TUser>, PasswordHasher<TUser>>();
|
||||
services.TryAddScoped<ILookupNormalizer, UpperInvariantLookupNormalizer>();
|
||||
|
||||
// No interface for the error describer so we can add errors without rev'ing the interface
|
||||
services.TryAddScoped<IdentityErrorDescriber>();
|
||||
services.TryAddScoped<ISecurityStampValidator, SecurityStampValidator<TUser>>();
|
||||
services.TryAddScoped<IUserClaimsPrincipalFactory<TUser>, UserClaimsPrincipalFactory<TUser>>();
|
||||
services.TryAddScoped<UserManager<TUser>, AspNetUserManager<TUser>>();
|
||||
services.TryAddScoped<SignInManager<TUser>, SignInManager<TUser>>();
|
||||
|
||||
if (setupAction != null)
|
||||
{
|
||||
services.Configure(setupAction);
|
||||
}
|
||||
|
||||
return new IdentityBuilder(typeof(TUser), services);
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,463 @@
|
||||
// Copyright (c) .NET Foundation. All rights reserved.
|
||||
// Licensed under the Apache License, Version 2.0. See License.txt in the project root for license information.
|
||||
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.ComponentModel;
|
||||
using System.Linq;
|
||||
using System.Security.Claims;
|
||||
using System.Threading;
|
||||
using System.Threading.Tasks;
|
||||
using MongoDbGenericRepository;
|
||||
using MongoDB.Driver;
|
||||
using AspNetCore.Identity.MongoDbCore.Extensions;
|
||||
using AspNetCore.Identity.MongoDbCore.Models;
|
||||
using AspNetCore.Identity.MongoDbCore.Infrastructure;
|
||||
using Microsoft.AspNetCore.Identity;
|
||||
|
||||
namespace AspNetCore.Identity.MongoDbCore
|
||||
{
|
||||
/// <summary>
|
||||
/// Creates a new instance of a persistence store for roles.
|
||||
/// </summary>
|
||||
/// <typeparam name="TRole">The type of the class representing a role</typeparam>
|
||||
public class MongoRoleStore<TRole> : MongoRoleStore<TRole, MongoDbContext, string>
|
||||
where TRole : MongoIdentityRole<string>
|
||||
{
|
||||
/// <summary>
|
||||
/// Constructs a new instance of <see cref="MongoRoleStore{TRole}"/>.
|
||||
/// </summary>
|
||||
/// <param name="context">The <see cref="IMongoDbContext"/>.</param>
|
||||
/// <param name="describer">The <see cref="IdentityErrorDescriber"/>.</param>
|
||||
public MongoRoleStore(IMongoDbContext context, IdentityErrorDescriber describer = null) : base(context, describer) { }
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Creates a new instance of a persistence store for roles.
|
||||
/// </summary>
|
||||
/// <typeparam name="TRole">The type of the class representing a role.</typeparam>
|
||||
/// <typeparam name="TContext">The type of the data context class used to access the store.</typeparam>
|
||||
public class MongoRoleStore<TRole, TContext> : MongoRoleStore<TRole, TContext, string>
|
||||
where TRole : MongoIdentityRole<string>
|
||||
where TContext : IMongoDbContext
|
||||
{
|
||||
/// <summary>
|
||||
/// Constructs a new instance of <see cref="MongoRoleStore{TRole, TContext}"/>.
|
||||
/// </summary>
|
||||
/// <param name="context">The <see cref="IMongoDbContext"/>.</param>
|
||||
/// <param name="describer">The <see cref="IdentityErrorDescriber"/>.</param>
|
||||
public MongoRoleStore(TContext context, IdentityErrorDescriber describer = null) : base(context, describer) { }
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Creates a new instance of a persistence store for roles.
|
||||
/// </summary>
|
||||
/// <typeparam name="TRole">The type of the class representing a role.</typeparam>
|
||||
/// <typeparam name="TContext">The type of the data context class used to access the store.</typeparam>
|
||||
/// <typeparam name="TKey">The type of the primary key for a role.</typeparam>
|
||||
public class MongoRoleStore<TRole, TContext, TKey> : MongoRoleStore<TRole, TContext, TKey, IdentityUserRole<TKey>, IdentityRoleClaim<TKey>>,
|
||||
IQueryableRoleStore<TRole>,
|
||||
IRoleClaimStore<TRole>
|
||||
where TRole : MongoIdentityRole<TKey>
|
||||
where TKey : IEquatable<TKey>
|
||||
where TContext : IMongoDbContext
|
||||
{
|
||||
/// <summary>
|
||||
/// Constructs a new instance of <see cref="MongoRoleStore{TRole, TContext, TKey}"/>.
|
||||
/// </summary>
|
||||
/// <param name="context">The <see cref="IMongoDbContext"/>.</param>
|
||||
/// <param name="describer">The <see cref="IdentityErrorDescriber"/>.</param>
|
||||
public MongoRoleStore(IMongoDbContext context, IdentityErrorDescriber describer = null) : base(context, describer) { }
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Creates a new instance of a persistence store for roles.
|
||||
/// </summary>
|
||||
/// <typeparam name="TRole">The type of the class representing a role.</typeparam>
|
||||
/// <typeparam name="TContext">The type of the data context class used to access the store.</typeparam>
|
||||
/// <typeparam name="TKey">The type of the primary key for a role.</typeparam>
|
||||
/// <typeparam name="TUserRole">The type of the class representing a user role.</typeparam>
|
||||
/// <typeparam name="TRoleClaim">The type of the class representing a role claim.</typeparam>
|
||||
public class MongoRoleStore<TRole, TContext, TKey, TUserRole, TRoleClaim> :
|
||||
IQueryableRoleStore<TRole>,
|
||||
IRoleClaimStore<TRole>
|
||||
where TRole : MongoIdentityRole<TKey>
|
||||
where TKey : IEquatable<TKey>
|
||||
where TContext : IMongoDbContext
|
||||
where TUserRole : IdentityUserRole<TKey>, new()
|
||||
where TRoleClaim : IdentityRoleClaim<TKey>, new()
|
||||
{
|
||||
/// <summary>
|
||||
/// Constructs a new instance of <see cref="MongoRoleStore{TRole, TContext, TKey, TUserRole, TRoleClaim}"/>.
|
||||
/// </summary>
|
||||
/// <param name="context">The <see cref="IMongoDbContext"/>.</param>
|
||||
/// <param name="describer">The <see cref="IdentityErrorDescriber"/>.</param>
|
||||
public MongoRoleStore(IMongoDbContext context, IdentityErrorDescriber describer = null)
|
||||
{
|
||||
if (context == null)
|
||||
{
|
||||
throw new ArgumentNullException(nameof(context));
|
||||
}
|
||||
Context = context;
|
||||
ErrorDescriber = describer ?? new IdentityErrorDescriber();
|
||||
}
|
||||
|
||||
private bool _disposed;
|
||||
|
||||
|
||||
/// <summary>
|
||||
/// Gets the database context for this store.
|
||||
/// </summary>
|
||||
private static IMongoDbContext Context { get; set; }
|
||||
|
||||
private static IMongoRepository _mongoRepository;
|
||||
private static IMongoRepository MongoRepository
|
||||
{
|
||||
get
|
||||
{
|
||||
if (_mongoRepository == null)
|
||||
{
|
||||
_mongoRepository = new MongoRepository(Context);
|
||||
}
|
||||
return _mongoRepository;
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Gets or sets the <see cref="IdentityErrorDescriber"/> for any error that occurred with the current operation.
|
||||
/// </summary>
|
||||
public IdentityErrorDescriber ErrorDescriber { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// Gets or sets a flag indicating if changes should be persisted after CreateAsync, UpdateAsync and DeleteAsync are called.
|
||||
/// </summary>
|
||||
/// <value>
|
||||
/// True if changes should be automatically persisted, otherwise false.
|
||||
/// </value>
|
||||
public bool AutoSaveChanges { get; set; } = true;
|
||||
|
||||
/// <summary>
|
||||
/// Creates a new role in a store as an asynchronous operation.
|
||||
/// </summary>
|
||||
/// <param name="role">The role to create in the store.</param>
|
||||
/// <param name="cancellationToken">The <see cref="CancellationToken"/> used to propagate notifications that the operation should be canceled.</param>
|
||||
/// <returns>A <see cref="Task{TResult}"/> that represents the <see cref="IdentityResult"/> of the asynchronous query.</returns>
|
||||
public async virtual Task<IdentityResult> CreateAsync(TRole role, CancellationToken cancellationToken = default(CancellationToken))
|
||||
{
|
||||
cancellationToken.ThrowIfCancellationRequested();
|
||||
ThrowIfDisposed();
|
||||
if (role == null)
|
||||
{
|
||||
throw new ArgumentNullException(nameof(role));
|
||||
}
|
||||
await MongoRepository.AddOneAsync<TRole, TKey>(role);
|
||||
return IdentityResult.Success;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Updates a role in a store as an asynchronous operation.
|
||||
/// </summary>
|
||||
/// <param name="role">The role to update in the store.</param>
|
||||
/// <param name="cancellationToken">The <see cref="CancellationToken"/> used to propagate notifications that the operation should be canceled.</param>
|
||||
/// <returns>A <see cref="Task{TResult}"/> that represents the <see cref="IdentityResult"/> of the asynchronous query.</returns>
|
||||
public async virtual Task<IdentityResult> UpdateAsync(TRole role, CancellationToken cancellationToken = default(CancellationToken))
|
||||
{
|
||||
cancellationToken.ThrowIfCancellationRequested();
|
||||
ThrowIfDisposed();
|
||||
if (role == null)
|
||||
{
|
||||
throw new ArgumentNullException(nameof(role));
|
||||
}
|
||||
var oldStamp = role.ConcurrencyStamp;
|
||||
role.ConcurrencyStamp = Guid.NewGuid().ToString();
|
||||
var collection = MongoRepository.Context.GetCollection<TRole>();
|
||||
var updateRes = await collection.ReplaceOneAsync(x => x.Id.Equals(role.Id)
|
||||
&& x.ConcurrencyStamp.Equals(oldStamp),
|
||||
role);
|
||||
if (updateRes.ModifiedCount == 0)
|
||||
{
|
||||
return IdentityResult.Failed(ErrorDescriber.ConcurrencyFailure());
|
||||
}
|
||||
return IdentityResult.Success;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Deletes a role from the store as an asynchronous operation.
|
||||
/// </summary>
|
||||
/// <param name="role">The role to delete from the store.</param>
|
||||
/// <param name="cancellationToken">The <see cref="CancellationToken"/> used to propagate notifications that the operation should be canceled.</param>
|
||||
/// <returns>A <see cref="Task{TResult}"/> that represents the <see cref="IdentityResult"/> of the asynchronous query.</returns>
|
||||
public async virtual Task<IdentityResult> DeleteAsync(TRole role, CancellationToken cancellationToken = default(CancellationToken))
|
||||
{
|
||||
cancellationToken.ThrowIfCancellationRequested();
|
||||
ThrowIfDisposed();
|
||||
if (role == null)
|
||||
{
|
||||
throw new ArgumentNullException(nameof(role));
|
||||
}
|
||||
var oldStamp = role.ConcurrencyStamp;
|
||||
role.ConcurrencyStamp = Guid.NewGuid().ToString();
|
||||
var collection = MongoRepository.Context.GetCollection<TRole>();
|
||||
var deleteRes = await collection.DeleteOneAsync(x => x.Id.Equals(role.Id)
|
||||
&& x.ConcurrencyStamp.Equals(oldStamp));
|
||||
if (deleteRes.DeletedCount == 0)
|
||||
{
|
||||
return IdentityResult.Failed(ErrorDescriber.ConcurrencyFailure());
|
||||
}
|
||||
return IdentityResult.Success;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Gets the ID for a role from the store as an asynchronous operation.
|
||||
/// </summary>
|
||||
/// <param name="role">The role whose ID should be returned.</param>
|
||||
/// <param name="cancellationToken">The <see cref="CancellationToken"/> used to propagate notifications that the operation should be canceled.</param>
|
||||
/// <returns>A <see cref="Task{TResult}"/> that contains the ID of the role.</returns>
|
||||
public virtual Task<string> GetRoleIdAsync(TRole role, CancellationToken cancellationToken = default(CancellationToken))
|
||||
{
|
||||
cancellationToken.ThrowIfCancellationRequested();
|
||||
ThrowIfDisposed();
|
||||
if (role == null)
|
||||
{
|
||||
throw new ArgumentNullException(nameof(role));
|
||||
}
|
||||
return Task.FromResult(ConvertIdToString(role.Id));
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Gets the name of a role from the store as an asynchronous operation.
|
||||
/// </summary>
|
||||
/// <param name="role">The role whose name should be returned.</param>
|
||||
/// <param name="cancellationToken">The <see cref="CancellationToken"/> used to propagate notifications that the operation should be canceled.</param>
|
||||
/// <returns>A <see cref="Task{TResult}"/> that contains the name of the role.</returns>
|
||||
public virtual Task<string> GetRoleNameAsync(TRole role, CancellationToken cancellationToken = default(CancellationToken))
|
||||
{
|
||||
cancellationToken.ThrowIfCancellationRequested();
|
||||
ThrowIfDisposed();
|
||||
if (role == null)
|
||||
{
|
||||
throw new ArgumentNullException(nameof(role));
|
||||
}
|
||||
return Task.FromResult(role.Name);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Sets the name of a role in the store as an asynchronous operation.
|
||||
/// </summary>
|
||||
/// <param name="role">The role whose name should be set.</param>
|
||||
/// <param name="roleName">The name of the role.</param>
|
||||
/// <param name="cancellationToken">The <see cref="CancellationToken"/> used to propagate notifications that the operation should be canceled.</param>
|
||||
/// <returns>The <see cref="Task"/> that represents the asynchronous operation.</returns>
|
||||
public virtual Task SetRoleNameAsync(TRole role, string roleName, CancellationToken cancellationToken = default(CancellationToken))
|
||||
{
|
||||
cancellationToken.ThrowIfCancellationRequested();
|
||||
ThrowIfDisposed();
|
||||
if (role == null)
|
||||
{
|
||||
throw new ArgumentNullException(nameof(role));
|
||||
}
|
||||
if (role.Name != roleName)
|
||||
{
|
||||
role.Name = roleName;
|
||||
return MongoRepository.UpdateOneAsync<TRole, TKey, string>(role, x => x.Name, role.Name);
|
||||
}
|
||||
|
||||
return Task.CompletedTask;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Converts the provided <paramref name="id"/> to a strongly typed key object.
|
||||
/// </summary>
|
||||
/// <param name="id">The id to convert.</param>
|
||||
/// <returns>An instance of <typeparamref name="TKey"/> representing the provided <paramref name="id"/>.</returns>
|
||||
public virtual TKey ConvertIdFromString(string id)
|
||||
{
|
||||
if (id == null)
|
||||
{
|
||||
return default(TKey);
|
||||
}
|
||||
return (TKey)TypeDescriptor.GetConverter(typeof(TKey)).ConvertFromInvariantString(id);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Converts the provided <paramref name="id"/> to its string representation.
|
||||
/// </summary>
|
||||
/// <param name="id">The id to convert.</param>
|
||||
/// <returns>An <see cref="string"/> representation of the provided <paramref name="id"/>.</returns>
|
||||
public virtual string ConvertIdToString(TKey id)
|
||||
{
|
||||
if (id == null)
|
||||
{
|
||||
return null;
|
||||
}
|
||||
|
||||
if (id.Equals(default(TKey)))
|
||||
{
|
||||
return null;
|
||||
}
|
||||
return id.ToString();
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Finds the role who has the specified ID as an asynchronous operation.
|
||||
/// </summary>
|
||||
/// <param name="id">The role ID to look for.</param>
|
||||
/// <param name="cancellationToken">The <see cref="CancellationToken"/> used to propagate notifications that the operation should be canceled.</param>
|
||||
/// <returns>A <see cref="Task{TResult}"/> that result of the look up.</returns>
|
||||
public virtual Task<TRole> FindByIdAsync(string id, CancellationToken cancellationToken = default(CancellationToken))
|
||||
{
|
||||
cancellationToken.ThrowIfCancellationRequested();
|
||||
ThrowIfDisposed();
|
||||
var roleId = ConvertIdFromString(id);
|
||||
return MongoRepository.GetOneAsync<TRole, TKey>(u => u.Id.Equals(roleId));
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Finds the role who has the specified normalized name as an asynchronous operation.
|
||||
/// </summary>
|
||||
/// <param name="normalizedName">The normalized role name to look for.</param>
|
||||
/// <param name="cancellationToken">The <see cref="CancellationToken"/> used to propagate notifications that the operation should be canceled.</param>
|
||||
/// <returns>A <see cref="Task{TResult}"/> that result of the look up.</returns>
|
||||
public virtual Task<TRole> FindByNameAsync(string normalizedName, CancellationToken cancellationToken = default(CancellationToken))
|
||||
{
|
||||
cancellationToken.ThrowIfCancellationRequested();
|
||||
ThrowIfDisposed();
|
||||
return MongoRepository.GetOneAsync<TRole, TKey>(r => r.NormalizedName == normalizedName);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Get a role's normalized name as an asynchronous operation.
|
||||
/// </summary>
|
||||
/// <param name="role">The role whose normalized name should be retrieved.</param>
|
||||
/// <param name="cancellationToken">The <see cref="CancellationToken"/> used to propagate notifications that the operation should be canceled.</param>
|
||||
/// <returns>A <see cref="Task{TResult}"/> that contains the name of the role.</returns>
|
||||
public virtual Task<string> GetNormalizedRoleNameAsync(TRole role, CancellationToken cancellationToken = default(CancellationToken))
|
||||
{
|
||||
cancellationToken.ThrowIfCancellationRequested();
|
||||
ThrowIfDisposed();
|
||||
if (role == null)
|
||||
{
|
||||
throw new ArgumentNullException(nameof(role));
|
||||
}
|
||||
return Task.FromResult(role.NormalizedName);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Set a role's normalized name as an asynchronous operation.
|
||||
/// </summary>
|
||||
/// <param name="role">The role whose normalized name should be set.</param>
|
||||
/// <param name="normalizedName">The normalized name to set</param>
|
||||
/// <param name="cancellationToken">The <see cref="CancellationToken"/> used to propagate notifications that the operation should be canceled.</param>
|
||||
/// <returns>The <see cref="Task"/> that represents the asynchronous operation.</returns>
|
||||
public virtual Task SetNormalizedRoleNameAsync(TRole role, string normalizedName, CancellationToken cancellationToken = default(CancellationToken))
|
||||
{
|
||||
cancellationToken.ThrowIfCancellationRequested();
|
||||
ThrowIfDisposed();
|
||||
if (role == null)
|
||||
{
|
||||
throw new ArgumentNullException(nameof(role));
|
||||
}
|
||||
if (role.NormalizedName != normalizedName)
|
||||
{
|
||||
role.NormalizedName = normalizedName;
|
||||
return MongoRepository.UpdateOneAsync<TRole, TKey, string>(role, x => x.NormalizedName, role.NormalizedName);
|
||||
}
|
||||
return Task.CompletedTask;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Throws if this class has been disposed.
|
||||
/// </summary>
|
||||
protected void ThrowIfDisposed()
|
||||
{
|
||||
if (_disposed)
|
||||
{
|
||||
throw new ObjectDisposedException(GetType().Name);
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Dispose the stores
|
||||
/// </summary>
|
||||
public void Dispose() => _disposed = true;
|
||||
|
||||
/// <summary>
|
||||
/// Get the claims associated with the specified <paramref name="role"/> as an asynchronous operation.
|
||||
/// </summary>
|
||||
/// <param name="role">The role whose claims should be retrieved.</param>
|
||||
/// <param name="cancellationToken">The <see cref="CancellationToken"/> used to propagate notifications that the operation should be canceled.</param>
|
||||
/// <returns>A <see cref="Task{TResult}"/> that contains the claims granted to a role.</returns>
|
||||
public async virtual Task<IList<Claim>> GetClaimsAsync(TRole role, CancellationToken cancellationToken = default(CancellationToken))
|
||||
{
|
||||
ThrowIfDisposed();
|
||||
if (role == null)
|
||||
{
|
||||
throw new ArgumentNullException(nameof(role));
|
||||
}
|
||||
return role.Claims.Select(e => e.ToClaim()).ToList();
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Adds the <paramref name="claim"/> given to the specified <paramref name="role"/>.
|
||||
/// </summary>
|
||||
/// <param name="role">The role to add the claim to.</param>
|
||||
/// <param name="claim">The claim to add to the role.</param>
|
||||
/// <param name="cancellationToken">The <see cref="CancellationToken"/> used to propagate notifications that the operation should be canceled.</param>
|
||||
/// <returns>The <see cref="Task"/> that represents the asynchronous operation.</returns>
|
||||
public virtual Task AddClaimAsync(TRole role, Claim claim, CancellationToken cancellationToken = default(CancellationToken))
|
||||
{
|
||||
ThrowIfDisposed();
|
||||
if (role == null)
|
||||
{
|
||||
throw new ArgumentNullException(nameof(role));
|
||||
}
|
||||
if (claim == null)
|
||||
{
|
||||
throw new ArgumentNullException(nameof(claim));
|
||||
}
|
||||
if (role.AddClaim(claim))
|
||||
{
|
||||
MongoRepository.UpdateOne<TRole, TKey, List<MongoClaim>>(role, e => e.Claims, role.Claims);
|
||||
}
|
||||
return Task.FromResult(false);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Removes the <paramref name="claim"/> given from the specified <paramref name="role"/>.
|
||||
/// </summary>
|
||||
/// <param name="role">The role to remove the claim from.</param>
|
||||
/// <param name="claim">The claim to remove from the role.</param>
|
||||
/// <param name="cancellationToken">The <see cref="CancellationToken"/> used to propagate notifications that the operation should be canceled.</param>
|
||||
/// <returns>The <see cref="Task"/> that represents the asynchronous operation.</returns>
|
||||
public async virtual Task RemoveClaimAsync(TRole role, Claim claim, CancellationToken cancellationToken = default(CancellationToken))
|
||||
{
|
||||
ThrowIfDisposed();
|
||||
if (role == null)
|
||||
{
|
||||
throw new ArgumentNullException(nameof(role));
|
||||
}
|
||||
if (claim == null)
|
||||
{
|
||||
throw new ArgumentNullException(nameof(claim));
|
||||
}
|
||||
if (role.RemoveClaim(claim))
|
||||
{
|
||||
await MongoRepository.UpdateOneAsync<TRole, TKey, List<MongoClaim>>(role, e => e.Claims, role.Claims);
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// A navigation property for the roles the store contains.
|
||||
/// </summary>
|
||||
public virtual IQueryable<TRole> Roles => Context.GetCollection<TRole>().AsQueryable();
|
||||
|
||||
/// <summary>
|
||||
/// Creates a entity representing a role claim.
|
||||
/// </summary>
|
||||
/// <param name="role">The associated role.</param>
|
||||
/// <param name="claim">The associated claim.</param>
|
||||
/// <returns>The role claim entity.</returns>
|
||||
protected virtual TRoleClaim CreateRoleClaim(TRole role, Claim claim)
|
||||
=> new TRoleClaim { RoleId = role.Id, ClaimType = claim.Type, ClaimValue = claim.Value };
|
||||
}
|
||||
}
|
||||
File diff suppressed because it is too large
Load Diff
File diff suppressed because it is too large
Load Diff
Generated
+99
@@ -0,0 +1,99 @@
|
||||
//------------------------------------------------------------------------------
|
||||
// <auto-generated>
|
||||
// Ce code a été généré par un outil.
|
||||
// Version du runtime :4.0.30319.42000
|
||||
//
|
||||
// Les modifications apportées à ce fichier peuvent provoquer un comportement incorrect et seront perdues si
|
||||
// le code est régénéré.
|
||||
// </auto-generated>
|
||||
//------------------------------------------------------------------------------
|
||||
|
||||
namespace AspNetCore.Identity.MongoDbCore {
|
||||
using System;
|
||||
|
||||
|
||||
/// <summary>
|
||||
/// Une classe de ressource fortement typée destinée, entre autres, à la consultation des chaînes localisées.
|
||||
/// </summary>
|
||||
// Cette classe a été générée automatiquement par la classe StronglyTypedResourceBuilder
|
||||
// à l'aide d'un outil, tel que ResGen ou Visual Studio.
|
||||
// Pour ajouter ou supprimer un membre, modifiez votre fichier .ResX, puis réexécutez ResGen
|
||||
// avec l'option /str ou régénérez votre projet VS.
|
||||
[global::System.CodeDom.Compiler.GeneratedCodeAttribute("System.Resources.Tools.StronglyTypedResourceBuilder", "15.0.0.0")]
|
||||
[global::System.Diagnostics.DebuggerNonUserCodeAttribute()]
|
||||
[global::System.Runtime.CompilerServices.CompilerGeneratedAttribute()]
|
||||
internal class Resources {
|
||||
|
||||
private static global::System.Resources.ResourceManager resourceMan;
|
||||
|
||||
private static global::System.Globalization.CultureInfo resourceCulture;
|
||||
|
||||
[global::System.Diagnostics.CodeAnalysis.SuppressMessageAttribute("Microsoft.Performance", "CA1811:AvoidUncalledPrivateCode")]
|
||||
internal Resources() {
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Retourne l'instance ResourceManager mise en cache utilisée par cette classe.
|
||||
/// </summary>
|
||||
[global::System.ComponentModel.EditorBrowsableAttribute(global::System.ComponentModel.EditorBrowsableState.Advanced)]
|
||||
internal static global::System.Resources.ResourceManager ResourceManager {
|
||||
get {
|
||||
if (object.ReferenceEquals(resourceMan, null)) {
|
||||
global::System.Resources.ResourceManager temp = new global::System.Resources.ResourceManager("AspNetCore.Identity.MongoDbCore.Resources", typeof(Resources).Assembly);
|
||||
resourceMan = temp;
|
||||
}
|
||||
return resourceMan;
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Remplace la propriété CurrentUICulture du thread actuel pour toutes
|
||||
/// les recherches de ressources à l'aide de cette classe de ressource fortement typée.
|
||||
/// </summary>
|
||||
[global::System.ComponentModel.EditorBrowsableAttribute(global::System.ComponentModel.EditorBrowsableState.Advanced)]
|
||||
internal static global::System.Globalization.CultureInfo Culture {
|
||||
get {
|
||||
return resourceCulture;
|
||||
}
|
||||
set {
|
||||
resourceCulture = value;
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Recherche une chaîne localisée semblable à AddEntityFrameworkStores can only be called with a role that derives from IdentityRole<TKey, TUserRole, TRoleClaim>..
|
||||
/// </summary>
|
||||
internal static string NotIdentityRole {
|
||||
get {
|
||||
return ResourceManager.GetString("NotIdentityRole", resourceCulture);
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Recherche une chaîne localisée semblable à AddEntityFrameworkStores can only be called with a user that derives from IdentityUser<TKey, TUserClaim, TUserRole, TUserLogin, TUserToken>..
|
||||
/// </summary>
|
||||
internal static string NotIdentityUser {
|
||||
get {
|
||||
return ResourceManager.GetString("NotIdentityUser", resourceCulture);
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Recherche une chaîne localisée semblable à Role {0} does not exist..
|
||||
/// </summary>
|
||||
internal static string RoleNotFound {
|
||||
get {
|
||||
return ResourceManager.GetString("RoleNotFound", resourceCulture);
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Recherche une chaîne localisée semblable à Value cannot be null or empty..
|
||||
/// </summary>
|
||||
internal static string ValueCannotBeNullOrEmpty {
|
||||
get {
|
||||
return ResourceManager.GetString("ValueCannotBeNullOrEmpty", resourceCulture);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,136 @@
|
||||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<root>
|
||||
<!--
|
||||
Microsoft ResX Schema
|
||||
|
||||
Version 2.0
|
||||
|
||||
The primary goals of this format is to allow a simple XML format
|
||||
that is mostly human readable. The generation and parsing of the
|
||||
various data types are done through the TypeConverter classes
|
||||
associated with the data types.
|
||||
|
||||
Example:
|
||||
|
||||
... ado.net/XML headers & schema ...
|
||||
<resheader name="resmimetype">text/microsoft-resx</resheader>
|
||||
<resheader name="version">2.0</resheader>
|
||||
<resheader name="reader">System.Resources.ResXResourceReader, System.Windows.Forms, ...</resheader>
|
||||
<resheader name="writer">System.Resources.ResXResourceWriter, System.Windows.Forms, ...</resheader>
|
||||
<data name="Name1"><value>this is my long string</value><comment>this is a comment</comment></data>
|
||||
<data name="Color1" type="System.Drawing.Color, System.Drawing">Blue</data>
|
||||
<data name="Bitmap1" mimetype="application/x-microsoft.net.object.binary.base64">
|
||||
<value>[base64 mime encoded serialized .NET Framework object]</value>
|
||||
</data>
|
||||
<data name="Icon1" type="System.Drawing.Icon, System.Drawing" mimetype="application/x-microsoft.net.object.bytearray.base64">
|
||||
<value>[base64 mime encoded string representing a byte array form of the .NET Framework object]</value>
|
||||
<comment>This is a comment</comment>
|
||||
</data>
|
||||
|
||||
There are any number of "resheader" rows that contain simple
|
||||
name/value pairs.
|
||||
|
||||
Each data row contains a name, and value. The row also contains a
|
||||
type or mimetype. Type corresponds to a .NET class that support
|
||||
text/value conversion through the TypeConverter architecture.
|
||||
Classes that don't support this are serialized and stored with the
|
||||
mimetype set.
|
||||
|
||||
The mimetype is used for serialized objects, and tells the
|
||||
ResXResourceReader how to depersist the object. This is currently not
|
||||
extensible. For a given mimetype the value must be set accordingly:
|
||||
|
||||
Note - application/x-microsoft.net.object.binary.base64 is the format
|
||||
that the ResXResourceWriter will generate, however the reader can
|
||||
read any of the formats listed below.
|
||||
|
||||
mimetype: application/x-microsoft.net.object.binary.base64
|
||||
value : The object must be serialized with
|
||||
: System.Runtime.Serialization.Formatters.Binary.BinaryFormatter
|
||||
: and then encoded with base64 encoding.
|
||||
|
||||
mimetype: application/x-microsoft.net.object.soap.base64
|
||||
value : The object must be serialized with
|
||||
: System.Runtime.Serialization.Formatters.Soap.SoapFormatter
|
||||
: and then encoded with base64 encoding.
|
||||
|
||||
mimetype: application/x-microsoft.net.object.bytearray.base64
|
||||
value : The object must be serialized into a byte array
|
||||
: using a System.ComponentModel.TypeConverter
|
||||
: and then encoded with base64 encoding.
|
||||
-->
|
||||
<xsd:schema id="root" xmlns="" xmlns:xsd="http://www.w3.org/2001/XMLSchema" xmlns:msdata="urn:schemas-microsoft-com:xml-msdata">
|
||||
<xsd:import namespace="http://www.w3.org/XML/1998/namespace" />
|
||||
<xsd:element name="root" msdata:IsDataSet="true">
|
||||
<xsd:complexType>
|
||||
<xsd:choice maxOccurs="unbounded">
|
||||
<xsd:element name="metadata">
|
||||
<xsd:complexType>
|
||||
<xsd:sequence>
|
||||
<xsd:element name="value" type="xsd:string" minOccurs="0" />
|
||||
</xsd:sequence>
|
||||
<xsd:attribute name="name" use="required" type="xsd:string" />
|
||||
<xsd:attribute name="type" type="xsd:string" />
|
||||
<xsd:attribute name="mimetype" type="xsd:string" />
|
||||
<xsd:attribute ref="xml:space" />
|
||||
</xsd:complexType>
|
||||
</xsd:element>
|
||||
<xsd:element name="assembly">
|
||||
<xsd:complexType>
|
||||
<xsd:attribute name="alias" type="xsd:string" />
|
||||
<xsd:attribute name="name" type="xsd:string" />
|
||||
</xsd:complexType>
|
||||
</xsd:element>
|
||||
<xsd:element name="data">
|
||||
<xsd:complexType>
|
||||
<xsd:sequence>
|
||||
<xsd:element name="value" type="xsd:string" minOccurs="0" msdata:Ordinal="1" />
|
||||
<xsd:element name="comment" type="xsd:string" minOccurs="0" msdata:Ordinal="2" />
|
||||
</xsd:sequence>
|
||||
<xsd:attribute name="name" type="xsd:string" use="required" msdata:Ordinal="1" />
|
||||
<xsd:attribute name="type" type="xsd:string" msdata:Ordinal="3" />
|
||||
<xsd:attribute name="mimetype" type="xsd:string" msdata:Ordinal="4" />
|
||||
<xsd:attribute ref="xml:space" />
|
||||
</xsd:complexType>
|
||||
</xsd:element>
|
||||
<xsd:element name="resheader">
|
||||
<xsd:complexType>
|
||||
<xsd:sequence>
|
||||
<xsd:element name="value" type="xsd:string" minOccurs="0" msdata:Ordinal="1" />
|
||||
</xsd:sequence>
|
||||
<xsd:attribute name="name" type="xsd:string" use="required" />
|
||||
</xsd:complexType>
|
||||
</xsd:element>
|
||||
</xsd:choice>
|
||||
</xsd:complexType>
|
||||
</xsd:element>
|
||||
</xsd:schema>
|
||||
<resheader name="resmimetype">
|
||||
<value>text/microsoft-resx</value>
|
||||
</resheader>
|
||||
<resheader name="version">
|
||||
<value>2.0</value>
|
||||
</resheader>
|
||||
<resheader name="reader">
|
||||
<value>System.Resources.ResXResourceReader, System.Windows.Forms, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089</value>
|
||||
</resheader>
|
||||
<resheader name="writer">
|
||||
<value>System.Resources.ResXResourceWriter, System.Windows.Forms, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089</value>
|
||||
</resheader>
|
||||
<data name="NotIdentityRole" xml:space="preserve">
|
||||
<value>AddEntityFrameworkStores can only be called with a role that derives from IdentityRole<TKey, TUserRole, TRoleClaim>.</value>
|
||||
<comment>error when the role does not derive from IdentityRole</comment>
|
||||
</data>
|
||||
<data name="NotIdentityUser" xml:space="preserve">
|
||||
<value>AddEntityFrameworkStores can only be called with a user that derives from IdentityUser<TKey, TUserClaim, TUserRole, TUserLogin, TUserToken>.</value>
|
||||
<comment>error when the user does not derive from IdentityUser</comment>
|
||||
</data>
|
||||
<data name="RoleNotFound" xml:space="preserve">
|
||||
<value>Role {0} does not exist.</value>
|
||||
<comment>error when a role does not exist</comment>
|
||||
</data>
|
||||
<data name="ValueCannotBeNullOrEmpty" xml:space="preserve">
|
||||
<value>Value cannot be null or empty.</value>
|
||||
<comment>error when something cannot be null or empty</comment>
|
||||
</data>
|
||||
</root>
|
||||
File diff suppressed because it is too large
Load Diff
Binary file not shown.
File diff suppressed because it is too large
Load Diff
@@ -0,0 +1,136 @@
|
||||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<root>
|
||||
<!--
|
||||
Microsoft ResX Schema
|
||||
|
||||
Version 2.0
|
||||
|
||||
The primary goals of this format is to allow a simple XML format
|
||||
that is mostly human readable. The generation and parsing of the
|
||||
various data types are done through the TypeConverter classes
|
||||
associated with the data types.
|
||||
|
||||
Example:
|
||||
|
||||
... ado.net/XML headers & schema ...
|
||||
<resheader name="resmimetype">text/microsoft-resx</resheader>
|
||||
<resheader name="version">2.0</resheader>
|
||||
<resheader name="reader">System.Resources.ResXResourceReader, System.Windows.Forms, ...</resheader>
|
||||
<resheader name="writer">System.Resources.ResXResourceWriter, System.Windows.Forms, ...</resheader>
|
||||
<data name="Name1"><value>this is my long string</value><comment>this is a comment</comment></data>
|
||||
<data name="Color1" type="System.Drawing.Color, System.Drawing">Blue</data>
|
||||
<data name="Bitmap1" mimetype="application/x-microsoft.net.object.binary.base64">
|
||||
<value>[base64 mime encoded serialized .NET Framework object]</value>
|
||||
</data>
|
||||
<data name="Icon1" type="System.Drawing.Icon, System.Drawing" mimetype="application/x-microsoft.net.object.bytearray.base64">
|
||||
<value>[base64 mime encoded string representing a byte array form of the .NET Framework object]</value>
|
||||
<comment>This is a comment</comment>
|
||||
</data>
|
||||
|
||||
There are any number of "resheader" rows that contain simple
|
||||
name/value pairs.
|
||||
|
||||
Each data row contains a name, and value. The row also contains a
|
||||
type or mimetype. Type corresponds to a .NET class that support
|
||||
text/value conversion through the TypeConverter architecture.
|
||||
Classes that don't support this are serialized and stored with the
|
||||
mimetype set.
|
||||
|
||||
The mimetype is used for serialized objects, and tells the
|
||||
ResXResourceReader how to depersist the object. This is currently not
|
||||
extensible. For a given mimetype the value must be set accordingly:
|
||||
|
||||
Note - application/x-microsoft.net.object.binary.base64 is the format
|
||||
that the ResXResourceWriter will generate, however the reader can
|
||||
read any of the formats listed below.
|
||||
|
||||
mimetype: application/x-microsoft.net.object.binary.base64
|
||||
value : The object must be serialized with
|
||||
: System.Runtime.Serialization.Formatters.Binary.BinaryFormatter
|
||||
: and then encoded with base64 encoding.
|
||||
|
||||
mimetype: application/x-microsoft.net.object.soap.base64
|
||||
value : The object must be serialized with
|
||||
: System.Runtime.Serialization.Formatters.Soap.SoapFormatter
|
||||
: and then encoded with base64 encoding.
|
||||
|
||||
mimetype: application/x-microsoft.net.object.bytearray.base64
|
||||
value : The object must be serialized into a byte array
|
||||
: using a System.ComponentModel.TypeConverter
|
||||
: and then encoded with base64 encoding.
|
||||
-->
|
||||
<xsd:schema id="root" xmlns="" xmlns:xsd="http://www.w3.org/2001/XMLSchema" xmlns:msdata="urn:schemas-microsoft-com:xml-msdata">
|
||||
<xsd:import namespace="http://www.w3.org/XML/1998/namespace" />
|
||||
<xsd:element name="root" msdata:IsDataSet="true">
|
||||
<xsd:complexType>
|
||||
<xsd:choice maxOccurs="unbounded">
|
||||
<xsd:element name="metadata">
|
||||
<xsd:complexType>
|
||||
<xsd:sequence>
|
||||
<xsd:element name="value" type="xsd:string" minOccurs="0" />
|
||||
</xsd:sequence>
|
||||
<xsd:attribute name="name" use="required" type="xsd:string" />
|
||||
<xsd:attribute name="type" type="xsd:string" />
|
||||
<xsd:attribute name="mimetype" type="xsd:string" />
|
||||
<xsd:attribute ref="xml:space" />
|
||||
</xsd:complexType>
|
||||
</xsd:element>
|
||||
<xsd:element name="assembly">
|
||||
<xsd:complexType>
|
||||
<xsd:attribute name="alias" type="xsd:string" />
|
||||
<xsd:attribute name="name" type="xsd:string" />
|
||||
</xsd:complexType>
|
||||
</xsd:element>
|
||||
<xsd:element name="data">
|
||||
<xsd:complexType>
|
||||
<xsd:sequence>
|
||||
<xsd:element name="value" type="xsd:string" minOccurs="0" msdata:Ordinal="1" />
|
||||
<xsd:element name="comment" type="xsd:string" minOccurs="0" msdata:Ordinal="2" />
|
||||
</xsd:sequence>
|
||||
<xsd:attribute name="name" type="xsd:string" use="required" msdata:Ordinal="1" />
|
||||
<xsd:attribute name="type" type="xsd:string" msdata:Ordinal="3" />
|
||||
<xsd:attribute name="mimetype" type="xsd:string" msdata:Ordinal="4" />
|
||||
<xsd:attribute ref="xml:space" />
|
||||
</xsd:complexType>
|
||||
</xsd:element>
|
||||
<xsd:element name="resheader">
|
||||
<xsd:complexType>
|
||||
<xsd:sequence>
|
||||
<xsd:element name="value" type="xsd:string" minOccurs="0" msdata:Ordinal="1" />
|
||||
</xsd:sequence>
|
||||
<xsd:attribute name="name" type="xsd:string" use="required" />
|
||||
</xsd:complexType>
|
||||
</xsd:element>
|
||||
</xsd:choice>
|
||||
</xsd:complexType>
|
||||
</xsd:element>
|
||||
</xsd:schema>
|
||||
<resheader name="resmimetype">
|
||||
<value>text/microsoft-resx</value>
|
||||
</resheader>
|
||||
<resheader name="version">
|
||||
<value>2.0</value>
|
||||
</resheader>
|
||||
<resheader name="reader">
|
||||
<value>System.Resources.ResXResourceReader, System.Windows.Forms, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089</value>
|
||||
</resheader>
|
||||
<resheader name="writer">
|
||||
<value>System.Resources.ResXResourceWriter, System.Windows.Forms, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089</value>
|
||||
</resheader>
|
||||
<data name="NotIdentityRole" xml:space="preserve">
|
||||
<value>AddEntityFrameworkStores can only be called with a role that derives from IdentityRole<TKey, TUserRole, TRoleClaim>.</value>
|
||||
<comment>error when the role does not derive from IdentityRole</comment>
|
||||
</data>
|
||||
<data name="NotIdentityUser" xml:space="preserve">
|
||||
<value>AddEntityFrameworkStores can only be called with a user that derives from IdentityUser<TKey, TUserClaim, TUserRole, TUserLogin, TUserToken>.</value>
|
||||
<comment>error when the user does not derive from IdentityUser</comment>
|
||||
</data>
|
||||
<data name="RoleNotFound" xml:space="preserve">
|
||||
<value>Role {0} does not exist.</value>
|
||||
<comment>error when a role does not exist</comment>
|
||||
</data>
|
||||
<data name="ValueCannotBeNullOrEmpty" xml:space="preserve">
|
||||
<value>Value cannot be null or empty.</value>
|
||||
<comment>error when something cannot be null or empty</comment>
|
||||
</data>
|
||||
</root>
|
||||
Reference in New Issue
Block a user