Skip to content

Commit 3167f39

Browse files
AllowAsyncOverSync option (#399)
1 parent 651b579 commit 3167f39

5 files changed

Lines changed: 60 additions & 31 deletions

File tree

net/DevExtreme.AspNet.Data.Tests/AsyncAdapterTests.cs

Lines changed: 11 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -21,6 +21,17 @@ public async Task NotSupported() {
2121
Assert.True(error is NotSupportedException);
2222
}
2323

24+
[Fact]
25+
public async Task AllowAsyncOverSync() {
26+
var error = await Record.ExceptionAsync(async delegate {
27+
await DataSourceLoader.LoadAsync(SAMPLE_DATA, new SampleLoadOptions {
28+
AllowAsyncOverSync = true
29+
});
30+
});
31+
32+
Assert.Null(error);
33+
}
34+
2435
[Fact]
2536
public async Task Canceled() {
2637
var token = new CancellationToken(true);

net/DevExtreme.AspNet.Data/Async/ReflectionAsyncAdapter.cs

Lines changed: 20 additions & 27 deletions
Original file line numberDiff line numberDiff line change
@@ -9,62 +9,55 @@
99
namespace DevExtreme.AspNet.Data.Async {
1010

1111
class ReflectionAsyncAdapter : IAsyncAdapter {
12-
QueryProviderInfo _providerInfo;
12+
readonly QueryProviderInfo _providerInfo;
13+
14+
public static bool SupportsProvider(QueryProviderInfo providerInfo)
15+
=> providerInfo.IsEFCore
16+
|| IsEF6(providerInfo)
17+
|| providerInfo.IsNH
18+
|| providerInfo.IsXPO;
19+
20+
static bool IsEF6(QueryProviderInfo providerInfo)
21+
=> providerInfo.IsEFClassic && providerInfo.Version.Major >= 6;
1322

1423
public ReflectionAsyncAdapter(QueryProviderInfo providerInfo) {
1524
_providerInfo = providerInfo;
1625
}
1726

18-
bool IsEF6 => _providerInfo.IsEFClassic && _providerInfo.Version.Major >= 6;
19-
bool IsEFCore => _providerInfo.IsEFCore;
20-
bool IsNH => _providerInfo.IsNH;
21-
bool IsXPO => _providerInfo.IsXPO;
22-
2327
public Task<int> CountAsync(IQueryProvider provider, Expression expr, CancellationToken cancellationToken) {
2428
MethodInfo GetCountAsyncMethod() {
25-
if(IsEFCore)
29+
if(_providerInfo.IsEFCore)
2630
return EFCoreMethods.CountAsyncMethod;
2731

28-
if(IsEF6)
32+
if(IsEF6(_providerInfo))
2933
return EF6Methods.CountAsyncMethod;
3034

31-
if(IsNH)
35+
if(_providerInfo.IsNH)
3236
return NHMethods.CountAsyncMethod;
3337

34-
if(IsXPO)
38+
if(_providerInfo.IsXPO)
3539
return XpoMethods.CountAsyncMethod;
3640

37-
throw ProviderNotSupported(provider);
41+
throw new NotSupportedException();
3842
}
3943

4044
return InvokeCountAsync(GetCountAsyncMethod(), provider, expr, cancellationToken);
4145
}
4246

4347
public Task<IEnumerable<T>> ToEnumerableAsync<T>(IQueryProvider provider, Expression expr, CancellationToken cancellationToken) {
44-
if(IsEFCore)
48+
if(_providerInfo.IsEFCore)
4549
return InvokeToListAsync<T>(EFCoreMethods.ToListAsyncMethod, provider, expr, cancellationToken);
4650

47-
if(IsEF6)
51+
if(IsEF6(_providerInfo))
4852
return InvokeToListAsync<T>(EF6Methods.ToListAsyncMethod, provider, expr, cancellationToken);
4953

50-
if(IsNH)
54+
if(_providerInfo.IsNH)
5155
return InvokeToListAsync<T>(NHMethods.ToListAsyncMethod, provider, expr, cancellationToken);
5256

53-
if(IsXPO)
57+
if(_providerInfo.IsXPO)
5458
return InvokeToArrayAsync<T>(XpoMethods.ToArrayAsyncMethod, provider, expr, cancellationToken);
5559

56-
throw ProviderNotSupported(provider);
57-
}
58-
59-
static Exception ProviderNotSupported(IQueryProvider provider) {
60-
var providerType = provider.GetType();
61-
if(providerType.IsGenericType)
62-
providerType = providerType.GetGenericTypeDefinition();
63-
64-
var message = $"Async operations for the LINQ provider '{providerType.FullName}' are not supported."
65-
+ $" You can implement a custom async adapter ({typeof(IAsyncAdapter).FullName}) and register it via '{typeof(CustomAsyncAdapters).FullName}.{nameof(CustomAsyncAdapters.RegisterAdapter)}'.";
66-
67-
return new NotSupportedException(message);
60+
throw new NotSupportedException();
6861
}
6962

7063
static class EF6Methods {

net/DevExtreme.AspNet.Data/DataSourceLoadOptionsBase.cs

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -110,6 +110,8 @@ public class DataSourceLoadOptionsBase {
110110
/// </summary>
111111
public bool? PaginateViaPrimaryKey { get; set; }
112112

113+
public bool AllowAsyncOverSync { get; set; }
114+
113115
#if DEBUG
114116
internal Action<Expression> ExpressionWatcher;
115117
internal bool UseEnumerableOnce;

net/DevExtreme.AspNet.Data/DataSourceLoaderImpl.cs

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -30,7 +30,7 @@ public DataSourceLoaderImpl(IQueryable source, DataSourceLoadOptionsBase options
3030

3131
Source = source;
3232
Context = new DataSourceLoadContext(options, providerInfo, Source.ElementType);
33-
CreateExecutor = expr => new ExpressionExecutor(Source.Provider, expr, providerInfo, cancellationToken, sync);
33+
CreateExecutor = expr => new ExpressionExecutor(Source.Provider, expr, providerInfo, cancellationToken, sync, options.AllowAsyncOverSync);
3434

3535
#if DEBUG
3636
ExpressionWatcher = options.ExpressionWatcher;

net/DevExtreme.AspNet.Data/ExpressionExecutor.cs

Lines changed: 26 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -15,14 +15,16 @@ class ExpressionExecutor {
1515
readonly QueryProviderInfo ProviderInfo;
1616
readonly CancellationToken CancellationToken;
1717
readonly bool Sync;
18+
readonly bool AllowAsyncOverSync;
1819

19-
public ExpressionExecutor(IQueryProvider provider, Expression expr, QueryProviderInfo providerInfo, CancellationToken cancellationToken, bool sync) {
20+
public ExpressionExecutor(IQueryProvider provider, Expression expr, QueryProviderInfo providerInfo, CancellationToken cancellationToken, bool sync, bool allowAsyncOverSync) {
2021
Provider = provider;
2122
Expr = expr;
2223

2324
ProviderInfo = providerInfo;
2425
CancellationToken = cancellationToken;
2526
Sync = sync;
27+
AllowAsyncOverSync = allowAsyncOverSync;
2628
}
2729

2830
public void BreakQueryableChain() {
@@ -64,8 +66,29 @@ IAsyncAdapter CreateAsyncAdapter() {
6466
if(Sync)
6567
return AsyncOverSyncAdapter.Instance;
6668

67-
return CustomAsyncAdapters.GetAdapter(Provider.GetType())
68-
?? new ReflectionAsyncAdapter(ProviderInfo);
69+
var providerType = Provider.GetType();
70+
71+
var customAdapter = CustomAsyncAdapters.GetAdapter(providerType);
72+
if(customAdapter != null)
73+
return customAdapter;
74+
75+
if(ReflectionAsyncAdapter.SupportsProvider(ProviderInfo))
76+
return new ReflectionAsyncAdapter(ProviderInfo);
77+
78+
if(AllowAsyncOverSync)
79+
return AsyncOverSyncAdapter.Instance;
80+
81+
throw ProviderNotSupported(providerType);
82+
}
83+
84+
static Exception ProviderNotSupported(Type providerType) {
85+
if(providerType.IsGenericType)
86+
providerType = providerType.GetGenericTypeDefinition();
87+
88+
var message = $"Async operations for the LINQ provider '{providerType.FullName}' are not supported."
89+
+ $" You can implement a custom async adapter ({typeof(IAsyncAdapter).FullName}) and register it via '{typeof(CustomAsyncAdapters).FullName}.{nameof(CustomAsyncAdapters.RegisterAdapter)}'.";
90+
91+
return new NotSupportedException(message);
6992
}
7093

7194
}

0 commit comments

Comments
 (0)