Browse Source

Merge remote-tracking branch 'origin/rel-4.0' into dev

pull/6227/head
Halil İbrahim Kalkan 6 years ago
parent
commit
9259bddb26
  1. 118
      docs/en/Migration-Guides/Abp-4_0-Angular.md
  2. 2
      docs/en/UI/Angular/Environment.md
  3. 26
      framework/src/Volo.Abp.Json/Volo/Abp/Json/SystemTextJson/JsonConverters/AbpDateTimeConverter.cs
  4. 20
      framework/src/Volo.Abp.Json/Volo/Abp/Json/SystemTextJson/JsonConverters/AbpHasExtraPropertiesJsonConverter.cs
  5. 23
      framework/src/Volo.Abp.Json/Volo/Abp/Json/SystemTextJson/JsonConverters/AbpNullableDateTimeConverter.cs
  6. 239
      framework/test/Volo.Abp.Json.Tests/Volo/Abp/Json/AbpSystemTextJsonSerializerProvider_Tests.cs
  7. 23
      framework/test/Volo.Abp.MemoryDb.Tests/Volo/Abp/MemoryDb/JsonConverters/EntityJsonConverter.cs
  8. 21
      modules/feature-management/src/Volo.Abp.FeatureManagement.Application.Contracts/Volo/Abp/FeatureManagement/JsonConverters/SelectionStringValueItemSourceJsonConverter.cs
  9. 26
      modules/feature-management/src/Volo.Abp.FeatureManagement.Application.Contracts/Volo/Abp/FeatureManagement/JsonConverters/StringValueTypeJsonConverter.cs
  10. 27
      modules/feature-management/src/Volo.Abp.FeatureManagement.Application.Contracts/Volo/Abp/FeatureManagement/JsonConverters/ValueValidatorJsonConverter.cs
  11. 8
      modules/feature-management/src/Volo.Abp.FeatureManagement.Domain/Volo/Abp/FeatureManagement/FeatureManager.cs
  12. 11
      modules/feature-management/test/Volo.Abp.FeatureManagement.Application.Tests/Volo/Abp/FeatureManagement/StringValueJsonConverter_Tests.cs
  13. 43
      modules/feature-management/test/Volo.Abp.FeatureManagement.Domain.Tests/Volo/Abp/FeatureManagement/FeatureManager_Tests.cs
  14. 2
      modules/feature-management/test/Volo.Abp.FeatureManagement.TestBase/Volo/Abp/FeatureManagement/FeatureValueRepository_Tests.cs
  15. 1
      modules/identityserver/src/Volo.Abp.IdentityServer.EntityFrameworkCore/Volo/Abp/IdentityServer/ApiResources/ApiResourceRepository.cs
  16. 1
      modules/identityserver/src/Volo.Abp.IdentityServer.EntityFrameworkCore/Volo/Abp/IdentityServer/ApiScopes/ApiScopeRepository.cs
  17. 11
      modules/identityserver/src/Volo.Abp.IdentityServer.EntityFrameworkCore/Volo/Abp/IdentityServer/Devices/DeviceFlowCodesRepository.cs
  18. 5
      modules/identityserver/src/Volo.Abp.IdentityServer.EntityFrameworkCore/Volo/Abp/IdentityServer/Grants/PersistedGrantRepository.cs
  19. 1
      modules/identityserver/src/Volo.Abp.IdentityServer.EntityFrameworkCore/Volo/Abp/IdentityServer/IdentityResources/IdentityResourceRepository.cs
  20. 1
      modules/identityserver/src/Volo.Abp.IdentityServer.MongoDB/Volo/Abp/IdentityServer/MongoDB/MongoApiResourceRepository.cs
  21. 6
      modules/identityserver/src/Volo.Abp.IdentityServer.MongoDB/Volo/Abp/IdentityServer/MongoDB/MongoApiScopeRepository.cs
  22. 5
      modules/identityserver/src/Volo.Abp.IdentityServer.MongoDB/Volo/Abp/IdentityServer/MongoDB/MongoClientRepository.cs
  23. 13
      modules/identityserver/src/Volo.Abp.IdentityServer.MongoDB/Volo/Abp/IdentityServer/MongoDB/MongoDeviceFlowCodesRepository.cs
  24. 1
      modules/identityserver/src/Volo.Abp.IdentityServer.MongoDB/Volo/Abp/IdentityServer/MongoDB/MongoIdentityResourceRepository.cs
  25. 7
      modules/identityserver/src/Volo.Abp.IdentityServer.MongoDB/Volo/Abp/IdentityServer/MongoDB/MongoPersistedGrantRepository.cs

118
docs/en/Migration-Guides/Abp-4_0-Angular.md

