CSLA.NET 6.0.0
CSLA .NET is a software development framework that helps you build a reusable, maintainable object-oriented business layer for your app.
LocalProxy.cs
Go to the documentation of this file.
1//-----------------------------------------------------------------------
2// <copyright file="LocalProxy.cs" company="Marimer LLC">
3// Copyright (c) Marimer LLC. All rights reserved.
4// Website: https://cslanet.com
5// </copyright>
6// <summary>Implements a data portal proxy to relay data portal</summary>
7//-----------------------------------------------------------------------
8using System;
9using System.Collections;
10using System.Threading;
11using System.Threading.Tasks;
12using Csla.Core;
13using Csla.Runtime;
14using Csla.Server;
16
17namespace Csla.Channels.Local
18{
24 public class LocalProxy : DataPortalClient.IDataPortalProxy, IDisposable
25 {
31 public LocalProxy(ApplicationContext applicationContext, LocalProxyOptions options)
32 {
33 OriginalApplicationContext = applicationContext;
34 var currentServiceProvider = OriginalApplicationContext.CurrentServiceProvider;
35 Options = options;
36
37 if (Options.UseLocalScope
38 && OriginalApplicationContext.LogicalExecutionLocation == ApplicationContext.LogicalExecutionLocations.Client
39 && OriginalApplicationContext.IsAStatefulContextManager)
40 {
41 // create new DI scope and provider
42 _scope = OriginalApplicationContext.CurrentServiceProvider.CreateScope();
43 currentServiceProvider = _scope.ServiceProvider;
44
45 // set runtime info to reflect that we're in a logical server-side
46 // data portal operation, so this "runtime" is stateless and
47 // we can't count on HttpContext
48 var runtimeInfo = currentServiceProvider.GetRequiredService<IRuntimeInfo>();
49 runtimeInfo.LocalProxyNewScopeExists = true;
50 }
51
52 CurrentApplicationContext = currentServiceProvider.GetRequiredService<ApplicationContext>();
53 _portal = currentServiceProvider.GetRequiredService<Server.IDataPortalServer>();
54 }
55
56 private ApplicationContext OriginalApplicationContext { get; set; }
57 private ApplicationContext CurrentApplicationContext { get; set; }
58 private readonly LocalProxyOptions Options;
59
60 private readonly IServiceScope _scope;
61 private readonly Server.IDataPortalServer _portal;
62 private bool disposedValue;
63
64 private void SetApplicationContext(object obj, ApplicationContext applicationContext)
65 {
66 // if there's no isolated scope, there's no reason to
67 // change the object graph's ApplicationContext
68 if (!Options.UseLocalScope)
69 return;
70
71 if (obj is IUseApplicationContext useApplicationContext)
72 SetApplicationContext(useApplicationContext, applicationContext);
73 }
74
75 private void SetApplicationContext(IUseApplicationContext useApplicationContext, ApplicationContext applicationContext)
76 {
77 // if there's no isolated scope, there's no reason to
78 // change the object graph's ApplicationContext
79 if (!Options.UseLocalScope)
80 return;
81
82 if (useApplicationContext != null && !ReferenceEquals(useApplicationContext.ApplicationContext, applicationContext))
83 {
84 useApplicationContext.ApplicationContext = applicationContext;
85
86 if (useApplicationContext is IUseFieldManager useFieldManager)
87 SetApplicationContext(useFieldManager.FieldManager, applicationContext);
88
89 if (useApplicationContext is IUseBusinessRules useBusinessRules)
90 SetApplicationContext(useBusinessRules.BusinessRules, applicationContext);
91
92 if (useApplicationContext is IManageProperties target)
93 {
94 foreach (var managedProperty in target.GetManagedProperties())
95 {
96 var isLazyLoadedProperty = (managedProperty.RelationshipType & RelationshipTypes.LazyLoad) == RelationshipTypes.LazyLoad;
97
98 //only dig into property if its not a lazy loaded property
99 // or if it is, then only if its loaded
100 if (!isLazyLoadedProperty
101 || (isLazyLoadedProperty && target.FieldExists(managedProperty)))
102 {
103 if (typeof(IUseApplicationContext).IsAssignableFrom(managedProperty.Type))
104 {
105 //property is directly assignable to the IUseApplicationContext so set it
106 SetApplicationContext((IUseApplicationContext)target.ReadProperty(managedProperty), applicationContext);
107 }
108 else if (typeof(IEnumerable).IsAssignableFrom(managedProperty.Type))
109 {
110 //property is a list and needs to be processed (could be a Csla.Core.MobileList or something like that)
111 var enumerable = (IEnumerable)target.ReadProperty(managedProperty);
112 if (enumerable != null)
113 {
114 foreach (var item in enumerable)
115 {
116 SetApplicationContext(item, applicationContext);
117 }
118 }
119 }
120 }
121 }
122 }
123
124 if (useApplicationContext is IContainsDeletedList containsDeletedList)
125 foreach (var item in containsDeletedList.DeletedList)
126 SetApplicationContext(item, applicationContext);
127
128 if (useApplicationContext is IEnumerable list)
129 foreach (var item in list)
130 SetApplicationContext(item, applicationContext);
131 }
132 }
133
140 private void ResetApplicationContext()
141 {
142 if (Options.UseLocalScope)
143 CurrentApplicationContext.ApplicationContextAccessor = OriginalApplicationContext.ApplicationContextAccessor;
144 }
145
156 public async Task<DataPortalResult> Create(
157 Type objectType, object criteria, DataPortalContext context, bool isSync)
158 {
159 DataPortalResult result;
160 SetApplicationContext(criteria, CurrentApplicationContext);
161 if (isSync || OriginalApplicationContext.LogicalExecutionLocation == ApplicationContext.LogicalExecutionLocations.Server)
162 {
163 result = await _portal.Create(objectType, criteria, context, isSync);
164 }
165 else
166 {
167 if (!Options.FlowSynchronizationContext || SynchronizationContext.Current == null)
168 result = await Task.Run(() => this._portal.Create(objectType, criteria, context, isSync));
169 else
170 result = await await Task.Factory.StartNew(() => this._portal.Create(objectType, criteria, context, isSync),
171 CancellationToken.None,
172 TaskCreationOptions.None,
173 TaskScheduler.FromCurrentSynchronizationContext());
174 }
175 ResetApplicationContext();
176 return result;
177 }
178
189 public async Task<DataPortalResult> Fetch(Type objectType, object criteria, DataPortalContext context, bool isSync)
190 {
191 DataPortalResult result;
192 SetApplicationContext(criteria, CurrentApplicationContext);
193 if (isSync || OriginalApplicationContext.LogicalExecutionLocation == ApplicationContext.LogicalExecutionLocations.Server)
194 {
195 result = await _portal.Fetch(objectType, criteria, context, isSync);
196 }
197 else
198 {
199 if (!Options.FlowSynchronizationContext || SynchronizationContext.Current == null)
200 result = await Task.Run(() => this._portal.Fetch(objectType, criteria, context, isSync));
201 else
202 result = await await Task.Factory.StartNew(() => this._portal.Fetch(objectType, criteria, context, isSync),
203 CancellationToken.None,
204 TaskCreationOptions.None,
205 TaskScheduler.FromCurrentSynchronizationContext());
206 }
207 ResetApplicationContext();
208 return result;
209 }
210
220 public async Task<DataPortalResult> Update(object obj, DataPortalContext context, bool isSync)
221 {
222 DataPortalResult result;
223 SetApplicationContext(obj, CurrentApplicationContext);
224 if (isSync || OriginalApplicationContext.LogicalExecutionLocation == ApplicationContext.LogicalExecutionLocations.Server)
225 {
226 result = await _portal.Update(obj, context, isSync);
227 }
228 else
229 {
230 if (!Options.FlowSynchronizationContext || SynchronizationContext.Current == null)
231 result = await Task.Run(() => this._portal.Update(obj, context, isSync));
232 else
233 result = await await Task.Factory.StartNew(() => this._portal.Update(obj, context, isSync),
234 CancellationToken.None,
235 TaskCreationOptions.None,
236 TaskScheduler.FromCurrentSynchronizationContext());
237 }
238 ResetApplicationContext();
239 return result;
240 }
241
252 public async Task<DataPortalResult> Delete(Type objectType, object criteria, DataPortalContext context, bool isSync)
253 {
254 DataPortalResult result;
255 SetApplicationContext(criteria, CurrentApplicationContext);
256 if (isSync || OriginalApplicationContext.LogicalExecutionLocation == ApplicationContext.LogicalExecutionLocations.Server)
257 {
258 result = await _portal.Delete(objectType, criteria, context, isSync);
259 }
260 else
261 {
262 if (!Options.FlowSynchronizationContext || SynchronizationContext.Current == null)
263 result = await Task.Run(() => this._portal.Delete(objectType, criteria, context, isSync));
264 else
265 result = await await Task.Factory.StartNew(() => this._portal.Delete(objectType, criteria, context, isSync),
266 CancellationToken.None,
267 TaskCreationOptions.None,
268 TaskScheduler.FromCurrentSynchronizationContext());
269 }
270 ResetApplicationContext();
271 return result;
272 }
273
279 public bool IsServerRemote
280 {
281 get { return false; }
282 }
283
288 protected virtual void Dispose(bool disposing)
289 {
290 if (!disposedValue)
291 {
292 if (disposing)
293 {
294 _scope?.Dispose();
295 }
296 disposedValue = true;
297 }
298 }
299
303 public void Dispose()
304 {
305 // Do not change this code. Put cleanup code in 'Dispose(bool disposing)' method
306 Dispose(disposing: true);
307 GC.SuppressFinalize(this);
308 }
309 }
310}
Provides consistent context information between the client and server DataPortal objects.
LogicalExecutionLocations LogicalExecutionLocation
Return Logical Execution Location - Client or Server This is applicable to Local mode as well
object GetRequiredService(Type serviceType)
Attempts to get service via DI using ServiceProviderServiceExtensions.GetRequiredService.
LogicalExecutionLocations
Enum representing the logical execution location The setting is set to server when server is execting...
bool IsAStatefulContextManager
Gets a value indicating whether the current context manager is used in a stateful context (e....
Implements a data portal proxy to relay data portal calls to an application server hosted locally in ...
Definition: LocalProxy.cs:25
async Task< DataPortalResult > Delete(Type objectType, object criteria, DataPortalContext context, bool isSync)
Called by DataPortal to delete a business object.
Definition: LocalProxy.cs:252
virtual void Dispose(bool disposing)
Dispose current object
Definition: LocalProxy.cs:288
async Task< DataPortalResult > Create(Type objectType, object criteria, DataPortalContext context, bool isSync)
Called by DataPortal to create a new business object.
Definition: LocalProxy.cs:156
async Task< DataPortalResult > Update(object obj, DataPortalContext context, bool isSync)
Called by DataPortal to update a business object.
Definition: LocalProxy.cs:220
bool IsServerRemote
Gets a value indicating whether this proxy will invoke a remote data portal server,...
Definition: LocalProxy.cs:280
LocalProxy(ApplicationContext applicationContext, LocalProxyOptions options)
Creates an instance of the type
Definition: LocalProxy.cs:31
void Dispose()
Dispose current object
Definition: LocalProxy.cs:303
async Task< DataPortalResult > Fetch(Type objectType, object criteria, DataPortalContext context, bool isSync)
Called by DataPortal to load an existing business object.
Definition: LocalProxy.cs:189
bool UseLocalScope
Gets or sets a value indicating whether a new dependency injection scope should be created for each d...
DataPortalResult defines the results of DataPortal operation.
Provides consistent context information between the client and server DataPortal objects.
Implement if a class requires access to the CSLA ApplicationContext type.
ApplicationContext ApplicationContext
Gets or sets the current ApplicationContext object.
Information about the current runtime environment.
Definition: IRuntimeInfo.cs:14
bool LocalProxyNewScopeExists
Gets a value indicating whether a LocalProxy (if configured and used) has created a new scope in prep...
Definition: IRuntimeInfo.cs:20
Task< DataPortalResult > Update(object obj, DataPortalContext context, bool isSync)
Update a business object.
Task< DataPortalResult > Create(Type objectType, object criteria, DataPortalContext context, bool isSync)
Create a new business object.
Task< DataPortalResult > Fetch(Type objectType, object criteria, DataPortalContext context, bool isSync)
Get an existing business object.
Task< DataPortalResult > Delete(Type objectType, object criteria, DataPortalContext context, bool isSync)
Delete a business object.
RelationshipTypes
List of valid relationship types between a parent object and another object through a managed propert...