Skip to content

Commit 384da1f

Browse files
Merge pull request #3546 from swegele/LocalProxy_InheritFromDataPortalProxy_2861
Normalize LocalProxy by subclassing DataPortalProxy #2861
2 parents 403098d + 004928a commit 384da1f

2 files changed

Lines changed: 147 additions & 15 deletions

File tree

Source/Csla/DataPortalClient/DataPortalProxy.cs

Lines changed: 60 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -100,6 +100,13 @@ public async virtual Task<DataPortalResult> Create(Type objectType, object crite
100100
{
101101
result = new DataPortalResult(ApplicationContext, null, ex);
102102
}
103+
104+
var operation = DataPortalOperations.Create;
105+
OnServerComplete(result, objectType, operation);
106+
107+
if (ExecutionIsNotOnLogicalOrPhysicalServer)
108+
OnServerCompleteClient(result, objectType, operation);
109+
103110
if (result.Error != null)
104111
throw result.Error;
105112
return result;
@@ -154,6 +161,13 @@ public async virtual Task<DataPortalResult> Fetch(Type objectType, object criter
154161
{
155162
result = new DataPortalResult(ApplicationContext, null, ex);
156163
}
164+
165+
var operation = DataPortalOperations.Fetch;
166+
OnServerComplete(result, objectType, operation);
167+
168+
if (ExecutionIsNotOnLogicalOrPhysicalServer)
169+
OnServerCompleteClient(result, objectType, operation);
170+
157171
if (result.Error != null)
158172
throw result.Error;
159173
return result;
@@ -202,6 +216,13 @@ public async virtual Task<DataPortalResult> Update(object obj, DataPortalContext
202216
{
203217
result = new DataPortalResult(ApplicationContext, null, ex);
204218
}
219+
220+
var operation = DataPortalOperations.Update;
221+
OnServerComplete(result, obj.GetType(), operation);
222+
223+
if (ExecutionIsNotOnLogicalOrPhysicalServer)
224+
OnServerCompleteClient(result, obj.GetType(), operation);
225+
205226
if (result.Error != null)
206227
throw result.Error;
207228
return result;
@@ -256,6 +277,13 @@ public async virtual Task<DataPortalResult> Delete(Type objectType, object crite
256277
{
257278
result = new DataPortalResult(ApplicationContext, null, ex);
258279
}
280+
281+
var operation = DataPortalOperations.Delete;
282+
OnServerComplete(result, objectType, operation);
283+
284+
if (ExecutionIsNotOnLogicalOrPhysicalServer)
285+
OnServerCompleteClient(result, objectType, operation);
286+
259287
if (result.Error != null)
260288
throw result.Error;
261289
return result;
@@ -311,6 +339,38 @@ private string GetRoutingToken(Type objectType)
311339
return result;
312340
}
313341

342+
/// <summary>
343+
/// Called after completion of DataPortal operation regardless if operation was originated from the client or from chained calls on the server side.
344+
/// </summary>
345+
/// <param name="result">Result from DataPortal operation.</param>
346+
/// <param name="objectType">Type of business object.</param>
347+
/// <param name="operationType">The requested data portal operation type</param>
348+
protected virtual void OnServerComplete(DataPortalResult result, Type objectType, DataPortalOperations operationType)
349+
{
350+
351+
}
352+
353+
/// <summary>
354+
/// Called after completion of a DataPortal operation which was initiated from the <see cref="ApplicationContext.ExecutionLocations.Client"/>
355+
/// This is NOT called on completion of chained DataPortal operations initiated on the server side.
356+
/// </summary>
357+
/// <param name="result">Result from DataPortal operation.</param>
358+
/// <param name="objectType">Type of business object.</param>
359+
/// <param name="operationType">The requested data portal operation type</param>
360+
protected virtual void OnServerCompleteClient(DataPortalResult result, Type objectType, DataPortalOperations operationType)
361+
{
362+
363+
}
364+
365+
internal bool ExecutionIsNotOnLogicalOrPhysicalServer
366+
{
367+
get
368+
{
369+
return ApplicationContext.LogicalExecutionLocation != ApplicationContext.LogicalExecutionLocations.Server
370+
&& ApplicationContext.ExecutionLocation != ApplicationContext.ExecutionLocations.Server;
371+
}
372+
}
373+
314374
#region Criteria
315375

316376
private CriteriaRequest GetBaseCriteriaRequest()

Source/Csla/DataPortalClient/LocalProxy.cs

Lines changed: 87 additions & 15 deletions
Original file line numberDiff line numberDiff line change
@@ -10,6 +10,7 @@
1010
using System.Threading;
1111
using System.Threading.Tasks;
1212
using Csla.Core;
13+
using Csla.DataPortalClient;
1314
using Csla.Runtime;
1415
using Csla.Server;
1516
using Microsoft.Extensions.DependencyInjection;
@@ -21,16 +22,16 @@ namespace Csla.Channels.Local
2122
/// calls to an application server hosted locally
2223
/// in the client process and AppDomain.
2324
/// </summary>
24-
public class LocalProxy : DataPortalClient.IDataPortalProxy
25+
public class LocalProxy : DataPortalProxy
2526
{
2627
/// <summary>
2728
/// Creates an instance of the type
2829
/// </summary>
2930
/// <param name="applicationContext">ApplicationContext</param>
3031
/// <param name="options">Options instance</param>
3132
public LocalProxy(ApplicationContext applicationContext, LocalProxyOptions options)
33+
: base(applicationContext)
3234
{
33-
OriginalApplicationContext = applicationContext;
3435
Options = options;
3536
}
3637

@@ -57,13 +58,27 @@ private void InitializeContext()
5758
_portal = currentServiceProvider.GetRequiredService<Server.IDataPortalServer>();
5859
}
5960

60-
private ApplicationContext OriginalApplicationContext { get; set; }
61-
private ApplicationContext CurrentApplicationContext { get; set; }
62-
private readonly LocalProxyOptions Options;
61+
/// <summary>
62+
/// Application Context supplied in CTOR. If this LocalProxy was created on client side or
63+
/// if <see cref="LocalProxyOptions.UseLocalScope"/> is false then it is the client ApplicationContext
64+
/// </summary>
65+
protected ApplicationContext OriginalApplicationContext {
66+
get { return base.ApplicationContext; }
67+
}
68+
69+
/// <summary>
70+
/// ApplicationContext currently in use for this proxy.
71+
/// If <see cref="LocalProxyOptions.UseLocalScope"/> is true, this is the ApplicationContext created in a new scope for
72+
/// logical server side data portal operations.
73+
/// If <see cref="LocalProxyOptions.UseLocalScope"/> is false, this is same as <see cref="OriginalApplicationContext"/>
74+
/// </summary>
75+
protected ApplicationContext CurrentApplicationContext { get; set; }
6376

77+
private readonly LocalProxyOptions Options;
6478
private IServiceScope _scope;
6579
private Server.IDataPortalServer _portal;
6680

81+
6782
private void SetApplicationContext(object obj, ApplicationContext applicationContext)
6883
{
6984
// if there's no isolated scope, there's no reason to
@@ -81,14 +96,14 @@ private void SetApplicationContext(IUseApplicationContext useApplicationContext,
8196
// change the object graph's ApplicationContext
8297
if (!Options.UseLocalScope)
8398
return;
84-
99+
85100
if (useApplicationContext != null && !ReferenceEquals(useApplicationContext.ApplicationContext, applicationContext))
86101
{
87102
useApplicationContext.ApplicationContext = applicationContext;
88103

89104
if (useApplicationContext is IUseFieldManager useFieldManager)
90105
SetApplicationContext(useFieldManager.FieldManager, applicationContext);
91-
106+
92107
if (useApplicationContext is IUseBusinessRules useBusinessRules)
93108
SetApplicationContext(useBusinessRules.BusinessRules, applicationContext);
94109

@@ -97,10 +112,10 @@ private void SetApplicationContext(IUseApplicationContext useApplicationContext,
97112
foreach (var managedProperty in target.GetManagedProperties())
98113
{
99114
var isLazyLoadedProperty = (managedProperty.RelationshipType & RelationshipTypes.LazyLoad) == RelationshipTypes.LazyLoad;
100-
115+
101116
//only dig into property if its not a lazy loaded property
102117
// or if it is, then only if its loaded
103-
if (!isLazyLoadedProperty
118+
if (!isLazyLoadedProperty
104119
|| (isLazyLoadedProperty && target.FieldExists(managedProperty)))
105120
{
106121
if (typeof(IUseApplicationContext).IsAssignableFrom(managedProperty.Type))
@@ -143,7 +158,15 @@ private void SetApplicationContext(IUseApplicationContext useApplicationContext,
143158
private void ResetApplicationContext()
144159
{
145160
if (Options.UseLocalScope)
161+
{
162+
if (CurrentApplicationContext is not null
163+
&& CurrentApplicationContext.LogicalExecutionLocation == ApplicationContext.LogicalExecutionLocations.Client)
164+
{
165+
RestoringClientSideApplicationContext(CurrentApplicationContext, OriginalApplicationContext);
166+
}
167+
146168
CurrentApplicationContext.ApplicationContextAccessor = OriginalApplicationContext.ApplicationContextAccessor;
169+
}
147170
}
148171

149172
private async Task DisposeScope()
@@ -164,7 +187,7 @@ private async Task DisposeScope()
164187
/// <see cref="Server.DataPortalContext" /> object passed to the server.
165188
/// </param>
166189
/// <param name="isSync">True if the client-side proxy should synchronously invoke the server.</param>
167-
public async Task<DataPortalResult> Create(
190+
public override async Task<DataPortalResult> Create(
168191
Type objectType, object criteria, DataPortalContext context, bool isSync)
169192
{
170193
DataPortalResult result;
@@ -192,6 +215,13 @@ public async Task<DataPortalResult> Create(
192215
{
193216
await DisposeScope();
194217
}
218+
219+
var operation = DataPortalOperations.Create;
220+
OnServerComplete(result, objectType, operation);
221+
222+
if (ExecutionIsNotOnLogicalOrPhysicalServer)
223+
OnServerCompleteClient(result, objectType, operation);
224+
195225
return result;
196226
}
197227

@@ -205,7 +235,7 @@ public async Task<DataPortalResult> Create(
205235
/// <see cref="Server.DataPortalContext" /> object passed to the server.
206236
/// </param>
207237
/// <param name="isSync">True if the client-side proxy should synchronously invoke the server.</param>
208-
public async Task<DataPortalResult> Fetch(Type objectType, object criteria, DataPortalContext context, bool isSync)
238+
public override async Task<DataPortalResult> Fetch(Type objectType, object criteria, DataPortalContext context, bool isSync)
209239
{
210240
DataPortalResult result;
211241
try
@@ -232,6 +262,13 @@ public async Task<DataPortalResult> Fetch(Type objectType, object criteria, Data
232262
{
233263
await DisposeScope();
234264
}
265+
266+
var operation = DataPortalOperations.Fetch;
267+
OnServerComplete(result, objectType, operation);
268+
269+
if (ExecutionIsNotOnLogicalOrPhysicalServer)
270+
OnServerCompleteClient(result, objectType, operation);
271+
235272
return result;
236273
}
237274

@@ -244,7 +281,7 @@ public async Task<DataPortalResult> Fetch(Type objectType, object criteria, Data
244281
/// <see cref="Server.DataPortalContext" /> object passed to the server.
245282
/// </param>
246283
/// <param name="isSync">True if the client-side proxy should synchronously invoke the server.</param>
247-
public async Task<DataPortalResult> Update(object obj, DataPortalContext context, bool isSync)
284+
public override async Task<DataPortalResult> Update(object obj, DataPortalContext context, bool isSync)
248285
{
249286
DataPortalResult result;
250287
try
@@ -271,6 +308,13 @@ public async Task<DataPortalResult> Update(object obj, DataPortalContext context
271308
{
272309
await DisposeScope();
273310
}
311+
312+
var operation = DataPortalOperations.Update;
313+
OnServerComplete(result, obj.GetType(), operation);
314+
315+
if (ExecutionIsNotOnLogicalOrPhysicalServer)
316+
OnServerCompleteClient(result, obj.GetType(), operation);
317+
274318
return result;
275319
}
276320

@@ -284,7 +328,7 @@ public async Task<DataPortalResult> Update(object obj, DataPortalContext context
284328
/// <see cref="Server.DataPortalContext" /> object passed to the server.
285329
/// </param>
286330
/// <param name="isSync">True if the client-side proxy should synchronously invoke the server.</param>
287-
public async Task<DataPortalResult> Delete(Type objectType, object criteria, DataPortalContext context, bool isSync)
331+
public override async Task<DataPortalResult> Delete(Type objectType, object criteria, DataPortalContext context, bool isSync)
288332
{
289333
DataPortalResult result;
290334
try
@@ -311,17 +355,45 @@ public async Task<DataPortalResult> Delete(Type objectType, object criteria, Dat
311355
{
312356
await DisposeScope();
313357
}
358+
359+
var operation = DataPortalOperations.Delete;
360+
OnServerComplete(result, objectType, operation);
361+
362+
if (ExecutionIsNotOnLogicalOrPhysicalServer)
363+
OnServerCompleteClient(result, objectType, operation);
364+
314365
return result;
315366
}
316367

368+
/// <summary>
369+
/// Not needed/implemented for Local Data Portal - throws not implemented exception
370+
/// </summary>
371+
/// <param name="serialized">Serialised request</param>
372+
/// <param name="operation">DataPortal operation</param>
373+
/// <param name="routingToken">Routing Tag for server</param>
374+
/// <param name="isSync">True if the client-side proxy should synchronously invoke the server.</param>
375+
/// <returns>Serialised response from server</returns>
376+
protected override Task<byte[]> CallDataPortalServer(byte[] serialized, string operation, string routingToken, bool isSync)
377+
{
378+
throw new NotImplementedException();
379+
}
380+
317381
/// <summary>
318382
/// Gets a value indicating whether this proxy will invoke
319383
/// a remote data portal server, or run the "server-side"
320384
/// data portal in the caller's process and AppDomain.
321385
/// </summary>
322-
public bool IsServerRemote
386+
public override bool IsServerRemote => false;
387+
388+
/// <summary>
389+
/// Method called once when execution returns to <see cref="ApplicationContext.LogicalExecutionLocations.Client"/> after a call to
390+
/// the dataportal. Only called when <see cref="LocalProxyOptions.UseLocalScope"/> is true.
391+
/// </summary>
392+
/// <param name="serverScopedApplicationContext">Context created in a new scope for use during logical server side operations</param>
393+
/// <param name="clientSideApplicationContext">Original context from the client side</param>
394+
protected virtual void RestoringClientSideApplicationContext(ApplicationContext serverScopedApplicationContext, ApplicationContext clientSideApplicationContext)
323395
{
324-
get { return false; }
396+
325397
}
326398
}
327399
}

0 commit comments

Comments
 (0)