@ -1,11 +1,121 @@
# Angular UI 3.3 to 4.0 Migration Guide
### Removed the Angular Account Module Public UI
## Angular v11
Angular UI is using the Authorization Code Flow to authenticate since the version 3.1.0 by default. Starting from the version 4.0, this is becoming the only option, because it is the recommended way of authenticating SPAs.
The new ABP Angular UI is based on Angular v11 and TypeScript v4. The difference between v10 and v11 is non-breaking so you do not have to update right away but it is recommended. Nevertheless, ABP modules will keep working with Angular v10. Therefore, if your project is Angular v10, you do not need to update to Angular 11. The update is usually very easy though.
You can read more about Angular v11 [here](https://blog.angular.io/version-11-of-angular-now-available-74721b7952f7)
## **Breaking Changes**
### **Localization**
Prior to ABP 4.x, we'd handled what locale files of Angular should be created to load them lazily. However, this made it impossible to add new locale files (to be lazily loaded) for our users. With ABP 4.x, we enabled an option to pass a function to `CoreModule`.
The quickest solution is as follows:
```typescript
// app.module.ts
import { registerLocale } from '@abp/ng.core/locale';
// or
// import { registerLocale } from '@volo/abp.ng.language-management/locale';
// if you have commercial license
@NgModule({
imports: [
// ...
CoreModule.forRoot({
// ...other options,
registerLocaleFn: registerLocale()
}),
//...
]
export class AppModule {}
```
You can find the related issue [here](https://github.com/abpframework/abp/issues/6066)
Also, please refer to [the docs](https://docs.abp.io/en/abp/latest/UI/Angular/Localization#registering-a-new-locale) for more information.
### **Removed the Angular Account Module Public UI**
With ABP 4.x, we have retired `@abp/ng.account`, it is no longer a part of our framework. There won't be any newer versions of this package as well. Therefore, you can delete anything related to this package.
There should be a config in `app-routing.module` for path `account` and `AccountConfigModule` import in `app.module`
However, if you are using the commercial version of this package, a.k.a `@volo/abp.ng.account`, this package will continue to exist because it contains `AccountAdminModule` which is still being maintained and developed. You only need to delete the route config from `app-routing.module`
You can find the related issue [here](https://github.com/abpframework/abp/issues/5652)
Angular UI is using the Authorization Code Flow to authenticate since version 3.1.0 by default. Starting from version 4.0, this is becoming the only option, because it is the recommended way of authenticating SPAs.
If you haven't done it yet, see [this post](https://blog.abp.io/abp/ABP-Framework-v3.1-RC-Has-Been-Released) to change the authentication of your application.
### Removed the SessionState
### State Management
In the ABP Angular UI, we've been using `NGXS` for state management. However, we've decided that the Angular UI should be agnostic with regard to state management. Our users should be able to handle the state in any way they prefer. They should be able to use any library other than `NGXS` or no library at all. That's why we have created our internal store in version 3.2. It is a simple utility class that employs `BehaviorSubject` internally.
You can examine it [here](https://github.com/abpframework/abp/blob/dev/npm/ng-packs/packages/core/src/lib/utils/internal-store-utils.ts)
With version 4.0, we will keep utilizing our `InternalStore` instead of `@ngxs/store` in our services and move away from `@ngxs/store`. We plan to remove any dependency of `NGXS` by version 5.0.
With this in mind, we've already deprecated some services and implemented some breaking changes.
#### Removed the `SessionState`
Use `SessionStateService` instead of the `SessionState`. See [this issue](https://github.com/abpframework/abp/issues/5606) for details.
#### Deprecated the `ConfigState`
`ConfigState` is now deprecated and should not be used.
`ConfigState` reference removed from `CoreModule`. If you want to use the `ConfigState` (not recommended), you should pass the state to `NgxsModule` as shown below:
```typescript
//app.module.ts
import { ConfigState } from '@abp/ng.core';
// ...
imports: [
NgxsModule.forRoot([ConfigState]),
// ...
```
Moving away from the global store, we create small services with a single responsibility. There are two new services available in version 4.0 which are `EnvironmentService` and `PermissionService`.
See [the related issue](https://github.com/abpframework/abp/issues/6154)
Please refer to the following docs for detail information and examples
- [`ConfigStateService`](../UI/Angular/Config-State-Service)
- [`EnvironmentService`](../UI/Angular/Environment#EnvironmentService)
- [`PermissionService`](../UI/Angular/Permission-Management#)
### Deprecated Interfaces
Some interfaces have long been marked as deprecated and now they are removed.
- Removed replaceable components state.
- Removed legacy identity types and service.
- Removed legacy tenant management types and service.
- Removed legacy feature management types and services.
- Removed legacy permission management types and service.
### Deprecated commercial interfaces
- Removed legacy audit logging types and services.
- Removed legacy identity types and services.
- Removed legacy language management types and services.
- Removed legacy saas types and services.
### Identity Server [COMMERCIAL]
With the new version of Identity Server, there happened some breaking changes in the backend (also in the database). We've implemented those in the Angular UI.
If you are just using the package `@volo/abp.ng.identity-server` as is, you will not need to do anything.
However, there are a couple of breaking changes we need to mention.
- As we have stated above, we want to remove the dependency of `NGXS`. Thus, we have deleted all of the actions defined in `identity-server.actions`. Those actions are not needed anymore and the state is managed locally. With the actions gone, `IdentityServerStateService` became unused and got deleted as well.
- `ApiScope` is also available as a new entity (It was part of `ApiResource` before). It provides tokens for entity prop, entity actions, toolbar, edit and create form contributors like the existing ones which are `Client`, `IdentityResource` and `ApiResource`
Use `SessionStateService` instead of the `SessionState`. See [this issue](https://github.com/abpframework/abp/issues/5606) for details.
- There were some deprecated interfaces within the `IdentityServer` namespace. Those are no longer being used, instead, their replacements were generated by `ABP Cli` using the `generate-proxy` command.

2
docs/en/UI/Angular/Environment.md

@ -102,7 +102,7 @@ export interface RemoteEnv {
* `method`: HTTP method to be used when retrieving environment config. Default: `GET`
* `headers`: If extra headers are needed for the request, it can be set through this field.
## EnvironmentService
## EnvironmentService
` EnvironmentService` is a singleton service, i.e. provided in root level of your application, and keeps the environment in the internal store.

26
framework/src/Volo.Abp.Json/Volo/Abp/Json/SystemTextJson/JsonConverters/AbpDateTimeConverter.cs

@ -1,4 +1,5 @@
using System;
using System.Globalization;
using System.Text.Json;
using System.Text.Json.Serialization;
using Microsoft.Extensions.Options;
@ -20,7 +21,28 @@ namespace Volo.Abp.Json.SystemTextJson.JsonConverters
public override DateTime Read(ref Utf8JsonReader reader, Type typeToConvert, JsonSerializerOptions options)
{
return _clock.Normalize(reader.GetDateTime());
if (!_options.DefaultDateTimeFormat.IsNullOrWhiteSpace())
{
if (reader.TokenType == JsonTokenType.String)
{
var s = reader.GetString();
if (DateTime.TryParseExact(s, _options.DefaultDateTimeFormat, CultureInfo.CurrentUICulture, DateTimeStyles.None, out var d1))
{
return _clock.Normalize(d1);
}
throw new JsonException($"'{s}' can't parse to DateTime({_options.DefaultDateTimeFormat})!");
}
throw new JsonException("Reader's TokenType is not String!");
}
if (reader.TryGetDateTime(out var d2))
{
return _clock.Normalize(d2);
}
throw new JsonException("Can't get datetime from the reader!");
}
public override void Write(Utf8JsonWriter writer, DateTime value, JsonSerializerOptions options)
@ -31,7 +53,7 @@ namespace Volo.Abp.Json.SystemTextJson.JsonConverters
}
else
{
writer.WriteStringValue(_clock.Normalize(value).ToString(_options.DefaultDateTimeFormat));
writer.WriteStringValue(_clock.Normalize(value).ToString(_options.DefaultDateTimeFormat, CultureInfo.CurrentUICulture));
}
}
}

20
framework/src/Volo.Abp.Json/Volo/Abp/Json/SystemTextJson/JsonConverters/AbpHasExtraPropertiesJsonConverter.cs

@ -16,15 +16,21 @@ namespace Volo.Abp.Json.SystemTextJson.JsonConverters
x.GetType() == typeof(AbpHasExtraPropertiesJsonConverterFactory));
var rootElement = JsonDocument.ParseValue(ref reader).RootElement;
var extensibleObject = JsonSerializer.Deserialize<T>(rootElement.GetRawText(), newOptions);
if (rootElement.ValueKind == JsonValueKind.Object)
{
var extensibleObject = JsonSerializer.Deserialize<T>(rootElement.GetRawText(), newOptions);
var extraProperties = rootElement.EnumerateObject().FirstOrDefault(x =>
x.Name.Equals(nameof(IHasExtraProperties.ExtraProperties), StringComparison.OrdinalIgnoreCase))
.Value.GetRawText();
var extraPropertyDictionary = JsonSerializer.Deserialize(extraProperties, typeof(ExtraPropertyDictionary), newOptions);
ObjectHelper.TrySetProperty(extensibleObject, x => x.ExtraProperties, () => extraPropertyDictionary);
var extraPropertiesJsonProperty = rootElement.EnumerateObject().FirstOrDefault(x => x.Name.Equals(nameof(IHasExtraProperties.ExtraProperties), StringComparison.OrdinalIgnoreCase));
if (extraPropertiesJsonProperty.Value.ValueKind == JsonValueKind.Object)
{
var extraPropertyDictionary = JsonSerializer.Deserialize(extraPropertiesJsonProperty.Value.GetRawText(), typeof(ExtraPropertyDictionary), newOptions);
ObjectHelper.TrySetProperty(extensibleObject, x => x.ExtraProperties, () => extraPropertyDictionary);
}
return extensibleObject;
return extensibleObject;
}
throw new JsonException("RootElement's ValueKind is not Object!");
}
public override void Write(Utf8JsonWriter writer, T value, JsonSerializerOptions options)

23
framework/src/Volo.Abp.Json/Volo/Abp/Json/SystemTextJson/JsonConverters/AbpNullableDateTimeConverter.cs

@ -1,4 +1,5 @@
using System;
using System.Globalization;
using System.Text.Json;
using System.Text.Json.Serialization;
using Microsoft.Extensions.Options;
@ -20,9 +21,25 @@ namespace Volo.Abp.Json.SystemTextJson.JsonConverters
public override DateTime? Read(ref Utf8JsonReader reader, Type typeToConvert, JsonSerializerOptions options)
{
if (reader.TryGetDateTime(out var dateTime))
if (!_options.DefaultDateTimeFormat.IsNullOrWhiteSpace())
{
return _clock.Normalize(dateTime);
if (reader.TokenType == JsonTokenType.String)
{
var s = reader.GetString();
if (DateTime.TryParseExact(s, _options.DefaultDateTimeFormat, CultureInfo.CurrentUICulture, DateTimeStyles.None, out var d1))
{
return _clock.Normalize(d1);
}
throw new JsonException($"'{s}' can't parse to DateTime({_options.DefaultDateTimeFormat})!");
}
throw new JsonException("Reader's TokenType is not String!");
}
if (reader.TryGetDateTime(out var d2))
{
return _clock.Normalize(d2);
}
return null;
@ -42,7 +59,7 @@ namespace Volo.Abp.Json.SystemTextJson.JsonConverters
}
else
{
writer.WriteStringValue(_clock.Normalize(value.Value).ToString(_options.DefaultDateTimeFormat));
writer.WriteStringValue(_clock.Normalize(value.Value).ToString(_options.DefaultDateTimeFormat, CultureInfo.CurrentUICulture));
}
}
}

239
framework/test/Volo.Abp.Json.Tests/Volo/Abp/Json/AbpSystemTextJsonSerializerProvider_Tests.cs

@ -1,30 +1,89 @@
using Shouldly;
using System;
using Microsoft.Extensions.DependencyInjection;
using Shouldly;
using Volo.Abp.Data;
using Volo.Abp.Json.SystemTextJson;
using Volo.Abp.ObjectExtending;
using Volo.Abp.Timing;
using Xunit;
namespace Volo.Abp.Json
{
public class AbpSystemTextJsonSerializerProvider_Tests : AbpJsonTestBase
public abstract class AbpSystemTextJsonSerializerProvider_TestBase : AbpJsonTestBase
{
private readonly AbpSystemTextJsonSerializerProvider _jsonSerializer;
protected AbpSystemTextJsonSerializerProvider JsonSerializer;
public AbpSystemTextJsonSerializerProvider_Tests()
public AbpSystemTextJsonSerializerProvider_TestBase()
{
_jsonSerializer = GetRequiredService<AbpSystemTextJsonSerializerProvider>();
JsonSerializer = GetRequiredService<AbpSystemTextJsonSerializerProvider>();
}
public class TestExtensibleObjectClass : ExtensibleObject
{
public string Name { get; set; }
}
public class FileWithBoolean
{
public string Name { get; set; }
public bool IsDeleted { get; set; }
}
public class FileWithNullableBoolean
{
public string Name { get; set; }
public bool? IsDeleted { get; set; }
}
public class FileWithEnum
{
public string Name { get; set; }
public FileType Type { get; set; }
}
public class FileWithNullableEnum
{
public string Name { get; set; }
public FileType? Type { get; set; }
}
public enum FileType
{
Zip = 0,
Exe = 2
}
public class FileWithDatetime
{
public string Name { get; set; }
public DateTime CreationTime { get; set; }
}
public class FileWithNullableDatetime
{
public string Name { get; set; }
public DateTime? CreationTime { get; set; }
}
}
public class AbpSystemTextJsonSerializerProvider_Tests : AbpSystemTextJsonSerializerProvider_TestBase
{
[Fact]
public void Serialize_Deserialize_With_Boolean()
{
var json = "{\"name\":\"abp\",\"IsDeleted\":\"fAlSe\"}";
var file = _jsonSerializer.Deserialize<FileWithBoolean>(json);
var file = JsonSerializer.Deserialize<FileWithBoolean>(json);
file.Name.ShouldBe("abp");
file.IsDeleted.ShouldBeFalse();
file.IsDeleted = false;
var newJson = _jsonSerializer.Serialize(file);
var newJson = JsonSerializer.Serialize(file);
newJson.ShouldBe("{\"name\":\"abp\",\"isDeleted\":false}");
}
@ -32,19 +91,19 @@ namespace Volo.Abp.Json
public void Serialize_Deserialize_With_Nullable_Boolean()
{
var json = "{\"name\":\"abp\",\"IsDeleted\":null}";
var file = _jsonSerializer.Deserialize<FileWithNullableBoolean>(json);
var file = JsonSerializer.Deserialize<FileWithNullableBoolean>(json);
file.Name.ShouldBe("abp");
file.IsDeleted.ShouldBeNull();
var newJson = _jsonSerializer.Serialize(file);
var newJson = JsonSerializer.Serialize(file);
newJson.ShouldBe("{\"name\":\"abp\",\"isDeleted\":null}");
json = "{\"name\":\"abp\",\"IsDeleted\":\"true\"}";
file = _jsonSerializer.Deserialize<FileWithNullableBoolean>(json);
file = JsonSerializer.Deserialize<FileWithNullableBoolean>(json);
file.IsDeleted.ShouldNotBeNull();
file.IsDeleted.Value.ShouldBeTrue();
newJson = _jsonSerializer.Serialize(file);
newJson = JsonSerializer.Serialize(file);
newJson.ShouldBe("{\"name\":\"abp\",\"isDeleted\":true}");
}
@ -52,11 +111,11 @@ namespace Volo.Abp.Json
public void Serialize_Deserialize_With_Enum()
{
var json = "{\"name\":\"abp\",\"type\":\"Exe\"}";
var file = _jsonSerializer.Deserialize<FileWithEnum>(json);
var file = JsonSerializer.Deserialize<FileWithEnum>(json);
file.Name.ShouldBe("abp");
file.Type.ShouldBe(FileType.Exe);
var newJson = _jsonSerializer.Serialize(file);
var newJson = JsonSerializer.Serialize(file);
newJson.ShouldBe("{\"name\":\"abp\",\"type\":2}");
}
@ -64,72 +123,178 @@ namespace Volo.Abp.Json
public void Serialize_Deserialize_With_Nullable_Enum()
{
var json = "{\"name\":\"abp\",\"type\":null}";
var file = _jsonSerializer.Deserialize<FileWithNullableEnum>(json);
var file = JsonSerializer.Deserialize<FileWithNullableEnum>(json);
file.Name.ShouldBe("abp");
file.Type.ShouldBeNull();
var newJson = _jsonSerializer.Serialize(file);
var newJson = JsonSerializer.Serialize(file);
newJson.ShouldBe("{\"name\":\"abp\",\"type\":null}");
json = "{\"name\":\"abp\",\"type\":\"Exe\"}";
file = _jsonSerializer.Deserialize<FileWithNullableEnum>(json);
file = JsonSerializer.Deserialize<FileWithNullableEnum>(json);
file.Type.ShouldNotBeNull();
file.Type.ShouldBe(FileType.Exe);
newJson = _jsonSerializer.Serialize(file);
newJson = JsonSerializer.Serialize(file);
newJson.ShouldBe("{\"name\":\"abp\",\"type\":2}");
}
[Fact]
public void Serialize_Deserialize_ExtensibleObject()
{
var json = "{\"name\":\"test\",\"extraProperties\":{\"One\":\"123\",\"Two\":456}}";
var extensibleObject = _jsonSerializer.Deserialize<TestExtensibleObjectClass>(json);
var extensibleObject = JsonSerializer.Deserialize<TestExtensibleObjectClass>(json);
extensibleObject.GetProperty("One").ShouldBe("123");
extensibleObject.GetProperty("Two").ShouldBe(456);
var newJson = _jsonSerializer.Serialize(extensibleObject);
var newJson = JsonSerializer.Serialize(extensibleObject);
newJson.ShouldBe(json);
}
class TestExtensibleObjectClass : ExtensibleObject
[Fact]
public void Serialize_Deserialize_ExtensibleObject_Without_String()
{
public string Name { get; set; }
var json = "{\"name\":\"test\"}";
var extensibleObject = JsonSerializer.Deserialize<TestExtensibleObjectClass>(json);
extensibleObject.ExtraProperties.ShouldNotBeNull();
extensibleObject.ExtraProperties.ShouldBeEmpty();
}
class FileWithBoolean
[Fact]
public void Serialize_Deserialize_ExtensibleObject_Without_Empty()
{
public string Name { get; set; }
var json = "{\"name\":\"test\",\"extraProperties\":{}}";
var extensibleObject = JsonSerializer.Deserialize<TestExtensibleObjectClass>(json);
extensibleObject.ExtraProperties.ShouldNotBeNull();
extensibleObject.ExtraProperties.ShouldBeEmpty();
}
public bool IsDeleted { get; set; }
[Fact]
public void Serialize_Deserialize_ExtensibleObject_Without_Null()
{
var json = "{\"name\":\"test\",\"extraProperties\":null}";
var extensibleObject = JsonSerializer.Deserialize<TestExtensibleObjectClass>(json);
extensibleObject.ExtraProperties.ShouldNotBeNull();
extensibleObject.ExtraProperties.ShouldBeEmpty();
}
class FileWithNullableBoolean
[Fact]
public void Serialize_Deserialize_With_Datetime()
{
public string Name { get; set; }
var json = "{\"name\":\"abp\",\"creationTime\":\"2020-11-20T00:00:00\"}";
var file = JsonSerializer.Deserialize<FileWithDatetime>(json);
file.CreationTime.Year.ShouldBe(2020);
file.CreationTime.Month.ShouldBe(11);
file.CreationTime.Day.ShouldBe(20);
public bool? IsDeleted { get; set; }
var newJson = JsonSerializer.Serialize(file);
newJson.ShouldBe(json);
}
class FileWithEnum
[Fact]
public void Serialize_Deserialize_With_Nullable_Datetime()
{
public string Name { get; set; }
var json = "{\"name\":\"abp\",\"creationTime\":null}";
var file = JsonSerializer.Deserialize<FileWithNullableDatetime>(json);
file.CreationTime.ShouldBeNull();
public FileType Type { get; set; }
json = "{\"name\":\"abp\"}";
file = JsonSerializer.Deserialize<FileWithNullableDatetime>(json);
file.CreationTime.ShouldBeNull();
json = "{\"name\":\"abp\",\"creationTime\":\"2020-11-20T00:00:00\"}";
file = JsonSerializer.Deserialize<FileWithNullableDatetime>(json);
file.CreationTime.ShouldNotBeNull();
file.CreationTime.Value.Year.ShouldBe(2020);
file.CreationTime.Value.Month.ShouldBe(11);
file.CreationTime.Value.Day.ShouldBe(20);
var newJson = JsonSerializer.Serialize(file);
newJson.ShouldBe(json);
}
}
class FileWithNullableEnum
public class AbpSystemTextJsonSerializerProvider_DateTimeFormat_Tests : AbpSystemTextJsonSerializerProvider_TestBase
{
protected override void AfterAddApplication(IServiceCollection services)
{
public string Name { get; set; }
services.Configure<AbpJsonOptions>(options =>
{
options.DefaultDateTimeFormat = "yyyy*MM*dd";
});
}
public FileType? Type { get; set; }
[Fact]
public void Serialize_Deserialize_With_Format_Datetime()
{
var json = "{\"name\":\"abp\",\"creationTime\":\"2020*11*20\"}";
var file = JsonSerializer.Deserialize<FileWithDatetime>(json);
file.CreationTime.Year.ShouldBe(2020);
file.CreationTime.Month.ShouldBe(11);
file.CreationTime.Day.ShouldBe(20);
var newJson = JsonSerializer.Serialize(file);
newJson.ShouldBe(json);
}
enum FileType
[Fact]
public void Serialize_Deserialize_With_Nullable_Format_Datetime()
{
Zip = 0,
Exe = 2
var json = "{\"name\":\"abp\",\"creationTime\":null}";
var file = JsonSerializer.Deserialize<FileWithNullableDatetime>(json);
file.CreationTime.ShouldBeNull();
json = "{\"name\":\"abp\"}";
file = JsonSerializer.Deserialize<FileWithNullableDatetime>(json);
file.CreationTime.ShouldBeNull();
json = "{\"name\":\"abp\",\"creationTime\":\"2020*11*20\"}";
file = JsonSerializer.Deserialize<FileWithNullableDatetime>(json);
file.CreationTime.ShouldNotBeNull();
file.CreationTime.Value.Year.ShouldBe(2020);
file.CreationTime.Value.Month.ShouldBe(11);
file.CreationTime.Value.Day.ShouldBe(20);
var newJson = JsonSerializer.Serialize(file);
newJson.ShouldBe(json);
}
}
public abstract class AbpSystemTextJsonSerializerProvider_Datetime_Kind_Tests : AbpSystemTextJsonSerializerProvider_TestBase
{
protected DateTimeKind Kind { get; set; } = DateTimeKind.Unspecified;
[Fact]
public void Serialize_Deserialize()
{
var json = "{\"name\":\"abp\",\"creationTime\":\"2020-11-20T00:00:00\"}";
var file = JsonSerializer.Deserialize<FileWithDatetime>(json);
file.CreationTime.Kind.ShouldBe(Kind);
}
}
public class AbpSystemTextJsonSerializerProvider_Datetime_Kind_UTC_Tests : AbpSystemTextJsonSerializerProvider_Datetime_Kind_Tests
{
protected override void AfterAddApplication(IServiceCollection services)
{
Kind = DateTimeKind.Utc;
services.Configure<AbpClockOptions>(x => x.Kind = Kind);
}
}
public class AbpSystemTextJsonSerializerProvider_Datetime_Kind_Local_Tests : AbpSystemTextJsonSerializerProvider_Datetime_Kind_Tests
{
protected override void AfterAddApplication(IServiceCollection services)
{
Kind = DateTimeKind.Local;
services.Configure<AbpClockOptions>(x => x.Kind = Kind);
}
}
public class AbpSystemTextJsonSerializerProvider_Datetime_Kind_Unspecified_Tests : AbpSystemTextJsonSerializerProvider_Datetime_Kind_Tests
{
}
}

23
framework/test/Volo.Abp.MemoryDb.Tests/Volo/Abp/MemoryDb/JsonConverters/EntityJsonConverter.cs

@ -6,21 +6,28 @@ using Volo.Abp.Domain.Entities;
namespace Volo.Abp.MemoryDb.JsonConverters
{
public class EntityJsonConverter<TEntity, TKey> : JsonConverter<TEntity>
where TEntity : IEntity<TKey>
where TEntity : Entity<TKey>
{
public override TEntity Read(ref Utf8JsonReader reader, Type typeToConvert, JsonSerializerOptions options)
{
var jsonDocument = JsonDocument.ParseValue(ref reader);
var entity = (TEntity)JsonSerializer.Deserialize(jsonDocument.RootElement.GetRawText(), typeToConvert);
var idJsonElement = jsonDocument.RootElement.GetProperty(nameof(IEntity<object>.Id));
var id = JsonSerializer.Deserialize<TKey>(idJsonElement.GetRawText());
if (id != null)
if (jsonDocument.RootElement.ValueKind == JsonValueKind.Object)
{
EntityHelper.TrySetId(entity, () => id);
var entity = (TEntity)JsonSerializer.Deserialize(jsonDocument.RootElement.GetRawText(), typeToConvert);
var idJsonElement = jsonDocument.RootElement.GetProperty(nameof(Entity<object>.Id));
if (idJsonElement.ValueKind != JsonValueKind.Undefined)
{
var id = JsonSerializer.Deserialize<TKey>(idJsonElement.GetRawText());
if (id != null)
{
EntityHelper.TrySetId(entity, () => id);
}
}
return entity;
}
return entity;
throw new JsonException("RootElement's ValueKind is not Object!");
}
public override void Write(Utf8JsonWriter writer, TEntity value, JsonSerializerOptions options)

21
modules/feature-management/src/Volo.Abp.FeatureManagement.Application.Contracts/Volo/Abp/FeatureManagement/JsonConverters/SelectionStringValueItemSourceJsonConverter.cs

@ -1,5 +1,4 @@
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text.Json;
using System.Text.Json.Serialization;
@ -11,16 +10,22 @@ namespace Volo.Abp.FeatureManagement.JsonConverters
{
public override ISelectionStringValueItemSource Read(ref Utf8JsonReader reader, Type typeToConvert, JsonSerializerOptions options)
{
var newOptions = JsonSerializerOptionsHelper.Create(options, this);
var rootElement = JsonDocument.ParseValue(ref reader).RootElement;
var items = rootElement.EnumerateObject().FirstOrDefault(x => x.Name.Equals(nameof(ISelectionStringValueItemSource.Items), StringComparison.OrdinalIgnoreCase)).Value.GetRawText();
var itemsJsonProperty = rootElement.EnumerateObject().FirstOrDefault(x =>
x.Name.Equals(nameof(ISelectionStringValueItemSource.Items), StringComparison.OrdinalIgnoreCase));
if (itemsJsonProperty.Value.ValueKind == JsonValueKind.Array)
{
var newOptions = JsonSerializerOptionsHelper.Create(options, this);
var selectionStringValueItem =
JsonSerializer.Deserialize<LocalizableSelectionStringValueItem[]>(itemsJsonProperty.Value.GetRawText(), newOptions) ??
Array.Empty<LocalizableSelectionStringValueItem>();
var selectionStringValueItem =
JsonSerializer.Deserialize<List<LocalizableSelectionStringValueItem>>(items, newOptions) ??
new List<LocalizableSelectionStringValueItem>();
return new StaticSelectionStringValueItemSource(selectionStringValueItem.As<ISelectionStringValueItem[]>());
}
return new StaticSelectionStringValueItemSource(selectionStringValueItem.ToArray().As<ISelectionStringValueItem[]>());
throw new JsonException($"Can't to get the {nameof(ISelectionStringValueItemSource.Items)} property of {nameof(ISelectionStringValueItemSource)}!");
}
public override void Write(Utf8JsonWriter writer, ISelectionStringValueItemSource value, JsonSerializerOptions options)

26
modules/feature-management/src/Volo.Abp.FeatureManagement.Application.Contracts/Volo/Abp/FeatureManagement/JsonConverters/StringValueTypeJsonConverter.cs

@ -11,15 +11,25 @@ namespace Volo.Abp.FeatureManagement.JsonConverters
public override IStringValueType Read(ref Utf8JsonReader reader, Type typeToConvert, JsonSerializerOptions options)
{
var rootElement = JsonDocument.ParseValue(ref reader).RootElement;
var name = rootElement.EnumerateObject().FirstOrDefault(x => x.Name.Equals(nameof(IStringValueType.Name), StringComparison.OrdinalIgnoreCase)).Value.GetString();
var newOptions = JsonSerializerOptionsHelper.Create(options, this, new ValueValidatorJsonConverter(), new SelectionStringValueItemSourceJsonConverter());
return name switch
var nameJsonProperty = rootElement.EnumerateObject().FirstOrDefault(x => x.Name.Equals(nameof(IStringValueType.Name), StringComparison.OrdinalIgnoreCase));
if (nameJsonProperty.Value.ValueKind == JsonValueKind.String)
{
"SelectionStringValueType" => JsonSerializer.Deserialize<SelectionStringValueType>(rootElement.GetRawText(), newOptions),
"FreeTextStringValueType" => JsonSerializer.Deserialize<FreeTextStringValueType>(rootElement.GetRawText(), newOptions),
"ToggleStringValueType" => JsonSerializer.Deserialize<ToggleStringValueType>(rootElement.GetRawText(), newOptions),
_ => throw new ArgumentException($"{nameof(IStringValueType)} named {name} was not found!")
};
var name = nameJsonProperty.Value.GetString();
var newOptions = JsonSerializerOptionsHelper.Create(options, this, new ValueValidatorJsonConverter(),
new SelectionStringValueItemSourceJsonConverter());
return name switch
{
"SelectionStringValueType" => JsonSerializer.Deserialize<SelectionStringValueType>(rootElement.GetRawText(), newOptions),
"FreeTextStringValueType" => JsonSerializer.Deserialize<FreeTextStringValueType>(rootElement.GetRawText(), newOptions),
"ToggleStringValueType" => JsonSerializer.Deserialize<ToggleStringValueType>(rootElement.GetRawText(), newOptions),
_ => throw new ArgumentException($"{nameof(IStringValueType)} named {name} was not found!")
};
}
throw new JsonException($"Can't to get the {nameof(IStringValueType.Name)} property of {nameof(IStringValueType)}!");
}
public override void Write(Utf8JsonWriter writer, IStringValueType value, JsonSerializerOptions options)

27
modules/feature-management/src/Volo.Abp.FeatureManagement.Application.Contracts/Volo/Abp/FeatureManagement/JsonConverters/ValueValidatorJsonConverter.cs

@ -13,21 +13,30 @@ namespace Volo.Abp.FeatureManagement.JsonConverters
public override IValueValidator Read(ref Utf8JsonReader reader, Type typeToConvert, JsonSerializerOptions options)
{
var rootElement = JsonDocument.ParseValue(ref reader).RootElement;
var name = rootElement.EnumerateObject().FirstOrDefault(x => x.Name.Equals(nameof(IValueValidator.Name), StringComparison.OrdinalIgnoreCase)).Value.GetString();
var valueValidator = CreateValueValidatorByName(name);
var propertiesRawText = rootElement.EnumerateObject().FirstOrDefault(x => x.Name.Equals(nameof(IValueValidator.Properties), StringComparison.OrdinalIgnoreCase)).Value.GetRawText();
var newOptions = JsonSerializerOptionsHelper.Create(options, this, new ObjectToInferredTypesConverter());
var properties = JsonSerializer.Deserialize<IDictionary<string, object>>(propertiesRawText, newOptions);
if (properties != null && properties.Any())
var nameJsonProperty = rootElement.EnumerateObject().FirstOrDefault(x => x.Name.Equals(nameof(IValueValidator.Name), StringComparison.OrdinalIgnoreCase));
if (nameJsonProperty.Value.ValueKind == JsonValueKind.String)
{
foreach (var property in properties)
var valueValidator = CreateValueValidatorByName(nameJsonProperty.Value.GetString());
var propertiesJsonProperty = rootElement.EnumerateObject().FirstOrDefault(x => x.Name.Equals(nameof(IValueValidator.Properties), StringComparison.OrdinalIgnoreCase));
if (propertiesJsonProperty.Value.ValueKind == JsonValueKind.Object)
{
valueValidator.Properties[property.Key] = property.Value;
var newOptions = JsonSerializerOptionsHelper.Create(options, this, new ObjectToInferredTypesConverter());
var properties = JsonSerializer.Deserialize<IDictionary<string, object>>(propertiesJsonProperty.Value.GetRawText(), newOptions);
if (properties != null && properties.Any())
{
foreach (var property in properties)
{
valueValidator.Properties[property.Key] = property.Value;
}
}
}
return valueValidator;
}
return valueValidator;
throw new JsonException($"Can't to get the {nameof(IValueValidator.Name)} property of {nameof(IValueValidator)}!");
}
public override void Write(Utf8JsonWriter writer, IValueValidator value, JsonSerializerOptions options)

8
modules/feature-management/src/Volo.Abp.FeatureManagement.Domain/Volo/Abp/FeatureManagement/FeatureManager.cs

@ -1,4 +1,4 @@
using System;
using System;
using System.Collections.Generic;
using System.Linq;
using System.Threading.Tasks;
@ -76,16 +76,14 @@ namespace Volo.Abp.FeatureManagement
Check.NotNull(providerName, nameof(providerName));
var featureDefinitions = FeatureDefinitionManager.GetAll();
var providers = Enumerable.Reverse(Providers)
.SkipWhile(c => c.Name != providerName);
var providers = Enumerable.Reverse(Providers).SkipWhile(c => c.Name != providerName);
if (!fallback)
{
providers = providers.TakeWhile(c => c.Name == providerName);
}
var providerList = providers.Reverse().ToList();
var providerList = providers.ToList();
if (!providerList.Any())
{
return new List<FeatureNameValueWithGrantedProvider>();

11
modules/feature-management/test/Volo.Abp.FeatureManagement.Application.Tests/Volo/Abp/FeatureManagement/StringValueJsonConverter_Tests.cs

@ -60,6 +60,14 @@ namespace Volo.Abp.FeatureManagement
MinValue = 10
}
}
},
new FeatureDto
{
Provider = new FeatureProviderDto
{
Name = "FeatureName",
Key = "FeatureKey"
}
}
}
}
@ -85,6 +93,9 @@ namespace Volo.Abp.FeatureManagement
featureListDto2.Groups[0].Features[2].ValueType.Validator.ShouldBeOfType<NumericValueValidator>();
featureListDto2.Groups[0].Features[2].ValueType.Validator.As<NumericValueValidator>().MaxValue.ShouldBe(1000);
featureListDto2.Groups[0].Features[2].ValueType.Validator.As<NumericValueValidator>().MinValue.ShouldBe(10);
featureListDto2.Groups[0].Features[3].Provider.Name.ShouldBe("FeatureName");
featureListDto2.Groups[0].Features[3].Provider.Key.ShouldBe("FeatureKey");
}
}
}

