Resync from Main Branch for 1.0 release.
This commit is contained in:
Родитель
692e17fbb9
Коммит
69b1ed5472
|
@ -1,4 +1,5 @@
|
|||
# CoreXT generated files
|
||||
# CoreXT generated files
|
||||
|
||||
.corext/gen/
|
||||
build/environment/
|
||||
|
||||
|
@ -6,8 +7,8 @@ build/environment/
|
|||
/.cake
|
||||
/version.txt
|
||||
/PSRunCmds*.ps1
|
||||
|
||||
# Build output
|
||||
|
||||
/bin/
|
||||
/binSigned/
|
||||
/obj/
|
||||
|
@ -51,6 +52,7 @@ TestResults
|
|||
|
||||
#Skip Nuget Packages
|
||||
/src/**/packages/*
|
||||
/src/**/.packages/*
|
||||
|
||||
# Build generated files in src
|
||||
/src/**/objd/**/*
|
||||
|
@ -88,6 +90,4 @@ src/Localize/Temp
|
|||
/src/GeneralTools/XrmSDK/TestXrmSDKConnection
|
||||
/src/GeneralTools/XrmSDK/StandardConsoleApp
|
||||
/src/GeneralTools/XrmSDK/CdsSdkShim
|
||||
|
||||
# Skip generated nuget.config
|
||||
/nuget.config
|
||||
/build/cake/test/*
|
||||
|
|
25
README.md
25
README.md
|
@ -16,8 +16,6 @@ This repository contains the code for the Microsoft.PowerPlatform.Dataverse.Clie
|
|||
|
||||
**IMPORTANT NOTES**
|
||||
|
||||
**The Dataverse ServiceClient is in Preview**
|
||||
|
||||
**The Dataverse ServiceClient cannot be built outside of Microsoft**
|
||||
This is due to a set of dependencies on nuget packages that are internally available only. At some point in the future, we will expose the supporting nuget packages when we have updated our server infrastructure to support plugin development on .net core.
|
||||
|
||||
|
@ -32,41 +30,30 @@ This nuget package has been deprecated (for now) ~~[Microsoft.Dynamics.Sdk.Messa
|
|||
|
||||
This library is and its supporting assemblies are a revision and update of the Microsoft.Xrm.Tooling.Connector.CrmServiceClient and the underlying Microsoft.Xrm.Sdk.Client libraries.
|
||||
|
||||
We are using this effort to for a few key things we have wanted to get done for a number of years,
|
||||
|
||||
1. Refactor and update our client libraries to allow us to spit up PowerPlatform Common Data Service SDK support from Microsoft Dynamics 365.
|
||||
2. Provide multi targeted library build that targets our supported .net client platforms.
|
||||
3. Update connection patterns and behaviors to be consistent with many of the broadly accepted patterns.
|
||||
4. Create a pattern to allow developers focus on the use of Dataverse, or Dataverse + Dynamics as they need.
|
||||
|
||||
We encourage you to read the release notes we provide with each nuget packages. As with most of our Nuget packages that are intended as tools or for developer consumption, we extensively comment in release notes.
|
||||
|
||||
At this time: (03/06/2022)
|
||||
At this time: (06/13/2022)
|
||||
The Client SDK libs supports the following and has the following notices:
|
||||
|
||||
* 0.6.x is **expected** to be the final preview release, followed by 1.0
|
||||
* 0.6.x refactors much of the primary ServiceClient interface, narrowing its focus to primary operations against Dataverse. the ballance of the feature set has been moved to Microsoft.PowerPlatform.Dataverse.Client.Extensions. - We are seeking feedback on this refactor.
|
||||
* VS 2022 + .net 6 is required to build this project currently. see: [global.json](global.json) for current requirements.
|
||||
* .net full framework 4.6.2, 4.7.2, 4.8 and .net core 3.0, 3.1, 5.0, 6.0
|
||||
* We now support all authentication types from CrmServiceClient for .net framework, ( Client\Secret, Client\Cert, UID\PW Noninteractive, UID\PW interactive.)
|
||||
* We support the following authentication types from CrmServiceClient for .net core: Client\Secret, Client\Cert, UID\PW interactive.
|
||||
* MSAL Port has been completed, this Lib is now using MSAL 4.35+
|
||||
* Plugin Development using this Client is NOT supported at this time.
|
||||
|
||||
From a scenario point of view, we are particularity interested in any issues or challenges when using these library in either Asp.net Core, Azure Functions, and Linux based scenarios.
|
||||
|
||||
If your working against Dataverse Only and or custom entities and sdk messages, you should only need Microsoft.PowerPlatform.Dataverse.Client. If you do not experience that, or find missing messages in the Dataverse only scenarios, please let us know in the issues area.
|
||||
|
||||
<b>Note: We are currently providing support for these nuget packages primarily via GitHub and Microsoft Support.
|
||||
<b>Note: We provide support for these nuget packages primarily via GitHub and Microsoft Support.
|
||||
Github Issues is the preferred venue at this time as the development team is actively working on this library.
|
||||
A number of our dev's and PM's do monitor this channel and can respond to questions and feedback.
|
||||
|
||||
While we are monitoring the community forums, you are encouraged to open issue [here](https://github.com/microsoft/PowerPlatform-CdsServiceClient/issues)
|
||||
While we are monitoring the community forums, you are encouraged to open issue [here](https://github.com/microsoft/PowerPlatform-DataverseServiceClient/issues)
|
||||
</b>
|
||||
|
||||
## Samples / Docs
|
||||
Samples and such will be updated overtime on the PowerApps Samples GitHub Site as we move forward with the evolution of this capability. That said, any of the existing CrmServiceClient samples can be used as a base to start. You can find those here: [Samples](https://github.com/microsoft/PowerApps-Samples/tree/master/cds/orgsvc/C%23)
|
||||
Samples and such will be continually updated overtime on the PowerApps Samples GitHub Site. Dataverse ServiceClient Samples can be found here:[Samples](https://github.com/microsoft/PowerApps-Samples/tree/master/cds/orgsvc)
|
||||
|
||||
For connections strings, docs on supported patterns are here: [Connection String Docs](https://docs.microsoft.com/en-us/powerapps/developer/common-data-service/xrm-tooling/use-connection-strings-xrm-tooling-connect)
|
||||
For connections strings, docs on supported patterns are here: [Connection String Docs](https://docs.microsoft.com/en-us/powerapps/developer/common-data-service/xrm-tooling/use-connection-strings-xrm-tooling-connect). This link will be updated as Dataverse Specific connection string documentation comes online.
|
||||
|
||||
Microsoft Documentation root for Dataverse ServiceClient can be found here: [Dataverse ServiceClient Docs](https://docs.microsoft.com/en-us/dotnet/api/microsoft.powerplatform.dataverse.client?view=dataverse-sdk-latest)
|
||||
|
||||
|
|
|
@ -0,0 +1,7 @@
|
|||
{
|
||||
"sdk": {
|
||||
"version": "6.0.202",
|
||||
"rollForward": "latestFeature",
|
||||
"allowPrerelease": false
|
||||
}
|
||||
}
|
|
@ -5,15 +5,15 @@
|
|||
<PackageVersion_AppInsights>2.9.1</PackageVersion_AppInsights>
|
||||
<PackageVersion_Adal>3.19.8</PackageVersion_Adal>
|
||||
<PackageVersion_MSAL>4.35.1</PackageVersion_MSAL>
|
||||
<PackageVersion_CdsSdk>4.7.7698-v9.0-master.release</PackageVersion_CdsSdk>
|
||||
<PackageVersion_CrmProxy>4.7.7698-v9.0-master.release</PackageVersion_CrmProxy>
|
||||
<PackageVersion_CdsSdk>4.7.9489-v9.0-master</PackageVersion_CdsSdk>
|
||||
<PackageVersion_CrmProxy>4.7.9409-v9.0-master</PackageVersion_CrmProxy>
|
||||
<PackageVersion_CDSServerNuget>4.6.6061-weekly-2108.5</PackageVersion_CDSServerNuget>
|
||||
<PackageVersion_CdsSdkProxy>4.7.6346-master</PackageVersion_CdsSdkProxy>
|
||||
<PackageVersion_Newtonsoft>11.0.2</PackageVersion_Newtonsoft>
|
||||
<PackageVersion_RestClientRuntime>2.3.20</PackageVersion_RestClientRuntime>
|
||||
<PackageVersion_XrmSdk>9.0.2.42</PackageVersion_XrmSdk>
|
||||
<PackageVersion_Dep_OutlookXrmSdk>9.0.2.34</PackageVersion_Dep_OutlookXrmSdk>
|
||||
<PackageVersion_BatchedTelemetry>2.0.11</PackageVersion_BatchedTelemetry>
|
||||
<PackageVersion_BatchedTelemetry>2.0.19</PackageVersion_BatchedTelemetry>
|
||||
<PackageVersion_DataverseClient>0.4.20</PackageVersion_DataverseClient>
|
||||
<PackageVersion_CoverletCollector>3.1.0</PackageVersion_CoverletCollector>
|
||||
<PackageVersion_Microsoft_Extensions>3.1.8</PackageVersion_Microsoft_Extensions>
|
||||
|
|
|
@ -578,7 +578,6 @@ namespace Microsoft.PowerPlatform.Dataverse.Client
|
|||
internal Func<string, Task<string>> GetAccessTokenAsync { get; set; }
|
||||
|
||||
|
||||
//TODO: COMPLETE EXPOSURE OF ADDITIONAL HEADER FEATURE
|
||||
/// <summary>
|
||||
/// Function to call to get the current headers for this request
|
||||
/// </summary>
|
||||
|
@ -2307,7 +2306,7 @@ namespace Microsoft.PowerPlatform.Dataverse.Client
|
|||
if (httpOperationException.Response.Headers.ContainsKey("Retry-After"))
|
||||
_retryPauseTimeRunning = TimeSpan.Parse(httpOperationException.Response.Headers["Retry-After"].FirstOrDefault());
|
||||
else
|
||||
_retryPauseTimeRunning = retryPauseTime; // default timespan.
|
||||
_retryPauseTimeRunning = retryPauseTime.Add(TimeSpan.FromSeconds(Math.Pow(2, retryCount))); ; // default timespan with back off is response does not contain the tag..
|
||||
}
|
||||
else
|
||||
{
|
||||
|
@ -3330,7 +3329,14 @@ namespace Microsoft.PowerPlatform.Dataverse.Client
|
|||
foreach (var itm in discoverResult.OrganizationDetailCollection)
|
||||
{
|
||||
var orgObj = Utilities.DeterminDiscoveryDataFromOrgDetail(new Uri(itm.Endpoints[EndpointType.OrganizationService]), out isOnPrem);
|
||||
AddOrgToOrgList(itm, orgObj.DisplayName, ref orgsList);
|
||||
if (orgObj != null)
|
||||
{
|
||||
AddOrgToOrgList(itm, orgObj.DisplayName, ref orgsList);
|
||||
}
|
||||
else
|
||||
{
|
||||
AddOrgToOrgList(itm, !string.IsNullOrEmpty(itm.Geo) ? itm.Geo : "Unknown", ref orgsList);
|
||||
}
|
||||
}
|
||||
}
|
||||
return orgsList;
|
||||
|
@ -3390,9 +3396,16 @@ namespace Microsoft.PowerPlatform.Dataverse.Client
|
|||
foreach (var itm in discoverResult.OrganizationDetailCollection)
|
||||
{
|
||||
var orgObj = Utilities.DeterminDiscoveryDataFromOrgDetail(new Uri(itm.Endpoints[EndpointType.OrganizationService]), out isOnPrem);
|
||||
if (trimToDiscoveryUri != null && !trimToDiscoveryUri.Equals(orgObj.DiscoveryServerUri))
|
||||
continue;
|
||||
AddOrgToOrgList(itm, orgObj.DisplayName, ref orgsList);
|
||||
if (orgObj != null)
|
||||
{
|
||||
if (trimToDiscoveryUri != null && !trimToDiscoveryUri.Equals(orgObj.DiscoveryServerUri))
|
||||
continue;
|
||||
AddOrgToOrgList(itm, orgObj.DisplayName, ref orgsList);
|
||||
}
|
||||
else
|
||||
{
|
||||
AddOrgToOrgList(itm, !string.IsNullOrEmpty(itm.Geo) ? itm.Geo : "Unknown", ref orgsList);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -0,0 +1,69 @@
|
|||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Linq;
|
||||
using System.Text;
|
||||
using System.Threading.Tasks;
|
||||
using Microsoft.Extensions.DependencyInjection;
|
||||
using Microsoft.PowerPlatform.Dataverse.Client.Model;
|
||||
|
||||
namespace Microsoft.PowerPlatform.Dataverse.Client
|
||||
{
|
||||
/// <summary>
|
||||
/// TBD
|
||||
/// </summary>
|
||||
public class DataverseServiceClientBuilder
|
||||
{
|
||||
private ConnectionOptions _connectionOptions;
|
||||
|
||||
/// <summary>
|
||||
///
|
||||
/// </summary>
|
||||
/// <param name="connectionOptions"></param>
|
||||
internal DataverseServiceClientBuilder(ConnectionOptions connectionOptions)
|
||||
{
|
||||
_connectionOptions = connectionOptions;
|
||||
throw new NotImplementedException("In Development - Not for use.");
|
||||
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
///
|
||||
/// </summary>
|
||||
/// <param name="connectionOptions"></param>
|
||||
/// <returns></returns>
|
||||
public static DataverseServiceClientBuilder Create(ConnectionOptions connectionOptions)
|
||||
{
|
||||
return new DataverseServiceClientBuilder(connectionOptions);
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// TBD
|
||||
/// </summary>
|
||||
public static class ServiceCollectionExtentions
|
||||
{
|
||||
/// <summary>
|
||||
/// TBD
|
||||
/// </summary>
|
||||
/// <param name="services"></param>
|
||||
/// <param name="connectionOptions"></param>
|
||||
/// <returns></returns>
|
||||
public static IServiceCollection AddDataverseServiceClient(
|
||||
this IServiceCollection services,
|
||||
Action<ConnectionOptions> connectionOptions)
|
||||
{
|
||||
throw new NotImplementedException("In Development - Not for use.");
|
||||
|
||||
//services.Configure(connectionOptions);
|
||||
|
||||
|
||||
// Register lib services here...
|
||||
// services.AddScoped<ILibraryService, DefaultLibraryService>();
|
||||
|
||||
//return services;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
}
|
|
@ -295,7 +295,7 @@ namespace Microsoft.PowerPlatform.Dataverse.Client.Extensions
|
|||
// if request should bypass plugin exec.
|
||||
if (bypassPluginExecution &&
|
||||
Utilities.FeatureVersionMinimums.IsFeatureValidForEnviroment(serviceClient.ConnectedOrgVersion, Utilities.FeatureVersionMinimums.AllowBypassCustomPlugin))
|
||||
req.Parameters.Add(Utilities.RequestHeaders.BYPASSCUSTOMPLUGINEXECUTION, true);
|
||||
req.Parameters[Utilities.RequestHeaders.BYPASSCUSTOMPLUGINEXECUTION] = true;
|
||||
|
||||
if (serviceClient.IsBatchOperationsAvailable)
|
||||
{
|
||||
|
|
|
@ -58,7 +58,7 @@ namespace Microsoft.PowerPlatform.Dataverse.Client.Extensions
|
|||
createReq.Target = NewEnt;
|
||||
createReq.Parameters.Add("SuppressDuplicateDetection", !enabledDuplicateDetection);
|
||||
if (!string.IsNullOrWhiteSpace(applyToSolution))
|
||||
createReq.Parameters.Add(Utilities.RequestHeaders.SOLUTIONUNIQUENAME, applyToSolution);
|
||||
createReq.Parameters[Utilities.RequestHeaders.SOLUTIONUNIQUENAME] = applyToSolution;
|
||||
|
||||
CreateResponse createResp = null;
|
||||
|
||||
|
|
|
@ -14,6 +14,28 @@ namespace Microsoft.PowerPlatform.Dataverse.Client.Model
|
|||
/// </summary>
|
||||
public class ConfigurationOptions
|
||||
{
|
||||
/// <summary>
|
||||
/// Updates the instance of Options with a previously created Options Object.
|
||||
/// </summary>
|
||||
/// <param name="options">PreLoaded Options Array</param>
|
||||
public void UpdateOptions(ConfigurationOptions options)
|
||||
{
|
||||
if (options != null)
|
||||
{
|
||||
EnableAffinityCookie = options.EnableAffinityCookie;
|
||||
MaxBufferPoolSizeOveride = options.MaxBufferPoolSizeOveride;
|
||||
MaxFaultSizeOverride = options.MaxFaultSizeOverride;
|
||||
MaxReceivedMessageSizeOverride = options.MaxReceivedMessageSizeOverride;
|
||||
MaxRetryCount = options.MaxRetryCount;
|
||||
MSALEnabledLogPII = options.MSALEnabledLogPII;
|
||||
MSALRequestTimeout = options.MSALRequestTimeout;
|
||||
MSALRetryCount = options.MSALRetryCount;
|
||||
RetryPauseTime = options.RetryPauseTime;
|
||||
UseWebApi = options.UseWebApi;
|
||||
UseWebApiLoginFlow = options.UseWebApiLoginFlow;
|
||||
}
|
||||
}
|
||||
|
||||
#region Dataverse Interaction Settings
|
||||
private int _maxRetryCount = Utils.AppSettingsHelper.GetAppSetting("ApiOperationRetryCountOverride", 10);
|
||||
|
||||
|
@ -139,7 +161,7 @@ namespace Microsoft.PowerPlatform.Dataverse.Client.Model
|
|||
/// <summary>
|
||||
/// Number of retries to Get a token from MSAL.
|
||||
/// </summary>
|
||||
public int MsalRetryCount
|
||||
public int MSALRetryCount
|
||||
{
|
||||
get => _msalRetryCount;
|
||||
set => _msalRetryCount = value;
|
||||
|
|
|
@ -117,6 +117,16 @@ namespace Microsoft.PowerPlatform.Dataverse.Client
|
|||
/// </summary>
|
||||
internal IOrganizationService _testOrgSvcInterface { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// ConnectionsOptions object used with connection presetup and staging for connect.
|
||||
/// </summary>
|
||||
private ConnectionOptions _setupConnectionOptions = null;
|
||||
|
||||
/// <summary>
|
||||
/// Connections Options holder for connection call.
|
||||
/// </summary>
|
||||
private ConnectionOptions _connectionOptions = null;
|
||||
|
||||
#endregion
|
||||
|
||||
#region Properties
|
||||
|
@ -454,7 +464,12 @@ namespace Microsoft.PowerPlatform.Dataverse.Client
|
|||
/// Returns the access token from the attached function.
|
||||
/// This is set via the ServiceContructor that accepts a target url and a function to return an access token.
|
||||
/// </summary>
|
||||
internal Func<string, Task<string>> GetAccessToken { get; set; }
|
||||
internal Func<string, Task<string>> GetAccessToken { get; set; } = null;
|
||||
|
||||
/// <summary>
|
||||
/// Returns any additional or custom headers that need to be added to the request to Dataverse.
|
||||
/// </summary>
|
||||
internal Func<Task<Dictionary<string, string>>> GetCustomHeaders { get; set; } = null;
|
||||
|
||||
/// <summary>
|
||||
/// Gets or Sets the current caller ID
|
||||
|
@ -626,7 +641,7 @@ namespace Microsoft.PowerPlatform.Dataverse.Client
|
|||
}
|
||||
|
||||
/// <summary>
|
||||
/// Server Hint for the number of concurrent threads that would provbide optimal processing.
|
||||
/// Server Hint for the number of concurrent threads that would provide optimal processing.
|
||||
/// </summary>
|
||||
public int RecommendedDegreesOfParallelism => _connectionSvc.RecommendedDegreesOfParallelism;
|
||||
|
||||
|
@ -664,6 +679,7 @@ namespace Microsoft.PowerPlatform.Dataverse.Client
|
|||
_batchManager = new BatchManager(_logEntry);
|
||||
_metadataUtlity = new MetadataUtility(this);
|
||||
_dynamicAppUtility = new DynamicEntityUtility(this, _metadataUtlity);
|
||||
IsReady = true;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
|
@ -679,21 +695,6 @@ namespace Microsoft.PowerPlatform.Dataverse.Client
|
|||
ConnectToService(dataverseConnectionString, logger);
|
||||
}
|
||||
|
||||
//REMOVED FROM BUILD FOR NOW
|
||||
///// <summary>
|
||||
///// Uses the Organization Web proxy Client provided by the user
|
||||
///// </summary>
|
||||
///// <param name="externalOrgWebProxyClient">User Provided Organization Web Proxy Client</param>
|
||||
///// <param name="logger">Logging provider <see cref="ILogger"/></param>
|
||||
//internal ServiceClient(OrganizationWebProxyClient externalOrgWebProxyClient, ILogger logger = null)
|
||||
//{
|
||||
// // Disabled for this build as we determine how to support server side Native Client
|
||||
|
||||
// //CreateServiceConnection(null, AuthenticationType.OAuth, string.Empty, string.Empty, string.Empty, null, string.Empty,
|
||||
// // MakeSecureString(string.Empty), string.Empty, string.Empty, string.Empty, false, false, null, string.Empty, null,
|
||||
// // PromptBehavior.Auto, externalOrgWebProxyClient, externalLogger: logger);
|
||||
//}
|
||||
|
||||
/// <summary>
|
||||
/// Creates an instance of ServiceClient who's authentication is managed by the caller.
|
||||
/// This requires the caller to implement a function that will accept the InstanceURI as a string will return the access token as a string on demand when the ServiceClient requires it.
|
||||
|
@ -896,13 +897,65 @@ namespace Microsoft.PowerPlatform.Dataverse.Client
|
|||
}
|
||||
|
||||
/// <summary>
|
||||
/// Creating the ServiceClient Connection with a Set of ConnectionOptionsObject and a default configuration.
|
||||
/// Creating the ServiceClient Connection with a ConnectionOptions Object and ConfigurationOptions Object. This allows for deferred create of a Dataverse Service Client.
|
||||
/// </summary>
|
||||
/// <param name="connectionOptions"></param>
|
||||
/// <param name="serviceClientConfiguration"></param>
|
||||
public ServiceClient(ConnectionOptions connectionOptions, IConfigureOptions<ConfigurationOptions> serviceClientConfiguration)
|
||||
/// <param name="connectionOptions">Describes how the Connection should be created.</param>
|
||||
/// <param name="deferConnection">False by Default, if True, stages the properties of the connection and returns. You must call .Connect() to complete the connection. </param>
|
||||
/// <param name="serviceClientConfiguration">Described Configuration Options for the connection.</param>
|
||||
public ServiceClient(ConnectionOptions connectionOptions, bool deferConnection = false, ConfigurationOptions serviceClientConfiguration = null)
|
||||
{
|
||||
throw new NotImplementedException("PreWork for Builder Support");
|
||||
// store the options and ready for connect call.
|
||||
_setupConnectionOptions = connectionOptions;
|
||||
|
||||
//_configuration
|
||||
if ( serviceClientConfiguration != null )
|
||||
_configuration.Value.UpdateOptions(serviceClientConfiguration);
|
||||
|
||||
|
||||
// External auth.
|
||||
if (connectionOptions.AccessTokenProviderFunctionAsync != null)
|
||||
{
|
||||
connectionOptions.AuthenticationType = AuthenticationType.ExternalTokenManagement;
|
||||
GetAccessToken = connectionOptions.AccessTokenProviderFunctionAsync;
|
||||
}
|
||||
|
||||
// Add custom header support.
|
||||
if ( connectionOptions.RequestAdditionalHeadersAsync != null )
|
||||
{
|
||||
GetCustomHeaders = connectionOptions.RequestAdditionalHeadersAsync;
|
||||
}
|
||||
|
||||
if (deferConnection)
|
||||
{
|
||||
_connectionOptions = connectionOptions;
|
||||
if (connectionOptions.Logger != null)
|
||||
connectionOptions.Logger.LogInformation("Connection creation has been deferred at user request");
|
||||
return;
|
||||
}
|
||||
|
||||
// Form Connection string.
|
||||
string connectionString = ConnectionStringConstants.CreateConnectionStringFromConnectionOptions(connectionOptions);
|
||||
ConnectToService(connectionString, connectionOptions.Logger);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Connects the Dataverse Service Client instance when staged with the Deferd Connection constructor.
|
||||
/// </summary>
|
||||
/// <returns></returns>
|
||||
public bool Connect()
|
||||
{
|
||||
if (_connectionOptions != null && IsReady == false)
|
||||
{
|
||||
if (_connectionOptions.Logger != null)
|
||||
_connectionOptions.Logger.LogInformation("Initiating connection to Dataverse");
|
||||
|
||||
string connectionString = ConnectionStringConstants.CreateConnectionStringFromConnectionOptions(_connectionOptions);
|
||||
ConnectToService(connectionString, _connectionOptions.Logger);
|
||||
_connectionOptions = null;
|
||||
return true;
|
||||
}
|
||||
else
|
||||
return false;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
|
@ -1194,6 +1247,8 @@ namespace Microsoft.PowerPlatform.Dataverse.Client
|
|||
{
|
||||
try
|
||||
{
|
||||
if (GetCustomHeaders != null)
|
||||
_connectionSvc.RequestAdditionalHeadersAsync = GetCustomHeaders;
|
||||
// Assign the log entry host to the ConnectionService engine
|
||||
ConnectionService tempConnectService = null;
|
||||
_connectionSvc.InternetProtocalToUse = useSsl ? "https" : "http";
|
||||
|
@ -1487,6 +1542,7 @@ namespace Microsoft.PowerPlatform.Dataverse.Client
|
|||
public HttpResponseMessage ExecuteWebRequest(HttpMethod method, string queryString, string body, Dictionary<string, List<string>> customHeaders, string contentType = default, CancellationToken cancellationToken = default)
|
||||
{
|
||||
_logEntry.ResetLastError(); // Reset Last Error
|
||||
ValidateConnectionLive();
|
||||
if (DataverseService == null)
|
||||
{
|
||||
_logEntry.Log("Dataverse Service not initialized", TraceEventType.Error);
|
||||
|
@ -1533,6 +1589,7 @@ namespace Microsoft.PowerPlatform.Dataverse.Client
|
|||
|
||||
internal OrganizationResponse ExecuteOrganizationRequestImpl(OrganizationRequest req, string logMessageTag = "User Defined", bool useWebAPI = false, bool bypassPluginExecution = false)
|
||||
{
|
||||
ValidateConnectionLive();
|
||||
if (req != null)
|
||||
{
|
||||
useWebAPI = Utilities.IsRequestValidForTranslationToWebAPI(req);
|
||||
|
@ -1555,6 +1612,7 @@ namespace Microsoft.PowerPlatform.Dataverse.Client
|
|||
|
||||
private async Task<OrganizationResponse> ExecuteOrganizationRequestAsyncImpl(OrganizationRequest req, CancellationToken cancellationToken, string logMessageTag = "User Defined", bool useWebAPI = false, bool bypassPluginExecution = false)
|
||||
{
|
||||
ValidateConnectionLive();
|
||||
cancellationToken.ThrowIfCancellationRequested();
|
||||
if (req != null)
|
||||
{
|
||||
|
@ -1587,6 +1645,7 @@ namespace Microsoft.PowerPlatform.Dataverse.Client
|
|||
/// <returns>Result of create request or null.</returns>
|
||||
internal async Task<OrganizationResponse> Command_ExecuteAsync(OrganizationRequest req, string errorStringCheck, System.Threading.CancellationToken cancellationToken, bool bypassPluginExecution = false)
|
||||
{
|
||||
ValidateConnectionLive();
|
||||
if (DataverseServiceAsync != null)
|
||||
{
|
||||
// if created based on Async Client.
|
||||
|
@ -1610,6 +1669,7 @@ namespace Microsoft.PowerPlatform.Dataverse.Client
|
|||
/// <returns>Result of create request or null.</returns>
|
||||
internal async Task<OrganizationResponse> Command_ExecuteAsyncImpl(OrganizationRequest req, string errorStringCheck, System.Threading.CancellationToken cancellationToken, bool bypassPluginExecution = false)
|
||||
{
|
||||
ValidateConnectionLive();
|
||||
Guid requestTrackingId = Guid.NewGuid();
|
||||
OrganizationResponse resp = null;
|
||||
Stopwatch logDt = new Stopwatch();
|
||||
|
@ -1646,7 +1706,7 @@ namespace Microsoft.PowerPlatform.Dataverse.Client
|
|||
|
||||
// if request should bypass plugin exec.
|
||||
if (bypassPluginExecution && Utilities.FeatureVersionMinimums.IsFeatureValidForEnviroment(_connectionSvc?.OrganizationVersion, Utilities.FeatureVersionMinimums.AllowBypassCustomPlugin))
|
||||
req.Parameters.Add(Utilities.RequestHeaders.BYPASSCUSTOMPLUGINEXECUTION, true);
|
||||
req.Parameters[Utilities.RequestHeaders.BYPASSCUSTOMPLUGINEXECUTION] = true;
|
||||
|
||||
_logEntry.Log(string.Format(CultureInfo.InvariantCulture, "Execute Command - {0}{1}: {3}RequestID={2}",
|
||||
req.RequestName,
|
||||
|
@ -1704,6 +1764,7 @@ namespace Microsoft.PowerPlatform.Dataverse.Client
|
|||
/// <returns>Result of create request or null.</returns>
|
||||
internal OrganizationResponse Command_Execute(OrganizationRequest req, string errorStringCheck, bool bypassPluginExecution = false)
|
||||
{
|
||||
ValidateConnectionLive();
|
||||
Guid requestTrackingId = Guid.NewGuid();
|
||||
OrganizationResponse resp = null;
|
||||
Stopwatch logDt = new Stopwatch();
|
||||
|
@ -1739,7 +1800,7 @@ namespace Microsoft.PowerPlatform.Dataverse.Client
|
|||
|
||||
// if request should bypass plugin exec.
|
||||
if (bypassPluginExecution && Utilities.FeatureVersionMinimums.IsFeatureValidForEnviroment(_connectionSvc?.OrganizationVersion, Utilities.FeatureVersionMinimums.AllowBypassCustomPlugin))
|
||||
req.Parameters.Add(Utilities.RequestHeaders.BYPASSCUSTOMPLUGINEXECUTION, true);
|
||||
req.Parameters[Utilities.RequestHeaders.BYPASSCUSTOMPLUGINEXECUTION] = true;
|
||||
|
||||
//RequestId Logging line for telemetry
|
||||
string requestIdLogSegement = _logEntry.GetFormatedRequestSessionIdString(requestTrackingId, SessionTrackingId);
|
||||
|
@ -1880,6 +1941,28 @@ namespace Microsoft.PowerPlatform.Dataverse.Client
|
|||
return null;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Validates that a connection is live and connected. Throws an exception if the connection is not active.
|
||||
/// </summary>
|
||||
/// <returns></returns>
|
||||
internal void ValidateConnectionLive()
|
||||
{
|
||||
if (!this.IsReady)
|
||||
{
|
||||
if (this._connectionOptions != null)
|
||||
{
|
||||
var failureExecpt = new DataverseConnectionException("Service Client is Staged for Connection but not Connected. You must call .Connect() on this client before using it.");
|
||||
_logEntry?.Log(failureExecpt);
|
||||
throw failureExecpt;
|
||||
}
|
||||
else
|
||||
{
|
||||
var failureExecpt = new DataverseConnectionException("Service Client is not connected to Dataverse. Please recreate this Service Client.");
|
||||
_logEntry?.Log(failureExecpt);
|
||||
throw failureExecpt;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
#region IOrganzation Service Proxy - Proxy object
|
||||
/// <summary>
|
||||
|
|
|
@ -1,12 +1,13 @@
|
|||
using System;
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Linq;
|
||||
using System.Text;
|
||||
using System.Threading.Tasks;
|
||||
using Microsoft.PowerPlatform.Dataverse.Client.InternalExtensions;
|
||||
|
||||
namespace Microsoft.PowerPlatform.Dataverse.Client
|
||||
{
|
||||
static class ConnectionStringConstants
|
||||
internal static class ConnectionStringConstants
|
||||
{
|
||||
public static readonly string[] ServiceUri = { "ServiceUri", "Service Uri", "Url", "Server" };
|
||||
public static readonly string[] UserName = { "UserName", "User Name", "UserId", "User Id" };
|
||||
|
@ -24,5 +25,57 @@ namespace Microsoft.PowerPlatform.Dataverse.Client
|
|||
public static readonly string[] SkipDiscovery = { "SkipDiscovery" };
|
||||
public static readonly string[] IntegratedSecurity = { "Integrated Security" };
|
||||
public static readonly string[] ClientSecret = { "ClientSecret" , "Secret" };
|
||||
|
||||
public static string CreateConnectionStringFromConnectionOptions(Model.ConnectionOptions options)
|
||||
{
|
||||
|
||||
if ( options != null)
|
||||
{
|
||||
StringBuilder sbConnectionString = new StringBuilder();
|
||||
if (options.ServiceUri != null)
|
||||
sbConnectionString.Append($"ServiceUri={options.ServiceUri};");
|
||||
|
||||
sbConnectionString.Append($"AuthType={options.AuthenticationType};");
|
||||
switch (options.AuthenticationType)
|
||||
{
|
||||
case AuthenticationType.AD:
|
||||
if (options.UseCurrentUserForLogin) sbConnectionString.Append($"Integrated Security=True;");
|
||||
sbConnectionString.Append($"UserName={options.UserName};");
|
||||
sbConnectionString.Append($"Password={options.Password.ToUnsecureString()};");
|
||||
if (!string.IsNullOrEmpty(options.Domain)) sbConnectionString.Append($"Domain={options.Domain};");
|
||||
break;
|
||||
case AuthenticationType.OAuth:
|
||||
if (options.UseCurrentUserForLogin) sbConnectionString.Append($"Integrated Security=True;");
|
||||
if (!string.IsNullOrEmpty(options.UserName)) sbConnectionString.Append($"UserName={options.UserName};");
|
||||
if (options.Password != null ) sbConnectionString.Append($"Password={options.Password.ToUnsecureString()};");
|
||||
if (!string.IsNullOrEmpty(options.TokenCacheStorePath)) sbConnectionString.Append($"TokenCacheStorePath={options.TokenCacheStorePath};");
|
||||
if (options.LoginPrompt.HasValue) sbConnectionString.Append($"LoginPrompt={options.LoginPrompt.Value};");
|
||||
sbConnectionString.Append($"ClientId={options.ClientId};");
|
||||
if (options.RedirectUri != null) sbConnectionString.Append($"RedirectUri={options.RedirectUri};");
|
||||
break;
|
||||
case AuthenticationType.Certificate:
|
||||
sbConnectionString.Append($"ClientId={options.ClientId};");
|
||||
sbConnectionString.Append($"CertificateThumbprint={options.CertificateThumbprint};");
|
||||
sbConnectionString.Append($"CertificateStoreName={options.CertificateStoreName};");
|
||||
break;
|
||||
case AuthenticationType.ClientSecret:
|
||||
sbConnectionString.Append($"ClientId={options.ClientId};");
|
||||
sbConnectionString.Append($"ClientSecret={options.ClientSecret};");
|
||||
break;
|
||||
case AuthenticationType.ExternalTokenManagement:
|
||||
break;
|
||||
case AuthenticationType.InvalidConnection:
|
||||
break;
|
||||
default:
|
||||
break;
|
||||
}
|
||||
if (options.SkipDiscovery) sbConnectionString.Append($"SkipDiscovery={options.SkipDiscovery};");
|
||||
sbConnectionString.Append($"RequireNewInstance={options.RequireNewInstance};");
|
||||
|
||||
return sbConnectionString.ToString();
|
||||
}
|
||||
else
|
||||
return string.Empty;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -1056,7 +1056,6 @@ namespace Microsoft.PowerPlatform.Dataverse.Client
|
|||
|
||||
}
|
||||
|
||||
|
||||
#region CookieHelpers
|
||||
/// <summary>
|
||||
/// Manage Pushing Cookies Forward in a switchable manner.
|
||||
|
|
|
@ -1445,9 +1445,16 @@ namespace Microsoft.PowerPlatform.Dataverse.ConnectControl
|
|||
foreach (var itm in discoverResult.OrganizationDetailCollection)
|
||||
{
|
||||
var orgObj = Utilities.DeterminDiscoveryDataFromOrgDetail(new Uri(itm.Endpoints[EndpointType.OrganizationService]), out isOnPrem, Geo: itm.Geo);
|
||||
if (trimToDiscoveryUri != null && !trimToDiscoveryUri.Equals(orgObj.DiscoveryServerUri))
|
||||
continue;
|
||||
AddOrgToOrgList(itm, orgObj.DisplayName, orgObj.DiscoveryServerUri);
|
||||
if (orgObj != null)
|
||||
{
|
||||
if (trimToDiscoveryUri != null && !trimToDiscoveryUri.Equals(orgObj.DiscoveryServerUri))
|
||||
continue;
|
||||
AddOrgToOrgList(itm, orgObj.DisplayName, orgObj.DiscoveryServerUri);
|
||||
}
|
||||
else
|
||||
{
|
||||
AddOrgToOrgList(itm, !string.IsNullOrEmpty(itm.Geo) ? itm.Geo : "Unknown", orgObj.DiscoveryServerUri);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -15,8 +15,8 @@ EndProject
|
|||
#EndProject
|
||||
Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "LiveTestsConsole", "UnitTests\LiveTestsConsole\LiveTestsConsole.csproj", "{5A1A4FFF-78F5-48A2-9AB0-3E507E938465}"
|
||||
EndProject
|
||||
Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "Microsoft.PowerPlatform.Dataverse.ServiceClientConverter", "Extensions\Microsoft.PowerPlatform.Dataverse.ServiceClientConverter\Microsoft.PowerPlatform.Dataverse.ServiceClientConverter.csproj", "{752E5268-3D99-485D-A31E-FC40AE9C0867}"
|
||||
EndProject
|
||||
#Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "Microsoft.PowerPlatform.Dataverse.ServiceClientConverter", "Extensions\Microsoft.PowerPlatform.Dataverse.ServiceClientConverter\Microsoft.PowerPlatform.Dataverse.ServiceClientConverter.csproj", "{752E5268-3D99-485D-A31E-FC40AE9C0867}"
|
||||
#EndProject
|
||||
Global
|
||||
GlobalSection(SolutionConfigurationPlatforms) = preSolution
|
||||
Debug|Any CPU = Debug|Any CPU
|
||||
|
|
|
@ -1,7 +1,7 @@
|
|||
|
||||
Microsoft Visual Studio Solution File, Format Version 12.00
|
||||
# Visual Studio Version 16
|
||||
VisualStudioVersion = 16.0.29609.76
|
||||
# Visual Studio Version 17
|
||||
VisualStudioVersion = 17.2.32526.322
|
||||
MinimumVisualStudioVersion = 10.0.40219.1
|
||||
Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "Microsoft.PowerPlatform.Dataverse.Client", "Client\Microsoft.PowerPlatform.Dataverse.Client.csproj", "{7303AAC5-BCEF-4BDB-B7D8-303490D506C6}"
|
||||
EndProject
|
||||
|
@ -11,8 +11,6 @@ Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "DataverseClient_Core_UnitTe
|
|||
EndProject
|
||||
Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "Microsoft.PowerPlatform.Dataverse.Client.Dynamics", "Extensions\DynamicsExtension\Microsoft.PowerPlatform.Dataverse.Client.Dynamics.csproj", "{8CE32D7B-EA3D-4725-A270-9780D366EDB7}"
|
||||
EndProject
|
||||
#Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "Microsoft.Dynamics.Sdk.Messages.Shell", "Extensions\Microsoft.Dynamics.Sdk.Messages\Microsoft.Dynamics.Sdk.Messages.Shell.csproj", "{503645DD-7711-40ED-8811-F06391F294AB}"
|
||||
#EndProject
|
||||
Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "LiveTestsConsole", "UnitTests\LiveTestsConsole\LiveTestsConsole.csproj", "{5A1A4FFF-78F5-48A2-9AB0-3E507E938465}"
|
||||
EndProject
|
||||
Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "Microsoft.PowerPlatform.Dataverse.ConnectControl", "ConnectControl\Microsoft.PowerPlatform.Dataverse.ConnectControl.csproj", "{294C017A-54A0-4582-A512-5B58B9220082}"
|
||||
|
@ -25,6 +23,8 @@ Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "Microsoft.PowerPlatform.Dat
|
|||
EndProject
|
||||
Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "Microsoft.PowerPlatform.Dataverse.WebResourceUtility", "WebResourceUtility\Microsoft.PowerPlatform.Dataverse.WebResourceUtility.csproj", "{FDFD6B7F-A925-40EE-98DC-2E06C1D1E3B6}"
|
||||
EndProject
|
||||
#Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "Microsoft.PowerPlatform.Dataverse.ServiceClientConverter", "Extensions\Microsoft.PowerPlatform.Dataverse.ServiceClientConverter\Microsoft.PowerPlatform.Dataverse.ServiceClientConverter.csproj", "{6F7522A6-3B98-40EE-B92B-5EA423E6F600}"
|
||||
#EndProject
|
||||
Global
|
||||
GlobalSection(SolutionConfigurationPlatforms) = preSolution
|
||||
CRMINTERNAL|Any CPU = CRMINTERNAL|Any CPU
|
||||
|
@ -71,18 +71,6 @@ Global
|
|||
{8CE32D7B-EA3D-4725-A270-9780D366EDB7}.Release|Any CPU.Build.0 = Release|Any CPU
|
||||
{8CE32D7B-EA3D-4725-A270-9780D366EDB7}.Release|x64.ActiveCfg = Release|Any CPU
|
||||
{8CE32D7B-EA3D-4725-A270-9780D366EDB7}.Release|x64.Build.0 = Release|Any CPU
|
||||
{503645DD-7711-40ED-8811-F06391F294AB}.CRMINTERNAL|Any CPU.ActiveCfg = Release|Any CPU
|
||||
{503645DD-7711-40ED-8811-F06391F294AB}.CRMINTERNAL|Any CPU.Build.0 = Release|Any CPU
|
||||
{503645DD-7711-40ED-8811-F06391F294AB}.CRMINTERNAL|x64.ActiveCfg = Release|Any CPU
|
||||
{503645DD-7711-40ED-8811-F06391F294AB}.CRMINTERNAL|x64.Build.0 = Release|Any CPU
|
||||
{503645DD-7711-40ED-8811-F06391F294AB}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
|
||||
{503645DD-7711-40ED-8811-F06391F294AB}.Debug|Any CPU.Build.0 = Debug|Any CPU
|
||||
{503645DD-7711-40ED-8811-F06391F294AB}.Debug|x64.ActiveCfg = Debug|Any CPU
|
||||
{503645DD-7711-40ED-8811-F06391F294AB}.Debug|x64.Build.0 = Debug|Any CPU
|
||||
{503645DD-7711-40ED-8811-F06391F294AB}.Release|Any CPU.ActiveCfg = Release|Any CPU
|
||||
{503645DD-7711-40ED-8811-F06391F294AB}.Release|Any CPU.Build.0 = Release|Any CPU
|
||||
{503645DD-7711-40ED-8811-F06391F294AB}.Release|x64.ActiveCfg = Release|Any CPU
|
||||
{503645DD-7711-40ED-8811-F06391F294AB}.Release|x64.Build.0 = Release|Any CPU
|
||||
{5A1A4FFF-78F5-48A2-9AB0-3E507E938465}.CRMINTERNAL|Any CPU.ActiveCfg = Release|Any CPU
|
||||
{5A1A4FFF-78F5-48A2-9AB0-3E507E938465}.CRMINTERNAL|Any CPU.Build.0 = Release|Any CPU
|
||||
{5A1A4FFF-78F5-48A2-9AB0-3E507E938465}.CRMINTERNAL|x64.ActiveCfg = Release|Any CPU
|
||||
|
@ -143,6 +131,18 @@ Global
|
|||
{FDFD6B7F-A925-40EE-98DC-2E06C1D1E3B6}.Release|Any CPU.Build.0 = Release|Any CPU
|
||||
{FDFD6B7F-A925-40EE-98DC-2E06C1D1E3B6}.Release|x64.ActiveCfg = Release|x64
|
||||
{FDFD6B7F-A925-40EE-98DC-2E06C1D1E3B6}.Release|x64.Build.0 = Release|x64
|
||||
{6F7522A6-3B98-40EE-B92B-5EA423E6F600}.CRMINTERNAL|Any CPU.ActiveCfg = Debug|Any CPU
|
||||
{6F7522A6-3B98-40EE-B92B-5EA423E6F600}.CRMINTERNAL|Any CPU.Build.0 = Debug|Any CPU
|
||||
{6F7522A6-3B98-40EE-B92B-5EA423E6F600}.CRMINTERNAL|x64.ActiveCfg = Debug|Any CPU
|
||||
{6F7522A6-3B98-40EE-B92B-5EA423E6F600}.CRMINTERNAL|x64.Build.0 = Debug|Any CPU
|
||||
{6F7522A6-3B98-40EE-B92B-5EA423E6F600}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
|
||||
{6F7522A6-3B98-40EE-B92B-5EA423E6F600}.Debug|Any CPU.Build.0 = Debug|Any CPU
|
||||
{6F7522A6-3B98-40EE-B92B-5EA423E6F600}.Debug|x64.ActiveCfg = Debug|Any CPU
|
||||
{6F7522A6-3B98-40EE-B92B-5EA423E6F600}.Debug|x64.Build.0 = Debug|Any CPU
|
||||
{6F7522A6-3B98-40EE-B92B-5EA423E6F600}.Release|Any CPU.ActiveCfg = Release|Any CPU
|
||||
{6F7522A6-3B98-40EE-B92B-5EA423E6F600}.Release|Any CPU.Build.0 = Release|Any CPU
|
||||
{6F7522A6-3B98-40EE-B92B-5EA423E6F600}.Release|x64.ActiveCfg = Release|Any CPU
|
||||
{6F7522A6-3B98-40EE-B92B-5EA423E6F600}.Release|x64.Build.0 = Release|Any CPU
|
||||
EndGlobalSection
|
||||
GlobalSection(SolutionProperties) = preSolution
|
||||
HideSolutionNode = FALSE
|
||||
|
|
|
@ -2,7 +2,7 @@
|
|||
|
||||
<PropertyGroup>
|
||||
<RootNamespace>Microsoft.PowerPlatform.Dataverse.ServiceClientConverter</RootNamespace>
|
||||
<ComponentAreaName>DataverseClient-Converter</ComponentAreaName>
|
||||
<ComponentAreaName>DataverseClient</ComponentAreaName>
|
||||
<SignAssembly>true</SignAssembly>
|
||||
</PropertyGroup>
|
||||
<Import Project="..\..\..\..\Build.Common.core.props" />
|
||||
|
@ -10,6 +10,11 @@
|
|||
<PropertyGroup>
|
||||
<GeneratePackageOnBuild>false</GeneratePackageOnBuild>
|
||||
<DocumentationFile>$(OutDir)\Microsoft.PowerPlatform.Dataverse.ServiceClientConverter.xml</DocumentationFile>
|
||||
<TargetFrameworks>net462;net472;net48</TargetFrameworks>
|
||||
</PropertyGroup>
|
||||
</Project>
|
||||
|
||||
<ItemGroup>
|
||||
<PackageReference Include="Microsoft.CrmSdk.XrmTooling.CoreAssembly" Version="9.1.0.110" />
|
||||
<PackageReference Include="Microsoft.PowerPlatform.Dataverse.Client" Version="1.0.0" />
|
||||
</ItemGroup>
|
||||
</Project>
|
||||
|
|
|
@ -1,3 +1,5 @@
|
|||
using Microsoft.PowerPlatform.Dataverse.Client;
|
||||
using Microsoft.Xrm.Tooling.Connector;
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Linq;
|
||||
|
@ -7,10 +9,98 @@ using System.Threading.Tasks;
|
|||
namespace Microsoft.PowerPlatform.Dataverse.ServiceClientConverter
|
||||
{
|
||||
/// <summary>
|
||||
///
|
||||
/// Provides Conversion utilities to convert between CrmServiceClient and Dataverse ServiceClient
|
||||
/// Works only for JWT based scenarios.
|
||||
/// </summary>
|
||||
public static class ServiceClientConverter
|
||||
{
|
||||
// TBD:// Post next release add converter to this method based on Nuget Packages.
|
||||
#region Crm ServiceClient to Dataverse
|
||||
|
||||
/// <summary>
|
||||
/// Create CrmServiceClient based on Dataverse ServiceClient
|
||||
/// </summary>
|
||||
/// <param name="crmServiceClient"></param>
|
||||
/// <returns>a new Dataverse ServiceClient from a CrmServiceClient</returns>
|
||||
public static ServiceClient ToServiceClient(this CrmServiceClient crmServiceClient)
|
||||
{
|
||||
_ = crmServiceClient ?? throw new ArgumentNullException(nameof(crmServiceClient));
|
||||
|
||||
if (
|
||||
crmServiceClient.ActiveAuthenticationType == Xrm.Tooling.Connector.AuthenticationType.IFD ||
|
||||
crmServiceClient.ActiveAuthenticationType == Xrm.Tooling.Connector.AuthenticationType.Claims ||
|
||||
crmServiceClient.ActiveAuthenticationType == Xrm.Tooling.Connector.AuthenticationType.InvalidConnection ||
|
||||
crmServiceClient.ActiveAuthenticationType == Xrm.Tooling.Connector.AuthenticationType.Office365 ||
|
||||
crmServiceClient.ActiveAuthenticationType == Xrm.Tooling.Connector.AuthenticationType.AD
|
||||
)
|
||||
{
|
||||
throw new ArgumentException($"Only JWT based authentication types are supported for this conversion - {crmServiceClient.ActiveAuthenticationType} is not supported", nameof(crmServiceClient));
|
||||
}
|
||||
|
||||
ServiceClient serviceClient = new ServiceClient(crmServiceClient.CrmConnectOrgUriActual, tokenProviderFunction: (uri) =>
|
||||
{
|
||||
if (crmServiceClient.CrmConnectOrgUriActual.ToString().Contains(uri))
|
||||
{
|
||||
return Task.FromResult(crmServiceClient.CurrentAccessToken);
|
||||
}
|
||||
else
|
||||
return null;
|
||||
})
|
||||
{
|
||||
UseWebApi = false
|
||||
};
|
||||
|
||||
return serviceClient;
|
||||
}
|
||||
|
||||
#endregion
|
||||
|
||||
#region Dataverse to Crm ServiceClient
|
||||
|
||||
/// <summary>
|
||||
/// Create Dataverse ServiceClient based on CrmServiceClient
|
||||
/// </summary>
|
||||
/// <param name="serviceClient"></param>
|
||||
/// <returns>a new CrmServiceClient from a Dataverse ServiceClient</returns>
|
||||
public static CrmServiceClient ToCrmServiceClient(this ServiceClient serviceClient)
|
||||
{
|
||||
_ = serviceClient ?? throw new ArgumentNullException(nameof(serviceClient));
|
||||
|
||||
if (
|
||||
serviceClient.ActiveAuthenticationType == Client.AuthenticationType.AD ||
|
||||
serviceClient.ActiveAuthenticationType == Client.AuthenticationType.InvalidConnection
|
||||
)
|
||||
{
|
||||
throw new ArgumentException($"Only JWT based authentication types are supported for this conversion - {serviceClient.ActiveAuthenticationType} is not supported", nameof(serviceClient));
|
||||
}
|
||||
|
||||
CrmServiceClient.AuthOverrideHook = new AuthHandler(serviceClient);
|
||||
CrmServiceClient crmServiceClient = new CrmServiceClient(serviceClient.ConnectedOrgUriActual, true);
|
||||
|
||||
return crmServiceClient;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Authentication token acquisition handler
|
||||
/// </summary>
|
||||
internal class AuthHandler : IOverrideAuthHookWrapper
|
||||
{
|
||||
private ServiceClient _localServiceClient;
|
||||
public AuthHandler(ServiceClient serviceClient)
|
||||
{
|
||||
_localServiceClient = serviceClient;
|
||||
}
|
||||
|
||||
public string GetAuthToken(Uri connectedUri)
|
||||
{
|
||||
if (_localServiceClient.ConnectedOrgUriActual.DnsSafeHost.ToString().Contains(connectedUri.DnsSafeHost.ToString()))
|
||||
{
|
||||
return _localServiceClient.CurrentAccessToken;
|
||||
}
|
||||
else
|
||||
return string.Empty;
|
||||
}
|
||||
}
|
||||
#endregion
|
||||
|
||||
}
|
||||
}
|
||||
|
|
|
@ -8,6 +8,7 @@ using Microsoft.Extensions.Logging;
|
|||
using Microsoft.PowerPlatform.Dataverse.Client;
|
||||
using Microsoft.PowerPlatform.Dataverse.Client.Auth;
|
||||
using Microsoft.PowerPlatform.Dataverse.Client.Extensions;
|
||||
using Microsoft.PowerPlatform.Dataverse.Client.Model;
|
||||
using Microsoft.PowerPlatform.Dataverse.Client.Utils;
|
||||
using Microsoft.Xrm.Sdk;
|
||||
using Microsoft.Xrm.Sdk.Messages;
|
||||
|
@ -18,6 +19,7 @@ using System.Collections.Generic;
|
|||
using System.Diagnostics;
|
||||
using System.IO;
|
||||
using System.Net.Http;
|
||||
using System.Security;
|
||||
using Xunit;
|
||||
using Xunit.Abstractions;
|
||||
#endregion
|
||||
|
@ -787,6 +789,33 @@ namespace Client_Core_Tests
|
|||
client._connectionSvc.AuthContext.IdToken.Should().BeNull();
|
||||
}
|
||||
|
||||
[SkippableConnectionTest]
|
||||
[Trait("Category", "Live Connect Required")]
|
||||
public void ConnectUsingServiceIdentity_ClientSecret_Consetup()
|
||||
{
|
||||
System.Net.ServicePointManager.SecurityProtocol = System.Net.SecurityProtocolType.Tls12;
|
||||
|
||||
ConnectionOptions connectionOptions = new ConnectionOptions()
|
||||
{
|
||||
AuthenticationType = Microsoft.PowerPlatform.Dataverse.Client.AuthenticationType.ClientSecret,
|
||||
ClientId = System.Environment.GetEnvironmentVariable("XUNITCONNTESTAPPID"),
|
||||
ClientSecret = System.Environment.GetEnvironmentVariable("XUNITCONNTESTSECRET"),
|
||||
ServiceUri = new Uri(System.Environment.GetEnvironmentVariable("XUNITCONNTESTURI")),
|
||||
Logger = Ilogger
|
||||
};
|
||||
|
||||
|
||||
// Connection params.
|
||||
var client = new ServiceClient(connectionOptions, deferConnection: true);
|
||||
Assert.NotNull(client);
|
||||
Assert.False(client.IsReady, "Client is showing True on Deferred Connection.");
|
||||
Assert.True(client.Connect(), "Connection was not activated");
|
||||
Assert.True(client.IsReady, "Failed to Create Connection via Constructor");
|
||||
|
||||
// Validate connection
|
||||
ValidateConnection(client);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// This Tests connection for UID/PW via connection string - direct connect.
|
||||
/// </summary>
|
||||
|
@ -891,6 +920,61 @@ namespace Client_Core_Tests
|
|||
// Check user after we validate connection again as it gets it from cached token
|
||||
client._connectionSvc.AuthContext.Account.Username.Should().BeEquivalentTo(Conn_UserName);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// This Tests connection for UID/PW via connection string - direct connect.
|
||||
/// </summary>
|
||||
[SkippableConnectionTest]
|
||||
[Trait("Category", "Live Connect Required")]
|
||||
public void ConnectUsingUserIdentity_UIDPW_ConSetup()
|
||||
{
|
||||
string UrlProspect = System.Environment.GetEnvironmentVariable("XUNITCONNTESTURI");
|
||||
if (UrlProspect.EndsWith("/") || UrlProspect.EndsWith("\\"))
|
||||
{
|
||||
UrlProspect = UrlProspect.Substring(0, UrlProspect.Length - 1);
|
||||
}
|
||||
|
||||
Uri Conn_Url = new Uri(UrlProspect);
|
||||
string Conn_UserName = System.Environment.GetEnvironmentVariable("XUNITCONNTESTUSERID");
|
||||
|
||||
System.Net.ServicePointManager.SecurityProtocol = System.Net.SecurityProtocolType.Tls12;
|
||||
ConnectionOptions connectionOptions = new ConnectionOptions()
|
||||
{
|
||||
AuthenticationType = Microsoft.PowerPlatform.Dataverse.Client.AuthenticationType.OAuth,
|
||||
ClientId = testSupport._SampleAppID.ToString(),
|
||||
RedirectUri = testSupport._SampleAppRedirect,
|
||||
ServiceUri = Conn_Url,
|
||||
UserName = Conn_UserName,
|
||||
Password = ServiceClient.MakeSecureString(System.Environment.GetEnvironmentVariable("XUNITCONNTESTPW")),
|
||||
LoginPrompt = PromptBehavior.Never,
|
||||
Logger = Ilogger
|
||||
};
|
||||
|
||||
|
||||
// Connection params.
|
||||
var client = new ServiceClient(connectionOptions, deferConnection: true);
|
||||
Assert.NotNull(client);
|
||||
Assert.False(client.IsReady, "Client is showing True on Deferred Connection.");
|
||||
Assert.True(client.Connect(), "Connection was not activated");
|
||||
Assert.True(client.IsReady, "Failed to Create Connection via Constructor");
|
||||
|
||||
// Validate connection
|
||||
ValidateConnection(client);
|
||||
|
||||
// Check user before we validate connection
|
||||
client._connectionSvc.AuthenticationTypeInUse.Should().BeEquivalentTo(Microsoft.PowerPlatform.Dataverse.Client.AuthenticationType.OAuth);
|
||||
client._connectionSvc.AuthContext.Scopes.Should().BeEquivalentTo(new string[] { $"{Conn_Url}/user_impersonation" });
|
||||
client._connectionSvc.AuthContext.Account.Should().NotBeNull();
|
||||
client._connectionSvc.AuthContext.IdToken.Should().NotBeEmpty();
|
||||
client._connectionSvc.AuthContext.Account.Username.Should().BeEquivalentTo(Conn_UserName);
|
||||
|
||||
// Validate connection
|
||||
ValidateConnection(client);
|
||||
|
||||
// Check user after we validate connection again as it gets it from cached token
|
||||
client._connectionSvc.AuthContext.Account.Username.Should().BeEquivalentTo(Conn_UserName);
|
||||
}
|
||||
|
||||
#region connectionValidationHelper
|
||||
|
||||
private void ValidateConnection(ServiceClient client)
|
||||
|
|
|
@ -1,6 +0,0 @@
|
|||
{
|
||||
"sdk": {
|
||||
"version": "3.1.401",
|
||||
"rollForward": "latestPatch"
|
||||
}
|
||||
}
|
|
@ -1,9 +1,9 @@
|
|||
Notice:
|
||||
This package is an extension to the Microsoft.PowerPlatform.Dataverse.Client Nuget package.
|
||||
This package is intended to work with .net full framework 4.6.2, 4.7.2 and 4.8, .net core 3.0 and 3.1
|
||||
This package is intended to work with .net full framework 4.6.2, 4.7.2 and 4.8, .net 3.1, net 5, and .net 6.0
|
||||
|
||||
++CURRENTRELEASEID++
|
||||
updated min dependency to DV ServiceClient 0.5.10
|
||||
updated min dependency to DV ServiceClient 1.0.0
|
||||
|
||||
0.5.10:
|
||||
Updated Newtonsoft.Json to v11.0.2 to match server.
|
||||
|
|
|
@ -12,19 +12,19 @@
|
|||
<description>This package contains the preview of the .net core ServiceClient Dynamics Extensions. Used to connect to Microsoft Dataverse. This Package has been authored by the Microsoft Dataverse SDK team.</description>
|
||||
<summary>ServiceClient and supporting libraries for use in building client applications to interact with the Dataverse</summary>
|
||||
<copyright>© Microsoft Corporation. All rights reserved.</copyright>
|
||||
<tags>Dynamics CommonDataService CDS PowerApps PowerPlatform CdsServiceClient Dataverse</tags>
|
||||
<tags>Dynamics CommonDataService CDS PowerApps PowerPlatform ServiceClient Dataverse</tags>
|
||||
<dependencies>
|
||||
<group targetFramework=".NETFramework4.6.2">
|
||||
<dependency id="Microsoft.PowerPlatform.Dataverse.Client" version="0.5.10" exclude="Build,Analyzers" />
|
||||
<dependency id="Microsoft.PowerPlatform.Dataverse.Client" version="1.0.0" exclude="Build,Analyzers" />
|
||||
</group>
|
||||
<group targetFramework=".NETFramework4.7.2">
|
||||
<dependency id="Microsoft.PowerPlatform.Dataverse.Client" version="0.5.10" exclude="Build,Analyzers" />
|
||||
<dependency id="Microsoft.PowerPlatform.Dataverse.Client" version="1.0.0" exclude="Build,Analyzers" />
|
||||
</group>
|
||||
<group targetFramework=".NETFramework4.8">
|
||||
<dependency id="Microsoft.PowerPlatform.Dataverse.Client" version="0.5.10" exclude="Build,Analyzers" />
|
||||
<dependency id="Microsoft.PowerPlatform.Dataverse.Client" version="1.0.0" exclude="Build,Analyzers" />
|
||||
</group>
|
||||
<group targetFramework=".NETCoreApp3.1">
|
||||
<dependency id="Microsoft.PowerPlatform.Dataverse.Client" version="0.5.10" exclude="Build,Analyzers" />
|
||||
<dependency id="Microsoft.PowerPlatform.Dataverse.Client" version="1.0.0" exclude="Build,Analyzers" />
|
||||
</group>
|
||||
</dependencies>
|
||||
<frameworkAssemblies>
|
||||
|
|
|
@ -1,13 +1,27 @@
|
|||
Notice:
|
||||
This package is in a public preview release.
|
||||
This package is intended to work with .net full framework 4.6.2, 4.7.2 and 4.8, .net core 3.1, 5.0 and 6.0
|
||||
General Documentation is the same as CrmServiceClient and can be found here:
|
||||
https://docs.microsoft.com/en-us/dotnet/api/microsoft.xrm.tooling.connector.crmserviceclient?view=dynamics-xrmtooling-ce-9
|
||||
General Documentation can be found here:
|
||||
https://docs.microsoft.com/en-us/dotnet/api/microsoft.powerplatform.dataverse.client?view=dataverse-sdk-latest
|
||||
Connection String Docs can be found here:
|
||||
https://docs.microsoft.com/en-us/powerapps/developer/common-data-service/xrm-tooling/use-connection-strings-xrm-tooling-connect
|
||||
Note: that only AD on FullFramework, OAuth, Certificate, ClientSecret Authentication types are supported at this time.
|
||||
Note: Only AD on FullFramework, OAuth, Certificate, ClientSecret Authentication types are supported at this time.
|
||||
|
||||
++CURRENTRELEASEID++
|
||||
Fixed a "Duplicate Key Error" issue created when manually adding some request parameters to an organization request, while also setting the appropriate property in the client
|
||||
Fix formatting issue with RequestId and Session Id.
|
||||
Fix exponential back off issue for WebAPI based calls when retrying based on a throttled connection.
|
||||
Added implementation for Connection and Configuration constructor.
|
||||
- Allows for a instance of the service client to be created and configured without initialization the client. The client can then be initialized later using the .Connect() method.
|
||||
- This constructor accepts 3 parameters
|
||||
- connectionOptions (ConnectionOptions) = Options necessary to create the connection.
|
||||
- deferConnection (bool) defaulted to false = When set to true, will configure but not create the connection until .Connect() is called.
|
||||
- serviceClientConfiguration (ConfigurationOptions) defaulted to null = When populated, pre-configures the connection configuration.
|
||||
- If deferred connection is set to true, .Connect() must be called before the client is useable.
|
||||
Added Connect() method for use with the deferred behavior of the Connection and Configuration Constructor.
|
||||
Activated support for adding additional headers to request when using the Configuration Constructor.
|
||||
Note: Dataverse will only allow specific headers to be used. Use of this capability requires foreknowledge of this capability and agreement with Power Platform Dataverse team.
|
||||
|
||||
0.6.6:
|
||||
Accepted fixes requested by Git user 0xced - thanks for your contrib's!
|
||||
Fixed Null ref bug for missing redirect URI (if it gets that far) https://github.com/microsoft/PowerPlatform-DataverseServiceClient/pull/246
|
||||
Fixed Missing ConfigureAwait's on some Async methods in auth chain. https://github.com/microsoft/PowerPlatform-DataverseServiceClient/pull/247
|
||||
|
@ -48,7 +62,7 @@ Dependency changes:
|
|||
0.5.17:
|
||||
Accepted fix requested here: https://github.com/microsoft/PowerPlatform-DataverseServiceClient/issues/205
|
||||
fixing delete by alternate key request in client.
|
||||
Fixed dependency issue for System.Security.Premisions (git #203)
|
||||
Fixed dependency issue for System.Security.Permissions (git #203)
|
||||
Refactored AuthorityResolver to discover AAD authentication authorities to allow for direct access by other clients.
|
||||
|
||||
|
||||
|
|
|
@ -9,10 +9,10 @@
|
|||
<projectUrl>https://github.com/microsoft/PowerPlatform-DataverseServiceClient</projectUrl>
|
||||
<icon>images\Dataverse.128x128.png</icon>
|
||||
<requireLicenseAcceptance>true</requireLicenseAcceptance>
|
||||
<description>This package contains the preview of the .net core Dataverse ServiceClient. Used to connect to Microsoft Dataverse. This Package has been authored by the Microsoft Dataverse SDK team.</description>
|
||||
<summary>CdsServiceClient and supporting libraries for use in building client applications to interact with the Dataverse</summary>
|
||||
<description>This package contains the .net core Dataverse ServiceClient. Used to connect to Microsoft Dataverse. This Package has been authored by the Microsoft Dataverse SDK team.</description>
|
||||
<summary>Dataverse ServiceClient and supporting libraries for use in building client applications to interact with the Dataverse</summary>
|
||||
<copyright>© Microsoft Corporation. All rights reserved.</copyright>
|
||||
<tags>Dynamics CommonDataService CDS PowerApps PowerPlatform CdsServiceClient Dataverse</tags>
|
||||
<tags>Dynamics CommonDataService CDS PowerApps PowerPlatform ServiceClient Dataverse</tags>
|
||||
<dependencies>
|
||||
<group targetFramework=".NETFramework4.6.2">
|
||||
<dependency id="Microsoft.Extensions.DependencyInjection" version="3.1.8" exclude="Build,Analyzers" />
|
||||
|
|
|
@ -20,13 +20,13 @@
|
|||
<tags>Dynamics CommonDataService CDS PowerApps PowerPlatform Dataverse</tags>
|
||||
<dependencies>
|
||||
<group targetFramework=".NETFramework4.6.2">
|
||||
<dependency id="Microsoft.PowerPlatform.Dataverse.Client" version="0.5.10" exclude="Build,Analyzers" />
|
||||
<dependency id="Microsoft.PowerPlatform.Dataverse.Client" version="1.0.0" exclude="Build,Analyzers" />
|
||||
</group>
|
||||
<group targetFramework=".NETFramework4.7.2">
|
||||
<dependency id="Microsoft.PowerPlatform.Dataverse.Client" version="0.5.10" exclude="Build,Analyzers" />
|
||||
<dependency id="Microsoft.PowerPlatform.Dataverse.Client" version="1.0.0" exclude="Build,Analyzers" />
|
||||
</group>
|
||||
<group targetFramework=".NETFramework4.8">
|
||||
<dependency id="Microsoft.PowerPlatform.Dataverse.Client" version="0.5.10" exclude="Build,Analyzers" />
|
||||
<dependency id="Microsoft.PowerPlatform.Dataverse.Client" version="1.0.0" exclude="Build,Analyzers" />
|
||||
</group>
|
||||
</dependencies>
|
||||
</metadata>
|
||||
|
|
|
@ -0,0 +1,9 @@
|
|||
Notice:
|
||||
Provides Conversion utilities to convert between CrmServiceClient and Dataverse ServiceClient.
|
||||
General Documentation about DataverseServiceClient can be found here:
|
||||
https://github.com/microsoft/PowerPlatform-DataverseServiceClient
|
||||
General Documentation about CrmServiceClient can be found here:
|
||||
https://docs.microsoft.com/en-us/dotnet/api/microsoft.xrm.tooling.connector.crmserviceclient?view=dynamics-xrmtooling-ce-9
|
||||
|
||||
++CURRENTRELEASEID++
|
||||
Provides Conversion utilities to convert between CrmServiceClient and Dataverse ServiceClient
|
|
@ -0,0 +1,41 @@
|
|||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<package xmlns="http://schemas.microsoft.com/packaging/2013/05/nuspec.xsd">
|
||||
<metadata>
|
||||
<id>Microsoft.PowerPlatform.Dataverse.ServiceClientConverter</id>
|
||||
<version>1.0.0</version>
|
||||
<authors>Microsoft</authors>
|
||||
<owners>crmsdk,Microsoft</owners>
|
||||
<licenseUrl>https://go.microsoft.com/fwlink/?linkid=2108407</licenseUrl>
|
||||
<projectUrl>https://github.com/microsoft/PowerPlatform-DataverseServiceClient</projectUrl>
|
||||
<requireLicenseAcceptance>true</requireLicenseAcceptance>
|
||||
<icon>images\Dataverse.128x128.png</icon>
|
||||
<description>This package contains utilities to convert between CrmServiceClient and Dataverse ServiceClient. This Package has been authored by the Microsoft Dataverse SDK team.</description>
|
||||
<summary>Provides Conversion utilities to convert between CrmServiceClient and Dataverse ServiceClient.</summary>
|
||||
<copyright>© Microsoft Corporation. All rights reserved.</copyright>
|
||||
<tags>Dynamics Dataverse PowerApps PowerPlatform ServiceClient</tags>
|
||||
<dependencies>
|
||||
<group targetFramework=".NETFramework4.6.2">
|
||||
<dependency id="Microsoft.CrmSdk.XrmTooling.CoreAssembly" version="9.1.0.110" exclude="Build,Analyzers" />
|
||||
<dependency id="Microsoft.PowerPlatform.Dataverse.Client" version="1.0.0" exclude="Build,Analyzers" />
|
||||
</group>
|
||||
<group targetFramework=".NETFramework4.7.2">
|
||||
<dependency id="Microsoft.CrmSdk.XrmTooling.CoreAssembly" version="9.1.0.110" exclude="Build,Analyzers" />
|
||||
<dependency id="Microsoft.PowerPlatform.Dataverse.Client" version="1.0.0" exclude="Build,Analyzers" />
|
||||
</group>
|
||||
<group targetFramework=".NETFramework4.8">
|
||||
<dependency id="Microsoft.CrmSdk.XrmTooling.CoreAssembly" version="9.1.0.110" exclude="Build,Analyzers" />
|
||||
<dependency id="Microsoft.PowerPlatform.Dataverse.Client" version="1.0.0" exclude="Build,Analyzers" />
|
||||
</group>
|
||||
</dependencies>
|
||||
</metadata>
|
||||
<files>
|
||||
<file target="" src="{licenseDir}\Other Redistributable.txt" />
|
||||
<file target="" src="{licenseDir}\Third Party Notices for Dynamics 365 SDK.docx" />
|
||||
<file target="images" src="{sharedImagesDir}\Desktop\Dataverse.128x128.png" />
|
||||
|
||||
<file target="lib\net48" src="{signedBinDir}\{configuration}\DataverseClient\net48\Microsoft.PowerPlatform.Dataverse.ServiceClientConverter.*" />
|
||||
<file target="lib\net472" src="{signedBinDir}\{configuration}\DataverseClient\net472\Microsoft.PowerPlatform.Dataverse.ServiceClientConverter.*" />
|
||||
<file target="lib\net462" src="{signedBinDir}\{configuration}\DataverseClient\net462\Microsoft.PowerPlatform.Dataverse.ServiceClientConverter.*" />
|
||||
|
||||
</files>
|
||||
</package>
|
Загрузка…
Ссылка в новой задаче