diff --git a/src/GeneralTools/DataverseClient/Client/ConnectionService.cs b/src/GeneralTools/DataverseClient/Client/ConnectionService.cs
index 6555109..422215f 100644
--- a/src/GeneralTools/DataverseClient/Client/ConnectionService.cs
+++ b/src/GeneralTools/DataverseClient/Client/ConnectionService.cs
@@ -616,8 +616,9 @@ internal ConnectionService(IOrganizationService testIOrganziationSvc , string ba
/// Sets up an initialized the Dataverse Service interface.
///
/// This is an initialized organization web Service proxy
+ /// Authentication Type to use
/// incoming Log Sink
- internal ConnectionService(OrganizationWebProxyClientAsync externalOrgWebProxyClient, DataverseTraceLogger logSink = null)
+ internal ConnectionService(OrganizationWebProxyClientAsync externalOrgWebProxyClient, AuthenticationType authType, DataverseTraceLogger logSink = null)
{
if (logSink == null)
{
@@ -643,7 +644,7 @@ internal ConnectionService(OrganizationWebProxyClientAsync externalOrgWebProxyCl
}
UseExternalConnection = true;
GenerateCacheKeys(true);
- _eAuthType = AuthenticationType.OAuth;
+ _eAuthType = authType;
}
///
@@ -1337,82 +1338,103 @@ private async Task RefreshInstanceDetails(IOrganizationService dvService, Uri ur
// Load the organization instance details
if (dvService != null)
{
- //TODO:// Add Logic here to improve perf by connecting to global disco.
- Guid guRequestId = Guid.NewGuid();
- logEntry.Log(string.Format("Querying Organization Instance Details. Request ID: {0}", guRequestId));
- Stopwatch dtQueryTimer = new Stopwatch();
- dtQueryTimer.Restart();
-
- var request = new RetrieveCurrentOrganizationRequest() { AccessType = 0, RequestId = guRequestId };
- RetrieveCurrentOrganizationResponse resp;
-
- if (_configuration.Value.UseWebApiLoginFlow)
+ try
{
- OrganizationResponse orgResp = await Command_WebAPIProcess_ExecuteAsync(
- request, null, false, null, Guid.Empty, false, _configuration.Value.MaxRetryCount, _configuration.Value.RetryPauseTime, new CancellationToken(), uriOfInstance).ConfigureAwait(false);
- try
+ //TODO:// Add Logic here to improve perf by connecting to global disco.
+ Guid trackingID = Guid.NewGuid();
+ logEntry.Log(string.Format("Querying Organization Instance Details. Request ID: {0}", trackingID));
+ Stopwatch dtQueryTimer = new Stopwatch();
+ dtQueryTimer.Restart();
+
+ var request = new RetrieveCurrentOrganizationRequest() { AccessType = 0, RequestId = trackingID };
+ RetrieveCurrentOrganizationResponse resp;
+ logEntry.Log(string.Format(CultureInfo.InvariantCulture, "Execute Command - RetrieveCurrentOrganizationRequest : RequestId={0}", dtQueryTimer.Elapsed.ToString()));
+ if (_configuration.Value.UseWebApiLoginFlow)
{
- resp = (RetrieveCurrentOrganizationResponse)orgResp;
+ OrganizationResponse orgResp = await Command_WebAPIProcess_ExecuteAsync(
+ request, null, false, null, Guid.Empty, false, _configuration.Value.MaxRetryCount, _configuration.Value.RetryPauseTime, new CancellationToken(), uriOfInstance).ConfigureAwait(false);
+ try
+ {
+ resp = (RetrieveCurrentOrganizationResponse)orgResp;
+ }
+ catch (Exception ex)
+ {
+ dtQueryTimer.Stop();
+ logEntry.Log(string.Format(CultureInfo.InvariantCulture, "Failed to Executed Command - RetrieveCurrentOrganizationRequest : RequestId={1} : total duration: {0}", dtQueryTimer.Elapsed.ToString(), trackingID.ToString()), TraceEventType.Error);
+ logEntry.Log("************ Exception - Failed to lookup current organization information", TraceEventType.Error, ex);
+ throw new DataverseOperationException($"Failure to convert OrganziationResponse to requested type - request was {request.RequestName}", ex);
+ }
}
- catch ( Exception ex )
+ else
{
- throw new DataverseOperationException($"Failure to convert OrganziationResponse to requested type - request was {request.RequestName}", ex);
+ try
+ {
+ resp = (RetrieveCurrentOrganizationResponse)dvService.Execute(request);
+ }
+ catch(Exception ex)
+ {
+ dtQueryTimer.Stop();
+ logEntry.Log(string.Format(CultureInfo.InvariantCulture, "Failed to Executed Command - RetrieveCurrentOrganizationRequest : RequestId={1} : total duration: {0}", dtQueryTimer.Elapsed.ToString(), trackingID.ToString()), TraceEventType.Error);
+ logEntry.Log("************ Exception - Failed to lookup current organization information", TraceEventType.Error, ex);
+ throw new DataverseOperationException("Exception - Failed to lookup current organization data", ex);
+ }
}
- }
- else
- {
- resp = (RetrieveCurrentOrganizationResponse)dvService.Execute(request);
- }
+ dtQueryTimer.Stop();
+ // Left in information mode intentionally
+ logEntry.Log(string.Format(CultureInfo.InvariantCulture, "Executed Command - RetrieveCurrentOrganizationRequest : RequestId={1} : total duration: {0}", dtQueryTimer.Elapsed.ToString(), trackingID.ToString()));
- dtQueryTimer.Stop();
- logEntry.Log(string.Format(CultureInfo.InvariantCulture, "Completed Querying Organization Instance Details, total duration: {0}", dtQueryTimer.Elapsed.ToString()));
- if (resp.Detail != null)
- {
- _OrgDetail = new OrganizationDetail();
- //Add Endpoints.
- foreach (var ep in resp.Detail.Endpoints)
+ if (resp.Detail != null)
{
- string endPointName = ep.Key.ToString();
- EndpointType epd = EndpointType.OrganizationDataService;
- Enum.TryParse(endPointName, out epd);
+ _OrgDetail = new OrganizationDetail();
+ //Add Endpoints.
+ foreach (var ep in resp.Detail.Endpoints)
+ {
+ string endPointName = ep.Key.ToString();
+ EndpointType epd = EndpointType.OrganizationDataService;
+ Enum.TryParse(endPointName, out epd);
- if (!_OrgDetail.Endpoints.ContainsKey(epd))
- _OrgDetail.Endpoints.Add(epd, ep.Value);
- else
- _OrgDetail.Endpoints[epd] = ep.Value;
+ if (!_OrgDetail.Endpoints.ContainsKey(epd))
+ _OrgDetail.Endpoints.Add(epd, ep.Value);
+ else
+ _OrgDetail.Endpoints[epd] = ep.Value;
+ }
+ _OrgDetail.FriendlyName = resp.Detail.FriendlyName;
+ _OrgDetail.OrganizationId = resp.Detail.OrganizationId;
+ _OrgDetail.OrganizationVersion = resp.Detail.OrganizationVersion;
+ _OrgDetail.EnvironmentId = resp.Detail.EnvironmentId;
+ _OrgDetail.TenantId = resp.Detail.TenantId;
+ _OrgDetail.Geo = resp.Detail.Geo;
+ _OrgDetail.UrlName = resp.Detail.UrlName;
+
+ OrganizationState ostate = OrganizationState.Disabled;
+ Enum.TryParse(_OrgDetail.State.ToString(), out ostate);
+
+ _OrgDetail.State = ostate;
+ _OrgDetail.UniqueName = resp.Detail.UniqueName;
+ _OrgDetail.UrlName = resp.Detail.UrlName;
}
- _OrgDetail.FriendlyName = resp.Detail.FriendlyName;
- _OrgDetail.OrganizationId = resp.Detail.OrganizationId;
- _OrgDetail.OrganizationVersion = resp.Detail.OrganizationVersion;
- _OrgDetail.EnvironmentId = resp.Detail.EnvironmentId;
- _OrgDetail.TenantId = resp.Detail.TenantId;
- _OrgDetail.Geo = resp.Detail.Geo;
- _OrgDetail.UrlName = resp.Detail.UrlName;
-
- OrganizationState ostate = OrganizationState.Disabled;
- Enum.TryParse(_OrgDetail.State.ToString(), out ostate);
- _OrgDetail.State = ostate;
- _OrgDetail.UniqueName = resp.Detail.UniqueName;
- _OrgDetail.UrlName = resp.Detail.UrlName;
- }
-
- _organization = _OrgDetail.UniqueName;
- ConnectedOrgFriendlyName = _OrgDetail.FriendlyName;
- ConnectedOrgPublishedEndpoints = _OrgDetail.Endpoints;
+ _organization = _OrgDetail.UniqueName;
+ ConnectedOrgFriendlyName = _OrgDetail.FriendlyName;
+ ConnectedOrgPublishedEndpoints = _OrgDetail.Endpoints;
- // try to create a version number from the org.
- OrganizationVersion = new Version("0.0.0.0");
- try
- {
- Version outVer = null;
- if (Version.TryParse(_OrgDetail.OrganizationVersion, out outVer))
+ // try to create a version number from the org.
+ OrganizationVersion = new Version("0.0.0.0");
+ try
{
- OrganizationVersion = outVer;
+ if (Version.TryParse(_OrgDetail.OrganizationVersion, out Version outVer))
+ {
+ OrganizationVersion = outVer;
+ }
}
+ catch { };
+ logEntry.Log("Completed Parsing Organization Instance Details", TraceEventType.Verbose);
+ }
+ catch (Exception ex)
+ {
+ logEntry.Log("************ Exception - Fault While initializing client - RefreshInstanceDetails", TraceEventType.Error, ex);
+ throw new DataverseConnectionException("Exception - Fault While initializing client - RefreshInstanceDetails", ex);
}
- catch { };
- logEntry.Log("Completed Parsing Organization Instance Details", TraceEventType.Verbose);
}
}
@@ -1421,7 +1443,7 @@ private async Task RefreshInstanceDetails(IOrganizationService dvService, Uri ur
///
///
///
- internal async Task GetWhoAmIDetails(IOrganizationService dvService, Guid trackingID = default(Guid))
+ internal async Task GetWhoAmIDetails(IOrganizationService dvService, Guid trackingID = default)
{
if (dvService != null)
{
@@ -1436,6 +1458,7 @@ private async Task RefreshInstanceDetails(IOrganizationService dvService, Uri ur
if (trackingID != Guid.Empty) // Add Tracking number of present.
req.RequestId = trackingID;
+ logEntry.Log(string.Format(CultureInfo.InvariantCulture, "Execute Command - WhoAmIRequest : RequestId={0}", trackingID.ToString()));
WhoAmIResponse resp;
if (_configuration.Value.UseWebApiLoginFlow)
{
@@ -1447,7 +1470,7 @@ private async Task RefreshInstanceDetails(IOrganizationService dvService, Uri ur
resp = (WhoAmIResponse)dvService.Execute(req);
}
- // Left in information mode intentionaly.
+ // Left in information mode intentionally.
logEntry.Log(string.Format(CultureInfo.InvariantCulture, "Executed Command - WhoAmIRequest : RequestId={1} : total duration: {0}", dtQueryTimer.Elapsed.ToString(), trackingID.ToString()));
return resp;
}
@@ -1455,7 +1478,7 @@ private async Task RefreshInstanceDetails(IOrganizationService dvService, Uri ur
{
logEntry.Log(string.Format(CultureInfo.InvariantCulture, "Failed to Executed Command - WhoAmIRequest : RequestId={1} : total duration: {0}", dtQueryTimer.Elapsed.ToString(), trackingID.ToString()), TraceEventType.Error);
logEntry.Log("************ Exception - Failed to lookup current user", TraceEventType.Error, ex);
- throw ex;
+ throw new DataverseOperationException("Exception - Failed to lookup current user", ex);
}
finally
{
@@ -1537,6 +1560,8 @@ internal void SetClonedProperties(ServiceClient sourceClient)
internal async Task Command_WebAPIProcess_ExecuteAsync(OrganizationRequest req, string logMessageTag, bool bypassPluginExecution,
MetadataUtility metadataUtlity, Guid callerId, bool disableConnectionLocking, int maxRetryCount, TimeSpan retryPauseTime, CancellationToken cancellationToken, Uri uriOfInstance = null)
{
+ cancellationToken.ThrowIfCancellationRequested();
+
if (!Utilities.IsRequestValidForTranslationToWebAPI(req)) // THIS WILL GET REMOVED AT SOME POINT, TEMP FOR TRANSTION //TODO:REMOVE ON COMPELTE
{
logEntry.Log("Execute Organization Request failed, WebAPI is only supported for limited type of messages at this time.", TraceEventType.Error);
@@ -1558,6 +1583,7 @@ internal async Task Command_WebAPIProcess_ExecuteAsync(Org
if (cReq != null)
{
// if CRUD type. get Entity
+ cancellationToken.ThrowIfCancellationRequested();
entityMetadata = metadataUtlity.GetEntityMetadata(EntityFilters.Relationships, cReq.LogicalName);
if (entityMetadata == null)
{
@@ -1574,6 +1600,7 @@ internal async Task Command_WebAPIProcess_ExecuteAsync(Org
if (cReq != null)
{
+ cancellationToken.ThrowIfCancellationRequested();
requestBodyObject = Utilities.ToExpandoObject(cReq, metadataUtlity, methodToExecute , logEntry);
if (cReq.RelatedEntities != null && cReq.RelatedEntities.Count > 0)
requestBodyObject = Utilities.ReleatedEntitiesToExpandoObject(requestBodyObject, cReq.LogicalName, cReq.RelatedEntities, metadataUtlity, methodToExecute, logEntry);
@@ -1721,7 +1748,7 @@ internal async Task Command_WebAPIProcess_ExecuteAsync(Org
}
// Execute request
- var sResp = await Command_WebExecuteAsync(postUri, bodyOfRequest, methodToExecute, headers, "application/json", logMessageTag, callerId, disableConnectionLocking, maxRetryCount, retryPauseTime, uriOfInstance).ConfigureAwait(false);
+ var sResp = await Command_WebExecuteAsync(postUri, bodyOfRequest, methodToExecute, headers, "application/json", logMessageTag, callerId, disableConnectionLocking, maxRetryCount, retryPauseTime, uriOfInstance, cancellationToken: cancellationToken).ConfigureAwait(false);
if (sResp != null && sResp.IsSuccessStatusCode)
{
if (req is CreateRequest)
@@ -1800,9 +1827,10 @@ internal async Task Command_WebAPIProcess_ExecuteAsync(Org
/// retry pause time
/// uri of instance
///
+ ///
///
internal async Task Command_WebExecuteAsync(string queryString, string body, HttpMethod method, Dictionary> customHeaders,
- string contentType, string errorStringCheck, Guid callerId, bool disableConnectionLocking, int maxRetryCount, TimeSpan retryPauseTime, Uri uriOfInstance = null, Guid requestTrackingId = default(Guid))
+ string contentType, string errorStringCheck, Guid callerId, bool disableConnectionLocking, int maxRetryCount, TimeSpan retryPauseTime, Uri uriOfInstance = null, Guid requestTrackingId = default, CancellationToken cancellationToken = default)
{
Stopwatch logDt = new Stopwatch();
int retryCount = 0;
@@ -1974,6 +2002,7 @@ internal async Task Command_WebExecuteAsync(string queryStr
resp = await ConnectionService.ExecuteHttpRequestAsync(
TargetUri.ToString(),
method,
+ cancellationToken: cancellationToken,
body: body,
customHeaders: customHeaders,
logSink: logEntry,
diff --git a/src/GeneralTools/DataverseClient/Client/Interfaces/IOrganizationServiceAsync2.cs b/src/GeneralTools/DataverseClient/Client/Interfaces/IOrganizationServiceAsync2.cs
index 112cb61..151e4a7 100644
--- a/src/GeneralTools/DataverseClient/Client/Interfaces/IOrganizationServiceAsync2.cs
+++ b/src/GeneralTools/DataverseClient/Client/Interfaces/IOrganizationServiceAsync2.cs
@@ -11,8 +11,24 @@ namespace Microsoft.PowerPlatform.Dataverse.Client
/// Interface containing extension methods provided by the DataverseServiceClient for the IOrganizationService Interface.
/// These extensions will only operate from within the client and are not supported server side.
///
- public interface IOrganizationServiceAsync2
+ public interface IOrganizationServiceAsync2 : IOrganizationServiceAsync
{
+ ///
+ /// Associate an entity with a set of entities
+ ///
+ ///
+ ///
+ ///
+ ///
+ /// Propagates notification that operations should be canceled.
+ Task AssociateAsync(string entityName, Guid entityId, Relationship relationship, EntityReferenceCollection relatedEntities, CancellationToken cancellationToken);
+ ///
+ /// Create an entity and process any related entities
+ ///
+ /// entity to create
+ /// Propagates notification that operations should be canceled.
+ /// The ID of the created record
+ Task CreateAsync(Entity entity, CancellationToken cancellationToken);
///
/// Create an entity and process any related entities
///
@@ -20,6 +36,51 @@ public interface IOrganizationServiceAsync2
/// Propagates notification that operations should be canceled.
/// Returns the newly created record
Task CreateAndReturnAsync(Entity entity, CancellationToken cancellationToken);
-
+ ///
+ /// Delete instance of an entity
+ ///
+ /// Logical name of entity
+ /// Id of entity
+ /// Propagates notification that operations should be canceled.
+ Task DeleteAsync(string entityName, Guid id, CancellationToken cancellationToken);
+ ///
+ /// Disassociate an entity with a set of entities
+ ///
+ ///
+ ///
+ ///
+ ///
+ /// Propagates notification that operations should be canceled.
+ Task DisassociateAsync(string entityName, Guid entityId, Relationship relationship, EntityReferenceCollection relatedEntities, CancellationToken cancellationToken);
+ ///
+ /// Perform an action in an organization specified by the request.
+ ///
+ /// Refer to SDK documentation for list of messages that can be used.
+ /// Propagates notification that operations should be canceled.
+ /// Results from processing the request
+ Task ExecuteAsync(OrganizationRequest request, CancellationToken cancellationToken);
+ ///
+ /// Retrieves instance of an entity
+ ///
+ /// Logical name of entity
+ /// Id of entity
+ /// Column Set collection to return with the request
+ /// Propagates notification that operations should be canceled.
+ /// Selected Entity
+ Task RetrieveAsync(string entityName, Guid id, ColumnSet columnSet, CancellationToken cancellationToken);
+ ///
+ /// Retrieves a collection of entities
+ ///
+ ///
+ /// Propagates notification that operations should be canceled.
+ /// Returns an EntityCollection Object containing the results of the query
+ Task RetrieveMultipleAsync(QueryBase query, CancellationToken cancellationToken);
+ ///
+ /// Updates an entity and process any related entities
+ ///
+ /// entity to update
+ /// Propagates notification that operations should be canceled.
+ Task UpdateAsync(Entity entity, CancellationToken cancellationToken);
}
+
}
diff --git a/src/GeneralTools/DataverseClient/Client/ServiceClient.cs b/src/GeneralTools/DataverseClient/Client/ServiceClient.cs
index 15c5f6e..2a870ca 100644
--- a/src/GeneralTools/DataverseClient/Client/ServiceClient.cs
+++ b/src/GeneralTools/DataverseClient/Client/ServiceClient.cs
@@ -1088,7 +1088,7 @@ internal void CreateServiceConnection(
// if using an user provided connection,.
if (externalOrgWebProxyClient != null)
{
- _connectionSvc = new ConnectionService(externalOrgWebProxyClient, _logEntry);
+ _connectionSvc = new ConnectionService(externalOrgWebProxyClient, requestedAuthType , _logEntry);
_connectionSvc.IsAClone = isCloned;
if (isCloned && incomingOrgVersion != null)
{
@@ -4955,8 +4955,9 @@ internal bool AddRequestToBatch(Guid batchId, OrganizationRequest req, string ba
/// Content your passing to the request
/// Headers in addition to the default headers added by for Executing a web request
/// Content Type attach to the request. this defaults to application/json if not set.
+ /// Cancellation token for the request
///
- public HttpResponseMessage ExecuteWebRequest(HttpMethod method, string queryString, string body, Dictionary> customHeaders, string contentType = default(string))
+ public HttpResponseMessage ExecuteWebRequest(HttpMethod method, string queryString, string body, Dictionary> customHeaders, string contentType = default, CancellationToken cancellationToken = default)
{
_logEntry.ResetLastError(); // Reset Last Error
if (DataverseService == null)
@@ -4981,7 +4982,7 @@ internal bool AddRequestToBatch(Guid batchId, OrganizationRequest req, string ba
queryString = baseQueryString;
}
- var result = _connectionSvc.Command_WebExecuteAsync(queryString, body, method, customHeaders, contentType, string.Empty, CallerId, _disableConnectionLocking, MaxRetryCount, RetryPauseTime).Result;
+ var result = _connectionSvc.Command_WebExecuteAsync(queryString, body, method, customHeaders, contentType, string.Empty, CallerId, _disableConnectionLocking, MaxRetryCount, RetryPauseTime, cancellationToken: cancellationToken).Result;
if (result == null)
throw LastException;
else
@@ -5024,6 +5025,7 @@ private OrganizationResponse ExecuteOrganizationRequestImpl(OrganizationRequest
private async Task ExecuteOrganizationRequestAsyncImpl(OrganizationRequest req, CancellationToken cancellationToken, string logMessageTag = "User Defined", bool useWebAPI = false, bool bypassPluginExecution = false)
{
+ cancellationToken.ThrowIfCancellationRequested();
if (req != null)
{
useWebAPI = Utilities.IsRequestValidForTranslationToWebAPI(req);
@@ -5418,6 +5420,7 @@ internal async Task Command_ExecuteAsyncImpl(OrganizationR
{
try
{
+ cancellationToken.ThrowIfCancellationRequested();
_retryPauseTimeRunning = _configuration.Value.RetryPauseTime;
retry = false;
if (!_disableConnectionLocking)
@@ -6163,6 +6166,99 @@ public void Update(Entity entity)
#endregion
#region IOrganzationServiceAsync helper - Proxy object
+ ///
+ /// Associate an entity with a set of entities
+ ///
+ ///
+ ///
+ ///
+ ///
+ public async Task AssociateAsync(string entityName, Guid entityId, Relationship relationship, EntityReferenceCollection relatedEntities)
+ {
+ await AssociateAsync(entityName, entityId, relationship, relatedEntities, CancellationToken.None).ConfigureAwait(false);
+ return;
+ }
+
+ ///
+ /// Create an entity and process any related entities
+ ///
+ /// entity to create
+ /// The ID of the created record
+ public async Task CreateAsync(Entity entity)
+ {
+ return await CreateAsync(entity, CancellationToken.None).ConfigureAwait(false);
+ }
+
+ ///
+ /// Delete instance of an entity
+ ///
+ /// Logical name of entity
+ /// Id of entity
+ public async Task DeleteAsync(string entityName, Guid id)
+ {
+ await DeleteAsync(entityName, id, CancellationToken.None).ConfigureAwait(false);
+ return;
+ }
+
+ ///
+ /// Disassociate an entity with a set of entities
+ ///
+ ///
+ ///
+ ///
+ ///
+ public async Task DisassociateAsync(string entityName, Guid entityId, Relationship relationship, EntityReferenceCollection relatedEntities)
+ {
+ await DisassociateAsync(entityName, entityId, relationship, relatedEntities, CancellationToken.None).ConfigureAwait(false);
+ return;
+ }
+
+ ///
+ /// Perform an action in an organization specified by the request.
+ ///
+ /// Refer to SDK documentation for list of messages that can be used.
+ /// Results from processing the request
+ public async Task ExecuteAsync(OrganizationRequest request)
+ {
+ return await ExecuteAsync(request, CancellationToken.None).ConfigureAwait(false);
+ }
+
+ ///
+ /// Retrieves instance of an entity
+ ///
+ /// Logical name of entity
+ /// Id of entity
+ /// Column Set collection to return with the request
+ /// Selected Entity
+ public async Task RetrieveAsync(string entityName, Guid id, ColumnSet columnSet)
+ {
+ return await RetrieveAsync(entityName, id, columnSet, CancellationToken.None).ConfigureAwait(false);
+ }
+
+ ///
+ /// Retrieves a collection of entities
+ ///
+ ///
+ /// Returns an EntityCollection Object containing the results of the query
+ public async Task RetrieveMultipleAsync(QueryBase query)
+ {
+ return await RetrieveMultipleAsync(query, CancellationToken.None).ConfigureAwait(false);
+ }
+
+ ///
+ /// Updates an entity and process any related entities
+ ///
+ /// entity to update
+ public async Task UpdateAsync(Entity entity)
+ {
+ await UpdateAsync(entity, CancellationToken.None).ConfigureAwait(false);
+ return;
+ }
+
+
+ #endregion
+
+ #region IOrganzationServiceAsync2 helper - Proxy object
///
/// Associate an entity with a set of entities
@@ -6192,7 +6288,7 @@ public async Task AssociateAsync(string entityName, Guid entityId, Relationship
/// entity to create
/// Propagates notification that operations should be canceled.
/// The ID of the created record
- public async Task CreateAsync(Entity entity, CancellationToken cancellationToken = default)
+ public async Task CreateAsync(Entity entity, CancellationToken cancellationToken)
{
// Relay to Update request.
CreateResponse resp = (CreateResponse)await ExecuteOrganizationRequestAsyncImpl(
@@ -6209,14 +6305,22 @@ public async Task CreateAsync(Entity entity, CancellationToken cancellatio
return resp.id;
}
-
///
/// Create an entity and process any related entities
///
/// entity to create
/// Propagates notification that operations should be canceled.
/// Returns the newly created record
- public Task CreateAndReturnAsync(Entity entity, CancellationToken cancellationToken = default)
+ public Task CreateAndReturnAsync(Entity entity, CancellationToken cancellationToken)
+ {
+ throw new NotImplementedException();
+ }
+ ///
+ /// Create an entity and process any related entities
+ ///
+ /// entity to create
+ /// Returns the newly created record
+ public Task CreateAndReturnAsync(Entity entity)
{
throw new NotImplementedException();
}
@@ -6227,7 +6331,7 @@ public Task CreateAndReturnAsync(Entity entity, CancellationToken cancel
/// Logical name of entity
/// Id of entity
/// Propagates notification that operations should be canceled.
- public async Task DeleteAsync(string entityName, Guid id, CancellationToken cancellationToken = default)
+ public async Task DeleteAsync(string entityName, Guid id, CancellationToken cancellationToken)
{
DeleteResponse resp = (DeleteResponse)await ExecuteOrganizationRequestAsyncImpl(
new DeleteRequest()
@@ -6249,7 +6353,7 @@ public async Task DeleteAsync(string entityName, Guid id, CancellationToken canc
///
///
/// Propagates notification that operations should be canceled.
- public async Task DisassociateAsync(string entityName, Guid entityId, Relationship relationship, EntityReferenceCollection relatedEntities, CancellationToken cancellationToken = default)
+ public async Task DisassociateAsync(string entityName, Guid entityId, Relationship relationship, EntityReferenceCollection relatedEntities, CancellationToken cancellationToken)
{
DisassociateResponse resp = (DisassociateResponse)await ExecuteOrganizationRequestAsyncImpl(new DisassociateRequest()
{
@@ -6269,7 +6373,7 @@ public async Task DisassociateAsync(string entityName, Guid entityId, Relationsh
/// Refer to SDK documentation for list of messages that can be used.
/// Propagates notification that operations should be canceled.
/// Results from processing the request
- public async Task ExecuteAsync(OrganizationRequest request, CancellationToken cancellationToken = default)
+ public async Task ExecuteAsync(OrganizationRequest request, CancellationToken cancellationToken)
{
OrganizationResponse resp = await ExecuteOrganizationRequestAsyncImpl(request
, cancellationToken
@@ -6280,7 +6384,6 @@ public async Task ExecuteAsync(OrganizationRequest request
return resp;
}
-
///
/// Retrieves instance of an entity
///
@@ -6289,7 +6392,7 @@ public async Task ExecuteAsync(OrganizationRequest request
/// Column Set collection to return with the request
/// Propagates notification that operations should be canceled.
/// Selected Entity
- public async Task RetrieveAsync(string entityName, Guid id, ColumnSet columnSet, CancellationToken cancellationToken = default)
+ public async Task RetrieveAsync(string entityName, Guid id, ColumnSet columnSet, CancellationToken cancellationToken)
{
RetrieveResponse resp = (RetrieveResponse)await ExecuteOrganizationRequestAsyncImpl(
new RetrieveRequest()
@@ -6311,7 +6414,7 @@ public async Task RetrieveAsync(string entityName, Guid id, ColumnSet co
///
/// Propagates notification that operations should be canceled.
/// Returns an EntityCollection Object containing the results of the query
- public async Task RetrieveMultipleAsync(QueryBase query, CancellationToken cancellationToken = default)
+ public async Task RetrieveMultipleAsync(QueryBase query, CancellationToken cancellationToken)
{
RetrieveMultipleResponse resp = (RetrieveMultipleResponse)await ExecuteOrganizationRequestAsyncImpl(new RetrieveMultipleRequest() { Query = query }, cancellationToken, "RetrieveMultiple to Dataverse via IOrganizationService").ConfigureAwait(false);
if (resp == null)
@@ -6325,7 +6428,7 @@ public async Task RetrieveMultipleAsync(QueryBase query, Cance
///
/// entity to update
/// Propagates notification that operations should be canceled.
- public async Task UpdateAsync(Entity entity, CancellationToken cancellationToken = default)
+ public async Task UpdateAsync(Entity entity, CancellationToken cancellationToken)
{
// Relay to Update request.
UpdateResponse resp = (UpdateResponse)await ExecuteOrganizationRequestAsyncImpl(
diff --git a/src/GeneralTools/DataverseClient/UnitTests/CdsClient_Core_Tests/ServiceClientTests.cs b/src/GeneralTools/DataverseClient/UnitTests/CdsClient_Core_Tests/ServiceClientTests.cs
index 1102090..d129afe 100644
--- a/src/GeneralTools/DataverseClient/UnitTests/CdsClient_Core_Tests/ServiceClientTests.cs
+++ b/src/GeneralTools/DataverseClient/UnitTests/CdsClient_Core_Tests/ServiceClientTests.cs
@@ -7,6 +7,7 @@
using Microsoft.Extensions.Logging;
using Microsoft.PowerPlatform.Dataverse.Client;
using Microsoft.PowerPlatform.Dataverse.Client.Auth;
+using Microsoft.PowerPlatform.Dataverse.Client.Utils;
using Microsoft.Xrm.Sdk;
using Microsoft.Xrm.Sdk.Messages;
using Microsoft.Xrm.Sdk.Metadata;
@@ -214,6 +215,21 @@ public void CreateRequestTests()
respId = cli.Create(acctEntity);
Assert.Equal(testSupport._DefaultId, respId);
+ // Test low level createAsync
+ respId = cli.CreateAsync(acctEntity).GetAwaiter().GetResult();
+ Assert.Equal(testSupport._DefaultId, respId);
+
+ try
+ {
+ // Test low level createAsyncwithCancelationToken
+ System.Threading.CancellationToken tok = new System.Threading.CancellationToken(true);
+ respId = cli.CreateAsync(acctEntity, tok).GetAwaiter().GetResult();
+ }
+ catch(Exception ex)
+ {
+ Assert.IsType(ex);
+ }
+
// Test Helper create
respId = cli.CreateNewRecord("account", newFields);
Assert.Equal(testSupport._DefaultId, respId);
diff --git a/src/nuspecs/Microsoft.PowerPlatform.Dataverse.Client.ReleaseNotes.txt b/src/nuspecs/Microsoft.PowerPlatform.Dataverse.Client.ReleaseNotes.txt
index e1fd230..2bf3bab 100644
--- a/src/nuspecs/Microsoft.PowerPlatform.Dataverse.Client.ReleaseNotes.txt
+++ b/src/nuspecs/Microsoft.PowerPlatform.Dataverse.Client.ReleaseNotes.txt
@@ -8,6 +8,16 @@ Notice:
Note: that only OAuth, Certificate, ClientSecret Authentication types are supported at this time.
++CURRENTRELEASEID++
+Fixed and issue with the client being non-castable to IOrganizationServiceAsync, Client will now cast again. (Internal Report)
+ Special note:
+ IOrganizationServiceAsync has async methods without cancellation support. this is required for service mapping as the dataverse server does not natively support this feature.
+ IOrganizationServiceAsync2 has async methods WITH cancellation support.
+ This surfaces in the client as 2 forms of each async method and is currently necessary to support internal auto generation of contracts for service communication. We will work to improve this in the future.
+ Cancellation events will currently raise an OperationCancelled Exception, this can either be the topmost exception, or embedded in a DataverseException.
+ Cancellation methods are 'preferred' if you need to support cancellation in your application.
+Fixed an issue with External authentication type not being properly passed though to cloned clients. (git #162)
+
+0.5.2:
***** Breaking Changes *****
Removed the constructor:
public ServiceClient(OrganizationWebProxyClient externalOrgWebProxyClient, ILogger logger = null)