diff --git a/.gitignore b/.gitignore index 401ae9a6..819cf615 100644 --- a/.gitignore +++ b/.gitignore @@ -139,3 +139,4 @@ UpgradeLog*.XML *.ide-shm *.ide-wal /.vs +/spkl/.vs/spkl diff --git a/spkl/CrmSvcUtilFilteringService/CrmSvcUtil.FilteringService.csproj b/spkl/CrmSvcUtilFilteringService/CrmSvcUtil.FilteringService.csproj index 6225a625..4c4e5be2 100644 --- a/spkl/CrmSvcUtilFilteringService/CrmSvcUtil.FilteringService.csproj +++ b/spkl/CrmSvcUtilFilteringService/CrmSvcUtil.FilteringService.csproj @@ -52,48 +52,66 @@ ..\packages\Microsoft.CrmSdk.CoreTools.9.0.0.7\content\bin\coretools\CrmSvcUtil.exe - ..\packages\Microsoft.CrmSdk.CoreAssemblies.9.0.0.7\lib\net452\Microsoft.Crm.Sdk.Proxy.dll + ..\packages\Microsoft.CrmSdk.CoreAssemblies.9.0.2.21\lib\net462\Microsoft.Crm.Sdk.Proxy.dll - - False - ..\packages\Microsoft.IdentityModel.Clients.ActiveDirectory.2.22.302111727\lib\net45\Microsoft.IdentityModel.Clients.ActiveDirectory.dll - True + + + ..\packages\Microsoft.IdentityModel.Clients.ActiveDirectory.5.2.4\lib\net45\Microsoft.IdentityModel.Clients.ActiveDirectory.dll - - False - ..\packages\Microsoft.IdentityModel.Clients.ActiveDirectory.2.22.302111727\lib\net45\Microsoft.IdentityModel.Clients.ActiveDirectory.WindowsForms.dll + + ..\packages\Microsoft.CrmSdk.XrmTooling.CoreAssembly.9.1.0.25\lib\net462\Microsoft.Rest.ClientRuntime.dll True - ..\packages\Microsoft.CrmSdk.CoreAssemblies.9.0.0.7\lib\net452\Microsoft.Xrm.Sdk.dll + ..\packages\Microsoft.CrmSdk.CoreAssemblies.9.0.2.21\lib\net462\Microsoft.Xrm.Sdk.dll - ..\packages\Microsoft.CrmSdk.Deployment.9.0.0.7\lib\net452\Microsoft.Xrm.Sdk.Deployment.dll - True + ..\packages\Microsoft.CrmSdk.Deployment.9.0.2.21\lib\net462\Microsoft.Xrm.Sdk.Deployment.dll - ..\packages\Microsoft.CrmSdk.Workflow.9.0.0.7\lib\net452\Microsoft.Xrm.Sdk.Workflow.dll + ..\packages\Microsoft.CrmSdk.Workflow.9.0.2.21\lib\net462\Microsoft.Xrm.Sdk.Workflow.dll - - ..\packages\Microsoft.CrmSdk.XrmTooling.CoreAssembly.9.0.0.7\lib\net452\Microsoft.Xrm.Tooling.Connector.dll + + ..\packages\Microsoft.CrmSdk.XrmTooling.CoreAssembly.9.1.0.25\lib\net462\Microsoft.Xrm.Tooling.Connector.dll True + + ..\packages\Newtonsoft.Json.12.0.3\lib\net45\Newtonsoft.Json.dll + + + + - + + ..\packages\System.Net.Http.4.3.4\lib\net46\System.Net.Http.dll + + + ..\packages\System.Security.Cryptography.Algorithms.4.3.1\lib\net461\System.Security.Cryptography.Algorithms.dll + + + ..\packages\System.Security.Cryptography.Encoding.4.3.0\lib\net46\System.Security.Cryptography.Encoding.dll + + + ..\packages\System.Security.Cryptography.Primitives.4.3.0\lib\net46\System.Security.Cryptography.Primitives.dll + + + ..\packages\System.Security.Cryptography.X509Certificates.4.3.2\lib\net461\System.Security.Cryptography.X509Certificates.dll + + @@ -108,7 +126,7 @@ - + PreserveNewest Designer @@ -120,16 +138,23 @@ + - + + + - + + + + + diff --git a/spkl/CrmSvcUtilFilteringService/app.config b/spkl/CrmSvcUtilFilteringService/app.config index eb4fca6a..dc96ecaa 100644 --- a/spkl/CrmSvcUtilFilteringService/app.config +++ b/spkl/CrmSvcUtilFilteringService/app.config @@ -14,6 +14,18 @@ + + + + + + + + + + + + \ No newline at end of file diff --git a/spkl/CrmSvcUtilFilteringService/bin/coretools/CrmSvcUtil.exe b/spkl/CrmSvcUtilFilteringService/bin/coretools/CrmSvcUtil.exe new file mode 100644 index 00000000..7c583880 Binary files /dev/null and b/spkl/CrmSvcUtilFilteringService/bin/coretools/CrmSvcUtil.exe differ diff --git a/spkl/CrmSvcUtilFilteringService/bin/coretools/CrmSvcUtil.exe.config b/spkl/CrmSvcUtilFilteringService/bin/coretools/CrmSvcUtil.exe.config new file mode 100644 index 00000000..ddcb24e8 --- /dev/null +++ b/spkl/CrmSvcUtilFilteringService/bin/coretools/CrmSvcUtil.exe.config @@ -0,0 +1,98 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/spkl/CrmSvcUtilFilteringService/bin/coretools/CrmSvcUtil.xml b/spkl/CrmSvcUtilFilteringService/bin/coretools/CrmSvcUtil.xml new file mode 100644 index 00000000..c933aa16 --- /dev/null +++ b/spkl/CrmSvcUtilFilteringService/bin/coretools/CrmSvcUtil.xml @@ -0,0 +1,1428 @@ + + + + CrmSvcUtil + + + + + Used to raise the interactive dialog to login. + + + + + Used to create a connection utilizing a passed in connection string. + + + + + Used to login via OAuth to CRM Online, Hidden for initial ship... but here to allow for complex auth situations. + + + + + Hidden... Used by devToolkit to set the Connection profile to use for this call. + + + + + Hidden... Used by the devToolkit to set the appName whos connection is being used. + + + + + Type of command line argument represented. + + + + + Argument is optional. + + + + + Argument is required. + + + + + The argument may appear multiple times. + + + + + Argument is a binary argument. If it shows up + it is equivalent to a true value. + + + + + Argument is hidden from the user. It can be supplied + on the command line, but will not show up in the + standard usage message. + + + + + Wrapper class for Command Line Argument PropertyInfos. + + + + + Character used to start a new command line paramter. + + + + + Character used to seperate command line parameter and value. + + + + + Format to use when constructing the short form description for an argument. + + + + + Represents a command line argument. + + + + + Creates a new command line argument attribute. + + Type of argument represented by the property. + Switch used by the command line argument + + + + Type of command line argument + + + + + Switch used to represent the argument. + + + + + Shortcut switch used to represent the argument. + + + + + Description of the command line argument. + + + + + Description of the parameter. + + + + + Utility class to parse command line arguments. + + + + + The object that contains the properties to set. + + + + + A mapping of argument switches to command line arguments. + + + + + A list of all of the arguments that are supported + + + + + Creates a new command line parser for the given object. + + The object containing the properties representing the command line args to set. + + + + Populates the command line arguments map. + + + + + Interface for IOrganization metadata + + + + + Array of complete EntityMetadata for the Organization. + + + + + Array of complete OptionSetMetadata for the Organization. + + + + + All SdkMessages for the Organization. + + + + + SDK Message result + + + + + Default constructor + + + + + Message name + + + + + Gets or sets whether the message is private + + + + + Gets or sets the customization level + + + + + Gets or sets the message id + + + + + Gets or sets the message pair id + + + + + Gets or sets the message pair namespace + + + + + Gets or sets the message request id + + + + + Gets or sets the message request name + + + + + Gets or sets the message request field name + + + + + Gets or sets whether the message request field is optional + + + + + Gets or sets the message request field parser + + + + + Gets or sets the message request field CLR parser + + + + + Gets or sets the message request response id + + + + + Gets or sets the message request response field value + + + + + Gets or sets the message request response field formatter + + + + + Gets or sets the message request response field CLR formatter + + + + + Gets or sets the message request response field name + + + + + Gets or sets the message request field position + + + + + Gets or sets the message response field position + + + + + Gets or sets the message filter id + + + + + Gets or sets the message primary OTC filter + + + + + Gets or sets the message secondary OTC filter + + + + + Set of SDK message results + + + + + Default constructor + + + + + Gets or sets an array of results + + + + + Gets or sets the paging cookie + + + + + Gets or sets a flag for more records + + + + + An SDK Message + + + + + Default constructor + + + + + Gets the SDK message name + + + + + Gets the SDK message id + + + + + Gets whether the SDK message is private + + + + + Gets whether the SDK message is a custom action + + + + + Gets a dictionary of message pairs + + + + + Gets a dictionary of message filters + + + + + Fills an SDK message from a given result + + + + + An SDK message filter + + + + + Constructor + + Message filter id + + + + Constructor + + Message filter id + Primary object type code + Secondary object type code + Whether the message filter is visible + + + + Gets the message filter id + + + + + Gets or sets the message filter primary object type code + + + + + Gets or sets the message secondary object type code + + + + + Gets or sets whether the message filter is visible + + + + + An SDK message pair + + + + + Constructor + + SDK message + Message pair id + Message namespace + + + + Gets the message pair id + + + + + Gets the message namespace + + + + + Gets or sets the message + + + + + Gets or sets the message request + + + + + Gets or sets the message response + + + + + An SDK message request + + + + + Constructor + + SDK Message + Message request id + Message request name + + + + Gets the message request id + + + + + Gets the message pair of the request + + + + + Gets the message request name + + + + + Gets a dictionary of message request fields + + + + + An SDK message request field + + + + + Constructor + + SDK message request + Request field index + Request field name + Request field CLR formatter + Whether the request field is optional + + + + Gets the SDK message request + + + + + Gets the message request field index + + + + + Gets the message request field name + + + + + Gets the message request field CLR formatter + + + + + Gets whether the message field is optional + + + + + Gets whether the message request field is generic + + + + + An SDK message response + + + + + Constructor + + Message response id + + + + Gets the message response id + + + + + Gets the message response fields + + + + + An SDK message response field + + + + + Constructor + + Field index + Field name + Field CLR formatter + Field value + + + + Gets the message response field index + + + + + Gets the message response field name + + + + + Gets the message response field CLR formatter + + + + + Gets the message response field value + + + + + SDK Messages + + + + + Constructor + + SDK message collection + + + + Gets the message collection + + + + + Gets the MessagePagingInfo for a given collection SDK messages + + + + + Message paging info + + + + + Gets or sets the paging cookie + + + + + Gets or sets whether the paging info has more records + + + + + Gets the message paging info from a set of message results + + + + + If true a child attribute cannot be published or externally consumed. + + + + + Management utility for the Device Id + + + + + Loads the device credentials (if they exist). If they don't + + Application id + URL for the current token issuer + + The issuerUri can be retrieved from the IServiceConfiguration interface's CurrentIssuer property. + + + + + Registers the given device with Live ID + + ID for the application + URL for the current token issuer + ClientCredentials that were registered + + The issuerUri can be retrieved from the IServiceConfiguration interface's CurrentIssuer property. + + + + + Registers the given device with Live ID + + ID for the application + URL for the current token issuer + Device name that should be registered + Device password that should be registered + ClientCredentials that were registered + + The issuerUri can be retrieved from the IServiceConfiguration interface's CurrentIssuer property. + + + + + Loads the device's credentials from the file system + + URL for the current token issuer + Device Credentials (if set) or null + + The issuerUri can be retrieved from the IServiceConfiguration interface's CurrentIssuer property. + + + + + Indicates an error during registration + + + + + Unspecified or Unknown Error occurred + + + + + Interface Disabled + + + + + Invalid Request Format + + + + + Unknown Client Version + + + + + Blank Password + + + + + Missing Device User Name or Password + + + + + Invalid Parameter Syntax + + + + + Internal Error + + + + + Device Already Exists + + + + + Indicates that Device Registration failed + + + + + Construct an instance of the DeviceRegistrationFailedException class + + + + + Construct an instance of the DeviceRegistrationFailedException class + + Error code that occurred + Subcode that occurred + + + + Construct an instance of the DeviceRegistrationFailedException class + + Error code that occurred + Subcode that occurred + Inner exception + + + + Construct an instance of the DeviceRegistrationFailedException class + + + + + + + Device requestration request + + + + + Default constructor + + + + + Constructor + + Application id + Device to register + + + + Gets or sets the device registration client info + + + + + Gets or sets the device registration authentication + + + + + Device registration client info + + + + + Gets or sets the device registration client info's application id + + + + + Gets or sets the device registration client info version + + + + + Device registration authentication + + + + + Gets or sets the device registration authentication member name + + + + + Gets or sets the device registration authentication password + + + + + Device registration response + + + + + Gets or sets whether the device registration was successful + + + + + Gets or sets the device registration puid + + + + + Gets or sets the device registration error + + + + + Gets or sets the device registration error sub code + + + + + Device registration response error + + + + + Gets or sets the device registration error code + + + + + Live device + + + + + Gets or sets the device version + + + + + Gets or sets the device user name + + + + + Gets or sets the device token + + + + + Gets or sets the device token expiry + + + + + Gets or sets the device clock skew + + + + + Device user name + + + + + Default constructor + + + + + Gets or sets the device user name + + + + + Gets or sets the device user type + + + + + Gets or sets the device user password + + + + + Gets or sets the device id + + + + + Gets or sets the device user's decrypted password + + + + + Creates client credentials for the device user + + An instance of ClientCredentials + + + + Interface for metadata provider query service + + + + + Retrieves entities for the given service + + Service to query + An EntityMetadata array + + + + Retrieves option sets for the given service + + Service to query + An OptionSetMetadataBase array + + + + Retrieves SDK requests for the given service + + Service to query + SdkMessages + + + + Special class to hold hardcoded entity and attribute name mappings. + + + + + Retrieves a name for the Entity being generated. + + + + + Static constructor. + + + + + Updates the timeout value to extend the amount of item that a request will wait. + + + + + Builds a connection string from the passed in parameters. + + + + + + Type of code to generate + + + + + Type Class + + + + + Type Enum + + + + + Type Field + + + + + Type Method + + + + + Type Property + + + + + Type Struct + + + + + Type Parameter + + + + + Interface that provides the ability to generate code based on organization metadata. + + + + + Writes code based on the organization metadata. + + Organization metadata to generate the code for. + Laguage to generate + Output file to write the generated code to. + Target namespace for the generated code. + ServiceProvider to query for additional services that can be used during code generation. + + + + Returns the type that gets generated for the OptionSetMetadata + + + + + Returns the type that gets generated for the Option + + + + + Returns the type that gets generated for the EntityMetadata + + + + + Returns the type that gets generated for the AttributeMetadata + + + + + Returns the type that gets generated for the SdkMessagePair + + + + + Returns the type that gets generated for the SdkMessageRequestField + + + + + Returns the type that gets generated for the SdkMessageResponseField + + + + + Interface that can be used to filter out specific pieces of metadata from having code generated for it. + + + + + Returns true to generate code for the OptionSet and false otherwise. + + + + + Returns true to generate code for the Option and false otherwise. + + + + + Returns true to generate code for the Entity and false otherwise. + + + + + Returns true to generate code for the Attribute and false otherwise. + + + + + Returns true to generate code for the 1:N, N:N, or N:1 relationship and false otherwise. + + + + + Returns true to generate code for the data context and false otherwise. + + + + + Interface for code writer message filter service + + + + + Returns true to generate code for the SDK Message and false otherwise. + + + + + Returns true to generate code for the SDK Message Pair and false otherwise. + + + + + Interface that can be used to customize the CodeDom before it generates code. + + + + + Customize the generated types before code is generated + + + + + Interface that provides metadata for a given organization. + + + + + Returns the metadata for a given organization. Subsequent calls to the method should + return the same set of information on the IOrganizationMetadata object. + + + + + Interface that provides metadata for a given organization. + + + + + Loads metadata for the given service + + Service to query + IOrganizationMetadata + + + + Used by the ICodeGenerationService to retrieve names for the CodeDOM objects being created. + + + + + Returns a name for the OptionSet being generated. + + + + + Retrieves a name for the Option being generated. + + + + + Retrieves a name for the Entity being generated. + + + + + Retrieves a name for the Attribute being generated. + + + + + Retrieves a name for the 1:N, N:N, or N:1 relationship being generated. + + + + + Retrieves a name for the data context being generated. + + + + + Retrieves a name for a set of entities. + + + + + Retrieves a name for the MessagePair being generated. + + + + + Retrieves a name for the Request Field being generated. + + + + + Retrieves a name for the Response Field being generated. + + + + + Used by the ICodeGenerationService to retrieve types for the CodeDOM objects being created. + + + + + Retrieves a CodeTypeReference for the entity set being generated. + + + + + Retrieves a CodeTypeReference for the attribute being generated. + + + + + Retrieves a CodeTypeReference for the 1:N, N:N, or N:1 relationship being generated. + + + + + Retrieves a CodeTypeReference for the Request Field being generated. + + + + + Retrieves a CodeTypeReference for the Response Field being generated. + + + + + Trace Logger for this project + + + + + Trace Tag. + + + + + String Builder Info. + + + + + Last Exception. + + + + + Last Error from CRM. + + + + + Last Exception from CRM . + + + + + Returns the trace source level for the current logger. + + + + + Constructor. + + trace source name + + + + Last error reset. + + + + + Log a Message. + + + + + + Log a Trace event. + + + + + + + Log a Trace event. + + Error Message + Trace Event type Information + Exception object + + + + Log an error with an Exception. + + + + + + Logs the error text to the stream. + + Exception to be written. + Stream writer to use to write the exception. + level of the exception, this deals with inner exceptions. + + + + Interaction logic for CRMInteractiveLogin.xaml + + + CRMInteractiveLogin + + + + + Microsoft.Xrm.Tooling.Connector services + + + + + Bool flag to determine if there is a connection + + + + + CRM Connection Manager component. + + + + + This is used to allow the UI to reset w/out closing + + + + + CRM Connection Manager + + + + + Host Name to use.. + + + + + Profile Name to use + + + + + When set to true, forces a user login, + + + + + Raised when a connection to CRM has completed. + + + + + Default constructor + + + + + Raised when the window loads for the first time. + + + + + + + Run Login process. + + + + + Updates from the Auto Login process. + + + + + + + Complete Event from the Auto Login process + + + + + + + Login control connect check starting. + + + + + + + Login control connect check status event. + + + + + + + Login control Error event. + + + + + + + Login Control Cancel event raised. + + + + + + + This raises and processes Success + + + + + InitializeComponent + + + + diff --git a/spkl/CrmSvcUtilFilteringService/bin/coretools/Microsoft.ApplicationInsights.dll b/spkl/CrmSvcUtilFilteringService/bin/coretools/Microsoft.ApplicationInsights.dll new file mode 100644 index 00000000..7d401e9f Binary files /dev/null and b/spkl/CrmSvcUtilFilteringService/bin/coretools/Microsoft.ApplicationInsights.dll differ diff --git a/spkl/CrmSvcUtilFilteringService/bin/coretools/Microsoft.Crm.Sdk.Proxy.dll b/spkl/CrmSvcUtilFilteringService/bin/coretools/Microsoft.Crm.Sdk.Proxy.dll new file mode 100644 index 00000000..9f07230b Binary files /dev/null and b/spkl/CrmSvcUtilFilteringService/bin/coretools/Microsoft.Crm.Sdk.Proxy.dll differ diff --git a/spkl/CrmSvcUtilFilteringService/bin/coretools/Microsoft.IdentityModel.Clients.ActiveDirectory.dll b/spkl/CrmSvcUtilFilteringService/bin/coretools/Microsoft.IdentityModel.Clients.ActiveDirectory.dll new file mode 100644 index 00000000..4f408cf0 Binary files /dev/null and b/spkl/CrmSvcUtilFilteringService/bin/coretools/Microsoft.IdentityModel.Clients.ActiveDirectory.dll differ diff --git a/spkl/CrmSvcUtilFilteringService/bin/coretools/Microsoft.PowerApps.AppInsights.BatchedTelemetry.dll b/spkl/CrmSvcUtilFilteringService/bin/coretools/Microsoft.PowerApps.AppInsights.BatchedTelemetry.dll new file mode 100644 index 00000000..634b57bf Binary files /dev/null and b/spkl/CrmSvcUtilFilteringService/bin/coretools/Microsoft.PowerApps.AppInsights.BatchedTelemetry.dll differ diff --git a/spkl/CrmSvcUtilFilteringService/bin/coretools/Microsoft.PowerApps.AppInsights.BatchedTelemetryChannel.dll b/spkl/CrmSvcUtilFilteringService/bin/coretools/Microsoft.PowerApps.AppInsights.BatchedTelemetryChannel.dll new file mode 100644 index 00000000..7d53d81f Binary files /dev/null and b/spkl/CrmSvcUtilFilteringService/bin/coretools/Microsoft.PowerApps.AppInsights.BatchedTelemetryChannel.dll differ diff --git a/spkl/CrmSvcUtilFilteringService/bin/coretools/Microsoft.Rest.ClientRuntime.dll b/spkl/CrmSvcUtilFilteringService/bin/coretools/Microsoft.Rest.ClientRuntime.dll new file mode 100644 index 00000000..6dc62c71 Binary files /dev/null and b/spkl/CrmSvcUtilFilteringService/bin/coretools/Microsoft.Rest.ClientRuntime.dll differ diff --git a/spkl/CrmSvcUtilFilteringService/bin/coretools/Microsoft.Xrm.Sdk.Deployment.dll b/spkl/CrmSvcUtilFilteringService/bin/coretools/Microsoft.Xrm.Sdk.Deployment.dll new file mode 100644 index 00000000..07107767 Binary files /dev/null and b/spkl/CrmSvcUtilFilteringService/bin/coretools/Microsoft.Xrm.Sdk.Deployment.dll differ diff --git a/spkl/CrmSvcUtilFilteringService/bin/coretools/Microsoft.Xrm.Sdk.dll b/spkl/CrmSvcUtilFilteringService/bin/coretools/Microsoft.Xrm.Sdk.dll new file mode 100644 index 00000000..b803c938 Binary files /dev/null and b/spkl/CrmSvcUtilFilteringService/bin/coretools/Microsoft.Xrm.Sdk.dll differ diff --git a/spkl/CrmSvcUtilFilteringService/bin/coretools/Microsoft.Xrm.Tooling.Connector.dll b/spkl/CrmSvcUtilFilteringService/bin/coretools/Microsoft.Xrm.Tooling.Connector.dll new file mode 100644 index 00000000..85d6b31f Binary files /dev/null and b/spkl/CrmSvcUtilFilteringService/bin/coretools/Microsoft.Xrm.Tooling.Connector.dll differ diff --git a/spkl/CrmSvcUtilFilteringService/bin/coretools/Microsoft.Xrm.Tooling.CrmConnectControl.dll b/spkl/CrmSvcUtilFilteringService/bin/coretools/Microsoft.Xrm.Tooling.CrmConnectControl.dll new file mode 100644 index 00000000..fb5e8519 Binary files /dev/null and b/spkl/CrmSvcUtilFilteringService/bin/coretools/Microsoft.Xrm.Tooling.CrmConnectControl.dll differ diff --git a/spkl/CrmSvcUtilFilteringService/bin/coretools/Microsoft.Xrm.Tooling.Ui.Styles.dll b/spkl/CrmSvcUtilFilteringService/bin/coretools/Microsoft.Xrm.Tooling.Ui.Styles.dll new file mode 100644 index 00000000..d6286822 Binary files /dev/null and b/spkl/CrmSvcUtilFilteringService/bin/coretools/Microsoft.Xrm.Tooling.Ui.Styles.dll differ diff --git a/spkl/CrmSvcUtilFilteringService/bin/coretools/Newtonsoft.Json.dll b/spkl/CrmSvcUtilFilteringService/bin/coretools/Newtonsoft.Json.dll new file mode 100644 index 00000000..b1a0fa9b Binary files /dev/null and b/spkl/CrmSvcUtilFilteringService/bin/coretools/Newtonsoft.Json.dll differ diff --git a/spkl/CrmSvcUtilFilteringService/bin/coretools/SolutionPackager.exe b/spkl/CrmSvcUtilFilteringService/bin/coretools/SolutionPackager.exe new file mode 100644 index 00000000..b966f5bb Binary files /dev/null and b/spkl/CrmSvcUtilFilteringService/bin/coretools/SolutionPackager.exe differ diff --git a/spkl/CrmSvcUtilFilteringService/bin/coretools/SolutionPackager.exe.config b/spkl/CrmSvcUtilFilteringService/bin/coretools/SolutionPackager.exe.config new file mode 100644 index 00000000..4b54542b --- /dev/null +++ b/spkl/CrmSvcUtilFilteringService/bin/coretools/SolutionPackager.exe.config @@ -0,0 +1,38 @@ + + + + + + + + + + + + + + + diff --git a/spkl/CrmSvcUtilFilteringService/bin/coretools/SolutionPackagerLib.dll b/spkl/CrmSvcUtilFilteringService/bin/coretools/SolutionPackagerLib.dll new file mode 100644 index 00000000..24e50d4d Binary files /dev/null and b/spkl/CrmSvcUtilFilteringService/bin/coretools/SolutionPackagerLib.dll differ diff --git a/spkl/CrmSvcUtilFilteringService/bin/coretools/System.Diagnostics.DiagnosticSource.dll b/spkl/CrmSvcUtilFilteringService/bin/coretools/System.Diagnostics.DiagnosticSource.dll new file mode 100644 index 00000000..c35584d9 Binary files /dev/null and b/spkl/CrmSvcUtilFilteringService/bin/coretools/System.Diagnostics.DiagnosticSource.dll differ diff --git a/spkl/CrmSvcUtilFilteringService/bin/coretools/System.ValueTuple.dll b/spkl/CrmSvcUtilFilteringService/bin/coretools/System.ValueTuple.dll new file mode 100644 index 00000000..1cadbf3e Binary files /dev/null and b/spkl/CrmSvcUtilFilteringService/bin/coretools/System.ValueTuple.dll differ diff --git a/spkl/CrmSvcUtilFilteringService/bin/coretools/pacTelemetryUpload.exe b/spkl/CrmSvcUtilFilteringService/bin/coretools/pacTelemetryUpload.exe new file mode 100644 index 00000000..c7d380da Binary files /dev/null and b/spkl/CrmSvcUtilFilteringService/bin/coretools/pacTelemetryUpload.exe differ diff --git a/spkl/CrmSvcUtilFilteringService/packages.config b/spkl/CrmSvcUtilFilteringService/packages.config index fd1bfa31..c0adb684 100644 --- a/spkl/CrmSvcUtilFilteringService/packages.config +++ b/spkl/CrmSvcUtilFilteringService/packages.config @@ -1,10 +1,15 @@  - - - - - - - + + + + + + + + + + + + \ No newline at end of file diff --git a/spkl/SparkleXrm.Tasks.Tests/DeployPluginAndWorkflowTests.cs b/spkl/SparkleXrm.Tasks.Tests/DeployPluginAndWorkflowTests.cs new file mode 100644 index 00000000..e125d244 --- /dev/null +++ b/spkl/SparkleXrm.Tasks.Tests/DeployPluginAndWorkflowTests.cs @@ -0,0 +1,125 @@ +using FakeItEasy; +using Microsoft.VisualStudio.TestTools.UnitTesting; +using Microsoft.Xrm.Sdk; +using Microsoft.Xrm.Sdk.Messages; +using Microsoft.Xrm.Tooling.Connector; +using System; +using System.Collections.Generic; +using System.Configuration; +using System.IO; +using System.Linq; +using System.Text; +using System.Threading.Tasks; + +namespace SparkleXrm.Tasks.Tests +{ + [TestClass] + public class DeployPluginAndWorkflowTests + { + [TestMethod] + [TestCategory("Integration Tests")] + public void DeployPlugins() + { + CrmServiceClient crmSvc = new CrmServiceClient(ConfigurationManager.ConnectionStrings["integration_testing"].ConnectionString); + var userId = crmSvc.GetMyCrmUserId(); + var trace = new TraceLogger(); + var pluginTask = new DeployPluginsTask(crmSvc, trace); + var path = Path.Combine(AppDomain.CurrentDomain.BaseDirectory, + @"..\..\..\TestPluginWorkflowCombined"); + + pluginTask.Execute(path); + } + + [TestMethod] + [TestCategory("Integration Tests")] + public void DeployWorfklows() + { + CrmServiceClient crmSvc = new CrmServiceClient(ConfigurationManager.ConnectionStrings["integration_testing"].ConnectionString); + var userId = crmSvc.GetMyCrmUserId(); + var trace = new TraceLogger(); + var path = Path.Combine(AppDomain.CurrentDomain.BaseDirectory, + @"..\..\..\TestPluginWorkflowCombined"); + + var wfTask = new DeployWorkflowActivitiesTask(crmSvc, trace); + + wfTask.Execute(path); + } + + [TestMethod] + [TestCategory("Unit Tests")] + public void DeployPluginsUnChangedActivities() + { + var fakeService = A.Fake(a => a.Strict()); + + var trace = new TraceLogger(); + var task = new DeployPluginsTask(fakeService, trace); + var path = Path.Combine(AppDomain.CurrentDomain.BaseDirectory, + @"..\..\..\TestPluginWorkflowCombined"); + + //var messageRequestBuilder = A.Fake(); + + var plugin = new PluginAssembly() + { + Id = Guid.NewGuid() + }; + + var pluginTypeToBeRemoved = new PluginType + { + Id = Guid.NewGuid(), + Name = "Type", + PluginAssemblyId = plugin.ToEntityReference(), + TypeName = "TypeName", + IsWorkflowActivity = false + }; + + var existingWFActivityNotToBeRemoved = new PluginType + { + Id = Guid.NewGuid(), + Name = "Type", + PluginAssemblyId = plugin.ToEntityReference(), + TypeName = "WFActivity", + IsWorkflowActivity = true + }; + + A.CallTo(() => fakeService.Execute(A.Ignored)).ReturnsLazily((a) => + { + var response = new RetrieveMultipleResponse(); + var logicalName = ((a.Arguments[0] as RetrieveMultipleRequest).Query as Microsoft.Xrm.Sdk.Query.QueryExpression).EntityName; + switch (logicalName) + { + case PluginAssembly.EntityLogicalName: + response["EntityCollection"] = new EntityCollection(new[] { plugin }); + break; + + case PluginType.EntityLogicalName: + response["EntityCollection"] = new EntityCollection(new[] { pluginTypeToBeRemoved, existingWFActivityNotToBeRemoved }); + break; + + case SdkMessageProcessingStepImage.EntityLogicalName: + case SdkMessageProcessingStep.EntityLogicalName: + response["EntityCollection"] = new EntityCollection(); + break; + + case SdkMessageFilter.EntityLogicalName: + response["EntityCollection"] = new EntityCollection(new[] { new SdkMessageFilter(){ + SdkMessageFilterId = Guid.NewGuid(), + SdkMessageId = new EntityReference(SdkMessage.EntityLogicalName,Guid.NewGuid()) + } }); + break; + } + + return response; + }); + + A.CallTo(() => fakeService.Update(A.Ignored)).DoesNothing(); + A.CallTo(() => fakeService.Create(A.Ignored)).ReturnsLazily((a) => + { + return Guid.NewGuid(); + }); + A.CallTo(() => fakeService.Delete( + A.That.Matches(a => a == PluginType.EntityLogicalName), + A.That.Matches(a => a == pluginTypeToBeRemoved.Id))).DoesNothing(); + task.Execute(path); + } + } +} \ No newline at end of file diff --git a/spkl/SparkleXrm.Tasks.Tests/DeployPluginTests.cs b/spkl/SparkleXrm.Tasks.Tests/DeployPluginTests.cs index f42e53be..06c4b39c 100644 --- a/spkl/SparkleXrm.Tasks.Tests/DeployPluginTests.cs +++ b/spkl/SparkleXrm.Tasks.Tests/DeployPluginTests.cs @@ -42,8 +42,8 @@ public void DeployWorkflowActivities() @"..\..\..\TestWorkflowActivity"); task.Execute(path); - } + [TestMethod] [TestCategory("Unit Tests")] public void TestGetWorkflowActivityMetadata() @@ -59,15 +59,15 @@ public void TestGetWorkflowActivityMetadata() var assemblyPath = new DirectoryService().SimpleSearch(testAssemblyPathRoot, "TestWorkflowActivity.dll"); - Assembly thisAssembly = Reflection.ReflectionOnlyLoadAssembly(assemblyPath); + Assembly thisAssembly = Reflection.LoadAssembly(assemblyPath); IEnumerable pluginTypes = Reflection.GetTypesInheritingFrom(thisAssembly, typeof(System.Activities.CodeActivity)); var workflowActivityCustomBaseClass = Reflection.GetAttributes(pluginTypes.Where(t => t.Name == "WorkflowActivityInheritingFromWorkflowActivityBase"), typeof(CrmPluginRegistrationAttribute).Name); - Assert.AreEqual(1, workflowActivityCustomBaseClass.Count(),"Custom Base Class Metadata"); + Assert.AreEqual(1, workflowActivityCustomBaseClass.Count(), "Custom Base Class Metadata"); var codeActivityBaseClass = Reflection.GetAttributes(pluginTypes.Where(t => t.Name == "WorkflowActivity"), typeof(CrmPluginRegistrationAttribute).Name); Assert.AreEqual(1, codeActivityBaseClass.Count(), "CodeActiviy Base Class Metadata"); - } + [TestMethod] [TestCategory("Unit Tests")] public void TestGetPluginMetadata() @@ -83,7 +83,7 @@ public void TestGetPluginMetadata() var assemblyPath = new DirectoryService().SimpleSearch(testAssemblyPathRoot, "TestPlugin.dll"); - Assembly thisAssembly = Reflection.ReflectionOnlyLoadAssembly(assemblyPath); + Assembly thisAssembly = Reflection.LoadAssembly(assemblyPath); IEnumerable pluginTypes = Reflection.GetTypesImplementingInterface(thisAssembly, typeof(Microsoft.Xrm.Sdk.IPlugin)); var attributes = Reflection.GetAttributes(pluginTypes.Where(t => t.Name == "PreValidateaccountUpdate"), typeof(CrmPluginRegistrationAttribute).Name); var pluginStep = (CrmPluginRegistrationAttribute)attributes.Where(s => s.ConstructorArguments[5].Value.ToString() == "Create Step").First().CreateFromData(); @@ -97,8 +97,7 @@ public void DuplicatePluginNameOnDownload() { // Since the name is used to uniquely identify plugins per type, we can't have existing duplicates when downloading steps - - // Arrange + // Arrange ServiceLocator.Init(); var trace = new TraceLogger(); @@ -122,7 +121,6 @@ public void DuplicatePluginNameOnDownload() Name = "step" } }; - }); var task = new DownloadPluginMetadataTask(ctx, trace); @@ -138,23 +136,17 @@ public void DuplicatePluginNameOnDownload() } catch (SparkleTaskException ex) { - exception = (ex.ExceptionType == SparkleTaskException.ExceptionTypes.DUPLICATE_STEP); - } // Assert Assert.IsTrue(exception, "Duplicate step names not detected"); - - - } [TestMethod] [TestCategory("Unit Tests")] public void DuplicatePluginNameOnDeploy() { - // Assemble List testType = new List() { @@ -169,13 +161,10 @@ public void DuplicatePluginNameOnDeploy() } catch (SparkleTaskException ex) { - exception = (ex.ExceptionType == SparkleTaskException.ExceptionTypes.DUPLICATE_STEP); - } // Assert Assert.IsTrue(exception, "Duplicate step names not detected"); - } [TestMethod] @@ -183,6 +172,7 @@ public void DuplicatePluginNameOnDeploy() public void GetGetAssemblies() { #region Assemble + ServiceLocator.Init(); var path = Path.Combine(AppDomain.CurrentDomain.BaseDirectory, @"..\..\..\TestPlugin"); @@ -192,29 +182,30 @@ public void GetGetAssemblies() // Get plugin config var defaultPluginConfig = config.GetPluginsConfig("default"); var debugConfig = config.GetPluginsConfig("debug"); - #endregion + + #endregion Assemble #region Act + var defaultAssemblies = config.GetAssemblies(defaultPluginConfig[0]); var debugAssemblies = config.GetAssemblies(debugConfig[0]); - #endregion + #endregion Act #region Assert + // The wildcard should return all 4 assemblies - Assert.IsTrue(defaultAssemblies.Count>1, "The wildcard should return all assemblies"); + Assert.IsTrue(defaultAssemblies.Count > 1, "The wildcard should return all assemblies"); // The specific assembly name should only return 1 Assert.AreEqual(1, debugAssemblies.Count, "The specific assembly name should only return 1"); - #endregion - + #endregion Assert } [CrmPluginRegistrationAttribute("step", "step", "step", "step", IsolationModeEnum.Sandbox)] [CrmPluginRegistrationAttribute("step", "step", "step", "step", IsolationModeEnum.Sandbox)] public class TestPluginWithDuplicateAttributes { - } } -} +} \ No newline at end of file diff --git a/spkl/SparkleXrm.Tasks.Tests/IntegrationTests.playlist b/spkl/SparkleXrm.Tasks.Tests/IntegrationTests.playlist new file mode 100644 index 00000000..3d84c54c --- /dev/null +++ b/spkl/SparkleXrm.Tasks.Tests/IntegrationTests.playlist @@ -0,0 +1 @@ + \ No newline at end of file diff --git a/spkl/SparkleXrm.Tasks.Tests/SparkleXrm.Tasks.Tests.csproj b/spkl/SparkleXrm.Tasks.Tests/SparkleXrm.Tasks.Tests.csproj index 8c125153..ded8896e 100644 --- a/spkl/SparkleXrm.Tasks.Tests/SparkleXrm.Tasks.Tests.csproj +++ b/spkl/SparkleXrm.Tasks.Tests/SparkleXrm.Tasks.Tests.csproj @@ -44,60 +44,109 @@ Plugins.snk - - ..\packages\FakeItEasy.4.1.1\lib\net45\FakeItEasy.dll + + ..\packages\FakeItEasy.5.5.0\lib\net45\FakeItEasy.dll - ..\packages\Microsoft.CrmSdk.CoreAssemblies.9.0.0.7\lib\net452\Microsoft.Crm.Sdk.Proxy.dll + ..\packages\Microsoft.CrmSdk.CoreAssemblies.9.0.2.23\lib\net462\Microsoft.Crm.Sdk.Proxy.dll - - ..\packages\Microsoft.IdentityModel.Clients.ActiveDirectory.2.22.302111727\lib\net45\Microsoft.IdentityModel.Clients.ActiveDirectory.dll + + + ..\packages\Microsoft.IdentityModel.Clients.ActiveDirectory.5.2.4\lib\net45\Microsoft.IdentityModel.Clients.ActiveDirectory.dll - - ..\packages\Microsoft.IdentityModel.Clients.ActiveDirectory.2.22.302111727\lib\net45\Microsoft.IdentityModel.Clients.ActiveDirectory.WindowsForms.dll + + ..\packages\Microsoft.CrmSdk.XrmTooling.CoreAssembly.9.1.0.38\lib\net462\Microsoft.Rest.ClientRuntime.dll False - ..\packages\Microsoft.CrmSdk.CoreAssemblies.9.0.0.7\lib\net452\Microsoft.Xrm.Sdk.dll + ..\packages\Microsoft.CrmSdk.CoreAssemblies.9.0.2.23\lib\net462\Microsoft.Xrm.Sdk.dll - ..\packages\Microsoft.CrmSdk.Deployment.9.0.0.7\lib\net452\Microsoft.Xrm.Sdk.Deployment.dll + ..\packages\Microsoft.CrmSdk.Deployment.9.0.2.23\lib\net462\Microsoft.Xrm.Sdk.Deployment.dll - ..\packages\Microsoft.CrmSdk.Workflow.9.0.0.7\lib\net452\Microsoft.Xrm.Sdk.Workflow.dll + ..\packages\Microsoft.CrmSdk.Workflow.9.0.2.23\lib\net462\Microsoft.Xrm.Sdk.Workflow.dll - - ..\packages\Microsoft.CrmSdk.XrmTooling.CoreAssembly.9.0.0.7\lib\net452\Microsoft.Xrm.Tooling.Connector.dll + + ..\packages\Microsoft.CrmSdk.XrmTooling.CoreAssembly.9.1.0.38\lib\net462\Microsoft.Xrm.Tooling.Connector.dll + + + ..\packages\Newtonsoft.Json.12.0.3\lib\net45\Newtonsoft.Json.dll - - ..\packages\System.Collections.Immutable.1.3.1\lib\portable-net45+win8+wp8+wpa81\System.Collections.Immutable.dll - True + + ..\packages\System.Buffers.4.5.0\lib\netstandard2.0\System.Buffers.dll + + + ..\packages\System.Collections.Immutable.1.7.0\lib\netstandard2.0\System.Collections.Immutable.dll + + + - - ..\packages\System.Runtime.4.3.0\lib\net462\System.Runtime.dll + + ..\packages\System.Memory.4.5.3\lib\netstandard2.0\System.Memory.dll + + + + ..\packages\System.Net.Http.4.3.4\lib\net46\System.Net.Http.dll + True + True + + + + + ..\packages\System.Numerics.Vectors.4.5.0\lib\net46\System.Numerics.Vectors.dll + + + ..\packages\System.Runtime.4.3.1\lib\net462\System.Runtime.dll + True True - - ..\packages\System.Runtime.Extensions.4.3.0\lib\net462\System.Runtime.Extensions.dll + + ..\packages\System.Runtime.CompilerServices.Unsafe.4.7.0\lib\netstandard2.0\System.Runtime.CompilerServices.Unsafe.dll + + + ..\packages\System.Runtime.Extensions.4.3.1\lib\net462\System.Runtime.Extensions.dll + True True + + ..\packages\System.Security.Cryptography.Algorithms.4.3.1\lib\net461\System.Security.Cryptography.Algorithms.dll + True + True + + + ..\packages\System.Security.Cryptography.Encoding.4.3.0\lib\net46\System.Security.Cryptography.Encoding.dll + True + True + + + ..\packages\System.Security.Cryptography.Primitives.4.3.0\lib\net46\System.Security.Cryptography.Primitives.dll + True + True + + + ..\packages\System.Security.Cryptography.X509Certificates.4.3.2\lib\net461\System.Security.Cryptography.X509Certificates.dll + True + True + + @@ -113,6 +162,7 @@ + diff --git a/spkl/SparkleXrm.Tasks.Tests/UnitTests.playlist b/spkl/SparkleXrm.Tasks.Tests/UnitTests.playlist new file mode 100644 index 00000000..57135c72 --- /dev/null +++ b/spkl/SparkleXrm.Tasks.Tests/UnitTests.playlist @@ -0,0 +1 @@ + \ No newline at end of file diff --git a/spkl/SparkleXrm.Tasks.Tests/app.config b/spkl/SparkleXrm.Tasks.Tests/app.config index 5719926d..e3c44456 100644 --- a/spkl/SparkleXrm.Tasks.Tests/app.config +++ b/spkl/SparkleXrm.Tasks.Tests/app.config @@ -21,7 +21,7 @@ - + @@ -63,6 +63,30 @@ + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/spkl/SparkleXrm.Tasks.Tests/packages.config b/spkl/SparkleXrm.Tasks.Tests/packages.config index d28400f7..d4327beb 100644 --- a/spkl/SparkleXrm.Tasks.Tests/packages.config +++ b/spkl/SparkleXrm.Tasks.Tests/packages.config @@ -1,12 +1,23 @@  - - - - - - - - - + + + + + + + + + + + + + + + + + + + + \ No newline at end of file diff --git a/spkl/SparkleXrm.Tasks/Config/ConfigFile.cs b/spkl/SparkleXrm.Tasks/Config/ConfigFile.cs index 20331219..67f1e750 100644 --- a/spkl/SparkleXrm.Tasks/Config/ConfigFile.cs +++ b/spkl/SparkleXrm.Tasks/Config/ConfigFile.cs @@ -15,6 +15,7 @@ public class ConfigFile public List plugins; public List earlyboundtypes; public List solutions; + [JsonIgnore] public string filePath; @@ -25,11 +26,12 @@ public virtual void Save() { File.Copy(file, file + DateTime.Now.ToString("yyyyMMddHHmmss") + ".bak"); } - File.WriteAllText(file, Newtonsoft.Json.JsonConvert.SerializeObject(this,Newtonsoft.Json.Formatting.Indented, new JsonSerializerSettings + File.WriteAllText(file, Newtonsoft.Json.JsonConvert.SerializeObject(this, Newtonsoft.Json.Formatting.Indented, new JsonSerializerSettings { NullValueHandling = NullValueHandling.Ignore })); } + public virtual SolutionPackageConfig[] GetSolutionConfig(string profile) { if (solutions == null) @@ -51,8 +53,8 @@ public virtual SolutionPackageConfig[] GetSolutionConfig(string profile) } return config; - } + public virtual EarlyBoundTypeConfig[] GetEarlyBoundConfig(string profile) { if (earlyboundtypes == null) @@ -63,7 +65,7 @@ public virtual EarlyBoundTypeConfig[] GetEarlyBoundConfig(string profile) generateOptionsetEnums = true, generateStateEnums = true } }; - + EarlyBoundTypeConfig[] config = null; if (profile == "default") { @@ -99,14 +101,14 @@ public virtual WebresourceDeployConfig[] GetWebresourceConfig(string profile) else { // Default profile or empty - config = webresources.Where(c => c.profile==null || c.profile.Replace(" ", "").Split(',').Contains("default") || String.IsNullOrWhiteSpace(c.profile)).ToArray(); + config = webresources.Where(c => c.profile == null || c.profile.Replace(" ", "").Split(',').Contains("default") || String.IsNullOrWhiteSpace(c.profile)).ToArray(); } return config; } public virtual PluginDeployConfig[] GetPluginsConfig(string profile) - { + { PluginDeployConfig[] config = null; if (plugins == null) return new PluginDeployConfig[0]; @@ -118,12 +120,12 @@ public virtual PluginDeployConfig[] GetPluginsConfig(string profile) if (profile != null) { - config = plugins.Where(c => c.profile!=null && c.profile.Replace(" ", "").Split(',').Contains(profile)).ToArray(); + config = plugins.Where(c => c.profile != null && c.profile.Replace(" ", "").Split(',').Contains(profile)).ToArray(); } else { // Default profile or empty - config = plugins.Where(c => c.profile==null || c.profile.Replace(" ", "").Split(',').Contains("default") || String.IsNullOrWhiteSpace(c.profile)).ToArray(); + config = plugins.Where(c => c.profile == null || c.profile.Replace(" ", "").Split(',').Contains("default") || String.IsNullOrWhiteSpace(c.profile)).ToArray(); } return config; @@ -135,15 +137,14 @@ public virtual List GetAssemblies(PluginDeployConfig plugin) List assemblies; var extension = Path.GetExtension(file); - + if (extension == "") file = Path.Combine(file, "*.dll"); - assemblies = ServiceLocator.DirectoryService.Search(this.filePath, file); return assemblies; } - } + public class ConfigFileService : IConfigFileService { public List FindConfig(string folder, bool raiseErrorIfNotFound = true) @@ -169,7 +170,7 @@ public List FindConfig(string folder, bool raiseErrorIfNotFound = tr foreach (var configPath in configfilePath) { // Check valid path and this is not the nuget package folder - if (configPath != null && !Regex.IsMatch(configPath, @"packages\\spkl[0-9|.]*\\tools")) + if (configPath != null && !Regex.IsMatch(configPath, @"packages\\spkl")) { var config = Newtonsoft.Json.JsonConvert.DeserializeObject(File.ReadAllText(configPath)); config.filePath = Path.GetDirectoryName(configPath); @@ -187,7 +188,5 @@ public List FindConfig(string folder, bool raiseErrorIfNotFound = tr return results; } - } - -} +} \ No newline at end of file diff --git a/spkl/SparkleXrm.Tasks/Config/EarlyBoundTypeConfig.cs b/spkl/SparkleXrm.Tasks/Config/EarlyBoundTypeConfig.cs index 2127652d..7e0d6f33 100644 --- a/spkl/SparkleXrm.Tasks/Config/EarlyBoundTypeConfig.cs +++ b/spkl/SparkleXrm.Tasks/Config/EarlyBoundTypeConfig.cs @@ -10,7 +10,9 @@ public class EarlyBoundTypeConfig { public string profile; public string entities; + public string[] entityCollection; public string actions; + public string[] actionCollection; public bool generateOptionsetEnums; public bool generateGlobalOptionsets; public bool generateStateEnums; diff --git a/spkl/SparkleXrm.Tasks/EntitiesTrim.cs b/spkl/SparkleXrm.Tasks/EntitiesTrim.cs index e948cdd8..8fe675d3 100644 --- a/spkl/SparkleXrm.Tasks/EntitiesTrim.cs +++ b/spkl/SparkleXrm.Tasks/EntitiesTrim.cs @@ -791,6 +791,10 @@ public System.Nullable IsWorkflowActivity { return this.GetAttributeValue>("isworkflowactivity"); } + set + { + this.SetAttributeValue("isworkflowactivity", value); + } } /// diff --git a/spkl/SparkleXrm.Tasks/PluginRegistraton.cs b/spkl/SparkleXrm.Tasks/PluginRegistraton.cs index 58b6a98b..8359c500 100644 --- a/spkl/SparkleXrm.Tasks/PluginRegistraton.cs +++ b/spkl/SparkleXrm.Tasks/PluginRegistraton.cs @@ -17,26 +17,14 @@ public class PluginRegistraton private OrganizationServiceContext _ctx; private IOrganizationService _service; private ITrace _trace; - private string[] _ignoredAssemblies = new string[] { - "Microsoft.Crm.Sdk.Proxy.dll", - "Microsoft.IdentityModel.dll", - "Microsoft.Xrm.Sdk.dll", - "Microsoft.Xrm.Sdk.Workflow.dll", - "Microsoft.IdentityModel.Clients.ActiveDirectory.dll", - "Microsoft.Extensions.FileSystemGlobbing.dll", - "Microsoft.IdentityModel.Clients.ActiveDirectory.WindowsForms.dll", - "Microsoft.Xrm.Sdk.Deployment.dll", - "Microsoft.Xrm.Tooling.Connector.dll", - "Newtonsoft.Json.dll", - "SparkleXrm.Tasks.dll" - }; + public PluginRegistraton(IOrganizationService service, OrganizationServiceContext context, ITrace trace) { _ctx = context; _service = service; _trace = trace; - } + /// /// If not null, components are added to this solution /// @@ -45,26 +33,27 @@ public PluginRegistraton(IOrganizationService service, OrganizationServiceContex public void RegisterWorkflowActivities(string path) { var assemblyFilePath = new FileInfo(path); - if (_ignoredAssemblies.Contains(assemblyFilePath.Name)) + if (Reflection.IgnoredAssemblies.Contains(assemblyFilePath.Name)) return; - // Load each assembly - Assembly assembly = Reflection.ReflectionOnlyLoadAssembly(assemblyFilePath.FullName); + // Load each assembly + Assembly assembly = Reflection.LoadAssembly(assemblyFilePath.FullName); if (assembly == null) return; - // Search for any types that interhit from IPlugin + AppDomain.CurrentDomain.ReflectionOnlyAssemblyResolve += (sender, args) => Assembly.ReflectionOnlyLoad(args.Name); + + // Search for any types that interhit from IPlugin IEnumerable pluginTypes = Reflection.GetTypesInheritingFrom(assembly, typeof(System.Activities.CodeActivity)); if (pluginTypes.Count() > 0) { - var plugin = RegisterAssembly(assemblyFilePath, assembly, pluginTypes); + var plugin = RegisterAssembly(assemblyFilePath, assembly, pluginTypes, isWorkflowActivity: true); if (plugin != null) { RegisterActivities(pluginTypes, plugin); } } - } private void RegisterActivities(IEnumerable pluginTypes, PluginAssembly plugin) @@ -73,17 +62,14 @@ private void RegisterActivities(IEnumerable pluginTypes, PluginAssembly pl foreach (var pluginType in pluginTypes) { - // Search for the CrmPluginStepAttribute var pluginAttributes = pluginType.GetCustomAttributesData().Where(a => a.AttributeType.Name == typeof(CrmPluginRegistrationAttribute).Name); PluginType sdkPluginType = null; if (pluginAttributes.Count() > 0) { - if (pluginAttributes.Count() > 1) { Debug.WriteLine("Workflow Activities can only have a single registration"); - } var workflowActivitiy = pluginAttributes.First().CreateFromData(); @@ -117,16 +103,12 @@ private void RegisterActivities(IEnumerable pluginTypes, PluginAssembly pl // Update _service.Update(sdkPluginType); } - - - } } } private void AddAssemblyToSolution(string solutionName, PluginAssembly assembly) { - // Find solution AddSolutionComponentRequest addToSolution = new AddSolutionComponentRequest() { @@ -137,7 +119,6 @@ private void AddAssemblyToSolution(string solutionName, PluginAssembly assembly) }; _trace.WriteLine("Adding to solution '{0}'", solutionName); _service.Execute(addToSolution); - } private void AddTypeToSolution(string solutionName, PluginType sdkPluginType) @@ -152,6 +133,7 @@ private void AddTypeToSolution(string solutionName, PluginType sdkPluginType) _trace.WriteLine("Adding to solution '{0}'", solutionName); _service.Execute(addToSolution); } + private void AddStepToSolution(string solutionName, SdkMessageProcessingStep sdkPluginType) { // Find solution @@ -164,25 +146,24 @@ private void AddStepToSolution(string solutionName, SdkMessageProcessingStep sdk }; _trace.WriteLine("Adding to solution '{0}'", solutionName); _service.Execute(addToSolution); - } - public void RegisterPlugin(string file, bool excludePluginSteps = false) { var assemblyFilePath = new FileInfo(file); - if (_ignoredAssemblies.Contains(assemblyFilePath.Name)) + if (assemblyFilePath.Name.StartsWith("System.") || Reflection.IgnoredAssemblies.Contains(assemblyFilePath.Name)) return; - // Load each assembly - Assembly peekAssembly = Reflection.ReflectionOnlyLoadAssembly(assemblyFilePath.FullName); + // Load each assembly + Assembly peekAssembly = Reflection.LoadAssembly(assemblyFilePath.FullName); if (peekAssembly == null) return; + _trace.WriteLine("Checking assembly '{0}' for plugins", assemblyFilePath.Name); - // Search for any types that interhit from IPlugin + // Search for any types that interhit from IPlugin IEnumerable pluginTypes = Reflection.GetTypesImplementingInterface(peekAssembly, typeof(Microsoft.Xrm.Sdk.IPlugin)); if (pluginTypes.Count() > 0) @@ -192,17 +173,15 @@ public void RegisterPlugin(string file, bool excludePluginSteps = false) var plugin = RegisterAssembly(assemblyFilePath, peekAssembly, pluginTypes); if (plugin != null) - if (plugin != null && !excludePluginSteps) - { - RegisterPluginSteps(pluginTypes, plugin); - } + if (plugin != null && !excludePluginSteps) + { + RegisterPluginSteps(pluginTypes, plugin); + } } - } - private PluginAssembly RegisterAssembly(FileInfo assemblyFilePath, Assembly assembly, IEnumerable pluginTypes) + private PluginAssembly RegisterAssembly(FileInfo assemblyFilePath, Assembly assembly, IEnumerable pluginTypes, bool isWorkflowActivity = false) { - // Get the isolation mode of the first attribute var firstType = Reflection.GetAttributes(pluginTypes, typeof(CrmPluginRegistrationAttribute).Name).FirstOrDefault(); if (firstType == null) @@ -246,7 +225,7 @@ private PluginAssembly RegisterAssembly(FileInfo assemblyFilePath, Assembly asse } else { - UnregisterRemovedPluginTypes(pluginTypes, plugin); + UnregisterRemovedPluginTypes(pluginTypes, plugin, isWorkflowActivity); _trace.WriteLine("Updating Plugin '{0}' from '{1}'", plugin.Name, assemblyFilePath.FullName); // Update @@ -262,11 +241,11 @@ private PluginAssembly RegisterAssembly(FileInfo assemblyFilePath, Assembly asse return plugin; } - private void UnregisterRemovedPluginTypes(IEnumerable pluginTypes, PluginAssembly plugin) + private void UnregisterRemovedPluginTypes(IEnumerable pluginTypes, PluginAssembly plugin, bool isWorkflowActivity = false) { _trace.WriteLine("Checking for orphaned PluginTypes: '{0}' ", plugin.Name); - var sdkPluginTypes = ServiceLocator.Queries.GetPluginTypes(_ctx, plugin); + var sdkPluginTypes = ServiceLocator.Queries.GetPluginTypes(_ctx, plugin).Where(t => (t.IsWorkflowActivity ?? false) == isWorkflowActivity); foreach (var sdkPluginType in sdkPluginTypes) { @@ -294,7 +273,6 @@ private void RegisterPluginSteps(IEnumerable pluginTypes, PluginAssembly p foreach (var pluginType in pluginTypes) { - // Search for the CrmPluginStepAttribute var pluginAttributes = pluginType.GetCustomAttributesData().Where(a => a.AttributeType.Name == typeof(CrmPluginRegistrationAttribute).Name); PluginType sdkPluginType = null; @@ -367,14 +345,11 @@ private List GetExistingSteps(PluginType sdkPluginType AsyncAutoDelete = s.AsyncAutoDelete, Attributes = s.Attributes, SdkMessageFilterId = s.SdkMessageFilterId - }).ToList(); return steps; - } - private void RegisterStep(PluginType sdkPluginType, List existingSteps, CustomAttributeData pluginAttribute) { var pluginStep = (CrmPluginRegistrationAttribute)pluginAttribute.CreateFromData(); @@ -433,9 +408,11 @@ private void RegisterStep(PluginType sdkPluginType, List existingImages, string imageName, ImageTypeEnum imagetype, string attributes) { if (String.IsNullOrWhiteSpace(imageName)) @@ -525,15 +498,18 @@ private SdkMessageProcessingStepImage RegisterImage(CrmPluginRegistrationAttribu case "Create": image.MessagePropertyName = "Id"; break; + case "SetState": case "SetStateDynamicEntity": image.MessagePropertyName = "EntityMoniker"; break; + case "Send": case "DeliverIncoming": case "DeliverPromote": image.MessagePropertyName = "EmailId"; break; + default: image.MessagePropertyName = "Target"; break; @@ -553,4 +529,4 @@ private SdkMessageProcessingStepImage RegisterImage(CrmPluginRegistrationAttribu return image; } } -} +} \ No newline at end of file diff --git a/spkl/SparkleXrm.Tasks/Reflection.cs b/spkl/SparkleXrm.Tasks/Reflection.cs index 817e6f4d..c2d25204 100644 --- a/spkl/SparkleXrm.Tasks/Reflection.cs +++ b/spkl/SparkleXrm.Tasks/Reflection.cs @@ -10,9 +10,23 @@ namespace SparkleXrm.Tasks { - public class Reflection + public class Reflection { - + public static string[] IgnoredAssemblies = new string[] { + "Microsoft.Crm.Sdk.Proxy.dll", + "Microsoft.IdentityModel.dll", + "Microsoft.Xrm.Sdk.dll", + "Microsoft.Xrm.Sdk.Workflow.dll", + "Microsoft.IdentityModel.Clients.ActiveDirectory.dll", + "Microsoft.Extensions.FileSystemGlobbing.dll", + "Microsoft.IdentityModel.Clients.ActiveDirectory.WindowsForms.dll", + "Microsoft.Xrm.Sdk.Deployment.dll", + "Microsoft.Xrm.Tooling.Connector.dll", + "Newtonsoft.Json.dll", + "SparkleXrm.Tasks.dll", + "System.Net.Http.dll", + "Microsoft.Rest.ClientRuntime.dll" + }; public static Assembly LoadAssembly(string path) { @@ -25,75 +39,31 @@ public static Assembly LoadAssembly(string path) { // Assembly already loaded so skip Debug.WriteLine("Assembly load error:" + ex.Message); - } return assembly; } - public static Assembly ReflectionOnlyLoadAssembly(string path) - { - string[] ignore = new string[] { "Microsoft.Crm.Sdk.Proxy.dll", "Microsoft.IdentityModel.dll", "Microsoft.Xrm.Sdk.dll","Microsoft.Xrm.Sdk.Workflow.dll" }; - if (ignore.Where(a => path.Contains(a)).FirstOrDefault() != null) - return null; - - Assembly assembly = null; - AppDomain.CurrentDomain.ReflectionOnlyAssemblyResolve += CurrentDomain_ReflectionOnlyAssemblyResolve; - try - { - assembly = Assembly.ReflectionOnlyLoadFrom(path); - } - catch (FileLoadException ex) - { - // Assembly already loaded so skip - Debug.WriteLine("Assembly load error:" + ex.Message); - - } - finally - { - AppDomain.CurrentDomain.ReflectionOnlyAssemblyResolve -= CurrentDomain_ReflectionOnlyAssemblyResolve; - } - return assembly; - } - - private static Assembly CurrentDomain_ReflectionOnlyAssemblyResolve(object sender, ResolveEventArgs args) - { - Assembly assembly; - string[] parts = args.Name.Split(','); - switch (parts[0]) - { - case "Microsoft.Xrm.Sdk": - assembly = System.Reflection.Assembly.ReflectionOnlyLoad(parts[0].Trim()); - break; - case "Microsoft.Crm.Sdk.Proxy": - assembly = System.Reflection.Assembly.ReflectionOnlyLoad(parts[0].Trim()); - break; - default: - assembly = System.Reflection.Assembly.ReflectionOnlyLoad(args.Name); - break; - } - - return assembly; - } - public static IEnumerable GetTypesImplementingInterface(Assembly assembly, Type interfaceName) { - AppDomain.CurrentDomain.ReflectionOnlyAssemblyResolve += CurrentDomain_ReflectionOnlyAssemblyResolve; - var types = assembly.DefinedTypes.Where(p => p.GetInterfaces().FirstOrDefault(a => a.Name == interfaceName.Name) != null); + var types = assembly.ExportedTypes.Where(p => p.GetInterfaces().FirstOrDefault(a => a.Name == interfaceName.Name) != null); Trace.WriteLine(types.FirstOrDefault()?.CustomAttributes.Count()); - AppDomain.CurrentDomain.ReflectionOnlyAssemblyResolve -= CurrentDomain_ReflectionOnlyAssemblyResolve; return types; } public static IEnumerable GetTypesInheritingFrom(Assembly assembly, Type type) { - // Load the containing assembly into the reflection context so that we can find all types deriving from System.Activities.CodeActivity - System.Reflection.Assembly.ReflectionOnlyLoad(type.Assembly.FullName); - AppDomain.CurrentDomain.ReflectionOnlyAssemblyResolve += CurrentDomain_ReflectionOnlyAssemblyResolve; - var containingAssembly = AppDomain.CurrentDomain.ReflectionOnlyGetAssemblies().Where(ab => ab.GetType(type.FullName) != null).First(); - var types = assembly.DefinedTypes.Where(p => containingAssembly.GetType(type.FullName).IsAssignableFrom(p)); - AppDomain.CurrentDomain.ReflectionOnlyAssemblyResolve -= CurrentDomain_ReflectionOnlyAssemblyResolve; - return types; + var definedTypes = assembly.DefinedTypes.Where(p => p.BaseType != null && p.BaseType.Name == type.Name).ToList(); + + var allTypes = new List(definedTypes); + foreach (var abstractType in definedTypes.Where(t => t.IsAbstract)) + { + var inheritingTypes = assembly.DefinedTypes.Where(t => t.IsClass && !t.IsAbstract && t.IsSubclassOf(abstractType.UnderlyingSystemType)).ToList(); + allTypes.AddRange(inheritingTypes); + } + + return allTypes; } + public static IEnumerable GetAttributes(IEnumerable types, string attributeName) { List attributes = new List(); @@ -109,12 +79,8 @@ public static IEnumerable GetAttributes(IEnumerable t } attributes.AddRange(data); } - + return attributes; } - - - } - -} +} \ No newline at end of file diff --git a/spkl/SparkleXrm.Tasks/SparkleXrm.Tasks.csproj b/spkl/SparkleXrm.Tasks/SparkleXrm.Tasks.csproj index 281cdc60..79bcf8a7 100644 --- a/spkl/SparkleXrm.Tasks/SparkleXrm.Tasks.csproj +++ b/spkl/SparkleXrm.Tasks/SparkleXrm.Tasks.csproj @@ -38,41 +38,40 @@ - ..\packages\Microsoft.CrmSdk.CoreAssemblies.9.0.0.5\lib\net452\Microsoft.Crm.Sdk.Proxy.dll + ..\packages\Microsoft.CrmSdk.CoreAssemblies.9.0.2.23\lib\net462\Microsoft.Crm.Sdk.Proxy.dll True - - ..\packages\Microsoft.Extensions.FileSystemGlobbing.2.0.0\lib\netstandard2.0\Microsoft.Extensions.FileSystemGlobbing.dll + + ..\packages\Microsoft.Extensions.FileSystemGlobbing.3.1.0\lib\netstandard2.0\Microsoft.Extensions.FileSystemGlobbing.dll - - ..\packages\Microsoft.IdentityModel.Clients.ActiveDirectory.2.22.302111727\lib\net45\Microsoft.IdentityModel.Clients.ActiveDirectory.dll - True - - - ..\packages\Microsoft.IdentityModel.Clients.ActiveDirectory.2.22.302111727\lib\net45\Microsoft.IdentityModel.Clients.ActiveDirectory.WindowsForms.dll - True + + ..\packages\Microsoft.IdentityModel.Clients.ActiveDirectory.5.2.4\lib\net45\Microsoft.IdentityModel.Clients.ActiveDirectory.dll False + + ..\packages\Microsoft.CrmSdk.XrmTooling.CoreAssembly.9.1.0.38\lib\net462\Microsoft.Rest.ClientRuntime.dll + True + - ..\packages\Microsoft.CrmSdk.CoreAssemblies.9.0.0.5\lib\net452\Microsoft.Xrm.Sdk.dll + ..\packages\Microsoft.CrmSdk.CoreAssemblies.9.0.2.23\lib\net462\Microsoft.Xrm.Sdk.dll True - ..\packages\Microsoft.CrmSdk.Deployment.9.0.0.5\lib\net452\Microsoft.Xrm.Sdk.Deployment.dll + ..\packages\Microsoft.CrmSdk.Deployment.9.0.2.23\lib\net462\Microsoft.Xrm.Sdk.Deployment.dll True - ..\packages\Microsoft.CrmSdk.Workflow.9.0.0.5\lib\net452\Microsoft.Xrm.Sdk.Workflow.dll + ..\packages\Microsoft.CrmSdk.Workflow.9.0.2.23\lib\net462\Microsoft.Xrm.Sdk.Workflow.dll - - ..\packages\Microsoft.CrmSdk.XrmTooling.CoreAssembly.9.0.0.7\lib\net452\Microsoft.Xrm.Tooling.Connector.dll + + ..\packages\Microsoft.CrmSdk.XrmTooling.CoreAssembly.9.1.0.38\lib\net462\Microsoft.Xrm.Tooling.Connector.dll True - - ..\packages\Newtonsoft.Json.10.0.3\lib\net45\Newtonsoft.Json.dll + + ..\packages\Newtonsoft.Json.12.0.3\lib\net45\Newtonsoft.Json.dll @@ -81,13 +80,43 @@ + + + + ..\packages\System.Net.Http.4.3.4\lib\net46\System.Net.Http.dll + True + True + + + + + ..\packages\System.Security.Cryptography.Algorithms.4.3.1\lib\net461\System.Security.Cryptography.Algorithms.dll + True + True + + + ..\packages\System.Security.Cryptography.Encoding.4.3.0\lib\net46\System.Security.Cryptography.Encoding.dll + True + True + + + ..\packages\System.Security.Cryptography.Primitives.4.3.0\lib\net46\System.Security.Cryptography.Primitives.dll + True + True + + + ..\packages\System.Security.Cryptography.X509Certificates.4.3.2\lib\net461\System.Security.Cryptography.X509Certificates.dll + True + True + + @@ -144,6 +173,7 @@ + @@ -158,16 +188,25 @@ + + + + + + + + + + \ No newline at end of file diff --git a/spkl/TestPluginWorkflowCombined/WorkFlowActivityBase.cs b/spkl/TestPluginWorkflowCombined/WorkFlowActivityBase.cs new file mode 100644 index 00000000..39124684 --- /dev/null +++ b/spkl/TestPluginWorkflowCombined/WorkFlowActivityBase.cs @@ -0,0 +1,321 @@ +// +// Copyright (c) 2017 All Rights Reserved +// +// +// 4/17/2017 12:29:58 PM +// Implements the WorkFlowActivityBase Workflow Activity. +// +// This code was generated by a tool. +// Runtime Version:4.0.30319.1 +// + +using System; +using System.Collections.Generic; +using System.Collections.ObjectModel; +using System.Globalization; +using System.Linq; +using System.Text; +using System.ServiceModel; +using System.Threading.Tasks; +using System.Activities; +using Microsoft.Xrm.Sdk; +using Microsoft.Xrm.Sdk.Workflow; +using System.Runtime.Serialization; + +namespace CrmVSSolution4.WorkflowActivityLibrary1 +{ + public abstract class WorkFlowActivityBase : CodeActivity + { + + public sealed class LocalWorkflowContext + { + internal IServiceProvider ServiceProvider + { + get; + + private set; + } + + internal IOrganizationService OrganizationService + { + get; + + private set; + } + + internal IWorkflowContext WorkflowExecutionContext + { + get; + + private set; + } + + internal ITracingService TracingService + { + get; + + private set; + } + + private LocalWorkflowContext() + { + } + + internal LocalWorkflowContext(CodeActivityContext executionContext) + { + if (executionContext == null) + { + throw new ArgumentNullException("serviceProvider"); + } + + // Obtain the execution context service from the service provider. + this.WorkflowExecutionContext = (IWorkflowContext)executionContext.GetExtension(); + + // Obtain the tracing service from the service provider. + this.TracingService = (ITracingService)executionContext.GetExtension(); + + // Obtain the Organization Service factory service from the service provider + IOrganizationServiceFactory factory = (IOrganizationServiceFactory)executionContext.GetExtension(); + + // Use the factory to generate the Organization Service. + this.OrganizationService = factory.CreateOrganizationService(this.WorkflowExecutionContext.UserId); + } + + internal void Trace(string message) + { + if (string.IsNullOrWhiteSpace(message) || this.TracingService == null) + { + return; + } + + if (this.WorkflowExecutionContext == null) + { + this.TracingService.Trace(message); + } + else + { + this.TracingService.Trace( + "{0}, Correlation Id: {1}, Initiating User: {2}", + message, + this.WorkflowExecutionContext.CorrelationId, + this.WorkflowExecutionContext.InitiatingUserId); + } + } + } + + protected override void Execute(CodeActivityContext context) + { + if (context == null) + { + throw new ArgumentNullException("serviceProvider"); + } + + // Construct the Local plug-in context. + LocalWorkflowContext localcontext = new LocalWorkflowContext(context); + + //localcontext.Trace(string.Format(CultureInfo.InvariantCulture, "Entered {0}.Execute()", this.ChildClassName)); + + try + { + //// Iterate over all of the expected registered events to ensure that the plugin + //// has been invoked by an expected event + //// For any given plug-in event at an instance in time, we would expect at most 1 result to match. + //Action entityAction = + // (from a in this.RegisteredEvents + // where ( + // a.Item1 == localcontext.PluginExecutionContext.Stage && + // a.Item2 == localcontext.PluginExecutionContext.MessageName && + // (string.IsNullOrWhiteSpace(a.Item3) ? true : a.Item3 == localcontext.PluginExecutionContext.PrimaryEntityName) + // ) + // select a.Item4).FirstOrDefault(); + + //if (entityAction != null) + //{ + // localcontext.Trace(string.Format( + // CultureInfo.InvariantCulture, + // "{0} is firing for Entity: {1}, Message: {2}", + // this.ChildClassName, + // localcontext.PluginExecutionContext.PrimaryEntityName, + // localcontext.PluginExecutionContext.MessageName)); + + // entityAction.Invoke(localcontext); + + // // now exit - if the derived plug-in has incorrectly registered overlapping event registrations, + // // guard against multiple executions. + // return; + //} + ExecuteCRMWorkFlowActivity(context, localcontext); + + } + catch (FaultException e) + { + localcontext.Trace(string.Format(CultureInfo.InvariantCulture, "Exception: {0}", e.ToString())); + + // Handle the exception. + throw; + } + finally + { + //localcontext.Trace(string.Format(CultureInfo.InvariantCulture, "Exiting {0}.Execute()", this.ChildClassName)); + } + } + + public virtual void ExecuteCRMWorkFlowActivity(CodeActivityContext context, LocalWorkflowContext crmWorkflowContext) + { + // Do nothing. + } + + + + + + //public IWorkflowContext ParentContext + //{ + // get { throw new NotImplementedException(); } + //} + + //public string StageName + //{ + // get { throw new NotImplementedException(); } + // } + + //public int WorkflowCategory + //{ + // get { throw new NotImplementedException(); } + // } + + //public int WorkflowMode + //{ + // get { throw new NotImplementedException(); } + //} + + //public Guid BusinessUnitId + //{ + // get { throw new NotImplementedException(); } + //} + + //public Guid CorrelationId + //{ + // get { throw new NotImplementedException(); } + //} + + //public int Depth + //{ + // get { throw new NotImplementedException(); } + //} + + //public Guid InitiatingUserId + //{ + // get { throw new NotImplementedException(); } + //} + + //public ParameterCollection InputParameters + //{ + // get { throw new NotImplementedException(); } + //} + + //public bool IsExecutingOffline + //{ + // get { throw new NotImplementedException(); } + //} + + //public bool IsInTransaction + //{ + // get { throw new NotImplementedException(); } + //} + + //public bool IsOfflinePlayback + //{ + // get { throw new NotImplementedException(); } + //} + + //public int IsolationMode + //{ + // get { throw new NotImplementedException(); } + //} + + //public string MessageName + //{ + // get { throw new NotImplementedException(); } + //} + + //public int Mode + //{ + // get { throw new NotImplementedException(); } + //} + + //public DateTime OperationCreatedOn + //{ + // get { throw new NotImplementedException(); } + //} + + //public Guid OperationId + //{ + // get { throw new NotImplementedException(); } + //} + + //public Guid OrganizationId + //{ + // get { throw new NotImplementedException(); } + //} + + //public string OrganizationName + //{ + // get { throw new NotImplementedException(); } + //} + + //public ParameterCollection OutputParameters + //{ + // get { throw new NotImplementedException(); } + //} + + //public EntityReference OwningExtension + //{ + // get { throw new NotImplementedException(); } + //} + + //public EntityImageCollection PostEntityImages + //{ + // get { throw new NotImplementedException(); } + //} + + //public EntityImageCollection PreEntityImages + //{ + // get { throw new NotImplementedException(); } + //} + + //public Guid PrimaryEntityId + //{ + // get { throw new NotImplementedException(); } + //} + + //public string PrimaryEntityName + //{ + // get { throw new NotImplementedException(); } + //} + + //public Guid? RequestId + //{ + // get { throw new NotImplementedException(); } + //} + + //public string SecondaryEntityName + //{ + // get { throw new NotImplementedException(); } + //} + + //public ParameterCollection SharedVariables + //{ + // get { throw new NotImplementedException(); } + //} + + //public Guid UserId + //{ + // get { throw new NotImplementedException(); } + //} + //protected override void Execute(CodeActivityContext context) + //{ + // throw new NotImplementedException(); + //} + } +} diff --git a/spkl/TestPluginWorkflowCombined/WorkflowActivity.cs b/spkl/TestPluginWorkflowCombined/WorkflowActivity.cs new file mode 100644 index 00000000..ef3f4baa --- /dev/null +++ b/spkl/TestPluginWorkflowCombined/WorkflowActivity.cs @@ -0,0 +1,68 @@ +// +// Copyright (c) 2017 All Rights Reserved +// +// +// 4/17/2017 12:30:49 PM +// Implements the WorkflowActivity Workflow Activity. +namespace TestWFSolution.WorkflowActivityLibrary1 +{ + using System; + using System.Activities; + using System.ServiceModel; + using Microsoft.Xrm.Sdk; + using Microsoft.Xrm.Sdk.Workflow; + + [CrmPluginRegistration( + "WorkflowActivity", "f584fb06-dc73-4cd8-b234-626cb5962293","Description","Group Name",IsolationModeEnum.Sandbox + )] + public sealed class WorkflowActivity : CodeActivity + { + /// + /// Executes the workflow activity. + /// + /// The execution context. + protected override void Execute(CodeActivityContext executionContext) + { + // Create the tracing service + ITracingService tracingService = executionContext.GetExtension(); + + if (tracingService == null) + { + throw new InvalidPluginExecutionException("Failed to retrieve tracing service."); + } + + tracingService.Trace("Entered WorkflowActivity.Execute(), Activity Instance Id: {0}, Workflow Instance Id: {1}", + executionContext.ActivityInstanceId, + executionContext.WorkflowInstanceId); + + // Create the context + IWorkflowContext context = executionContext.GetExtension(); + + if (context == null) + { + throw new InvalidPluginExecutionException("Failed to retrieve workflow context."); + } + + tracingService.Trace("WorkflowActivity.Execute(), Correlation Id: {0}, Initiating User: {1}", + context.CorrelationId, + context.InitiatingUserId); + + IOrganizationServiceFactory serviceFactory = executionContext.GetExtension(); + IOrganizationService service = serviceFactory.CreateOrganizationService(context.UserId); + + try + { + // TODO: Implement your custom Workflow business logic. + } + catch (FaultException e) + { + tracingService.Trace("Exception: {0}", e.ToString()); + + // Handle the exception. + throw; + } + + tracingService.Trace("Exiting WorkflowActivity.Execute(), Correlation Id: {0}", context.CorrelationId); + } + } +} \ No newline at end of file diff --git a/spkl/TestPluginWorkflowCombined/WorkflowActivityInheritingFromWorkflowActivityBase.cs b/spkl/TestPluginWorkflowCombined/WorkflowActivityInheritingFromWorkflowActivityBase.cs new file mode 100644 index 00000000..f18299fc --- /dev/null +++ b/spkl/TestPluginWorkflowCombined/WorkflowActivityInheritingFromWorkflowActivityBase.cs @@ -0,0 +1,51 @@ +using System; +using System.Collections.Generic; +using System.Linq; +using System.Text; +using System.Activities; +using Microsoft.Xrm.Sdk; +using System.ServiceModel; +using Microsoft.Xrm.Sdk.Workflow; +using CrmVSSolution4.WorkflowActivityLibrary1; + +namespace TestWFSolution.WorkflowActivityLibrary1 +{ + [CrmPluginRegistration( + "WorkflowActivityInheritingFromWorkflowActivityBase", "93AB069C-188B-4929-BF1E-9622DEDD5209", "Description", "Group Name", IsolationModeEnum.Sandbox + )] + public class WorkflowActivityInheritingFromWorkflowActivityBase : WorkFlowActivityBase + { + + /// + /// Executes the WorkFlow. + /// + /// The which contains the + /// + /// + /// + /// For improved performance, Microsoft Dynamics 365 caches WorkFlow instances. + /// The WorkFlow's Execute method should be written to be stateless as the constructor + /// is not called for every invocation of the WorkFlow. Also, multiple system threads + /// could execute the WorkFlow at the same time. All per invocation state information + /// is stored in the context. This means that you should not use global variables in WorkFlows. + /// + public override void ExecuteCRMWorkFlowActivity(CodeActivityContext executionContext, LocalWorkflowContext crmWorkflowContext) + { + + if (crmWorkflowContext == null) + { + throw new ArgumentNullException("crmWorkflowContext"); + } + + try + { + // TODO: Implement your custom activity handling. + } + catch (FaultException e) + { + // Handle the exception. + throw e; + } + } + } +} diff --git a/spkl/TestPluginWorkflowCombined/app.config b/spkl/TestPluginWorkflowCombined/app.config new file mode 100644 index 00000000..50f6b166 --- /dev/null +++ b/spkl/TestPluginWorkflowCombined/app.config @@ -0,0 +1,19 @@ + + + + + + + + + + + + + + + + + + + \ No newline at end of file diff --git a/spkl/TestPluginWorkflowCombined/deploy-plugins.bat b/spkl/TestPluginWorkflowCombined/deploy-plugins.bat new file mode 100644 index 00000000..9bd05314 --- /dev/null +++ b/spkl/TestPluginWorkflowCombined/deploy-plugins.bat @@ -0,0 +1,14 @@ +@echo off +set package_root=..\ +REM Find the spkl in the package folder (irrespective of version) +For /R %package_root% %%G IN (spkl.exe) do ( + IF EXIST "%%G" (set spkl_path=%%G + goto :continue) + ) + +:continue +@echo Using '%spkl_path%' +REM spkl plugins [path] [connection-string] [/p:release] +"%spkl_path%" plugins + +pause \ No newline at end of file diff --git a/spkl/TestPluginWorkflowCombined/packages.config b/spkl/TestPluginWorkflowCombined/packages.config new file mode 100644 index 00000000..7d9031ca --- /dev/null +++ b/spkl/TestPluginWorkflowCombined/packages.config @@ -0,0 +1,15 @@ + + + + + + + + + + + + + + + \ No newline at end of file diff --git a/spkl/TestPluginWorkflowCombined/spkl.json b/spkl/TestPluginWorkflowCombined/spkl.json new file mode 100644 index 00000000..68b15cb8 --- /dev/null +++ b/spkl/TestPluginWorkflowCombined/spkl.json @@ -0,0 +1,21 @@ +{ + "plugins": [ + { + "assemblypath": "bin\\Debug\\TestPluginWFCombined.dll", + "classRegex": "((public( sealed)? class (?'class'[\\w]*)[\\W]*?)((?'plugin':[\\W]*?((IPlugin)|(PluginBase)|(Plugin)))|(?'wf':[\\W]*?CodeActivity)))" + } + ], + "earlyboundtypes": [ + { + "profile": "default", + "entities": "account,contact,quote,goal", + "actions": "dev1_simpleaction", + "generateOptionsetEnums": true, + "generateGlobalOptionsets": false, + "generateStateEnums": true, + "filename": "EarlyBoundTypes.cs", + "classNamespace": "TestPlugin", + "serviceContextName": "XrmSvc" + } + ] +} \ No newline at end of file diff --git a/spkl/TestWorkflowActivity/TestWorkflowActivity.csproj b/spkl/TestWorkflowActivity/TestWorkflowActivity.csproj index 8b2f33de..5d436913 100644 --- a/spkl/TestWorkflowActivity/TestWorkflowActivity.csproj +++ b/spkl/TestWorkflowActivity/TestWorkflowActivity.csproj @@ -38,25 +38,28 @@ - ..\packages\Microsoft.CrmSdk.CoreAssemblies.9.0.0.7\lib\net452\Microsoft.Crm.Sdk.Proxy.dll + ..\packages\Microsoft.CrmSdk.CoreAssemblies.9.0.2.23\lib\net462\Microsoft.Crm.Sdk.Proxy.dll - - ..\packages\Microsoft.IdentityModel.Clients.ActiveDirectory.2.22.302111727\lib\net45\Microsoft.IdentityModel.Clients.ActiveDirectory.dll + + ..\packages\Microsoft.IdentityModel.Clients.ActiveDirectory.5.2.4\lib\net45\Microsoft.IdentityModel.Clients.ActiveDirectory.dll - - ..\packages\Microsoft.IdentityModel.Clients.ActiveDirectory.2.22.302111727\lib\net45\Microsoft.IdentityModel.Clients.ActiveDirectory.WindowsForms.dll + + ..\packages\Microsoft.CrmSdk.XrmTooling.CoreAssembly.9.1.0.38\lib\net462\Microsoft.Rest.ClientRuntime.dll - ..\packages\Microsoft.CrmSdk.CoreAssemblies.9.0.0.7\lib\net452\Microsoft.Xrm.Sdk.dll + ..\packages\Microsoft.CrmSdk.CoreAssemblies.9.0.2.23\lib\net462\Microsoft.Xrm.Sdk.dll - ..\packages\Microsoft.CrmSdk.Deployment.9.0.0.7\lib\net452\Microsoft.Xrm.Sdk.Deployment.dll + ..\packages\Microsoft.CrmSdk.Deployment.9.0.2.23\lib\net462\Microsoft.Xrm.Sdk.Deployment.dll - ..\packages\Microsoft.CrmSdk.Workflow.9.0.0.7\lib\net452\Microsoft.Xrm.Sdk.Workflow.dll + ..\packages\Microsoft.CrmSdk.Workflow.9.0.2.23\lib\net462\Microsoft.Xrm.Sdk.Workflow.dll - - ..\packages\Microsoft.CrmSdk.XrmTooling.CoreAssembly.9.0.0.7\lib\net452\Microsoft.Xrm.Tooling.Connector.dll + + ..\packages\Microsoft.CrmSdk.XrmTooling.CoreAssembly.9.1.0.38\lib\net462\Microsoft.Xrm.Tooling.Connector.dll + + + ..\packages\Newtonsoft.Json.12.0.3\lib\net45\Newtonsoft.Json.dll @@ -65,13 +68,33 @@ + + + + ..\packages\System.Net.Http.4.3.4\lib\net46\System.Net.Http.dll + + + + + ..\packages\System.Security.Cryptography.Algorithms.4.3.1\lib\net461\System.Security.Cryptography.Algorithms.dll + + + ..\packages\System.Security.Cryptography.Encoding.4.3.0\lib\net46\System.Security.Cryptography.Encoding.dll + + + ..\packages\System.Security.Cryptography.Primitives.4.3.0\lib\net46\System.Security.Cryptography.Primitives.dll + + + ..\packages\System.Security.Cryptography.X509Certificates.4.3.2\lib\net461\System.Security.Cryptography.X509Certificates.dll + + @@ -80,7 +103,6 @@ - diff --git a/spkl/TestWorkflowActivity/app.config b/spkl/TestWorkflowActivity/app.config index a01b86a1..cf1c053c 100644 --- a/spkl/TestWorkflowActivity/app.config +++ b/spkl/TestWorkflowActivity/app.config @@ -2,5 +2,32 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + \ No newline at end of file diff --git a/spkl/TestWorkflowActivity/packages.config b/spkl/TestWorkflowActivity/packages.config index febd59d4..7d9031ca 100644 --- a/spkl/TestWorkflowActivity/packages.config +++ b/spkl/TestWorkflowActivity/packages.config @@ -1,8 +1,15 @@  - - - - - + + + + + + + + + + + + \ No newline at end of file diff --git a/spkl/spkl.sln b/spkl/spkl.sln index 0ee38620..a769b361 100644 --- a/spkl/spkl.sln +++ b/spkl/spkl.sln @@ -1,7 +1,7 @@  Microsoft Visual Studio Solution File, Format Version 12.00 -# Visual Studio 15 -VisualStudioVersion = 15.0.26730.12 +# Visual Studio Version 16 +VisualStudioVersion = 16.0.29728.190 MinimumVisualStudioVersion = 10.0.40219.1 Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "SparkleXrm.Tasks", "SparkleXrm.Tasks\SparkleXrm.Tasks.csproj", "{439FFD12-81E6-41DD-8AED-35A526051D45}" EndProject @@ -41,6 +41,8 @@ Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "CrmSvcUtil.FilteringService EndProject Project("{F5034706-568F-408A-B7B3-4D38C6DB8A32}") = "BuildTasks", "BuildTasks\BuildTasks.pssproj", "{6CAFC0C6-A428-4D30-A9F9-700E829FEA51}" EndProject +Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "TestPluginWorkflowCombined", "TestPluginWorkflowCombined\TestPluginWorkflowCombined.csproj", "{147A132A-D2FF-46FA-8EBA-132BBB3DA405}" +EndProject Global GlobalSection(SolutionConfigurationPlatforms) = preSolution Debug|Any CPU = Debug|Any CPU @@ -113,6 +115,14 @@ Global {6CAFC0C6-A428-4D30-A9F9-700E829FEA51}.Release|Any CPU.Build.0 = Release|Any CPU {6CAFC0C6-A428-4D30-A9F9-700E829FEA51}.Release|x86.ActiveCfg = Release|Any CPU {6CAFC0C6-A428-4D30-A9F9-700E829FEA51}.Release|x86.Build.0 = Release|Any CPU + {147A132A-D2FF-46FA-8EBA-132BBB3DA405}.Debug|Any CPU.ActiveCfg = Debug|Any CPU + {147A132A-D2FF-46FA-8EBA-132BBB3DA405}.Debug|Any CPU.Build.0 = Debug|Any CPU + {147A132A-D2FF-46FA-8EBA-132BBB3DA405}.Debug|x86.ActiveCfg = Debug|Any CPU + {147A132A-D2FF-46FA-8EBA-132BBB3DA405}.Debug|x86.Build.0 = Debug|Any CPU + {147A132A-D2FF-46FA-8EBA-132BBB3DA405}.Release|Any CPU.ActiveCfg = Release|Any CPU + {147A132A-D2FF-46FA-8EBA-132BBB3DA405}.Release|Any CPU.Build.0 = Release|Any CPU + {147A132A-D2FF-46FA-8EBA-132BBB3DA405}.Release|x86.ActiveCfg = Release|Any CPU + {147A132A-D2FF-46FA-8EBA-132BBB3DA405}.Release|x86.Build.0 = Release|Any CPU EndGlobalSection GlobalSection(SolutionProperties) = preSolution HideSolutionNode = FALSE @@ -122,6 +132,7 @@ Global {57E6527B-0860-4208-986B-776C9B159A41} = {A40D37EB-2570-43F8-B852-82C91A5A101D} {E1D15DFB-F2BA-40F5-8C1C-34482C1D74B6} = {A40D37EB-2570-43F8-B852-82C91A5A101D} {A9FDFE00-5D28-47C6-863D-41C463D6FC5E} = {A40D37EB-2570-43F8-B852-82C91A5A101D} + {147A132A-D2FF-46FA-8EBA-132BBB3DA405} = {A40D37EB-2570-43F8-B852-82C91A5A101D} EndGlobalSection GlobalSection(ExtensibilityGlobals) = postSolution SolutionGuid = {F41929D6-0D4E-46F0-8FEC-EFDADE19CC3D} diff --git a/spkl/spkl/App.config b/spkl/spkl/App.config index 83ef53d4..13ee2802 100644 --- a/spkl/spkl/App.config +++ b/spkl/spkl/App.config @@ -23,11 +23,11 @@ - + - + @@ -70,6 +70,26 @@ + + + + + + + + + + + + + + + + + + + + diff --git a/spkl/spkl/CommandLineArgs.cs b/spkl/spkl/CommandLineArgs.cs index aa699848..1b857c49 100644 --- a/spkl/spkl/CommandLineArgs.cs +++ b/spkl/spkl/CommandLineArgs.cs @@ -7,7 +7,7 @@ namespace SparkleXrmTask { - [CommandLineArguments(Program = "spkl", Title = "SpakleXrm Deployment Tasks", Description = "Let SparkleXrm do the work for you!")] + [CommandLineArguments(Program = "spkl", Title = "SparkleXrm Deployment Tasks", Description = "Let SparkleXrm do the work for you!")] public class CommandLineArgs { [CommandLineParameter(Command = "?", Default = false, Description = "Show Help", Name = "Help", IsHelp = true)] @@ -26,7 +26,6 @@ public class CommandLineArgs pack = Packs an unpacked solution into a new Solution Zip - grabbing the latest assemblies and webresources from their mapped locations import = Packs a solution as per the 'pack' task, and then imports into Dynamics 365 ")] - public string Task { get; set; } [CommandLineParameter(Name = "Overwrite", Command = "o", Required = false, Description = "Optional overwrite webresource files when downloading webresources")] @@ -41,7 +40,7 @@ public class CommandLineArgs [CommandLineParameter(Name = "profile", Command = "p", ParameterIndex = 4, Required = false, Description = "Optional profile name. If ommitted, default will be used")] public string Profile { get; set; } - [CommandLineParameter(Name = "solution prefix", Command= "s", Required = false, Description = "Optional Prefix to filter webresources when downloading the config.")] + [CommandLineParameter(Name = "solution prefix", Command = "s", Required = false, Description = "Optional Prefix to filter webresources when downloading the config.")] public string Prefix { get; set; } [CommandLineParameter(Name = "Wait for keypress", Command = "w", Required = false, Description = "Optional wait for a key press at the end of task run")] @@ -52,5 +51,8 @@ public class CommandLineArgs [CommandLineParameter(Name = "Exclude Plugin Steps", Command = "e", Required = false, Description = "Exclude plugin steps when deploying plugins")] public bool ExcludePluginSteps { get; set; } + + [CommandLineParameter(Name = "Legacy Login Mode", Command = "l", Required = false, Description = "Use the legacy command line login mode")] + public bool LegacyLogin { get; set; } } -} +} \ No newline at end of file diff --git a/spkl/spkl/Package/spkl.nuspec b/spkl/spkl/Package/spkl.nuspec index 982fa28c..501e8f1a 100644 --- a/spkl/spkl/Package/spkl.nuspec +++ b/spkl/spkl/Package/spkl.nuspec @@ -1,53 +1,53 @@  - - spkl - 1.0.0$suffix$ - spkl - Dynamics 365 deployment task runner - Scott Durow - https://github.com/scottdurow/SparkleXrm/blob/master/MIT-License.txt - https://github.com/scottdurow/SparkleXrm/wiki/spkl - https://raw.githubusercontent.com/scottdurow/SparkleXrm/master/NuGet/SparkleXRM.png - true - Simple and Lightweight deployment task runner for Dynamics 365 - $releasenotes$ - en-GB - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - + + spkl + 1.0.0$suffix$ + spkl - Dynamics 365 deployment task runner + Scott Durow + https://github.com/scottdurow/SparkleXrm/blob/master/MIT-License.txt + https://github.com/scottdurow/SparkleXrm/wiki/spkl + https://raw.githubusercontent.com/scottdurow/SparkleXrm/master/NuGet/SparkleXRM.png + true + Simple and Lightweight deployment task runner for Dynamics 365 + $releasenotes$ + en-GB + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + \ No newline at end of file diff --git a/spkl/spkl/Program.cs b/spkl/spkl/Program.cs index 9e8bec37..f314b441 100644 --- a/spkl/spkl/Program.cs +++ b/spkl/spkl/Program.cs @@ -1,11 +1,11 @@ - -using CmdLine; +using CmdLine; using Microsoft.Crm.Sdk.Messages; using Microsoft.Crm.Sdk.Samples; using Microsoft.Xrm.Sdk; using Microsoft.Xrm.Sdk.Client; using Microsoft.Xrm.Tooling.Connector; using SparkleXrm.Tasks; +using SparkleXrmTask.XrmToolingCmdLine; using System; using System.Collections.Generic; using System.IO; @@ -18,20 +18,28 @@ namespace SparkleXrmTask { - class Program - { - static void Main(string[] args) + internal class Program + { + private static void Main(string[] args) { Console.ForegroundColor = ConsoleColor.DarkYellow; + Console.WriteLine(@" + __ .__ + ____________ | | _| | + / ___/\____ \| |/ / | + \___ \ | |_> > <| |__ +/____ >| __/|__|_ \____/ + \/ |__| \/ "); + Console.WriteLine("spkl Task Runner v" + Assembly.GetEntryAssembly().GetName().Version + "\tTasks v" + Assembly.GetAssembly(typeof(SparkleXrm.Tasks.BaseTask)).GetName().Version); - + Console.ForegroundColor = ConsoleColor.Gray; bool error = false; CommandLineArgs arguments = null; try { arguments = CommandLine.Parse(); - + Run(arguments); } catch (CommandLineException exception) @@ -87,12 +95,12 @@ static void Main(string[] args) Console.WriteLine(ex.Message); Console.ForegroundColor = ConsoleColor.DarkGray; Console.WriteLine(ex.StackTrace); - + // Display the details of the inner exception. if (ex.InnerException != null) { Console.WriteLine(ex.InnerException.Message); - + FaultException fe = ex.InnerException as FaultException; if (fe != null) @@ -121,7 +129,7 @@ static void Main(string[] args) Environment.ExitCode = 1; } } - if (arguments!=null && arguments.WaitForKey == true) + if (arguments != null && arguments.WaitForKey == true) { Console.ForegroundColor = ConsoleColor.White; Console.WriteLine("Press any key..."); @@ -142,18 +150,32 @@ private static void Run(CommandLineArgs arguments) if (arguments.Connection == null) { - // No Connection is supplied to ask for connection on command line - ServerConnection serverConnect = new ServerConnection(); - ServerConnection.Configuration config = serverConnect.GetServerConfiguration(arguments.IgnoreLocalPrincipal); - - arguments.Connection = BuildConnectionString(config); + if (arguments.LegacyLogin) + { + Console.ForegroundColor = ConsoleColor.Blue; + Console.Write("On-premises/Legacy Login"); + Console.ForegroundColor = ConsoleColor.Gray; + // This login code will not work with the latest versions of CDS + // No Connection is supplied to ask for connection on command line + ServerConnection serverConnect = new ServerConnection(); + ServerConnection.Configuration config = serverConnect.GetServerConfiguration(arguments.IgnoreLocalPrincipal); + + arguments.Connection = BuildConnectionString(config); - using (var serviceProxy = new OrganizationServiceProxy(config.OrganizationUri, config.HomeRealmUri, config.Credentials, config.DeviceCredentials)) + using (var serviceProxy = new OrganizationServiceProxy(config.OrganizationUri, config.HomeRealmUri, config.Credentials, config.DeviceCredentials)) + { + // This statement is required to enable early-bound type support. + serviceProxy.EnableProxyTypes(); + serviceProxy.Timeout = new TimeSpan(1, 0, 0); + RunTask(arguments, serviceProxy, trace); + } + } + else { - // This statement is required to enable early-bound type support. - serviceProxy.EnableProxyTypes(); - serviceProxy.Timeout = new TimeSpan(1, 0, 0); - RunTask(arguments, serviceProxy, trace); + var toolingConnector = new XrmToolingConnection(); + var client = toolingConnector.Connect(); + arguments.Connection = toolingConnector.ConnectionString; + RunTask(arguments, client, trace); } } else if (arguments.Connection == "") @@ -173,15 +195,14 @@ private static void Run(CommandLineArgs arguments) var password = ConsoleEx.ReadPassword('*'); arguments.Connection = arguments.Connection.Replace(passwordMatch.Value, "Password=" + password); } - + CrmServiceClient.MaxConnectionTimeout = new TimeSpan(1, 0, 0); using (var serviceProxy = new CrmServiceClient(arguments.Connection)) { - if (serviceProxy.OrganizationServiceProxy == null) + if (!serviceProxy.IsReady) { - throw new SparkleTaskException(SparkleTaskException.ExceptionTypes.AUTH_ERROR, String.Format("Error connecting to the Organization Service Proxy: {0}", serviceProxy.LastCrmError)); + throw new SparkleTaskException(SparkleTaskException.ExceptionTypes.AUTH_ERROR, String.Format("Error connecting to the Organization Service: {0}", serviceProxy.LastCrmError)); } - serviceProxy.OrganizationServiceProxy.Timeout = new TimeSpan(1, 0, 0); if (!serviceProxy.IsReady) { trace.WriteLine("Not Ready {0} {1}", serviceProxy.LastCrmError, serviceProxy.LastCrmException); @@ -196,7 +217,6 @@ private static void Run(CommandLineArgs arguments) Console.WriteLine(exception.ArgumentHelp.Message); Console.WriteLine(exception.ArgumentHelp.GetHelpText(Console.BufferWidth)); } - } private static string BuildConnectionString(ServerConnection.Configuration config) @@ -211,7 +231,7 @@ private static string BuildConnectionString(ServerConnection.Configuration confi // AuthType=AD;Url=http://contoso:8080/Test; Domain=CONTOSO; Username=jsmith; Password=passcode - // Office 365 + // Office 365 // AuthType = Office365; Username = jsmith@contoso.onmicrosoft.com; Password = passcode; Url = https://contoso.crm.dynamics.com // IFD @@ -223,6 +243,7 @@ private static string BuildConnectionString(ServerConnection.Configuration confi connectionString = String.Format("AuthType=AD;Url={0}", config.OrganizationUri); break; + case AuthenticationProviderType.Federation: connectionString = String.Format("AuthType=IFD;Url={0}", config.OrganizationUri); break; @@ -282,7 +303,6 @@ private static void RunTask(CommandLineArgs arguments, IOrganizationService serv { if (arguments.Path == null) { - arguments.Path = Directory.GetCurrentDirectory(); } else @@ -291,11 +311,17 @@ private static void RunTask(CommandLineArgs arguments, IOrganizationService serv arguments.Path = arguments.Path.TrimEnd('\\'); arguments.Path = Path.Combine(Directory.GetCurrentDirectory(), arguments.Path); } - + BaseTask task = null; string command = arguments.Task.ToLower(); switch (command) { + case "whoami": + trace.WriteLine("Who Am I?"); + var whoAmIResponse = service.Execute(new WhoAmIRequest()) as WhoAmIResponse; + Console.WriteLine($"OrgId:'{whoAmIResponse.OrganizationId}' UserId:'{whoAmIResponse.UserId}'"); + return; + case "plugins": trace.WriteLine("Deploying Plugins"); task = new DeployPluginsTask(service, trace) @@ -328,36 +354,49 @@ private static void RunTask(CommandLineArgs arguments, IOrganizationService serv task = new DownloadWebresourceConfigTask(service, trace); task.Prefix = arguments.Prefix; break; + case "earlybound": trace.WriteLine("Generating early bound types"); var earlyBound = new EarlyBoundClassGeneratorTask(service, trace); task = earlyBound; earlyBound.ConectionString = arguments.Connection; break; + case "unpack": trace.WriteLine("Unpacking solution"); var packager = new SolutionPackagerTask(service, trace); packager.command = command; task = packager; break; + case "unpacksolution": trace.WriteLine("Unpacking solution Zip"); var unpackfromsolution = new SolutionPackagerTask(service, trace); unpackfromsolution.command = command; task = unpackfromsolution; break; + case "pack": trace.WriteLine("Packing Solution"); var pack = new SolutionPackagerTask(service, trace); pack.command = command; task = pack; break; + case "import": trace.WriteLine("Packing & Import Solution"); var import = new SolutionPackagerTask(service, trace); import.command = command; task = import; break; + + case "export": + trace.WriteLine("Exporting Solution"); + var export = new SolutionPackagerTask(service, trace); + export.command = command; + task = export; + break; + case "compare": trace.WriteLine("Comparing Solution"); var compare = new SolutionPackagerTask(service, trace); @@ -366,7 +405,6 @@ private static void RunTask(CommandLineArgs arguments, IOrganizationService serv break; } - if (task != null) { if (arguments.Profile != null) @@ -374,7 +412,7 @@ private static void RunTask(CommandLineArgs arguments, IOrganizationService serv task.Execute(arguments.Path); } else - throw new SparkleTaskException(SparkleTaskException.ExceptionTypes.NO_TASK_SUPPLIED, String.Format("Task '{0}' not recognised. Please consult help!", arguments.Task.ToLower())); + throw new SparkleTaskException(SparkleTaskException.ExceptionTypes.NO_TASK_SUPPLIED, String.Format("Task '{0}' not recognised. Please consult help!", arguments.Task.ToLower())); } } -} +} \ No newline at end of file diff --git a/spkl/spkl/XrmToolingCmdLine/SavedConnection.cs b/spkl/spkl/XrmToolingCmdLine/SavedConnection.cs new file mode 100644 index 00000000..eb71537c --- /dev/null +++ b/spkl/spkl/XrmToolingCmdLine/SavedConnection.cs @@ -0,0 +1,9 @@ +namespace SparkleXrmTask.XrmToolingCmdLine +{ + public class SavedConnection + { + public string EnvironmentUrl; + public string UserName; + public string DisplayName; + } +} \ No newline at end of file diff --git a/spkl/spkl/XrmToolingCmdLine/XrmToolingConnection.cs b/spkl/spkl/XrmToolingCmdLine/XrmToolingConnection.cs new file mode 100644 index 00000000..abf3901b --- /dev/null +++ b/spkl/spkl/XrmToolingCmdLine/XrmToolingConnection.cs @@ -0,0 +1,173 @@ +using Microsoft.Xrm.Tooling.Connector; +using Newtonsoft.Json; +using System; +using System.Collections.Generic; +using System.IO; +using System.Text.RegularExpressions; +using System.Linq; + +namespace SparkleXrmTask.XrmToolingCmdLine +{ + public class XrmToolingConnection + { + /// + /// Connection configurations - no credentials or tokens are stored here + /// + public static readonly string ConnectionsFilePath = Path.Combine( + Path.Combine(Environment.GetFolderPath(Environment.SpecialFolder.ApplicationData), "spkl"), + "Connections.json"); + + /// + /// Token Cache is used to store the Xrm Tooling tokens so user is not always prompted to login where possible + /// + public static readonly string TokenPath = Path.Combine( + Path.Combine(Environment.GetFolderPath(Environment.SpecialFolder.ApplicationData), "spkl"), + "TokenCache"); + + public string ConnectionString { get; internal set; } + private List _savedConnections = new List(); + + public XrmToolingConnection() + { + LoadSettings(); + } + + public CrmServiceClient Connect() + { + Console.ForegroundColor = ConsoleColor.Blue; + Console.WriteLine("Office365 Login"); + Console.ForegroundColor = ConsoleColor.Cyan; + Console.WriteLine("Note: Use /l switch for on-premises or legacy login"); + Console.ForegroundColor = ConsoleColor.Gray; + + var connectionStringRoot = $@"AuthType=OAuth; + AppId=51f81489-12ee-4a9e-aaae-a2591f45987d; + RedirectUri=app://58145B91-0C36-4500-8554-080854F2AC97; + TokenCacheStorePath={XrmToolingConnection.TokenPath}"; + + // Show list of saved connections + // We don't store the credentials but instead use the Xrm.Tooling token cache + var configNumber = -1; + if (_savedConnections.Count > 0) + { + var i = 1; + Console.WriteLine("(0) Add New Server Configuration"); + foreach (SavedConnection connection in _savedConnections) + { + Console.WriteLine($"({i}) {connection.EnvironmentUrl}, {connection.DisplayName}, {connection.UserName}"); + i++; + } + + Console.Write($"\nSpecify the saved server configuration number (0-{_savedConnections.Count}) [{_savedConnections.Count}] : "); + var input = Console.ReadLine(); + Console.WriteLine(); + if (input == string.Empty) + { + input = _savedConnections.Count.ToString(); + } + + if (!int.TryParse(input, out configNumber)) + { + configNumber = -1; + } + } + + SavedConnection selectedConnection; + var loginPrompt = "Auto"; + var newConnection = configNumber <= 0; + if (newConnection) + { + selectedConnection = new SavedConnection(); + var envUrl = ReadLine("Environment/Organization Url (e.g. org123.crm.dynamics.com)", regex: @"^(? c.EnvironmentUrl.Equals(selectedConnection.EnvironmentUrl, StringComparison.InvariantCultureIgnoreCase) && + c.UserName.Equals(selectedConnection.UserName, StringComparison.InvariantCultureIgnoreCase)); + _savedConnections.Add(selectedConnection); + SaveSettings(); + } + this.ConnectionString = connectionString; + return client; + } + else + { + throw new Exception($"Cannot connect: {client.LastCrmError}", client.LastCrmException); + } + } + + private void LoadSettings() + { + if (File.Exists(XrmToolingConnection.ConnectionsFilePath)) + { + string configJson = File.ReadAllText(XrmToolingConnection.ConnectionsFilePath); + _savedConnections = JsonConvert.DeserializeObject>(configJson); + } + } + + private void SaveSettings() + { + string configJson = JsonConvert.SerializeObject(_savedConnections); + File.WriteAllText(XrmToolingConnection.ConnectionsFilePath, configJson); + } + + private string ReadLine(string prompt, string regex = null, string defaultValue = null) + { + if (defaultValue != null) + { + prompt += $"[{defaultValue}]"; + } + + bool isValid = true; + string returnedValue = defaultValue; + do + { + Console.Write(prompt + ": "); + string input = Console.ReadLine(); + if (input.Length > 0) + { + if (regex != null && Regex.IsMatch(input, regex)) + { + returnedValue = input; + isValid = true; + } + else + { + Console.WriteLine("\nInput invalid"); + isValid = false; + } + } + else if (defaultValue == null) + { + Console.WriteLine("\nInput Required"); + isValid = false; + } + } while (!isValid); + Console.Write("\n"); + return returnedValue; + } + } +} \ No newline at end of file diff --git a/spkl/spkl/packages.config b/spkl/spkl/packages.config index 157c3ce5..1d8dc83f 100644 --- a/spkl/spkl/packages.config +++ b/spkl/spkl/packages.config @@ -1,18 +1,24 @@  - - - - - - - - + + + + + + + + + + + + + + + + + - - - - + \ No newline at end of file diff --git a/spkl/spkl/spkl.csproj b/spkl/spkl/spkl.csproj index 984776fe..d652530d 100644 --- a/spkl/spkl/spkl.csproj +++ b/spkl/spkl/spkl.csproj @@ -39,66 +39,82 @@ True - False - ..\packages\Microsoft.CrmSdk.CoreAssemblies.9.0.0.7\lib\net452\Microsoft.Crm.Sdk.Proxy.dll + ..\packages\Microsoft.CrmSdk.CoreAssemblies.9.0.2.23\lib\net462\Microsoft.Crm.Sdk.Proxy.dll True - - False - ..\packages\Microsoft.IdentityModel.Clients.ActiveDirectory.2.22.302111727\lib\net45\Microsoft.IdentityModel.Clients.ActiveDirectory.dll - True + + ..\packages\Microsoft.IdentityModel.Clients.ActiveDirectory.5.2.4\lib\net45\Microsoft.IdentityModel.Clients.ActiveDirectory.dll - - False - ..\packages\Microsoft.IdentityModel.Clients.ActiveDirectory.2.22.302111727\lib\net45\Microsoft.IdentityModel.Clients.ActiveDirectory.WindowsForms.dll + + ..\packages\Microsoft.CrmSdk.XrmTooling.CoreAssembly.9.1.0.38\lib\net462\Microsoft.Rest.ClientRuntime.dll True - False - ..\packages\Microsoft.CrmSdk.CoreAssemblies.9.0.0.7\lib\net452\Microsoft.Xrm.Sdk.dll + ..\packages\Microsoft.CrmSdk.CoreAssemblies.9.0.2.23\lib\net462\Microsoft.Xrm.Sdk.dll True - ..\packages\Microsoft.CrmSdk.Deployment.9.0.0.7\lib\net452\Microsoft.Xrm.Sdk.Deployment.dll + ..\packages\Microsoft.CrmSdk.Deployment.9.0.2.23\lib\net462\Microsoft.Xrm.Sdk.Deployment.dll True - False - ..\packages\Microsoft.CrmSdk.Workflow.9.0.0.7\lib\net452\Microsoft.Xrm.Sdk.Workflow.dll + ..\packages\Microsoft.CrmSdk.Workflow.9.0.2.23\lib\net462\Microsoft.Xrm.Sdk.Workflow.dll True - - ..\packages\Microsoft.CrmSdk.XrmTooling.CoreAssembly.9.0.0.7\lib\net452\Microsoft.Xrm.Tooling.Connector.dll + + ..\packages\Microsoft.CrmSdk.XrmTooling.CoreAssembly.9.1.0.38\lib\net462\Microsoft.Xrm.Tooling.Connector.dll True + + ..\packages\Newtonsoft.Json.12.0.3\lib\net45\Newtonsoft.Json.dll + - - ..\packages\System.Collections.Immutable.1.3.1\lib\portable-net45+win8+wp8+wpa81\System.Collections.Immutable.dll - True + + ..\packages\System.Buffers.4.5.0\lib\netstandard2.0\System.Buffers.dll + + + ..\packages\System.Collections.Immutable.1.7.0\lib\netstandard2.0\System.Collections.Immutable.dll + - - ..\packages\System.Runtime.4.3.0\lib\net462\System.Runtime.dll - True + + ..\packages\System.Memory.4.5.3\lib\netstandard2.0\System.Memory.dll + + + + ..\packages\System.Net.Http.4.3.4\lib\net46\System.Net.Http.dll - - ..\packages\System.Runtime.Extensions.4.3.0\lib\net462\System.Runtime.Extensions.dll + + + + ..\packages\System.Numerics.Vectors.4.5.0\lib\net46\System.Numerics.Vectors.dll + + + ..\packages\System.Runtime.4.3.1\lib\net462\System.Runtime.dll + True True - - ..\packages\System.Net.Http.4.3.3\lib\net46\System.Net.Http.dll + + ..\packages\System.Runtime.CompilerServices.Unsafe.4.7.0\lib\netstandard2.0\System.Runtime.CompilerServices.Unsafe.dll + + + ..\packages\System.Runtime.Extensions.4.3.1\lib\net462\System.Runtime.Extensions.dll + True + True - ..\packages\System.Security.Cryptography.Algorithms.4.3.0\lib\net461\System.Security.Cryptography.Algorithms.dll + ..\packages\System.Security.Cryptography.Algorithms.4.3.1\lib\net461\System.Security.Cryptography.Algorithms.dll + True + True ..\packages\System.Security.Cryptography.Encoding.4.3.0\lib\net46\System.Security.Cryptography.Encoding.dll @@ -106,13 +122,16 @@ ..\packages\System.Security.Cryptography.Primitives.4.3.0\lib\net46\System.Security.Cryptography.Primitives.dll - - ..\packages\System.Security.Cryptography.X509Certificates.4.3.0\lib\net461\System.Security.Cryptography.X509Certificates.dll + + ..\packages\System.Security.Cryptography.X509Certificates.4.3.2\lib\net461\System.Security.Cryptography.X509Certificates.dll + True + True + @@ -129,6 +148,8 @@ + + @@ -136,6 +157,7 @@ + @@ -172,16 +194,25 @@ + + + + + + + + +