43
modules/feature-management/test/Volo.Abp.FeatureManagement.Domain.Tests/Volo/Abp/FeatureManagement/FeatureManager_Tests.cs

@ -1,4 +1,5 @@
using System;
using System.Linq;
using System.Threading.Tasks;
using Shouldly;
using Volo.Abp.Features;
@ -111,5 +112,47 @@ namespace Volo.Abp.FeatureManagement
(await _featureChecker.IsEnabledAsync(TestFeatureDefinitionProvider.SocialLogins)).ShouldBeTrue();
}
}
[Fact]
public async Task Should_Get_FeatureValues_With_Provider_For_A_Provider()
{
var featureNameValueWithGrantedProviders = await _featureManager.GetAllWithProviderAsync(
EditionFeatureValueProvider.ProviderName,
TestEditionIds.Enterprise.ToString()
);
featureNameValueWithGrantedProviders.ShouldContain(x =>
x.Name == TestFeatureDefinitionProvider.SocialLogins
&& x.Value == true.ToString().ToLowerInvariant() &&
x.Provider.Name == EditionFeatureValueProvider.ProviderName);
featureNameValueWithGrantedProviders.ShouldContain(x =>
x.Name == TestFeatureDefinitionProvider.EmailSupport &&
x.Value == true.ToString().ToLowerInvariant() &&
x.Provider.Name == EditionFeatureValueProvider.ProviderName);
//Default Value
featureNameValueWithGrantedProviders.ShouldContain(x =>
x.Name == TestFeatureDefinitionProvider.DailyAnalysis &&
x.Value == false.ToString().ToLowerInvariant() &&
x.Provider.Name == DefaultValueFeatureValueProvider.ProviderName);
featureNameValueWithGrantedProviders.ShouldContain(x =>
x.Name == TestFeatureDefinitionProvider.UserCount &&
x.Value == "20" &&
x.Provider.Name == EditionFeatureValueProvider.ProviderName);
featureNameValueWithGrantedProviders.ShouldContain(x =>
x.Name == TestFeatureDefinitionProvider.ProjectCount &&
x.Value == "3" &&
x.Provider.Name == EditionFeatureValueProvider.ProviderName);
featureNameValueWithGrantedProviders.ShouldContain(x =>
x.Name == TestFeatureDefinitionProvider.BackupCount &&
x.Value == "5" &&
x.Provider.Name == EditionFeatureValueProvider.ProviderName);
}
}
}

