1010using System . Threading ;
1111using System . Threading . Tasks ;
1212using Csla . Core ;
13+ using Csla . DataPortalClient ;
1314using Csla . Runtime ;
1415using Csla . Server ;
1516using 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