2
modules/feature-management/test/Volo.Abp.FeatureManagement.TestBase/Volo/Abp/FeatureManagement/FeatureValueRepository_Tests.cs

@ -41,7 +41,7 @@ namespace Volo.Abp.FeatureManagement
}
[Fact]
public async Task FindAAllsync()
public async Task FindAllAsync()
{
var featureValues = await Repository.FindAllAsync(
TestFeatureDefinitionProvider.ProjectCount,

1
modules/identityserver/src/Volo.Abp.IdentityServer.EntityFrameworkCore/Volo/Abp/IdentityServer/ApiResources/ApiResourceRepository.cs

@ -22,6 +22,7 @@ namespace Volo.Abp.IdentityServer.ApiResources
{
var query = from apiResource in DbSet.IncludeDetails(includeDetails)
where apiResource.Name == apiResourceName
orderby apiResource.Id
select apiResource;
return await query.FirstOrDefaultAsync(GetCancellationToken(cancellationToken));

1
modules/identityserver/src/Volo.Abp.IdentityServer.EntityFrameworkCore/Volo/Abp/IdentityServer/ApiScopes/ApiScopeRepository.cs

@ -28,6 +28,7 @@ namespace Volo.Abp.IdentityServer.ApiScopes
{
var query = from scope in DbSet.IncludeDetails(includeDetails)
where scopeNames.Contains(scope.Name)
orderby scope.Id
select scope;
return await query.ToListAsync(GetCancellationToken(cancellationToken));

11
modules/identityserver/src/Volo.Abp.IdentityServer.EntityFrameworkCore/Volo/Abp/IdentityServer/Devices/DeviceFlowCodesRepository.cs

@ -24,16 +24,19 @@ namespace Volo.Abp.IdentityServer.Devices
CancellationToken cancellationToken = default)
{
return await DbSet
.FirstOrDefaultAsync(d => d.UserCode == userCode, GetCancellationToken(cancellationToken))
;
.Where(d => d.UserCode == userCode)
.OrderBy(d => d.Id)
.FirstOrDefaultAsync(GetCancellationToken(cancellationToken));
}
public virtual async Task<DeviceFlowCodes> FindByDeviceCodeAsync(
string deviceCode,
string deviceCode,
CancellationToken cancellationToken = default)
{
return await DbSet
.FirstOrDefaultAsync(d => d.DeviceCode == deviceCode, GetCancellationToken(cancellationToken));
.Where(d => d.DeviceCode == deviceCode)
.OrderBy(d => d.Id)
.FirstOrDefaultAsync(GetCancellationToken(cancellationToken));
}
public virtual async Task<List<DeviceFlowCodes>> GetListByExpirationAsync(DateTime maxExpirationDate, int maxResultCount,

5
modules/identityserver/src/Volo.Abp.IdentityServer.EntityFrameworkCore/Volo/Abp/IdentityServer/Grants/PersistedGrantRepository.cs

@ -29,7 +29,10 @@ namespace Volo.Abp.IdentityServer.Grants
string key,
CancellationToken cancellationToken = default)
{
return await DbSet.FirstOrDefaultAsync(x => x.Key == key, GetCancellationToken(cancellationToken));
return await DbSet
.Where(x => x.Key == key)
.OrderBy(x => x.Id)
.FirstOrDefaultAsync(GetCancellationToken(cancellationToken));
}
public virtual async Task<List<PersistedGrant>> GetListBySubjectIdAsync(

1
modules/identityserver/src/Volo.Abp.IdentityServer.EntityFrameworkCore/Volo/Abp/IdentityServer/IdentityResources/IdentityResourceRepository.cs

@ -57,6 +57,7 @@ namespace Volo.Abp.IdentityServer.IdentityResources
return await DbSet
.IncludeDetails(includeDetails)
.Where(x => x.Name == name)
.OrderBy(x => x.Id)
.FirstOrDefaultAsync(GetCancellationToken(cancellationToken));
}

1
modules/identityserver/src/Volo.Abp.IdentityServer.MongoDB/Volo/Abp/IdentityServer/MongoDB/MongoApiResourceRepository.cs

@ -23,6 +23,7 @@ namespace Volo.Abp.IdentityServer.MongoDB
{
return await GetMongoQueryable()
.Where(ar => ar.Name == apiResourceName)
.OrderBy(ar => ar.Id)
.FirstOrDefaultAsync(GetCancellationToken(cancellationToken));
}

6
modules/identityserver/src/Volo.Abp.IdentityServer.MongoDB/Volo/Abp/IdentityServer/MongoDB/MongoApiScopeRepository.cs

@ -22,7 +22,10 @@ namespace Volo.Abp.IdentityServer.MongoDB
public async Task<ApiScope> GetByNameAsync(string scopeName, bool includeDetails = true, CancellationToken cancellationToken = default)
{
return await GetMongoQueryable().FirstOrDefaultAsync(x => x.Name == scopeName, GetCancellationToken(cancellationToken));
return await GetMongoQueryable()
.Where(x => x.Name == scopeName)
.OrderBy(x => x.Id)
.FirstOrDefaultAsync(GetCancellationToken(cancellationToken));
}
public async Task<List<ApiScope>> GetListByNameAsync(string[] scopeNames, bool includeDetails = false,
@ -30,6 +33,7 @@ namespace Volo.Abp.IdentityServer.MongoDB
{
var query = from scope in GetMongoQueryable()
where scopeNames.Contains(scope.Name)
orderby scope.Id
select scope;
return await query.ToListAsync(GetCancellationToken(cancellationToken));

5
modules/identityserver/src/Volo.Abp.IdentityServer.MongoDB/Volo/Abp/IdentityServer/MongoDB/MongoClientRepository.cs

@ -26,7 +26,10 @@ namespace Volo.Abp.IdentityServer.MongoDB
bool includeDetails = true,
CancellationToken cancellationToken = default)
{
return await GetMongoQueryable().FirstOrDefaultAsync(x => x.ClientId == clientId, GetCancellationToken(cancellationToken));
return await GetMongoQueryable()
.Where(x => x.ClientId == clientId)
.OrderBy(x => x.Id)
.FirstOrDefaultAsync(GetCancellationToken(cancellationToken));
}
public virtual async Task<List<Client>> GetListAsync(

13
modules/identityserver/src/Volo.Abp.IdentityServer.MongoDB/Volo/Abp/IdentityServer/MongoDB/MongoDeviceFlowCodesRepository.cs

@ -24,18 +24,21 @@ namespace Volo.Abp.IdentityServer.MongoDB
CancellationToken cancellationToken = default)
{
return await GetMongoQueryable()
.FirstOrDefaultAsync(d => d.UserCode == userCode, GetCancellationToken(cancellationToken))
;
.Where(d => d.UserCode == userCode)
.OrderBy(x => x.Id)
.FirstOrDefaultAsync(GetCancellationToken(cancellationToken));
}
public virtual async Task<DeviceFlowCodes> FindByDeviceCodeAsync(string deviceCode, CancellationToken cancellationToken = default)
{
return await GetMongoQueryable()
.FirstOrDefaultAsync(d => d.DeviceCode == deviceCode, GetCancellationToken(cancellationToken));
.Where(d => d.DeviceCode == deviceCode)
.OrderBy(x => x.Id)
.FirstOrDefaultAsync(GetCancellationToken(cancellationToken));
}
public virtual async Task<List<DeviceFlowCodes>> GetListByExpirationAsync(
DateTime maxExpirationDate,
DateTime maxExpirationDate,
int maxResultCount,
CancellationToken cancellationToken = default)
{
@ -46,4 +49,4 @@ namespace Volo.Abp.IdentityServer.MongoDB
.ToListAsync(GetCancellationToken(cancellationToken));
}
}
}
}

1
modules/identityserver/src/Volo.Abp.IdentityServer.MongoDB/Volo/Abp/IdentityServer/MongoDB/MongoIdentityResourceRepository.cs

@ -37,6 +37,7 @@ namespace Volo.Abp.IdentityServer.MongoDB
{
return await GetMongoQueryable()
.Where(x => x.Name == name)
.OrderBy(x => x.Id)
.FirstOrDefaultAsync(GetCancellationToken(cancellationToken));
}

7
modules/identityserver/src/Volo.Abp.IdentityServer.MongoDB/Volo/Abp/IdentityServer/MongoDB/MongoPersistedGrantRepository.cs

@ -1,4 +1,4 @@
using System;
using System;
using System.Collections.Generic;
using System.Linq;
using System.Threading;
@ -27,9 +27,10 @@ namespace Volo.Abp.IdentityServer.MongoDB
public virtual async Task<PersistedGrant> FindByKeyAsync(string key, CancellationToken cancellationToken = default)
{
return await GetMongoQueryable()
.FirstOrDefaultAsync(x => x.Key == key, GetCancellationToken(cancellationToken));
.Where(x => x.Key == key)
.OrderBy(x => x.Id)
.FirstOrDefaultAsync(GetCancellationToken(cancellationToken));
}
public virtual async Task<List<PersistedGrant>> GetListBySubjectIdAsync(string subjectId, CancellationToken cancellationToken = default)

Loading…
Cancel
Save