├── MFaaP.MFWSClient.sln.DotSettings
├── MFaaP.MFWSClient
├── GlobalSuppressions.cs
├── MFaaP.MFWSClient.csproj.DotSettings
├── Searching
│ ├── QuickSearchCondition.cs
│ ├── IncludeDeletedObjectsSearchCondition.cs
│ ├── ObjectTypeSearchCondition.cs
│ ├── PropertyValues
│ │ ├── TextPropertyValueSearchCondition.cs
│ │ ├── BooleanPropertyValueSearchCondition.cs
│ │ ├── DatePropertyValueSearchCondition.cs
│ │ ├── LookupPropertyValueSearchCondition.cs
│ │ ├── MultiSelectLookupPropertyValueSearchCondition.cs
│ │ ├── PropertyValueSearchConditionBase.cs
│ │ └── NumericPropertyValueSearchCondition.cs
│ ├── SearchConditionOperators.cs
│ ├── ISearchCondition.cs
│ ├── SearchConditionBase.cs
│ └── ValueListSearchCondition.cs
├── MFWSExtensions.cs
├── MFWSVaultOperationsBase.cs
├── RestRequestEventArgs.cs
├── RestResponseEventArgs.cs
├── ExtensionMethods
│ ├── RestRequestExtensionMethods.cs
│ ├── DictionaryExtensionMethods.cs
│ ├── IEnumerableExtensionMethods.cs
│ ├── UriBuilderExtensionMethods.cs
│ ├── IEnumerablePluginInfoConfigurationExtensionMethods.cs
│ └── FolderContentItemExtensionMethods.cs
├── MFWSClient.cs
├── MFaaP.MFWSClient.csproj
├── OAuth2
│ └── OAuth2TokenResponse.cs
├── MFWSVaultClassGroupOperations.cs
├── MFWSClient.Session.cs
├── MFWSVaultValueListOperations.cs
├── MFWSVaultObjectTypeOperations.cs
├── MFWSVaultExtensionAuthenticationOperations.cs
├── MFWSVaultValueListItemOperations.cs
├── MFWSVaultExtensionMethodOperations.cs
├── MFWSVaultExternalObjectOperations.cs
├── MFWSVaultPropertyDefOperations.cs
├── MFWSVaultViewOperations.cs
└── MFWSVaultClassOperations.cs
├── MFaaP.MFWSClient.Tests
├── ExtensionMethods
│ ├── ListParameterExtensionMethods.cs
│ └── IRestRequestExtensionMethods.cs
├── Properties
│ └── AssemblyInfo.cs
├── MFWSVaultClassGroupOperations.cs
├── Setup.cs
├── MFWSClient.cs
├── MFWSVaultObjectTypeOperations.cs
├── MFWSVaultValueListOperations.cs
├── MFaaP.MFWSClient.Tests.csproj
├── MFWSVaultAutomaticMetadataOperations.cs
├── MFWSVaultClassOperations.cs
├── MFWSVaultExtensionAuthenticationOperations.cs
└── MFWSVaultExtensionMethodOperations.cs
├── LICENSE.md
├── MFaaP.MFWSClient.sln
├── .github
└── workflows
│ ├── dotnet-core.yml
│ └── manual.yml
├── .gitattributes
├── CODE_OF_CONDUCT.md
├── CONTRIBUTING.md
└── .gitignore
/MFaaP.MFWSClient.sln.DotSettings:
--------------------------------------------------------------------------------
1 |
2 | MFWS
--------------------------------------------------------------------------------
/MFaaP.MFWSClient/GlobalSuppressions.cs:
--------------------------------------------------------------------------------
1 | // This file is used by Code Analysis to maintain SuppressMessage
2 | // attributes that are applied to this project.
3 | // Project-level suppressions either have no target or are given
4 | // a specific target and scoped to a namespace, type, member, etc.
5 |
6 | using System.Diagnostics.CodeAnalysis;
7 |
8 | [assembly: SuppressMessage("Naming", "CA1712:Do not prefix enum values with type name", Justification = "M-Files standard", Scope = "module")]
9 |
--------------------------------------------------------------------------------
/MFaaP.MFWSClient/MFaaP.MFWSClient.csproj.DotSettings:
--------------------------------------------------------------------------------
1 |
2 | True
3 | True
--------------------------------------------------------------------------------
/MFaaP.MFWSClient/Searching/QuickSearchCondition.cs:
--------------------------------------------------------------------------------
1 | using System;
2 |
3 | namespace MFaaP.MFWSClient
4 | {
5 | ///
6 | /// Represents a "quick search" search condition.
7 | ///
8 |
9 | public class QuickSearchCondition
10 | : SearchConditionBase
11 | {
12 | ///
13 | /// Creates a , searching for the value supplied.
14 | ///
15 | /// The value to search for.
16 | public QuickSearchCondition(string value)
17 | : base("q", SearchConditionOperators.Equals, value)
18 | {
19 | }
20 |
21 | ///
22 | public override string EncodedValue => this.Value;
23 | }
24 | }
--------------------------------------------------------------------------------
/MFaaP.MFWSClient/MFWSExtensions.cs:
--------------------------------------------------------------------------------
1 | using System;
2 | namespace MFaaP.MFWSClient
3 | {
4 | ///
5 | /// Enabling or disabling extensions enables specific functionality within the web service.
6 | ///
7 | [Flags]
8 | // ReSharper disable once InconsistentNaming
9 | public enum MFWSExtensions
10 | {
11 | ///
12 | /// No extensions are enabled.
13 | ///
14 | None = 0,
15 |
16 | ///
17 | /// Enables extensions commonly used with the M-Files Web Access.
18 | ///
19 | // ReSharper disable once InconsistentNaming
20 | MFWA = 1,
21 |
22 | ///
23 | /// Enables IML (requires server-side version and licensing support).
24 | ///
25 | // ReSharper disable once InconsistentNaming
26 | IML = 2
27 | }
28 | }
--------------------------------------------------------------------------------
/MFaaP.MFWSClient.Tests/ExtensionMethods/ListParameterExtensionMethods.cs:
--------------------------------------------------------------------------------
1 | using System.Collections.Generic;
2 | using System.Linq;
3 | using RestSharp;
4 |
5 | namespace MFaaP.MFilesAPI.Tests.ExtensionMethods
6 | {
7 | public static class ListParameterExtensionMethods
8 | {
9 | public static string GetQuerystringParameter(this List parameters, string name)
10 | {
11 | return parameters?
12 | .Where(p => p.Type == ParameterType.QueryString)
13 | .Where(p => p.Name == name)
14 | .Select(p => p.Value as string)
15 | .FirstOrDefault();
16 | }
17 |
18 | public static string GetMethodQuerystringParameter(this List parameters)
19 | {
20 | return parameters.GetQuerystringParameter("_method");
21 | }
22 | }
23 | }
24 |
--------------------------------------------------------------------------------
/MFaaP.MFWSClient/MFWSVaultOperationsBase.cs:
--------------------------------------------------------------------------------
1 | using System;
2 |
3 | namespace MFaaP.MFWSClient
4 | {
5 | ///
6 | /// Vault operations base class.
7 | ///
8 | public abstract class MFWSVaultOperationsBase
9 | {
10 | ///
11 | /// The that this object uses to interact with the server.
12 | ///
13 | protected MFWSClientBase MFWSClient { get; private set; }
14 |
15 | ///
16 | /// Creates a new object.
17 | ///
18 | /// The client to interact with the server.
19 | internal MFWSVaultOperationsBase(MFWSClientBase client)
20 | {
21 | this.MFWSClient = client ?? throw new ArgumentNullException(nameof(client));
22 | }
23 | }
24 | }
25 |
--------------------------------------------------------------------------------
/MFaaP.MFWSClient/Searching/IncludeDeletedObjectsSearchCondition.cs:
--------------------------------------------------------------------------------
1 | using System;
2 |
3 | namespace MFaaP.MFWSClient
4 | {
5 | ///
6 | /// Represents a search condition that includes deleted objects.
7 | /// By default the M-Files Web Service excludes deleted objects.
8 | ///
9 |
10 | public class IncludeDeletedObjectsSearchCondition
11 | : SearchConditionBase
12 | {
13 | ///
14 | /// Creates a .
15 | /// Note that this search condition is a "flag"; by including it the value is irrelevant and will include deleted objects.
16 | ///
17 | public IncludeDeletedObjectsSearchCondition()
18 | : base("d", SearchConditionOperators.Equals)
19 | {
20 | }
21 |
22 | ///
23 | public override string EncodedValue => "include";
24 | }
25 | }
--------------------------------------------------------------------------------
/MFaaP.MFWSClient/RestRequestEventArgs.cs:
--------------------------------------------------------------------------------
1 | using System;
2 | using System.Collections.Generic;
3 | using System.IO;
4 | using System.Linq;
5 | using System.Text;
6 | using RestSharp;
7 |
8 | namespace MFaaP.MFWSClient
9 | {
10 | ///
11 | /// Event argument for the event.
12 | ///
13 | public class RestRequestEventArgs
14 | : EventArgs
15 | {
16 | ///
17 | /// The request being executed.
18 | ///
19 | public RestRequest RestRequest { get; private set; }
20 |
21 | ///
22 | /// Instantiates a for the supplied request.
23 | ///
24 | /// The request being executed.
25 | public RestRequestEventArgs(RestRequest restRequest)
26 | {
27 | this.RestRequest = restRequest;
28 | }
29 | }
30 | }
--------------------------------------------------------------------------------
/MFaaP.MFWSClient/RestResponseEventArgs.cs:
--------------------------------------------------------------------------------
1 | using System;
2 | using System.Collections.Generic;
3 | using System.IO;
4 | using System.Linq;
5 | using System.Text;
6 | using RestSharp;
7 |
8 | namespace MFaaP.MFWSClient
9 | {
10 | ///
11 | /// Event argument for the event.
12 | ///
13 | public class RestResponseEventArgs
14 | : EventArgs
15 | {
16 | ///
17 | /// The response from the request.
18 | ///
19 | public RestResponse RestResponse { get; private set; }
20 |
21 | ///
22 | /// Instantiates a for the supplied response.
23 | ///
24 | /// The response from the request.
25 | public RestResponseEventArgs(RestResponse restResponse)
26 | {
27 | this.RestResponse = restResponse;
28 | }
29 | }
30 | }
--------------------------------------------------------------------------------
/MFaaP.MFWSClient.Tests/ExtensionMethods/IRestRequestExtensionMethods.cs:
--------------------------------------------------------------------------------
1 | using System;
2 | using System.Linq;
3 | using Newtonsoft.Json;
4 | using RestSharp;
5 |
6 | namespace MFaaP.MFWSClient.Tests.ExtensionMethods
7 | {
8 | // ReSharper disable once InconsistentNaming
9 | internal static class RestRequestExtensionMethods
10 | {
11 | ///
12 | /// Extracts the body from the request and attempts to deserialize it to the provided type.
13 | ///
14 | /// The body type.
15 | /// The request.
16 | /// The value, or null.
17 | public static T DeserializeBody(this RestRequest request)
18 | {
19 | // Sanity.
20 | if(null == request)
21 | throw new ArgumentNullException(nameof(request));
22 |
23 | // Get the body or return null if none found.
24 | return JsonConvert
25 | .DeserializeObject(request.Parameters.FirstOrDefault(p => p.Type == ParameterType.RequestBody)?.Value?.ToString() ?? null);
26 | }
27 |
28 | }
29 | }
30 |
--------------------------------------------------------------------------------
/MFaaP.MFWSClient/Searching/ObjectTypeSearchCondition.cs:
--------------------------------------------------------------------------------
1 | using System;
2 |
3 | namespace MFaaP.MFWSClient
4 | {
5 | ///
6 | /// Represents a search condition that restricts by object type.
7 | ///
8 |
9 | public class ObjectTypeSearchCondition
10 | : SearchConditionBase
11 | {
12 | ///
13 | /// Creates a , searching for the value supplied.
14 | ///
15 | /// The Id of the object type to retrieve.
16 | /// The operator to use (defaults to Equals if not provided).
17 | /// Whether to invert the search operator (defaults to false if not provided).
18 | public ObjectTypeSearchCondition(int objectTypeId, SearchConditionOperators searchConditionOperator = SearchConditionOperators.Equals, bool invertOperator = false)
19 | : base("o", searchConditionOperator, objectTypeId, invertOperator)
20 | {
21 | }
22 |
23 | ///
24 | public override string EncodedValue => this.Value.ToString();
25 | }
26 | }
--------------------------------------------------------------------------------
/LICENSE.md:
--------------------------------------------------------------------------------
1 | # The MIT License (MIT)
2 |
3 | Copyright (c) 2017 M-Files Oy
4 |
5 | Permission is hereby granted, free of charge, to any person obtaining a copy
6 | of this software and associated documentation files (the "Software"), to deal
7 | in the Software without restriction, including without limitation the rights
8 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
9 | copies of the Software, and to permit persons to whom the Software is
10 | furnished to do so, subject to the following conditions:
11 |
12 | The above copyright notice and this permission notice shall be included in all
13 | copies or substantial portions of the Software.
14 |
15 | **THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
16 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
17 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
18 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
19 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
20 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
21 | SOFTWARE.**
22 |
--------------------------------------------------------------------------------
/MFaaP.MFWSClient/ExtensionMethods/RestRequestExtensionMethods.cs:
--------------------------------------------------------------------------------
1 | using System;
2 | using System.Collections.Generic;
3 | using System.IO;
4 | using System.Linq;
5 | using System.Text;
6 | using RestSharp;
7 |
8 | namespace MFaaP.MFWSClient.ExtensionMethods
9 | {
10 | ///
11 | /// REST request extension methods.
12 | ///
13 | public static class RestRequestExtensionMethods
14 | {
15 | ///
16 | /// Calls if the
17 | /// is not null or whitespace.
18 | ///
19 | /// The request to add the parameter to.
20 | /// The name of the parameter.
21 | /// The value of the parameter.
22 | /// The request, for chaining.
23 | public static RestRequest AddParameterIfNotNullOrWhitespace(this RestRequest request, string name, string value)
24 | {
25 | // Call the other method if appropriate.
26 | if (false == string.IsNullOrWhiteSpace(value))
27 | request.AddParameter(name, value);
28 |
29 | // Return the request for chaining.
30 | return request;
31 | }
32 | }
33 | }
34 |
--------------------------------------------------------------------------------
/MFaaP.MFWSClient/Searching/PropertyValues/TextPropertyValueSearchCondition.cs:
--------------------------------------------------------------------------------
1 | using System;
2 |
3 | namespace MFaaP.MFWSClient
4 | {
5 | ///
6 | /// Represents a search condition that restricts by a text property value.
7 | ///
8 |
9 | public class TextPropertyValueSearchCondition
10 | : PropertyValueSearchConditionBase
11 | {
12 | ///
13 | /// Creates a , searching for the value supplied.
14 | ///
15 | /// The Id of the property def to search by.
16 | /// The value to search by.
17 | /// The operator to use (defaults to Equals if not provided).
18 | /// Whether to invert the search operator (defaults to false if not provided).
19 | public TextPropertyValueSearchCondition(
20 | int propertyDefId,
21 | string value,
22 | SearchConditionOperators searchConditionOperator = SearchConditionOperators.Equals,
23 | bool invertOperator = false)
24 | : base(propertyDefId, value, searchConditionOperator, invertOperator)
25 | {
26 | }
27 | }
28 | }
--------------------------------------------------------------------------------
/MFaaP.MFWSClient/Searching/PropertyValues/BooleanPropertyValueSearchCondition.cs:
--------------------------------------------------------------------------------
1 | using System;
2 |
3 | namespace MFaaP.MFWSClient
4 | {
5 | ///
6 | /// Represents a search condition that restricts by a boolean property value.
7 | ///
8 |
9 | public class BooleanPropertyValueSearchCondition
10 | : PropertyValueSearchConditionBase
11 | {
12 | ///
13 | /// Creates a , searching for the value supplied.
14 | ///
15 | /// The Id of the property def to search by.
16 | /// The value to search by.
17 | /// The operator to use (defaults to Equals if not provided).
18 | /// Whether to invert the search operator (defaults to false if not provided).
19 | public BooleanPropertyValueSearchCondition(
20 | int propertyDefId,
21 | bool value,
22 | SearchConditionOperators searchConditionOperator = SearchConditionOperators.Equals,
23 | bool invertOperator = false)
24 | : base(propertyDefId, value, searchConditionOperator, invertOperator)
25 | {
26 | }
27 |
28 | ///
29 | public override string EncodedValue => this.Value ? "true" : "false";
30 | }
31 | }
--------------------------------------------------------------------------------
/MFaaP.MFWSClient/Searching/PropertyValues/DatePropertyValueSearchCondition.cs:
--------------------------------------------------------------------------------
1 | using System;
2 |
3 | namespace MFaaP.MFWSClient
4 | {
5 | ///
6 | /// Represents a search condition that restricts by a Date property value.
7 | ///
8 |
9 | public class DatePropertyValueSearchCondition
10 | : PropertyValueSearchConditionBase
11 | {
12 | ///
13 | /// Creates a , searching for the value supplied.
14 | ///
15 | /// The Id of the property def to search by.
16 | /// The value to search by.
17 | /// The operator to use (defaults to Equals if not provided).
18 | /// Whether to invert the search operator (defaults to false if not provided).
19 | public DatePropertyValueSearchCondition(
20 | int propertyDefId,
21 | DateTime value,
22 | SearchConditionOperators searchConditionOperator = SearchConditionOperators.Equals,
23 | bool invertOperator = false)
24 | : base(propertyDefId, value, searchConditionOperator, invertOperator)
25 | {
26 | }
27 |
28 | ///
29 | public override string EncodedValue => this.Value.ToString("yyyy-MM-dd");
30 | }
31 | }
--------------------------------------------------------------------------------
/MFaaP.MFWSClient/Searching/SearchConditionOperators.cs:
--------------------------------------------------------------------------------
1 | using System;
2 |
3 | namespace MFaaP.MFWSClient
4 | {
5 | ///
6 | /// An enumeration of the supported operators (from http://www.m-files.com/mfws/syntax.html#sect:search-encoding).
7 | ///
8 |
9 | public enum SearchConditionOperators
10 | {
11 | ///
12 | /// The default operator; note this throws an exception if used.
13 | ///
14 | Unknown = 0,
15 |
16 | ///
17 | /// Equals. ("=")
18 | ///
19 | Equals = 1,
20 |
21 | ///
22 | /// Less than. ("<<=")
23 | ///
24 | LessThan = 2,
25 |
26 | ///
27 | /// Less than or equal to. (";<=")
28 | ///
29 | LessThanOrEqual = 3,
30 |
31 | ///
32 | /// Greater than. (">>=")
33 | ///
34 | GreaterThan = 4,
35 |
36 | ///
37 | /// Greater than or equal to. (">=")
38 | ///
39 | GreaterThanOrEqual = 5,
40 |
41 | ///
42 | /// Matches (including wildcards). ("**=")
43 | ///
44 | MatchesWildcard = 6,
45 |
46 | ///
47 | /// Contains. ("*=")
48 | ///
49 | Contains = 7,
50 |
51 | ///
52 | /// Starts with. ("^=")
53 | ///
54 | StartsWith = 8
55 | }
56 | }
--------------------------------------------------------------------------------
/MFaaP.MFWSClient/MFWSClient.cs:
--------------------------------------------------------------------------------
1 | using RestSharp;
2 | using System;
3 |
4 | namespace MFaaP.MFWSClient
5 | {
6 | public partial class MFWSClient
7 | : MFWSClientBase
8 | {
9 |
10 | ///
11 | /// Creates an MFWSClient pointing at the MFWA site.
12 | ///
13 | /// The base url of the MFWA (web access) site; note that this should be of the form
14 | /// "http://localhost", not of the form "http://localhost/REST".
15 | public MFWSClient(string baseUrl)
16 | : base(baseUrl)
17 | {
18 | }
19 |
20 | ///
21 | /// Creates an MFWSClient pointing at the MFWA site.
22 | ///
23 | /// The base url of the MFWA (web access) site; note that this should be of the form
24 | /// "http://localhost", not of the form "http://localhost/REST".
25 | public MFWSClient(Uri baseUrl)
26 | : base(baseUrl)
27 | {
28 | }
29 |
30 | ///
31 | /// Creates an MFWSClient pointing at the MFWA site.
32 | ///
33 | /// The to use for HTTP requests.
34 | protected MFWSClient(IRestClient restClient)
35 | : base(restClient)
36 | {
37 | }
38 | }
39 |
40 | }
41 |
--------------------------------------------------------------------------------
/MFaaP.MFWSClient/ExtensionMethods/DictionaryExtensionMethods.cs:
--------------------------------------------------------------------------------
1 | using System;
2 | using System.Collections.Generic;
3 |
4 | namespace MFaaP.MFWSClient.ExtensionMethods
5 | {
6 | ///
7 | /// Dictionary extension methods.
8 | ///
9 | public static class DictionaryExtensionMethods
10 | {
11 | ///
12 | /// Gets the value from the dictionary, if the key exists.
13 | /// If the key does not exist then returns a default value.
14 | ///
15 | /// The type of the keys in the dictionary.
16 | /// The type of the values in the dictionary.
17 | /// The dictionary.
18 | /// The key to look up.
19 | /// The default value to return if the key cannot be found.
20 | /// The value in the dictionary with the supplied key, or a default value if not found.
21 | public static TB GetValueOrDefault(this Dictionary dictionary, TA key, TB defaultValue = default)
22 | {
23 | // Sanity.
24 | if(null == dictionary)
25 | throw new ArgumentNullException(nameof(dictionary));
26 |
27 | // If it has it then return it, otherwise default.
28 | return dictionary.ContainsKey(key)
29 | ? dictionary[key]
30 | : defaultValue;
31 | }
32 | }
33 | }
34 |
--------------------------------------------------------------------------------
/MFaaP.MFWSClient/Searching/PropertyValues/LookupPropertyValueSearchCondition.cs:
--------------------------------------------------------------------------------
1 | using System;
2 |
3 | namespace MFaaP.MFWSClient
4 | {
5 | ///
6 | /// Represents a search condition that restricts by a lookup property value.
7 | ///
8 |
9 | public class LookupPropertyValueSearchCondition
10 | : PropertyValueSearchConditionBase
11 | {
12 | ///
13 | /// Creates a , searching for the lookup value supplied.
14 | ///
15 | /// The Id of the property def to search by.
16 | /// The Ids of the lookup value to search by.
17 | /// The operator to use (defaults to Equals if not provided).
18 | /// Whether to invert the search operator (defaults to false if not provided).
19 | /// If multiple lookup Ids are present, then objects matching any one of the Ids will be returned (e.g. "class is one of 1, 2, 3, or 4").
20 | public LookupPropertyValueSearchCondition(
21 | int propertyDefId,
22 | SearchConditionOperators searchConditionOperator = SearchConditionOperators.Equals,
23 | bool invertOperator = false,
24 | params int[] lookupIds)
25 | : base(propertyDefId, string.Join(",", lookupIds), searchConditionOperator, invertOperator)
26 | {
27 | }
28 | }
29 | }
--------------------------------------------------------------------------------
/MFaaP.MFWSClient/Searching/PropertyValues/MultiSelectLookupPropertyValueSearchCondition.cs:
--------------------------------------------------------------------------------
1 | using System;
2 |
3 | namespace MFaaP.MFWSClient
4 | {
5 | ///
6 | /// Represents a search condition that restricts by a multi-select lookup property value.
7 | ///
8 |
9 | public class MultiSelectLookupPropertyValueSearchCondition
10 | : PropertyValueSearchConditionBase
11 | {
12 | ///
13 | /// Creates a , searching for the lookup value supplied.
14 | ///
15 | /// The Id of the property def to search by.
16 | /// The Ids of the lookup value to search by.
17 | /// The operator to use (defaults to Equals if not provided).
18 | /// Whether to invert the search operator (defaults to false if not provided).
19 | /// If multiple lookup Ids are present, then objects matching any one of the Ids will be returned (e.g. "class is one of 1, 2, 3, or 4").
20 | public MultiSelectLookupPropertyValueSearchCondition(
21 | int propertyDefId,
22 | SearchConditionOperators searchConditionOperator = SearchConditionOperators.Equals,
23 | bool invertOperator = false,
24 | params int[] lookupIds)
25 | : base(propertyDefId, string.Join(",", lookupIds), searchConditionOperator, invertOperator)
26 | {
27 | }
28 | }
29 | }
--------------------------------------------------------------------------------
/MFaaP.MFWSClient.Tests/Properties/AssemblyInfo.cs:
--------------------------------------------------------------------------------
1 | using System.Reflection;
2 | using System.Runtime.CompilerServices;
3 | using System.Runtime.InteropServices;
4 |
5 | // General Information about an assembly is controlled through the following
6 | // set of attributes. Change these attribute values to modify the information
7 | // associated with an assembly.
8 | [assembly: AssemblyTitle("MFaaP.MFWSClient.Tests")]
9 | [assembly: AssemblyDescription("")]
10 | [assembly: AssemblyConfiguration("")]
11 | [assembly: AssemblyCompany("")]
12 | [assembly: AssemblyProduct("MFaaP.MFWSClient.Tests")]
13 | [assembly: AssemblyCopyright("Copyright © 2017")]
14 | [assembly: AssemblyTrademark("")]
15 | [assembly: AssemblyCulture("")]
16 |
17 | // Setting ComVisible to false makes the types in this assembly not visible
18 | // to COM components. If you need to access a type in this assembly from
19 | // COM, set the ComVisible attribute to true on that type.
20 | [assembly: ComVisible(false)]
21 |
22 | // The following GUID is for the ID of the typelib if this project is exposed to COM
23 | [assembly: Guid("166eb0f7-92dc-4fe0-935f-55afe17146d9")]
24 |
25 | // Version information for an assembly consists of the following four values:
26 | //
27 | // Major Version
28 | // Minor Version
29 | // Build Number
30 | // Revision
31 | //
32 | // You can specify all the values or you can default the Build and Revision Numbers
33 | // by using the '*' as shown below:
34 | // [assembly: AssemblyVersion("1.0.*")]
35 | [assembly: AssemblyVersion("1.0.0.0")]
36 | [assembly: AssemblyFileVersion("1.0.0.0")]
37 |
--------------------------------------------------------------------------------
/MFaaP.MFWSClient/Searching/PropertyValues/PropertyValueSearchConditionBase.cs:
--------------------------------------------------------------------------------
1 | using System;
2 |
3 | namespace MFaaP.MFWSClient
4 | {
5 | ///
6 | /// Represents a search condition that restricts by a property value.
7 | ///
8 |
9 | public abstract class PropertyValueSearchConditionBase
10 | : SearchConditionBase
11 | {
12 | ///
13 | /// The Id of the property definition to search by.
14 | ///
15 | public int PropertyDefId { get; set; }
16 |
17 | ///
18 | /// Creates a , searching for the value supplied.
19 | ///
20 | /// The Id of the property def to search by.
21 | /// The value to search by.
22 | /// The operator to use (defaults to Equals if not provided).
23 | /// Whether to invert the search operator (defaults to false if not provided).
24 | protected PropertyValueSearchConditionBase(
25 | int propertyDefId,
26 | T value,
27 | SearchConditionOperators searchConditionOperator = SearchConditionOperators.Equals,
28 | bool invertOperator = false)
29 | : base("p", searchConditionOperator, value, invertOperator)
30 | {
31 | this.PropertyDefId = propertyDefId;
32 | }
33 |
34 | ///
35 | public override string Expression => $"{base.Expression}{this.PropertyDefId}";
36 |
37 | ///
38 | public override string EncodedValue => this.Value.ToString();
39 | }
40 | }
--------------------------------------------------------------------------------
/MFaaP.MFWSClient.Tests/MFWSVaultClassGroupOperations.cs:
--------------------------------------------------------------------------------
1 | using System.Collections.Generic;
2 | using System.Threading.Tasks;
3 | using Microsoft.VisualStudio.TestTools.UnitTesting;
4 | using RestSharp;
5 |
6 | namespace MFaaP.MFWSClient.Tests
7 | {
8 | [TestClass]
9 | public class MFWSVaultClassGroupOperations
10 | {
11 |
12 | #region GetClassGroups
13 |
14 | ///
15 | /// Ensures that a call to
16 | /// requests the correct resource address with the correct method.
17 | ///
18 | [TestMethod]
19 | public async Task GetClassGroupsAsync()
20 | {
21 | // Create our test runner.
22 | var runner = new RestApiTestRunner>(Method.Get, "/REST/structure/classes.aspx?objtype=0&bygroup=true");
23 |
24 | // Execute.
25 | await runner.MFWSClient.ClassGroupOperations.GetClassGroupsAsync(0);
26 |
27 | // Verify.
28 | runner.Verify();
29 | }
30 |
31 | ///
32 | /// Ensures that a call to
33 | /// requests the correct resource address with the correct method.
34 | ///
35 | [TestMethod]
36 | public void GetClassGroups()
37 | {
38 | // Create our test runner.
39 | var runner = new RestApiTestRunner>(Method.Get, "/REST/structure/classes.aspx?objtype=0&bygroup=true");
40 |
41 | // Execute.
42 | runner.MFWSClient.ClassGroupOperations.GetClassGroups(0);
43 |
44 | // Verify.
45 | runner.Verify();
46 | }
47 |
48 | #endregion
49 | }
50 | }
51 |
--------------------------------------------------------------------------------
/MFaaP.MFWSClient/MFaaP.MFWSClient.csproj:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 | netstandard2.0
5 | MIT
6 |
7 |
8 |
9 | 9.0
10 |
11 |
12 |
13 |
14 |
15 |
16 |
17 |
18 |
19 |
20 |
21 |
22 |
23 |
24 | M-Files Corporation
25 | Sample .NET wrapper for the M-Files Web Service. Not designed for production use.
26 | Copyright (c) 2020 onwards, M-Files Corporation
27 |
28 |
29 |
30 | MFaaP.MFWSClient
31 | false
32 | M-Files REST-API MFWS wrapper
33 | https://github.com/M-Files/Libraries.MFWSClient
34 | https://github.com/M-Files/Libraries.MFWSClient
35 |
36 |
37 |
38 |
39 |
40 |
41 |
42 |
43 |
--------------------------------------------------------------------------------
/MFaaP.MFWSClient.Tests/Setup.cs:
--------------------------------------------------------------------------------
1 | using Microsoft.VisualStudio.TestTools.UnitTesting;
2 | using System;
3 | using System.Collections.Generic;
4 | using System.IO;
5 | using System.Linq;
6 | using System.Text;
7 | using System.Threading.Tasks;
8 |
9 | namespace MFaaP.MFWSClient.Tests
10 | {
11 | [TestClass]
12 | public class SetupAssemblyInitializer
13 | {
14 | [AssemblyInitialize]
15 | public static void AssemblyInit(TestContext context)
16 | {
17 | var assemblies = new List()
18 | {
19 | "System.Text.Json",
20 | "System.Runtime.CompilerServices.Unsafe"
21 | };
22 | var assemlbyResolveHelper = new AssemblyResolveHelper(assemblies);
23 | AppDomain.CurrentDomain.AssemblyResolve += assemlbyResolveHelper.OnAssemlbyResolve;
24 | }
25 | }
26 | public class AssemblyResolveHelper
27 | {
28 | public AssemblyResolveHelper(string assemblyName)
29 | {
30 | _assemlbyNames.Add(assemblyName);
31 | }
32 |
33 | public AssemblyResolveHelper(List assemblyNames)
34 | {
35 | if (assemblyNames != null)
36 | {
37 | _assemlbyNames = assemblyNames;
38 | }
39 | }
40 |
41 | private List _assemlbyNames = new List();
42 |
43 | public System.Reflection.Assembly OnAssemlbyResolve(object sender, ResolveEventArgs args)
44 | {
45 | var assemblyName = _assemlbyNames.FirstOrDefault(i => i == args.Name.Split(',')[0]);
46 | if (assemblyName != null)
47 | {
48 | string assemlbyPath = Path.Combine(Path.GetDirectoryName(System.Reflection.Assembly.GetExecutingAssembly().Location), assemblyName + ".dll");
49 |
50 | if (File.Exists(assemlbyPath))
51 | {
52 | return System.Reflection.Assembly.LoadFrom(assemlbyPath);
53 | }
54 | }
55 | return null;
56 | }
57 | }
58 | }
59 |
--------------------------------------------------------------------------------
/MFaaP.MFWSClient/ExtensionMethods/IEnumerableExtensionMethods.cs:
--------------------------------------------------------------------------------
1 | using System;
2 | using System.Collections.Generic;
3 | using System.Text;
4 |
5 | namespace MFaaP.MFWSClient.ExtensionMethods
6 | {
7 | ///
8 | /// Extension methods for IEnumerable{T}.
9 | ///
10 | // ReSharper disable once InconsistentNaming
11 | public static class IEnumerableExtensionMethods
12 | {
13 | ///
14 | /// Creates a string from the sequence by concatenating the result
15 | /// of the specified string selector function for each element.
16 | ///
17 | public static string ToConcatenatedString(this IEnumerable source,
18 | Func stringSelector)
19 | {
20 | return source.ToConcatenatedString(stringSelector, String.Empty);
21 | }
22 |
23 | ///
24 | /// Creates a string from the sequence by concatenating the result
25 | /// of the specified string selector function for each element.
26 | ///
27 | /// A function describing how to select a string from the source.
28 | /// The string which separates each concatenated item.
29 | /// The source collection to enumerate.
30 | public static string ToConcatenatedString(this IEnumerable source,
31 | Func stringSelector,
32 | string separator)
33 | {
34 | var b = new StringBuilder();
35 | bool needsSeparator = false; // don't use for first item
36 |
37 | foreach (var item in source)
38 | {
39 | if (needsSeparator)
40 | b.Append(separator);
41 |
42 | b.Append(stringSelector(item));
43 | needsSeparator = true;
44 | }
45 |
46 | return b.ToString();
47 | }
48 | }
49 | }
50 |
--------------------------------------------------------------------------------
/MFaaP.MFWSClient/Searching/ISearchCondition.cs:
--------------------------------------------------------------------------------
1 | namespace MFaaP.MFWSClient
2 | {
3 | ///
4 | /// Represents a single search condition.
5 | ///
6 | /// See http://www.m-files.com/mfws/syntax.html#sect:search-encoding .
7 | public interface ISearchCondition
8 | {
9 | ///
10 | /// The expression to use in the search.
11 | ///
12 | /// See http://www.m-files.com/mfws/syntax.html#sect:search-encoding .
13 | string Expression { get; }
14 |
15 | ///
16 | /// Whether to invert the .
17 | ///
18 | /// See http://www.m-files.com/mfws/syntax.html#sect:search-encoding .
19 | bool InvertOperator { get; set; }
20 |
21 | ///
22 | /// The operator to use in the search.
23 | ///
24 | /// See http://www.m-files.com/mfws/syntax.html#sect:search-encoding .
25 | SearchConditionOperators Operator { get; set; }
26 |
27 | ///
28 | /// Gets the encoded value as a string for use in the search.
29 | ///
30 | /// See http://www.m-files.com/mfws/syntax.html#sect:search-encoding .
31 | string EncodedValue { get; }
32 | }
33 |
34 | ///
35 | /// Represents a single search condition.
36 | /// Used alongside to provide a strongly-typed value.
37 | ///
38 | /// See http://www.m-files.com/mfws/syntax.html#sect:search-encoding .
39 | public interface ISearchCondition
40 | : ISearchCondition
41 | {
42 | ///
43 | /// The (raw) value to use in the search.
44 | ///
45 | /// See http://www.m-files.com/mfws/syntax.html#sect:search-encoding .
46 | T Value { get; set; }
47 | }
48 | }
49 |
--------------------------------------------------------------------------------
/MFaaP.MFWSClient/OAuth2/OAuth2TokenResponse.cs:
--------------------------------------------------------------------------------
1 | using System.Text.Json.Serialization;
2 |
3 | namespace MFaaP.MFWSClient.OAuth2
4 | {
5 | ///
6 | /// Represents a set of tokens returned from an OAuth 2.0 token endpoint.
7 | /// The should be "Bearer", and the can be used
8 | /// to access resources. Should this expire, a subsequent request can be made using the
9 | /// to retrieve an updated token.
10 | ///
11 | public class OAuth2TokenResponse
12 | {
13 | ///
14 | /// The token type. Should be "Bearer".
15 | ///
16 | [JsonPropertyName("token_type")]
17 | public string TokenType { get; set; }
18 |
19 | ///
20 | /// Any scopes defined for the tokens.
21 | ///
22 | [JsonPropertyName("scope")]
23 | public string Scope { get; set; }
24 |
25 | ///
26 | /// How long - since the original request - the access token is valid for.
27 | ///
28 | [JsonPropertyName("expires_in")]
29 | public long ExpiresIn { get; set; }
30 |
31 | //[JsonPropertyName("ext_expires_in")]
32 | //public long ExtExpiresIn { get; set; }
33 |
34 | ///
35 | /// When the access token expires.
36 | ///
37 | [JsonPropertyName("expires_on")]
38 | public long ExpiresOn { get; set; }
39 |
40 | ///
41 | /// When token becomes valid.
42 | ///
43 |
44 | [JsonPropertyName("not_before")]
45 | public long NotBefore { get; set; }
46 |
47 | ///
48 | /// The resource this token is for.
49 | ///
50 | [JsonPropertyName("resource")]
51 | public string Resource { get; set; }
52 |
53 | ///
54 | /// The access token.
55 | ///
56 | [JsonPropertyName("access_token")]
57 | public string AccessToken { get; set; }
58 |
59 | ///
60 | /// The refresh token.
61 | ///
62 | [JsonPropertyName("refresh_token")]
63 | public string RefreshToken { get; set; }
64 |
65 | ///
66 | /// The ID token.
67 | ///
68 | [JsonPropertyName("id_token")]
69 | public string IdToken { get; set; }
70 |
71 | }
72 | }
73 |
--------------------------------------------------------------------------------
/MFaaP.MFWSClient/Searching/SearchConditionBase.cs:
--------------------------------------------------------------------------------
1 | using System;
2 |
3 | namespace MFaaP.MFWSClient
4 | {
5 | ///
6 | /// A base implementation of .
7 | ///
8 |
9 | public abstract class SearchConditionBase
10 | : ISearchCondition
11 | {
12 | ///
13 | public virtual string Expression { get; }
14 |
15 | ///
16 | public bool InvertOperator { get; set; }
17 |
18 | ///
19 | public SearchConditionOperators Operator { get; set; }
20 |
21 | ///
22 | public abstract string EncodedValue { get; }
23 |
24 | ///
25 | /// Creates a with the supplied
26 | /// basic information.
27 | ///
28 | /// The expression (querystring parameter name).
29 | /// The operator (e.g. equals) to use for the match.
30 | /// Whether to invert the operator (true) or not (false).
31 | protected SearchConditionBase(
32 | string expression,
33 | SearchConditionOperators op,
34 | bool invertOperator = false)
35 | {
36 | this.Expression = expression;
37 | this.InvertOperator = invertOperator;
38 | this.Operator = op;
39 | }
40 | }
41 |
42 | ///
43 | /// A base implementation of .
44 | ///
45 |
46 | public abstract class SearchConditionBase
47 | : SearchConditionBase, ISearchCondition
48 | {
49 | ///
50 | public T Value { get; set; }
51 |
52 | ///
53 | /// Creates a with the supplied
54 | /// basic information.
55 | ///
56 | /// The expression (querystring parameter name).
57 | /// The operator (e.g. equals) to use for the match.
58 | /// The typed value to match.
59 | /// Whether to invert the operator (true) or not (false).
60 | protected SearchConditionBase(
61 | string expression,
62 | SearchConditionOperators op,
63 | T value,
64 | bool invertOperator = false)
65 | : base(expression, op, invertOperator)
66 | {
67 | this.Value = value;
68 | }
69 | }
70 | }
--------------------------------------------------------------------------------
/MFaaP.MFWSClient.sln:
--------------------------------------------------------------------------------
1 |
2 | Microsoft Visual Studio Solution File, Format Version 12.00
3 | # Visual Studio Version 17
4 | VisualStudioVersion = 17.8.34004.107
5 | MinimumVisualStudioVersion = 10.0.40219.1
6 | Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "MFaaP.MFWSClient", "MFaaP.MFWSClient\MFaaP.MFWSClient.csproj", "{B28D0C6A-C87B-461D-BD12-D627E9F653FC}"
7 | EndProject
8 | Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "MFaaP.MFWSClient.Tests", "MFaaP.MFWSClient.Tests\MFaaP.MFWSClient.Tests.csproj", "{166EB0F7-92DC-4FE0-935F-55AFE17146D9}"
9 | EndProject
10 | Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "Documentation", "Documentation", "{832FAFF8-5A7F-4CE7-8459-1F5D8312F044}"
11 | ProjectSection(SolutionItems) = preProject
12 | CODE_OF_CONDUCT.md = CODE_OF_CONDUCT.md
13 | CONTRIBUTING.md = CONTRIBUTING.md
14 | LICENSE.md = LICENSE.md
15 | Readme.md = Readme.md
16 | EndProjectSection
17 | EndProject
18 | Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "Actions", "Actions", "{4F12170C-831C-4FDC-9396-9275D12980B3}"
19 | ProjectSection(SolutionItems) = preProject
20 | .github\workflows\dotnet-core.yml = .github\workflows\dotnet-core.yml
21 | .github\workflows\manual.yml = .github\workflows\manual.yml
22 | EndProjectSection
23 | EndProject
24 | Global
25 | GlobalSection(SolutionConfigurationPlatforms) = preSolution
26 | Debug|Any CPU = Debug|Any CPU
27 | Release|Any CPU = Release|Any CPU
28 | EndGlobalSection
29 | GlobalSection(ProjectConfigurationPlatforms) = postSolution
30 | {B28D0C6A-C87B-461D-BD12-D627E9F653FC}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
31 | {B28D0C6A-C87B-461D-BD12-D627E9F653FC}.Debug|Any CPU.Build.0 = Debug|Any CPU
32 | {B28D0C6A-C87B-461D-BD12-D627E9F653FC}.Release|Any CPU.ActiveCfg = Release|Any CPU
33 | {B28D0C6A-C87B-461D-BD12-D627E9F653FC}.Release|Any CPU.Build.0 = Release|Any CPU
34 | {166EB0F7-92DC-4FE0-935F-55AFE17146D9}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
35 | {166EB0F7-92DC-4FE0-935F-55AFE17146D9}.Debug|Any CPU.Build.0 = Debug|Any CPU
36 | {166EB0F7-92DC-4FE0-935F-55AFE17146D9}.Release|Any CPU.ActiveCfg = Release|Any CPU
37 | {166EB0F7-92DC-4FE0-935F-55AFE17146D9}.Release|Any CPU.Build.0 = Release|Any CPU
38 | EndGlobalSection
39 | GlobalSection(SolutionProperties) = preSolution
40 | HideSolutionNode = FALSE
41 | EndGlobalSection
42 | GlobalSection(ExtensibilityGlobals) = postSolution
43 | SolutionGuid = {7C9E686E-6319-490D-8980-D4EF3B0C6326}
44 | EndGlobalSection
45 | EndGlobal
46 |
--------------------------------------------------------------------------------
/MFaaP.MFWSClient/MFWSVaultClassGroupOperations.cs:
--------------------------------------------------------------------------------
1 | using System;
2 | using System.Collections.Generic;
3 | using System.Linq;
4 | using System.Threading;
5 | using System.Threading.Tasks;
6 | using RestSharp;
7 |
8 | namespace MFaaP.MFWSClient
9 | {
10 | ///
11 | /// Methods to create and modify objects.
12 | ///
13 | public class MFWSVaultClassGroupOperations
14 | : MFWSVaultOperationsBase
15 | {
16 | ///
17 | /// Creates a new object.
18 | ///
19 | /// The client to interact with the server.
20 | internal MFWSVaultClassGroupOperations(MFWSClientBase client)
21 | : base(client)
22 | {
23 | }
24 |
25 |
26 |
27 | ///
28 | /// Gets a list of all class groups with classes in the vault for a given object type.
29 | ///
30 | /// The type of the object.
31 | /// A cancellation token for the request.
32 | /// All classes in the vault for the supplied object type.
33 | /// This may be filtered by the user's permissions.
34 | public async Task> GetClassGroupsAsync(int objectTypeId, CancellationToken token = default)
35 | {
36 | // Create the request.
37 | var request = new RestRequest($"/REST/structure/classes.aspx?objtype={objectTypeId}&bygroup=true");
38 |
39 | // Make the request and get the response.
40 | var response = await this.MFWSClient.Get>(request, token)
41 | .ConfigureAwait(false);
42 |
43 | // Return the data.
44 | return response.Data;
45 | }
46 |
47 | ///
48 | /// Gets a list of all classes in the vault for a given object type.
49 | ///
50 | /// The type of the object.
51 | /// A cancellation token for the request.
52 | /// All classes in the vault for the supplied object type.
53 | /// This may be filtered by the user's permissions.
54 | public List GetClassGroups(int objectTypeId, CancellationToken token = default)
55 | {
56 | // Execute the async method.
57 | return this.GetClassGroupsAsync(objectTypeId, token)
58 | .ConfigureAwait(false)
59 | .GetAwaiter()
60 | .GetResult();
61 | }
62 |
63 | }
64 |
65 | }
66 |
--------------------------------------------------------------------------------
/MFaaP.MFWSClient/MFWSClient.Session.cs:
--------------------------------------------------------------------------------
1 | using System;
2 | using System.Threading;
3 | using System.Threading.Tasks;
4 | using RestSharp;
5 |
6 | namespace MFaaP.MFWSClient
7 | {
8 | public partial class MFWSClient
9 | {
10 | ///
11 | /// Retrieves information about the vault for the current session, if available.
12 | ///
13 | /// A cancellation token for the request.
14 | /// An awaitable task.
15 | public async Task GetCurrentSessionVaultAsync(CancellationToken token = default)
16 | {
17 | // Build up the request.
18 | var request = new RestRequest("/REST/session/vault");
19 |
20 | // Execute the request.
21 | var response = await this.Get(request, token)
22 | .ConfigureAwait(false);
23 |
24 | // Return the content.
25 | return response?.Data;
26 | }
27 |
28 | ///
29 | /// Retrieves information about the vault for the current session, if available.
30 | ///
31 | /// A cancellation token for the request.
32 | /// The vault returned by the request.
33 | public Vault GetCurrentSessionVault(CancellationToken token = default)
34 | {
35 | // Execute the async method.
36 | return this.GetCurrentSessionVaultAsync(token)
37 | .ConfigureAwait(false)
38 | .GetAwaiter()
39 | .GetResult();
40 | }
41 |
42 | ///
43 | /// Retrieves information about the current session, if available.
44 | ///
45 | /// A cancellation token for the request.
46 | /// An awaitable task.
47 | public async Task GetCurrentSessionInfoAsync(CancellationToken token = default)
48 | {
49 | // Build up the request.
50 | var request = new RestRequest("/REST/session");
51 |
52 | // Execute the request.
53 | var response = await this.Get(request, token)
54 | .ConfigureAwait(false);
55 |
56 | // Return the content.
57 | return response?.Data;
58 | }
59 |
60 | ///
61 | /// Retrieves information about the current session, if available.
62 | ///
63 | /// A cancellation token for the request.
64 | /// The vault returned by the request.
65 | public SessionInfo GetCurrentSessionInfo(CancellationToken token = default)
66 | {
67 | // Execute the async method.
68 | return this.GetCurrentSessionInfoAsync(token)
69 | .ConfigureAwait(false)
70 | .GetAwaiter()
71 | .GetResult();
72 | }
73 | }
74 | }
75 |
--------------------------------------------------------------------------------
/.github/workflows/dotnet-core.yml:
--------------------------------------------------------------------------------
1 | name: Publish to nuget
2 |
3 | on:
4 | push:
5 | branches: [ release, prerelease ]
6 |
7 | jobs:
8 | build:
9 | timeout-minutes: 15
10 | runs-on: 'windows-2022'
11 |
12 | steps:
13 | - uses: actions/checkout@v3
14 | with:
15 | fetch-depth: 0
16 |
17 | - name: versionSuffix
18 | shell: pwsh
19 | run: |
20 | $versionSuffix = '${{ github.event.inputs.versionSuffix }}'
21 | If([string]::IsNullOrEmpty($versionSuffix))
22 | {
23 | $versionSuffix = '${{ github.ref_name }}'
24 | }
25 | $versionSuffix = '-' + ($versionSuffix -replace '[^a-zA-Z0-9]','-')
26 |
27 | If($versionSuffix -eq '-release')
28 | {
29 | $versionSuffix = ''
30 | }
31 | If(('-', '-master', '-main') -eq $versionSuffix)
32 | {
33 | $versionSuffix = '-prerelease'
34 | }
35 | echo "versionSuffix=$versionSuffix" | Out-File -FilePath $Env:GITHUB_ENV -Append
36 |
37 | - name: Get version number
38 | shell: pwsh
39 | run: |
40 | If([string]::IsNullOrEmpty({{ env.versionSuffix }}))
41 | {
42 | # No suffix. Fine.
43 | $versionNumber = Get-Date -Format "yy.M.${{ github.run_number }}"
44 | }
45 | else
46 | {
47 | # Suffix; ensure we add .0 in version number to stop them appearing above full releases.
48 | $versionNumber = Get-Date -Format "yy.M.0.${{ github.run_number }}"
49 | }
50 | echo "versionNumber=$versionNumber${{ env.versionSuffix }}" | Out-File -FilePath $Env:GITHUB_ENV -Encoding utf-8 -Append
51 |
52 | - name: Setup MSBuild path
53 | uses: microsoft/setup-msbuild@v1.1
54 | with:
55 | vs-version: '[17.0,)'
56 |
57 | - name: Setup dot net
58 | uses: actions/setup-dotnet@v3
59 | with:
60 | dotnet-version: |
61 | 3.1.x
62 | 5.0.x
63 | 6.0.x
64 | 7.0.x
65 | 8.0.x
66 |
67 | - name: Build with dotnet
68 | run: dotnet build ./MFaaP.MFWSClient/MFaaP.MFWSClient.csproj --configuration Release -p:Version=${{ env.versionNumber }}
69 |
70 | - name: Create nuget package
71 | run: dotnet pack ./MFaaP.MFWSClient/MFaaP.MFWSClient.csproj --configuration Release -p:Version=${{ env.versionNumber }}
72 |
73 | - name: Push with dotnet
74 | run: dotnet nuget push ./MFaaP.MFWSClient/bin/Release/MFaaP.MFWSClient.${{ env.versionNumber }}.nupkg --api-key ${{ secrets.NUGET_API_KEY }} --source https://api.nuget.org/v3/index.json --skip-duplicate
--------------------------------------------------------------------------------
/.gitattributes:
--------------------------------------------------------------------------------
1 | ###############################################################################
2 | # Set default behavior to automatically normalize line endings.
3 | ###############################################################################
4 | * text=auto
5 |
6 | ###############################################################################
7 | # Set default behavior for command prompt diff.
8 | #
9 | # This is need for earlier builds of msysgit that does not have it on by
10 | # default for csharp files.
11 | # Note: This is only used by command line
12 | ###############################################################################
13 | #*.cs diff=csharp
14 |
15 | ###############################################################################
16 | # Set the merge driver for project and solution files
17 | #
18 | # Merging from the command prompt will add diff markers to the files if there
19 | # are conflicts (Merging from VS is not affected by the settings below, in VS
20 | # the diff markers are never inserted). Diff markers may cause the following
21 | # file extensions to fail to load in VS. An alternative would be to treat
22 | # these files as binary and thus will always conflict and require user
23 | # intervention with every merge. To do so, just uncomment the entries below
24 | ###############################################################################
25 | #*.sln merge=binary
26 | #*.csproj merge=binary
27 | #*.vbproj merge=binary
28 | #*.vcxproj merge=binary
29 | #*.vcproj merge=binary
30 | #*.dbproj merge=binary
31 | #*.fsproj merge=binary
32 | #*.lsproj merge=binary
33 | #*.wixproj merge=binary
34 | #*.modelproj merge=binary
35 | #*.sqlproj merge=binary
36 | #*.wwaproj merge=binary
37 |
38 | ###############################################################################
39 | # behavior for image files
40 | #
41 | # image files are treated as binary by default.
42 | ###############################################################################
43 | #*.jpg binary
44 | #*.png binary
45 | #*.gif binary
46 |
47 | ###############################################################################
48 | # diff behavior for common document formats
49 | #
50 | # Convert binary document formats to text before diffing them. This feature
51 | # is only available from the command line. Turn it on by uncommenting the
52 | # entries below.
53 | ###############################################################################
54 | #*.doc diff=astextplain
55 | #*.DOC diff=astextplain
56 | #*.docx diff=astextplain
57 | #*.DOCX diff=astextplain
58 | #*.dot diff=astextplain
59 | #*.DOT diff=astextplain
60 | #*.pdf diff=astextplain
61 | #*.PDF diff=astextplain
62 | #*.rtf diff=astextplain
63 | #*.RTF diff=astextplain
64 |
--------------------------------------------------------------------------------
/.github/workflows/manual.yml:
--------------------------------------------------------------------------------
1 | name: Manual
2 |
3 | on:
4 | workflow_dispatch:
5 | # Inputs the workflow accepts.
6 | inputs:
7 | versionSuffix:
8 | description: 'Version suffix'
9 | required: false
10 | default: ''
11 |
12 | jobs:
13 | build:
14 | timeout-minutes: 15
15 | runs-on: 'windows-2022'
16 |
17 | steps:
18 | - uses: actions/checkout@v3
19 | with:
20 | fetch-depth: 0
21 |
22 | - name: versionSuffix
23 | shell: pwsh
24 | run: |
25 | $versionSuffix = '${{ github.event.inputs.versionSuffix }}'
26 | If([string]::IsNullOrEmpty($versionSuffix))
27 | {
28 | $versionSuffix = '${{ github.ref_name }}'
29 | }
30 | $versionSuffix = '-' + ($versionSuffix -replace '[^a-zA-Z0-9]','-')
31 |
32 | If($versionSuffix -eq '-release')
33 | {
34 | $versionSuffix = ''
35 | }
36 | If(('-', '-master', '-main') -eq $versionSuffix)
37 | {
38 | $versionSuffix = '-prerelease'
39 | }
40 | echo "versionSuffix=$versionSuffix" | Out-File -FilePath $Env:GITHUB_ENV -Append
41 |
42 | - name: Get version number
43 | shell: pwsh
44 | run: |
45 | If([string]::IsNullOrEmpty({{ env.versionSuffix }}))
46 | {
47 | # No suffix. Fine.
48 | $versionNumber = Get-Date -Format "yy.M.${{ github.run_number }}"
49 | }
50 | else
51 | {
52 | # Suffix; ensure we add .0 in version number to stop them appearing above full releases.
53 | $versionNumber = Get-Date -Format "yy.M.0.${{ github.run_number }}"
54 | }
55 | echo "versionNumber=$versionNumber${{ env.versionSuffix }}" | Out-File -FilePath $Env:GITHUB_ENV -Encoding utf-8 -Append
56 |
57 | - name: Setup MSBuild path
58 | uses: microsoft/setup-msbuild@v1.1
59 | with:
60 | vs-version: '[17.0,)'
61 |
62 | - name: Setup dot net
63 | uses: actions/setup-dotnet@v3
64 | with:
65 | dotnet-version: |
66 | 3.1.x
67 | 5.0.x
68 | 6.0.x
69 | 7.0.x
70 | 8.0.x
71 |
72 | - name: Build with dotnet
73 | run: dotnet build ./MFaaP.MFWSClient/MFaaP.MFWSClient.csproj --configuration Release -p:Version=${{ env.versionNumber }}
74 |
75 | - name: Create nuget package
76 | run: dotnet pack ./MFaaP.MFWSClient/MFaaP.MFWSClient.csproj --configuration Release -p:Version=${{ env.versionNumber }}
77 |
78 | - name: Push with dotnet
79 | run: dotnet nuget push ./MFaaP.MFWSClient/bin/Release/MFaaP.MFWSClient.${{ env.versionNumber }}.nupkg --api-key ${{ secrets.NUGET_API_KEY }} --source https://api.nuget.org/v3/index.json --skip-duplicate
--------------------------------------------------------------------------------
/CODE_OF_CONDUCT.md:
--------------------------------------------------------------------------------
1 | # M-Files Web Service .NET Wrapper client
2 |
3 | ## Our Pledge
4 |
5 | In the interest of fostering an open and welcoming environment, we as
6 | contributors and maintainers pledge to making participation in our project and
7 | our community a harassment-free experience for everyone, regardless of age, body
8 | size, disability, ethnicity, gender identity and expression, level of experience,
9 | nationality, personal appearance, race, religion, or sexual identity and
10 | orientation.
11 |
12 | ## Our Standards
13 |
14 | Examples of behavior that contributes to creating a positive environment
15 | include:
16 |
17 | * Using welcoming and inclusive language
18 | * Being respectful of differing viewpoints and experiences
19 | * Gracefully accepting constructive criticism
20 | * Focusing on what is best for the community
21 | * Showing empathy towards other community members
22 |
23 | Examples of unacceptable behavior by participants include:
24 |
25 | * The use of sexualized language or imagery and unwelcome sexual attention or
26 | advances
27 | * Trolling, insulting/derogatory comments, and personal or political attacks
28 | * Public or private harassment
29 | * Publishing others' private information, such as a physical or electronic
30 | address, without explicit permission
31 | * Other conduct which could reasonably be considered inappropriate in a
32 | professional setting
33 |
34 | ## Our Responsibilities
35 |
36 | Project maintainers are responsible for clarifying the standards of acceptable
37 | behavior and are expected to take appropriate and fair corrective action in
38 | response to any instances of unacceptable behavior.
39 |
40 | Project maintainers have the right and responsibility to remove, edit, or
41 | reject comments, commits, code, wiki edits, issues, and other contributions
42 | that are not aligned to this Code of Conduct, or to ban temporarily or
43 | permanently any contributor for other behaviors that they deem inappropriate,
44 | threatening, offensive, or harmful.
45 |
46 | ## Scope
47 |
48 | This Code of Conduct applies both within project spaces and in public spaces
49 | when an individual is representing the project or its community. Examples of
50 | representing a project or community include using an official project e-mail
51 | address, posting via an official social media account, or acting as an appointed
52 | representative at an online or offline event. Representation of a project may be
53 | further defined and clarified by project maintainers.
54 |
55 | ## Enforcement
56 |
57 | Instances of abusive, harassing, or otherwise unacceptable behavior may be
58 | reported by contacting the project team at
59 | [devsupport@m-files.com](mailto:devsupport@m-files.com). All complaints will be
60 | reviewed and investigated and will result in a response that
61 | is deemed necessary and appropriate to the circumstances. The project team is
62 | obligated to maintain confidentiality with regard to the reporter of an incident.
63 | Further details of specific enforcement policies may be posted separately.
64 |
65 | Project maintainers who do not follow or enforce the Code of Conduct in good
66 | faith may face temporary or permanent repercussions as determined by other
67 | members of the project's leadership.
68 |
69 | ## Attribution
70 |
71 | This Code of Conduct is adapted from the [Contributor Covenant][homepage], version 1.4,
72 | available at [http://contributor-covenant.org/version/1/4][version]
73 |
74 | [homepage]: http://contributor-covenant.org
75 | [version]: http://contributor-covenant.org/version/1/4/
76 |
--------------------------------------------------------------------------------
/MFaaP.MFWSClient/Searching/ValueListSearchCondition.cs:
--------------------------------------------------------------------------------
1 | using System;
2 | using System.Linq;
3 |
4 | namespace MFaaP.MFWSClient
5 | {
6 | ///
7 | /// Represents a search condition that restricts by a property reference to a value list item (any property).
8 | ///
9 | /// Can be used for both value lists and object types.
10 |
11 | public class ValueListSearchCondition
12 | : SearchConditionBase
13 | {
14 | ///
15 | /// The Id of the value list to search by.
16 | ///
17 | public int ValueListId { get; set; }
18 |
19 | ///
20 | /// The (M-Files internal) Ids of value list items that must be
21 | /// referenced by an object for it to match.
22 | ///
23 | /// Only used if is .
24 | public int[] InternalIds { get; set; }
25 |
26 | ///
27 | /// The external Ids of value list items that must be
28 | /// referenced by an object for it to match.
29 | ///
30 | /// Only used if is .
31 | public string[] ExternalIds { get; set; }
32 |
33 | ///
34 | /// Gets the type of search condition (internal ID or external ID) which is being used.
35 | ///
36 | public ValueListItemIdType Type { get; set; }
37 | = ValueListItemIdType.Id;
38 |
39 | ///
40 | /// Creates a , searching for the value supplied.
41 | ///
42 | /// The Id of the property def to search by.
43 | /// The Ids of the value list items to match.
44 | public ValueListSearchCondition(
45 | int valueListId,
46 | params int[] internalValueListItemIds)
47 | : base("vl", SearchConditionOperators.Equals, false)
48 | {
49 | this.ValueListId = valueListId;
50 | this.InternalIds = internalValueListItemIds;
51 | this.Type = ValueListItemIdType.Id;
52 | }
53 |
54 | ///
55 | /// Creates a , searching for the value supplied.
56 | ///
57 | /// The Id of the property def to search by.
58 | /// The Ids of the value list items to match.
59 | public ValueListSearchCondition(
60 | int valueListId,
61 | params string[] externalValueListItemIds)
62 | : base("vl", SearchConditionOperators.Equals, false)
63 | {
64 | this.ValueListId = valueListId;
65 | this.ExternalIds = externalValueListItemIds;
66 | this.Type = ValueListItemIdType.ExternalId;
67 | }
68 |
69 | ///
70 | public override string Expression => $"{base.Expression}{this.ValueListId}";
71 |
72 | ///
73 | public override string EncodedValue =>
74 | this.Type == ValueListItemIdType.Id
75 | ? String.Join(",", this.InternalIds)
76 | : String.Join(",", this.ExternalIds.Select( i => "e" + i))
77 | ;
78 | }
79 |
80 | ///
81 | /// The type of Id to match against.
82 | ///
83 | public enum ValueListItemIdType
84 | {
85 | ///
86 | /// Notes that the matched value is the internal M-Files Id of the value list item.
87 | ///
88 | Id = 0,
89 |
90 | ///
91 | /// Notes that the matched value is the external Id of the value list item (when using external object types or value lists).
92 | ///
93 | ExternalId = 1
94 | }
95 | }
96 |
--------------------------------------------------------------------------------
/MFaaP.MFWSClient/ExtensionMethods/UriBuilderExtensionMethods.cs:
--------------------------------------------------------------------------------
1 | using System;
2 | using System.Collections.Generic;
3 | using System.Collections.Specialized;
4 | using System.IO;
5 | using System.Linq;
6 | using System.Text;
7 | using System.Web;
8 |
9 | //using RestSharp.Extensions.MonoHttp;
10 |
11 | namespace MFaaP.MFWSClient.ExtensionMethods
12 | {
13 | ///
14 | /// URI builder extension methods.
15 | ///
16 | public static class UriBuilderExtensionMethods
17 | {
18 | ///
19 | /// Sets the specified query parameter key-value pair of the URI only if the value is not null and not whitespace.
20 | /// If the key already exists, the value is overwritten.
21 | ///
22 | public static UriBuilder SetQueryParamIfNotNullOrWhitespace(this UriBuilder uri, string key, string value)
23 | {
24 | // Call the other method if appropriate.
25 | if (false == string.IsNullOrWhiteSpace(value))
26 | uri.SetQueryParam(key, value);
27 |
28 | // Return the builder for chaining.
29 | return uri;
30 | }
31 |
32 | ///
33 | /// Sets the specified query parameter key-value pair of the URI.
34 | /// If the key already exists, the value is overwritten.
35 | ///
36 | public static UriBuilder SetQueryParam(this UriBuilder uri, string key, string value)
37 | {
38 | var collection = uri.ParseQuery();
39 |
40 | // add (or replace existing) key-value pair
41 | collection.Set(key, value);
42 |
43 | string query = collection
44 | .AsKeyValuePairs()
45 | .ToConcatenatedString(pair =>
46 | pair.Key == null
47 | ? pair.Value
48 | : pair.Key + "=" + pair.Value, "&");
49 |
50 | uri.Query = query;
51 |
52 | return uri;
53 | }
54 |
55 | ///
56 | /// Gets the query string key-value pairs of the URI.
57 | /// Note that the one of the keys may be null ("?123") and
58 | /// that one of the keys may be an empty string ("?=123").
59 | ///
60 | public static IEnumerable> GetQueryParams(
61 | this UriBuilder uri)
62 | {
63 | return uri.ParseQuery().AsKeyValuePairs();
64 | }
65 |
66 | ///
67 | /// Gets the query string key-value pairs of the URI.
68 | /// Note that the one of the keys may be null ("?123") and
69 | /// that one of the keys may be an empty string ("?=123").
70 | ///
71 | public static Dictionary GetQueryParamsDictionary(
72 | this UriBuilder uri)
73 | {
74 | return uri.ParseQuery().AsDictionary();
75 | }
76 |
77 | ///
78 | /// Converts the legacy NameValueCollection into a strongly-typed KeyValuePair sequence.
79 | ///
80 | static IEnumerable> AsKeyValuePairs(this NameValueCollection collection)
81 | {
82 | foreach (string key in collection.AllKeys)
83 | {
84 | yield return new KeyValuePair(key, collection.Get(key));
85 | }
86 | }
87 |
88 | ///
89 | /// Converts the legacy NameValueCollection into a strongly-typed KeyValuePair sequence.
90 | ///
91 | static Dictionary AsDictionary(this NameValueCollection collection)
92 | {
93 | var dictionary = new Dictionary();
94 | foreach (string key in collection.AllKeys)
95 | {
96 | dictionary.Add(key, collection.Get(key));
97 | }
98 | return dictionary;
99 | }
100 |
101 | ///
102 | /// Parses the query string of the URI into a NameValueCollection.
103 | ///
104 | static NameValueCollection ParseQuery(this UriBuilder uri)
105 | {
106 | return HttpUtility.ParseQueryString(uri.Query);
107 | }
108 | }
109 | }
110 |
--------------------------------------------------------------------------------
/MFaaP.MFWSClient/Searching/PropertyValues/NumericPropertyValueSearchCondition.cs:
--------------------------------------------------------------------------------
1 | using System;
2 |
3 | namespace MFaaP.MFWSClient
4 | {
5 | ///
6 | /// Represents a search condition that restricts by a text property value.
7 | ///
8 |
9 | public class NumericPropertyValueSearchCondition
10 | : TextPropertyValueSearchCondition
11 | {
12 | ///
13 | /// Creates a , searching for the value supplied.
14 | ///
15 | /// The Id of the property def to search by.
16 | /// The value to search by.
17 | /// The operator to use (defaults to Equals if not provided).
18 | /// Whether to invert the search operator (defaults to false if not provided).
19 | public NumericPropertyValueSearchCondition(
20 | int propertyDefId,
21 | int value,
22 | SearchConditionOperators searchConditionOperator = SearchConditionOperators.Equals,
23 | bool invertOperator = false)
24 | : base(propertyDefId, value.ToString(), searchConditionOperator, invertOperator)
25 | {
26 | }
27 |
28 | ///
29 | /// Creates a , searching for the value supplied.
30 | ///
31 | /// The Id of the property def to search by.
32 | /// The value to search by.
33 | /// The operator to use (defaults to Equals if not provided).
34 | /// Whether to invert the search operator (defaults to false if not provided).
35 | public NumericPropertyValueSearchCondition(
36 | int propertyDefId,
37 | long value,
38 | SearchConditionOperators searchConditionOperator = SearchConditionOperators.Equals,
39 | bool invertOperator = false)
40 | : base(propertyDefId, value.ToString(), searchConditionOperator, invertOperator)
41 | {
42 | }
43 |
44 | ///
45 | /// Creates a , searching for the value supplied.
46 | ///
47 | /// The Id of the property def to search by.
48 | /// The value to search by.
49 | /// The operator to use (defaults to Equals if not provided).
50 | /// Whether to invert the search operator (defaults to false if not provided).
51 | public NumericPropertyValueSearchCondition(
52 | int propertyDefId,
53 | double value,
54 | SearchConditionOperators searchConditionOperator = SearchConditionOperators.Equals,
55 | bool invertOperator = false)
56 | : base(propertyDefId, value.ToString(), searchConditionOperator, invertOperator)
57 | {
58 | }
59 |
60 | ///
61 | /// Creates a , searching for the value supplied.
62 | ///
63 | /// The Id of the property def to search by.
64 | /// The value to search by.
65 | /// The operator to use (defaults to Equals if not provided).
66 | /// Whether to invert the search operator (defaults to false if not provided).
67 | public NumericPropertyValueSearchCondition(
68 | int propertyDefId,
69 | float value,
70 | SearchConditionOperators searchConditionOperator = SearchConditionOperators.Equals,
71 | bool invertOperator = false)
72 | : base(propertyDefId, value.ToString(), searchConditionOperator, invertOperator)
73 | {
74 | }
75 | }
76 | }
--------------------------------------------------------------------------------
/MFaaP.MFWSClient/ExtensionMethods/IEnumerablePluginInfoConfigurationExtensionMethods.cs:
--------------------------------------------------------------------------------
1 | using System;
2 | using System.Collections.Generic;
3 | using System.Linq;
4 | using MFaaP.MFWSClient;
5 | using MFaaP.MFWSClient.OAuth2;
6 |
7 | namespace MFaaP.MFWSClient
8 | {
9 | ///
10 | /// Helper methods for working with authentication plugin configuration data.
11 | ///
12 | // ReSharper disable once InconsistentNaming
13 | public static class IEnumerablePluginInfoConfigurationExtensionMethods
14 | {
15 | ///
16 | /// The for OAuth 2.0 configurations.
17 | ///
18 | private const string OAuth2PluginConfigurationProtocol = "OAuth 2.0";
19 |
20 | ///
21 | /// Returns true if the plugin configuration data contains an OAuth 2.0 authentication configuration.
22 | ///
23 | /// The list of defined authentication plugins defined.
24 | /// True if OAuth is found, false otherwise.
25 | /// Use to obtain the configuration efficiently.
26 | public static bool SupportsOAuth2(this IEnumerable pluginInfoConfiguration)
27 | {
28 | // Sanity.
29 | if (null == pluginInfoConfiguration)
30 | throw new ArgumentNullException(nameof(pluginInfoConfiguration));
31 |
32 | // Use the other overload.
33 | OAuth2Configuration configuration;
34 | return pluginInfoConfiguration.TryGetOAuth2Configuration(out configuration);
35 | }
36 |
37 | ///
38 | /// Obtains the plugin configuration for the OAuth 2.0 authentication process.
39 | ///
40 | /// The list of defined authentication plugins defined.
41 | /// The configuration, if found, or null otherwise.
42 | /// True if OAuth is found, false otherwise.
43 | public static bool TryGetOAuth2Configuration(this IEnumerable pluginInfoConfiguration, out OAuth2Configuration oAuth2Configuration)
44 | {
45 | // Is OAuth 2.0 specified?
46 | oAuth2Configuration = pluginInfoConfiguration?
47 | .Where(pic => pic.Protocol == IEnumerablePluginInfoConfigurationExtensionMethods.OAuth2PluginConfigurationProtocol)?
48 | .Select(pic => OAuth2Configuration.ParseFrom(pic))?
49 | .FirstOrDefault();
50 |
51 | // Did we get a value?
52 | return oAuth2Configuration != null;
53 |
54 | }
55 |
56 | ///
57 | /// Obtains the plugin configuration for the OAuth 2.0 authentication process.
58 | ///
59 | /// The list of defined authentication plugins defined.
60 | /// The configuration, if found, or null otherwise.
61 | /// True if OAuth is found, false otherwise.
62 | public static bool TryGetOAuth2Configuration(this IEnumerable pluginInfoConfiguration, string configurationName, out OAuth2Configuration oAuth2Configuration)
63 | {
64 | // Is OAuth 2.0 specified?
65 | oAuth2Configuration = pluginInfoConfiguration?
66 | .Where(pic => pic.Protocol == IEnumerablePluginInfoConfigurationExtensionMethods.OAuth2PluginConfigurationProtocol && pic.Name == configurationName)?
67 | .Select(pic => OAuth2Configuration.ParseFrom(pic))?
68 | .FirstOrDefault();
69 |
70 | // Did we get a value?
71 | return oAuth2Configuration != null;
72 |
73 | }
74 | }
75 | }
76 |
--------------------------------------------------------------------------------
/MFaaP.MFWSClient.Tests/MFWSClient.cs:
--------------------------------------------------------------------------------
1 | using System;
2 | using System.Collections.Generic;
3 | using System.Threading;
4 | using System.Threading.Tasks;
5 | using Microsoft.VisualStudio.TestTools.UnitTesting;
6 | using Moq;
7 | using RestSharp;
8 |
9 | namespace MFaaP.MFWSClient.Tests
10 | {
11 | [TestClass]
12 | public partial class MFWSClient
13 | {
14 |
15 | ///
16 | /// Ensures that a call to
17 | /// requests the correct resource address with the correct method.
18 | ///
19 | [TestMethod]
20 | public async Task GetMetadataStructureIDsByAliasesAsync()
21 | {
22 | // Create our test runner.
23 | var runner = new RestApiTestRunner(Method.Post, "/REST/structure/metadatastructure/itemidbyalias.aspx");
24 |
25 | // Set up the expected body.
26 | var body = new VaultStructureAliasRequest();
27 | runner.SetExpectedRequestBody(body);
28 |
29 | // Execute.
30 | await runner.MFWSClient.GetMetadataStructureIDsByAliasesAsync(body);
31 |
32 | // Verify.
33 | runner.Verify();
34 | }
35 |
36 | ///
37 | /// Ensures that a call to
38 | /// requests the correct resource address with the correct method.
39 | ///
40 | [TestMethod]
41 | public void GetMetadataStructureIDsByAliases()
42 | {
43 | // Create our test runner.
44 | var runner = new RestApiTestRunner(Method.Post, "/REST/structure/metadatastructure/itemidbyalias.aspx");
45 |
46 | // Set up the expected body.
47 | var body = new VaultStructureAliasRequest();
48 | runner.SetExpectedRequestBody(body);
49 |
50 | // Execute.
51 | runner.MFWSClient.GetMetadataStructureIDsByAliases(body);
52 |
53 | // Verify.
54 | runner.Verify();
55 | }
56 |
57 | [TestMethod]
58 | public void InstantiationAlsoPopulatesPropertiesAndFields()
59 | {
60 | var client = new MFaaP.MFWSClient.MFWSClient("http://localhost");
61 | Assert.IsNotNull(client.AutomaticMetadataOperations);
62 | Assert.IsNotNull(client.ClassGroupOperations);
63 | Assert.IsNotNull(client.ClassOperations);
64 | Assert.IsNotNull(client.ExtensionAuthenticationOperations);
65 | Assert.IsNotNull(client.ExtensionMethodOperations);
66 | Assert.IsNotNull(client.ExternalObjectOperations);
67 | Assert.IsNotNull(client.ObjectFileOperations);
68 | Assert.IsNotNull(client.ObjectOperations);
69 | Assert.IsNotNull(client.ObjectPropertyOperations);
70 | Assert.IsNotNull(client.ObjectSearchOperations);
71 | Assert.IsNotNull(client.ObjectTypeOperations);
72 | Assert.IsNotNull(client.PropertyDefOperations);
73 | Assert.IsNotNull(client.ValueListItemOperations);
74 | Assert.IsNotNull(client.ValueListOperations);
75 | Assert.IsNotNull(client.WorkflowOperations);
76 | Assert.IsNotNull(client.CookieContainer);
77 | }
78 |
79 | ///
80 | /// Creates a MFWSClient using the supplied mock request client.
81 | ///
82 | /// The mocked rest client.
83 | ///
84 | public static MFaaP.MFWSClient.MFWSClient GetMFWSClient(Moq.Mock restClientMoq)
85 | {
86 | // Sanity.
87 | if(null == restClientMoq)
88 | throw new ArgumentNullException(nameof(restClientMoq));
89 |
90 | // Ensure that we have a default parameter collection, if it's not been mocked already.
91 | if (null == restClientMoq.Object.DefaultParameters)
92 | {
93 | var defaultParameters = new DefaultParameters(new ReadOnlyRestClientOptions(new RestClientOptions()));
94 | restClientMoq
95 | .SetupGet(p => p.DefaultParameters)
96 | .Returns(defaultParameters);
97 | }
98 |
99 | // Return our proxy.
100 | return new MFWSClientProxy(restClientMoq.Object);
101 | }
102 |
103 | ///
104 | /// A proxy around
105 | /// to allow provision of a mocked .
106 | ///
107 | private class MFWSClientProxy
108 | : MFaaP.MFWSClient.MFWSClient
109 | {
110 | ///
111 | public MFWSClientProxy(IRestClient restClient)
112 | : base(restClient)
113 | {
114 | }
115 | protected override void OnAfterExecuteRequest(RestResponse e)
116 | {
117 | // If the response is null it's because we were testing for the wrong endpoint details.
118 | if (null == e)
119 | {
120 | Assert.Fail("Incorrect HTTP request (either method, endpoint address, or return type was invalid).");
121 | return;
122 | }
123 |
124 | // Base implementation.
125 | base.OnAfterExecuteRequest(e);
126 | }
127 |
128 | protected override IRestClient GenerateClientForSingleSignOn()
129 | {
130 | // We use the current mock client
131 | return RestClient;
132 | }
133 | }
134 | }
135 | }
136 |
--------------------------------------------------------------------------------
/MFaaP.MFWSClient.Tests/MFWSVaultObjectTypeOperations.cs:
--------------------------------------------------------------------------------
1 | using System.Collections.Generic;
2 | using System.Threading.Tasks;
3 | using Microsoft.VisualStudio.TestTools.UnitTesting;
4 | using Newtonsoft.Json.Linq;
5 | using RestSharp;
6 |
7 | namespace MFaaP.MFWSClient.Tests
8 | {
9 | [TestClass]
10 | public class MFWSVaultObjectTypeOperations
11 | {
12 |
13 | #region Object type alias to ID resolution
14 |
15 | ///
16 | /// Ensures that a call to
17 | /// requests the correct resource address with the correct method.
18 | ///
19 | [TestMethod]
20 | public async Task GetObjectTypeIDByAliasAsync()
21 | {
22 | // Create our test runner.
23 | var runner = new RestApiTestRunner>(Method.Post, "/REST/structure/objecttypes/itemidbyalias.aspx");
24 |
25 | // Set up the expected body.
26 | var body = new JArray { "hello world" };
27 | runner.SetExpectedRequestBody(body);
28 |
29 | // Execute.
30 | await runner.MFWSClient.ObjectTypeOperations.GetObjectTypeIDByAliasAsync("hello world");
31 |
32 | // Verify.
33 | runner.Verify();
34 | }
35 |
36 | ///
37 | /// Ensures that a call to
38 | /// requests the correct resource address with the correct method.
39 | ///
40 | [TestMethod]
41 | public async Task GetObjectTypeIDsByAliasesAsync()
42 | {
43 | // Create our test runner.
44 | var runner = new RestApiTestRunner>(Method.Post, "/REST/structure/objecttypes/itemidbyalias.aspx");
45 |
46 | // Set up the expected body.
47 | var body = new JArray { "hello", "world", "third option" };
48 | runner.SetExpectedRequestBody(body);
49 |
50 | // Execute.
51 | await runner.MFWSClient.ObjectTypeOperations.GetObjectTypeIDsByAliasesAsync(aliases: new string[] { "hello", "world", "third option" });
52 |
53 | // Verify.
54 | runner.Verify();
55 | }
56 |
57 | ///
58 | /// Ensures that a call to
59 | /// requests the correct resource address with the correct method.
60 | ///
61 | [TestMethod]
62 | public void GetObjectTypeIDsByAliases()
63 | {
64 | // Create our test runner.
65 | var runner = new RestApiTestRunner>(Method.Post, "/REST/structure/objecttypes/itemidbyalias.aspx");
66 |
67 | // Set up the expected body.
68 | var body = new JArray { "hello", "world", "third option" };
69 | runner.SetExpectedRequestBody(body);
70 |
71 | // Execute.
72 | runner.MFWSClient.ObjectTypeOperations.GetObjectTypeIDsByAliases(aliases: new string[] { "hello", "world", "third option" });
73 |
74 | // Verify.
75 | runner.Verify();
76 | }
77 |
78 | ///
79 | /// Ensures that a call to
80 | /// requests the correct resource address with the correct method.
81 | ///
82 | [TestMethod]
83 | public void GetObjectTypeIDByAlias()
84 | {
85 | // Create our test runner.
86 | var runner = new RestApiTestRunner>(Method.Post, "/REST/structure/objecttypes/itemidbyalias.aspx");
87 |
88 | // Set up the expected body.
89 | var body = new JArray { "hello world" };
90 | runner.SetExpectedRequestBody(body);
91 |
92 | // Execute.
93 | runner.MFWSClient.ObjectTypeOperations.GetObjectTypeIDByAlias("hello world");
94 |
95 | // Verify.
96 | runner.Verify();
97 | }
98 |
99 | #endregion
100 |
101 | #region GetObjectTypes
102 |
103 | ///
104 | /// Ensures that a call to
105 | /// requests the correct resource address using the correct method.
106 | ///
107 | [TestMethod]
108 | public async Task GetObjectTypesAsync()
109 | {
110 | // Create our test runner.
111 | var runner = new RestApiTestRunner>(Method.Get, "/REST/structure/objecttypes.aspx");
112 |
113 | // Execute.
114 | await runner.MFWSClient.ObjectTypeOperations.GetObjectTypesAsync();
115 |
116 | // Verify.
117 | runner.Verify();
118 | }
119 |
120 | ///
121 | /// Ensures that a call to
122 | /// requests the correct resource address using the correct method.
123 | ///
124 | [TestMethod]
125 | public void GetObjectTypes()
126 | {
127 | // Create our test runner.
128 | var runner = new RestApiTestRunner>(Method.Get, "/REST/structure/objecttypes.aspx");
129 |
130 | // Execute.
131 | runner.MFWSClient.ObjectTypeOperations.GetObjectTypes();
132 |
133 | // Verify.
134 | runner.Verify();
135 | }
136 |
137 | #endregion
138 |
139 | }
140 | }
141 |
--------------------------------------------------------------------------------
/MFaaP.MFWSClient.Tests/MFWSVaultValueListOperations.cs:
--------------------------------------------------------------------------------
1 | using System.Collections.Generic;
2 | using System.Threading;
3 | using System.Threading.Tasks;
4 | using Microsoft.VisualStudio.TestTools.UnitTesting;
5 | using Moq;
6 | using Newtonsoft.Json.Linq;
7 | using RestSharp;
8 |
9 | namespace MFaaP.MFWSClient.Tests
10 | {
11 | [TestClass]
12 | public class MFWSVaultValueListOperations
13 | {
14 |
15 | #region Value list alias to ID resolution
16 |
17 | ///
18 | /// Ensures that a call to
19 | /// requests the correct resource address with the correct method.
20 | ///
21 | [TestMethod]
22 | public async Task GetValueListIDByAliasAsync()
23 | {
24 | // Create our test runner.
25 | var runner = new RestApiTestRunner>(Method.Post, "/REST/structure/valuelists/itemidbyalias.aspx");
26 |
27 | // Set up the expected body.
28 | var body = new JArray { "hello world" };
29 | runner.SetExpectedRequestBody(body);
30 |
31 | // Execute.
32 | await runner.MFWSClient.ValueListOperations.GetValueListIDByAliasAsync("hello world");
33 |
34 | // Verify.
35 | runner.Verify();
36 | }
37 |
38 | ///
39 | /// Ensures that a call to
40 | /// requests the correct resource address with the correct method.
41 | ///
42 | [TestMethod]
43 | public async Task GetValueListIDsByAliasesAsync()
44 | {
45 | // Create our test runner.
46 | var runner = new RestApiTestRunner>(Method.Post, "/REST/structure/valuelists/itemidbyalias.aspx");
47 |
48 | // Set up the expected body.
49 | var body = new JArray { "hello", "world", "third option" };
50 | runner.SetExpectedRequestBody(body);
51 |
52 | // Execute.
53 | await runner.MFWSClient.ValueListOperations.GetValueListIDsByAliasesAsync(aliases: new string[] { "hello", "world", "third option" });
54 |
55 | // Verify.
56 | runner.Verify();
57 | }
58 |
59 | ///
60 | /// Ensures that a call to
61 | /// requests the correct resource address with the correct method.
62 | ///
63 | [TestMethod]
64 | public void GetValueListIDsByAliases()
65 | {
66 | // Create our test runner.
67 | var runner = new RestApiTestRunner>(Method.Post, "/REST/structure/valuelists/itemidbyalias.aspx");
68 |
69 | // Set up the expected body.
70 | var body = new JArray { "hello", "world", "third option" };
71 | runner.SetExpectedRequestBody(body);
72 |
73 | // Execute.
74 | runner.MFWSClient.ValueListOperations.GetValueListIDsByAliases(aliases: new string[] { "hello", "world", "third option" });
75 |
76 | // Verify.
77 | runner.Verify();
78 | }
79 |
80 | ///
81 | /// Ensures that a call to
82 | /// requests the correct resource address with the correct method.
83 | ///
84 | [TestMethod]
85 | public void GetValueListIDByAlias()
86 | {
87 | // Create our test runner.
88 | var runner = new RestApiTestRunner>(Method.Post, "/REST/structure/valuelists/itemidbyalias.aspx");
89 |
90 | // Set up the expected body.
91 | var body = new JArray { "hello world" };
92 | runner.SetExpectedRequestBody(body);
93 |
94 | // Execute.
95 | runner.MFWSClient.ValueListOperations.GetValueListIDByAlias("hello world");
96 |
97 | // Verify.
98 | runner.Verify();
99 | }
100 |
101 | #endregion
102 |
103 | #region GetValueLists
104 |
105 | ///
106 | /// Ensures that a call to
107 | /// requests the correct resource address and method.
108 | ///
109 | [TestMethod]
110 | public async Task GetValueListsAsync()
111 | {
112 | // Create our test runner.
113 | var runner = new RestApiTestRunner>(Method.Get, "/REST/valuelists.aspx");
114 |
115 | // Set up the expected body.
116 |
117 | // Execute.
118 | await runner.MFWSClient.ValueListOperations.GetValueListsAsync();
119 |
120 | // Verify.
121 | runner.Verify();
122 | }
123 |
124 | ///
125 | /// Ensures that a call to
126 | /// requests the correct resource address and method.
127 | ///
128 | [TestMethod]
129 | public void GetValueLists()
130 | {
131 | // Create our test runner.
132 | var runner = new RestApiTestRunner>(Method.Get, "/REST/valuelists.aspx");
133 |
134 | // Set up the expected body.
135 |
136 | // Execute.
137 | runner.MFWSClient.ValueListOperations.GetValueLists();
138 |
139 | // Verify.
140 | runner.Verify();
141 | }
142 |
143 | #endregion
144 |
145 | }
146 | }
147 |
--------------------------------------------------------------------------------
/MFaaP.MFWSClient/MFWSVaultValueListOperations.cs:
--------------------------------------------------------------------------------
1 | using System;
2 | using System.Collections.Generic;
3 | using System.Linq;
4 | using System.Threading;
5 | using System.Threading.Tasks;
6 | using RestSharp;
7 |
8 | namespace MFaaP.MFWSClient
9 | {
10 | ///
11 | /// The VaultValueListOperations class represents the available value list operations.
12 | ///
13 | /// ref: https://www.m-files.com/api/documentation/latest/index.html#MFilesAPI~VaultValueListOperations.html
14 | public class MFWSVaultValueListOperations
15 | : MFWSVaultOperationsBase
16 | {
17 | ///
18 | internal MFWSVaultValueListOperations(MFWSClientBase client)
19 | : base(client)
20 | {
21 | }
22 |
23 | #region Value list alias to ID resolution
24 |
25 | ///
26 | /// Retrieves the ID for a value list with a given alias in the vault.
27 | ///
28 | /// The alias for the value list.
29 | /// A cancellation token for the request.
30 | /// An awaitable task for the request.
31 | /// Returns -1 if the alias cannot be resolved (e.g. no value lists have the alias, or more than one does).
32 | /// Only available in M-Files 12.0.6768.0 upwards.
33 | public async Task GetValueListIDByAliasAsync(string alias, CancellationToken token = default)
34 | {
35 | // Use the other overload.
36 | var output = await this.GetValueListIDsByAliasesAsync(token, aliases: new string[] { alias });
37 | return output?.Count == 1
38 | ? output[0]
39 | : -1;
40 | }
41 |
42 | ///
43 | /// Retrieves the IDs for value lists with given aliases in the vault.
44 | ///
45 | /// The aliases for the value list.
46 | /// A cancellation token for the request.
47 | /// An awaitable task for the request.
48 | /// Returns -1 if the alias cannot be resolved (e.g. no value lists have the alias, or more than one does).
49 | /// Only available in M-Files 12.0.6768.0 upwards.
50 | public async Task> GetValueListIDsByAliasesAsync(CancellationToken token = default, params string[] aliases)
51 | {
52 | // Sanity.
53 | if (null == aliases)
54 | throw new ArgumentNullException(nameof(aliases));
55 | if (0 == aliases.Length)
56 | return new List();
57 |
58 | // Create the request.
59 | var request = new RestRequest($"/REST/structure/valuelists/itemidbyalias.aspx");
60 |
61 | // Assign the body.
62 | request.AddJsonBody(aliases);
63 |
64 | // Make the request and get the response.
65 | var response = await this.MFWSClient.Post>(request, token)
66 | .ConfigureAwait(false);
67 |
68 | // Return the data.
69 | return aliases.Select(alias => response.Data.ContainsKey(alias) ? response.Data[alias] : -1).ToList();
70 | }
71 |
72 | ///
73 | /// Retrieves the IDs for value lists with given aliases in the vault.
74 | ///
75 | /// The aliases for the value list.
76 | /// A cancellation token for the request.
77 | /// An awaitable task for the request.
78 | /// Returns -1 if the alias cannot be resolved (e.g. no value lists have the alias, or more than one does).
79 | public List GetValueListIDsByAliases(CancellationToken token = default, params string[] aliases)
80 | {
81 | // Execute the async method.
82 | return this.GetValueListIDsByAliasesAsync(token, aliases)
83 | .ConfigureAwait(false)
84 | .GetAwaiter()
85 | .GetResult();
86 | }
87 |
88 | ///
89 | /// Retrieves the ID for a value list with a given alias in the vault.
90 | ///
91 | /// The alias for the value list.
92 | /// A cancellation token for the request.
93 | /// An awaitable task for the request.
94 | /// Returns -1 if the alias cannot be resolved (e.g. no value lists have the alias, or more than one does).
95 | /// Only available in M-Files 12.0.6768.0 upwards.
96 | public int GetValueListIDByAlias(string alias, CancellationToken token = default)
97 | {
98 | // Use the other overload.
99 | var output = this.GetValueListIDsByAliases(token, aliases: new string[] { alias });
100 | return output?.Count == 1
101 | ? output[0]
102 | : -1;
103 | }
104 |
105 | #endregion
106 |
107 | ///
108 | /// Gets a list of all value lists in the vault.
109 | ///
110 | /// A cancellation token for the request.
111 | /// All value lists in the vault.
112 | /// This may be filtered by the user's permissions.
113 | public async Task> GetValueListsAsync(CancellationToken token = default)
114 | {
115 | // Create the request.
116 | var request = new RestRequest($"/REST/valuelists.aspx");
117 |
118 | // Make the request and get the response.
119 | var response = await this.MFWSClient.Get>(request, token)
120 | .ConfigureAwait(false);
121 |
122 | // Return the data.
123 | return response.Data;
124 | }
125 |
126 | ///
127 | /// Gets a list of all value lists in the vault.
128 | ///
129 | /// A cancellation token for the request.
130 | /// All value lists in the vault.
131 | /// This may be filtered by the user's permissions.
132 | public List GetValueLists(CancellationToken token = default)
133 | {
134 | // Execute the async method.
135 | return this.GetValueListsAsync(token)
136 | .ConfigureAwait(false)
137 | .GetAwaiter()
138 | .GetResult();
139 | }
140 | }
141 | }
142 |
--------------------------------------------------------------------------------
/MFaaP.MFWSClient/MFWSVaultObjectTypeOperations.cs:
--------------------------------------------------------------------------------
1 | using System;
2 | using System.Collections.Generic;
3 | using System.Linq;
4 | using System.Threading;
5 | using System.Threading.Tasks;
6 | using RestSharp;
7 |
8 | namespace MFaaP.MFWSClient
9 | {
10 | ///
11 | /// A group of methods for creating and modifying object types.
12 | ///
13 | /// ref: https://www.m-files.com/api/documentation/latest/index.html#MFilesAPI~VaultObjectTypeOperations.html
14 | public class MFWSVaultObjectTypeOperations
15 | : MFWSVaultOperationsBase
16 | {
17 |
18 | ///
19 | public MFWSVaultObjectTypeOperations(MFWSClientBase client)
20 | : base(client)
21 | {
22 | }
23 |
24 | #region Object type alias to ID resolution
25 |
26 | ///
27 | /// Retrieves the ID for an object type with a given alias in the vault.
28 | ///
29 | /// The alias for the object type.
30 | /// A cancellation token for the request.
31 | /// An awaitable task for the request.
32 | /// Returns -1 if the alias cannot be resolved (e.g. no object types have the alias, or more than one does).
33 | /// Only available in M-Files 12.0.6768.0 upwards.
34 | public async Task GetObjectTypeIDByAliasAsync(string alias, CancellationToken token = default)
35 | {
36 | // Use the other overload.
37 | var output = await this.GetObjectTypeIDsByAliasesAsync(token, aliases: new string[] { alias });
38 | return output?.Count == 1
39 | ? output[0]
40 | : -1;
41 | }
42 |
43 | ///
44 | /// Retrieves the IDs for object types with given aliases in the vault.
45 | ///
46 | /// The aliases for the object type.
47 | /// A cancellation token for the request.
48 | /// An awaitable task for the request.
49 | /// Returns -1 if the alias cannot be resolved (e.g. no object type have the alias, or more than one does).
50 | /// Only available in M-Files 12.0.6768.0 upwards.
51 | public async Task> GetObjectTypeIDsByAliasesAsync(CancellationToken token = default, params string[] aliases)
52 | {
53 | // Sanity.
54 | if (null == aliases)
55 | throw new ArgumentNullException(nameof(aliases));
56 | if (0 == aliases.Length)
57 | return new List();
58 |
59 | // Create the request.
60 | var request = new RestRequest($"/REST/structure/objecttypes/itemidbyalias.aspx");
61 |
62 | // Assign the body.
63 | request.AddJsonBody(aliases);
64 |
65 | // Make the request and get the response.
66 | var response = await this.MFWSClient.Post>(request, token)
67 | .ConfigureAwait(false);
68 |
69 | // Return the data.
70 | return aliases.Select(alias => response.Data.ContainsKey(alias) ? response.Data[alias] : -1).ToList();
71 | }
72 |
73 | ///
74 | /// Retrieves the IDs for object types with given aliases in the vault.
75 | ///
76 | /// The aliases for the object type.
77 | /// A cancellation token for the request.
78 | /// An awaitable task for the request.
79 | /// Returns -1 if the alias cannot be resolved (e.g. no object type have the alias, or more than one does).
80 | public List GetObjectTypeIDsByAliases(CancellationToken token = default, params string[] aliases)
81 | {
82 | // Execute the async method.
83 | return this.GetObjectTypeIDsByAliasesAsync(token, aliases)
84 | .ConfigureAwait(false)
85 | .GetAwaiter()
86 | .GetResult();
87 | }
88 |
89 | ///
90 | /// Retrieves the ID for an object type with a given alias in the vault.
91 | ///
92 | /// The alias for the object type.
93 | /// A cancellation token for the request.
94 | /// An awaitable task for the request.
95 | /// Returns -1 if the alias cannot be resolved (e.g. no object types have the alias, or more than one does).
96 | /// Only available in M-Files 12.0.6768.0 upwards.
97 | public int GetObjectTypeIDByAlias(string alias, CancellationToken token = default)
98 | {
99 | // Use the other overload.
100 | var output = this.GetObjectTypeIDsByAliases(token, aliases: new string[] { alias });
101 | return output?.Count == 1
102 | ? output[0]
103 | : -1;
104 | }
105 |
106 | #endregion
107 |
108 | ///
109 | /// Gets a list of all "real" object types in the vault.
110 | ///
111 | /// A cancellation token for the request.
112 | /// All object types in the vault.
113 | /// This may be filtered by the user's permissions.
114 | public async Task> GetObjectTypesAsync(CancellationToken token = default)
115 | {
116 | // Create the request.
117 | var request = new RestRequest($"/REST/structure/objecttypes.aspx");
118 |
119 | // Make the request and get the response.
120 | var response = await this.MFWSClient.Get>(request, token)
121 | .ConfigureAwait(false);
122 |
123 | // Return the data.
124 | return response.Data;
125 | }
126 |
127 | ///
128 | /// Gets a list of all "real" object types in the vault.
129 | ///
130 | /// A cancellation token for the request.
131 | /// All object types in the vault.
132 | /// This may be filtered by the user's permissions.
133 | public List GetObjectTypes(CancellationToken token = default)
134 | {
135 | // Execute the async method.
136 | return this.GetObjectTypesAsync(token)
137 | .ConfigureAwait(false)
138 | .GetAwaiter()
139 | .GetResult();
140 | }
141 | }
142 | }
143 |
--------------------------------------------------------------------------------
/MFaaP.MFWSClient.Tests/MFaaP.MFWSClient.Tests.csproj:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 | Debug
5 | AnyCPU
6 | {166EB0F7-92DC-4FE0-935F-55AFE17146D9}
7 | Library
8 | Properties
9 | MFaaP.MFWSClient.Tests
10 | MFaaP.MFWSClient.Tests
11 | v4.8
12 | 512
13 | {3AC096D0-A1C2-E12C-1390-A8335801FDAB};{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}
14 | 10.0
15 | $(MSBuildExtensionsPath32)\Microsoft\VisualStudio\v$(VisualStudioVersion)
16 | $(ProgramFiles)\Common Files\microsoft shared\VSTT\$(VisualStudioVersion)\UITestExtensionPackages
17 | False
18 | UnitTest
19 |
20 |
21 |
22 | true
23 | full
24 | false
25 | bin\Debug\
26 | DEBUG;TRACE
27 | prompt
28 | 4
29 |
30 |
31 | pdbonly
32 | true
33 | bin\Release\
34 | TRACE
35 | prompt
36 | 4
37 |
38 |
39 |
40 |
41 |
42 |
43 |
44 |
45 |
46 |
47 |
48 |
49 |
50 |
51 |
52 |
53 |
54 |
55 |
56 |
57 |
58 |
59 |
60 |
61 |
62 |
63 |
64 |
65 |
66 |
67 |
68 |
69 |
70 |
71 |
72 |
73 |
74 |
75 |
76 |
77 |
78 |
79 |
80 |
81 | {b28d0c6a-c87b-461d-bd12-d627e9f653fc}
82 | MFaaP.MFWSClient
83 |
84 |
85 |
86 |
87 | 4.20.72
88 |
89 |
90 | 13.0.3
91 |
92 |
93 | 112.0.0
94 |
95 |
96 |
97 |
98 |
99 |
100 | False
101 |
102 |
103 | False
104 |
105 |
106 | False
107 |
108 |
109 | False
110 |
111 |
112 |
113 |
114 |
115 |
116 |
123 |
--------------------------------------------------------------------------------
/CONTRIBUTING.md:
--------------------------------------------------------------------------------
1 | # Contributing
2 |
3 | First off, thank you for considering contributing to the M-Files Web Service .NET Wrapper client.
4 | By contributing you agree to abide by our [code of conduct](CODE_OF_CONDUCT.md).
5 |
6 | ## 0. What contributions do you accept?
7 |
8 | This repository is designed as a reference point for developers looking to work with the APIs and Frameworks which [M-Files](http://www.m-files.com) exposes.
9 | This repository is designed to be primarily maintained by M-Files staff, but contributions will be considered for merging into the repository.
10 |
11 | **We suggest that you [contact devsupport@m-files.com](mailto:devsupport@m-files.com) prior to submitting a pull request, especially if the
12 | pull request will contain a code or process sample. We will discuss concerns, likelihood of acceptance, and additional content that may be required
13 | from you to support your submission prior to you investing your time.**
14 |
15 | At a minimum, all contributions must be:
16 |
17 | * **Consistent in style and format** to other code.
18 | * **Fully commented and clean**. This is a repository for developers to learn. If your code is not easy to understand then we may ask you to refactor it.
19 | * **Useful to, and usable by,** other developers. If your sample or code change has limited scope then we may ask you to maintain your fork separately, and we will point developers across to it if they are interested.
20 | * ** Backed by unit tests ** to ensure that the code functions as expected.
21 |
22 | *Not all pull requests will be accepted. If your pull request is not accepted then please do not take this personally.*
23 |
24 | ## How do I contribute?
25 |
26 | ### 1. Research
27 |
28 | If you have a question then please initially post on on the
29 | [M-Files Developer Community Yammer network](https://www.yammer.com/m-filesdevelopercommunity).
30 |
31 | If you have identified a bug, or an area in which the code could be improved, then
32 | [search the issue tracker](https://github.com/M-Files/Libraries.MFWSClient/issues?q=something)
33 | to see if someone else in the community has already created a ticket.
34 | If not, go ahead and [make one](https://github.com/M-Files/Libraries.MFWSClient/issues/new)!
35 |
36 | Please ensure that:
37 |
38 | * Bugs should have the phrase `BUG: ` at the start of the title.
39 | A good title would be `BUG: REST API wrapper MFWSVaultObjectOperations.CheckOut does not check out an object`.
40 | * A request for an additional sample should have `SAMPLE: ` at the start of the title.
41 | A good title would be `SAMPLE: UIX application showing a command that's only displayed when certain object types are selected`.
42 | * An issue noting a limitation of an existing library should have `EXTENSION: ` at the start of the title.
43 | A good title for an extension would be `EXTENSION: MFWSVaultObjectPropertyOperations.MarkAssignmentComplete is not implemented`.
44 |
45 | ### 2. Fork & create a branch
46 |
47 | If this is something you think you can fix, then
48 | [fork the repository](https://help.github.com/articles/fork-a-repo)
49 | and create a branch with a descriptive name.
50 |
51 | A good branch name would be (where issue #325 is the ticket you're working on):
52 |
53 | ```sh
54 | git checkout -b 325-rest-wrapper-add-objectpropertyoperations.markassignmentcomplete
55 | ```
56 |
57 | ### 3. Get the test suite running
58 |
59 | Download the repository and open it with Visual Studio 2015. The solution should download all required
60 | packages on build, and should compile with no changes required.
61 |
62 | The test suite is written using MSTest and can be [run from within Visual Studio](https://msdn.microsoft.com/en-us/library/ms182470.aspx).
63 | All tests should pass before any changes are made.
64 |
65 | ### 4. Did you find a bug?
66 |
67 | * **Ensure the bug was not already reported** by [searching all
68 | issues](https://github.com/M-Files/Libraries.MFWSClient/issues?q=).
69 |
70 | * If you're unable to find an open issue addressing the problem, [open a new
71 | one](https://github.com/M-Files/Libraries.MFWSClient/issues/new). Be sure to
72 | include a **title and clear description**, as much relevant information as
73 | possible. Include:
74 | * Steps that can be taken to reproduce the issue.
75 | * M-Files server and versions.
76 | * Operating systems affected.
77 | * If possible, a **code sample** or an **executable test case** demonstrating
78 | the expected behavior that is not occurring.
79 |
80 | ### 5. Implement your fix or feature
81 |
82 | At this point, you're ready to make your changes within your new branch!
83 |
84 | ### 6. Ensure that your changes or additions work
85 |
86 | Confirm that your changes perform as expected. You should test against the latest
87 | released version of M-Files, and fully document any performance, security or version
88 | requirements.
89 |
90 | ### 7. Make a pull request
91 |
92 | At this point, you should switch back to your master branch and make sure it's
93 | up to date with our's master branch:
94 |
95 | ```sh
96 | git remote add upstream git@github.com:M-Files/Libraries.MFWSClient.git
97 | git checkout master
98 | git pull upstream master
99 | ```
100 |
101 | Then update your feature branch from your local copy of master, and push it!
102 |
103 | ```sh
104 | git checkout 325-rest-wrapper-add-objectpropertyoperations.markassignmentcomplete
105 | git rebase master
106 | git push --set-upstream origin 325-rest-wrapper-add-objectpropertyoperations.markassignmentcomplete
107 | ```
108 |
109 | Finally, go to GitHub and
110 | [make a pull request](https://help.github.com/articles/creating-a-pull-request)
111 |
112 |
113 | ### 8. Keeping your pull request updated
114 |
115 | If a maintainer asks you to "rebase" your pull request, they're saying that a lot of code
116 | has changed since you forked your code, and that you need to update your branch so it's easier to merge.
117 |
118 | To learn more about rebasing in Git, there are a lot of
119 | [good](http://git-scm.com/book/en/Git-Branching-Rebasing)
120 | [resources](https://help.github.com/articles/interactive-rebase),
121 | but here's the suggested workflow:
122 |
123 | ```sh
124 | git checkout 325-rest-wrapper-add-objectpropertyoperations.markassignmentcomplete
125 | git pull --rebase upstream master
126 | git push --force-with-lease 325-rest-wrapper-add-objectpropertyoperations.markassignmentcomplete
127 | ```
128 |
129 | **Once your code is rebased, you will need to re-run any tests.**
130 |
131 | ## Guidelines for merging a pull request
132 |
133 | A pull request can only be merged by a maintainer if:
134 |
135 | * It is passing all tests.
136 | * It has no requested changes.
137 | * It is up to date with current master.
138 | * It passes our other contributing guidelines.
--------------------------------------------------------------------------------
/MFaaP.MFWSClient/MFWSVaultExtensionAuthenticationOperations.cs:
--------------------------------------------------------------------------------
1 | using System;
2 | using System.Collections.Generic;
3 | using System.Net;
4 | using System.Threading;
5 | using System.Threading.Tasks;
6 | using System.Web;
7 | using RestSharp;
8 | //using RestSharp.Extensions.MonoHttp;
9 |
10 | namespace MFaaP.MFWSClient
11 | {
12 | ///
13 | /// The 'VaultExtensionAuthenticationOperations' class represents the available extension authentication operations.
14 | ///
15 | /// ref: https://www.m-files.com/api/documentation/latest/index.html#MFilesAPI~VaultExtensionAuthenticationOperations.html
16 | public class MFWSVaultExtensionAuthenticationOperations
17 | : MFWSVaultOperationsBase
18 | {
19 | ///
20 | /// Creates a new object.
21 | ///
22 | /// The client to interact with the server.
23 | internal MFWSVaultExtensionAuthenticationOperations(MFWSClientBase client)
24 | : base(client)
25 | {
26 | }
27 |
28 | #region Retrieval of external repository information
29 |
30 | ///
31 | /// Returns the repositories configured within the vault.
32 | ///
33 | /// A cancellation token for the request.
34 | /// An awaitable task.
35 | public async Task> GetExtensionAuthenticationTargetsAsync(CancellationToken token = default)
36 | {
37 | // Create the request.
38 | var request = new RestRequest($"/REST/repositories.aspx");
39 |
40 | // Make the request and get the response.
41 | var response = await this.MFWSClient.Get>(request, token)
42 | .ConfigureAwait(false);
43 |
44 | // Return the data.
45 | return response.Data;
46 | }
47 |
48 | ///
49 | /// Returns the repositories configured within the vault.
50 | ///
51 | /// A cancellation token for the request.
52 | /// The authentication targets.
53 | public List GetExtensionAuthenticationTargets(CancellationToken token = default)
54 | {
55 | // Execute the async method.
56 | return this.GetExtensionAuthenticationTargetsAsync(token)
57 | .ConfigureAwait(false)
58 | .GetAwaiter()
59 | .GetResult();
60 | }
61 |
62 | #endregion
63 |
64 | #region Logging into external repository connection
65 |
66 | ///
67 | /// Attempts to log into an external repository connection.
68 | ///
69 | /// The connection to authenticate against.
70 | /// The authentication details to use.
71 | /// A cancellation token for the request.
72 | /// An awaitable task.
73 | public async Task LogInWithExtensionAuthenticationAsync(
74 | string targetID,
75 | RepositoryAuthentication authentication,
76 | CancellationToken token = default)
77 | {
78 | // Sanity.
79 | if (null == targetID)
80 | throw new ArgumentNullException(nameof(targetID));
81 | if (string.IsNullOrWhiteSpace(targetID))
82 | throw new ArgumentException("The target cannot be null or empty.", nameof(targetID));
83 | if (null == authentication)
84 | throw new ArgumentNullException(nameof(authentication));
85 | if (string.IsNullOrWhiteSpace(authentication.ConfigurationName))
86 | throw new ArgumentException("The authentication plugin configuration name must be provided.", nameof(authentication));
87 |
88 | // Create the request.
89 | var request = new RestRequest($"/REST/repositories/{WebUtility.UrlEncode(targetID)}/session.aspx");
90 |
91 | // If authentication token is a blank string, replace it with null.
92 | // This is because the remote end tests against null.
93 | if (string.IsNullOrWhiteSpace(authentication.AuthenticationToken))
94 | authentication.AuthenticationToken = null;
95 |
96 | // Set the request body.
97 | request.AddJsonBody(authentication);
98 |
99 | // Make the request and get the response.
100 | var response = await this.MFWSClient.Post(request, token)
101 | .ConfigureAwait(false);
102 |
103 | // Return the data.
104 | return response.Data;
105 | }
106 |
107 | ///
108 | /// Attempts to log into an external repository connection.
109 | ///
110 | /// The connection to authenticate against.
111 | /// The authentication details to use.
112 | /// A cancellation token for the request.
113 | /// The repository state after login attempt.
114 | public RepositoryAuthenticationStatus LogInWithExtensionAuthentication(
115 | string targetID,
116 | RepositoryAuthentication authentication,
117 | CancellationToken token = default)
118 | {
119 | // Execute the async method.
120 | return this.LogInWithExtensionAuthenticationAsync(targetID, authentication, token)
121 | .ConfigureAwait(false)
122 | .GetAwaiter()
123 | .GetResult();
124 | }
125 |
126 | #endregion
127 |
128 | #region Logging out of external repository connection
129 |
130 | ///
131 | /// Logs out with the existing extension authentication data.
132 | ///
133 | /// The connection to authenticate against.
134 | /// A cancellation token for the request.
135 | /// An awaitable task.
136 | public async Task LogOutWithExtensionAuthenticationAsync(
137 | string targetID,
138 | CancellationToken token = default)
139 | {
140 | if (null == targetID)
141 | throw new ArgumentNullException(nameof(targetID));
142 | if (string.IsNullOrWhiteSpace(targetID))
143 | throw new ArgumentException("The target cannot be null or empty.", nameof(targetID));
144 |
145 | // Create the request.
146 | var request = new RestRequest($"/REST/repositories/{WebUtility.UrlEncode(targetID)}/session.aspx");
147 |
148 | // Make the request and get the response.
149 | await this.MFWSClient.Delete(request, token)
150 | .ConfigureAwait(false);
151 | }
152 |
153 | ///
154 | /// Logs out with the existing extension authentication data.
155 | ///
156 | /// The connection to authenticate against.
157 | /// A cancellation token for the request.
158 | public void LogOutWithExtensionAuthentication(
159 | string targetID,
160 | CancellationToken token = default)
161 | {
162 | // Execute the async method.
163 | this.LogOutWithExtensionAuthenticationAsync(targetID, token)
164 | .ConfigureAwait(false)
165 | .GetAwaiter()
166 | .GetResult();
167 | }
168 |
169 | #endregion
170 |
171 | }
172 | }
173 |
--------------------------------------------------------------------------------
/MFaaP.MFWSClient/MFWSVaultValueListItemOperations.cs:
--------------------------------------------------------------------------------
1 | using System;
2 | using System.Net;
3 | using System.Threading;
4 | using System.Threading.Tasks;
5 | using RestSharp;
6 | using RestSharp.Extensions;
7 |
8 | namespace MFaaP.MFWSClient
9 | {
10 | ///
11 | /// Value list item operations.
12 | ///
13 | public class MFWSVaultValueListItemOperations
14 | : MFWSVaultOperationsBase
15 | {
16 | ///
17 | public MFWSVaultValueListItemOperations(MFWSClientBase client)
18 | : base(client)
19 | {
20 | }
21 |
22 | ///
23 | /// Gets the contents of the value list with Id .
24 | ///
25 | /// The Id of the value list to return the items from.
26 | /// If has a value, is used to filter the items by name.
27 | /// A cancellation token for the request.
28 | /// If 0, uses Mfiles default at server (default 500 items returned)
29 | /// The contents of the value list.
30 | /// Note that this may be limited.
31 | public async Task> GetValueListItemsAsync(int valueListId, string nameFilter = null, CancellationToken token = default, int limit = 0)
32 | {
33 | // Create the request.
34 | var request = new RestRequest($"/REST/valuelists/{valueListId}/items");
35 |
36 | // Filter by name?
37 | var querySeperator = "?";
38 | if (false == string.IsNullOrWhiteSpace(nameFilter))
39 | {
40 | request.Resource += "?filter=" + WebUtility.UrlEncode(nameFilter);
41 | querySeperator = "&";
42 | }
43 |
44 | if (limit > 0)
45 | {
46 | request.Resource += $"{querySeperator}limit={limit.ToString()}";
47 | }
48 |
49 | // Make the request and get the response.
50 | var response = await this.MFWSClient.Get>(request, token)
51 | .ConfigureAwait(false);
52 |
53 | // Return the data.
54 | return response.Data;
55 | }
56 |
57 | ///
58 | /// Gets the contents of the value list with Id .
59 | ///
60 | /// The Id of the value list to return the items from.
61 | /// If has a value, is used to filter the items by name.
62 | /// A cancellation token for the request.
63 | /// If 0, uses Mfiles default at server (default 500 items returned)
64 | /// The contents of the value list.
65 | /// Note that this may be limited.
66 | public Results GetValueListItems(int valueListId, string nameFilter = null, CancellationToken token = default, int limit = 0)
67 | {
68 | // Execute the async method.
69 | return this.GetValueListItemsAsync(valueListId, nameFilter, token, limit)
70 | .ConfigureAwait(false)
71 | .GetAwaiter()
72 | .GetResult();
73 | }
74 |
75 |
76 | ///
77 | /// Creates a new item with the in the value list with id .
78 | ///
79 | /// The Id of the value list to create the new item in.
80 | /// Name of the new value list item to create.
81 | /// A cancellation token for the request.
82 | /// The newly created value list item
83 | public Task AddValueListItemAsync(int valueListId, string newItemName, CancellationToken token = default)
84 | {
85 | // Sanity.
86 | if (string.IsNullOrWhiteSpace(newItemName))
87 | throw new ArgumentException("The value list item must have a name.", nameof(newItemName));
88 |
89 | // Create the value list item instance.
90 | var newValueListItem = new ValueListItem
91 | {
92 | Name = newItemName,
93 | ValueListID = valueListId
94 | };
95 |
96 | // Use the other overload.
97 | return this.AddValueListItemAsync(valueListId, newValueListItem, token);
98 | }
99 |
100 | /// Creates a new item with the in the value list with id .
101 | ///
102 | /// The Id of the value list to create the new item in.
103 | /// Name of the new value list item to create.
104 | /// A cancellation token for the request.
105 | /// The newly created value list item
106 | public ValueListItem AddValueListItem(int valueListId, string newItemName, CancellationToken token = default)
107 | {
108 | // Execute the async method.
109 | return this.AddValueListItemAsync(valueListId, newItemName, token)
110 | .ConfigureAwait(false)
111 | .GetAwaiter()
112 | .GetResult();
113 | }
114 |
115 | ///
116 | /// Creates a new in the value list with id .
117 | ///
118 | /// The Id of the value list to create the new item in.
119 | /// The value list item to create.
120 | /// A cancellation token for the request.
121 | /// The newly created value list item
122 | public async Task AddValueListItemAsync(int valueListId, ValueListItem valueListItem, CancellationToken token = default)
123 | {
124 | // Sanity.
125 | if (null == valueListItem)
126 | throw new ArgumentNullException(nameof(valueListItem));
127 | if (valueListItem.ValueListID != valueListId)
128 | valueListItem.ValueListID = valueListId;
129 | if (string.IsNullOrWhiteSpace(valueListItem.Name))
130 | throw new ArgumentException("The value list item must have a name.", nameof(valueListItem));
131 |
132 | // Create the request.
133 | var request = new RestRequest($"/REST/valuelists/{valueListId}/items");
134 | request.AddJsonBody(valueListItem);
135 |
136 | // Make the request and get the response.
137 | var response = await this.MFWSClient.Post(request, token)
138 | .ConfigureAwait(false);
139 |
140 | return response.Data;
141 | }
142 |
143 | ///
144 | /// Creates a new in the value list with id .
145 | ///
146 | /// The Id of the value list to create the new item in.
147 | /// The value list item to create.
148 | /// A cancellation token for the request.
149 | /// The newly created value list item
150 | public ValueListItem AddValueListItem(int valueListId, ValueListItem valueListItem, CancellationToken token = default)
151 | {
152 | // Execute the async method.
153 | return this.AddValueListItemAsync(valueListId, valueListItem, token)
154 | .ConfigureAwait(false)
155 | .GetAwaiter()
156 | .GetResult();
157 | }
158 | }
159 | }
160 |
--------------------------------------------------------------------------------
/MFaaP.MFWSClient/MFWSVaultExtensionMethodOperations.cs:
--------------------------------------------------------------------------------
1 | using System;
2 | using System.Threading;
3 | using System.Threading.Tasks;
4 | using RestSharp;
5 |
6 | namespace MFaaP.MFWSClient
7 | {
8 | ///
9 | /// Vault extension operations.
10 | ///
11 | public class MFWSVaultExtensionMethodOperations
12 | : MFWSVaultOperationsBase
13 | {
14 |
15 | ///
16 | /// Creates a new object.
17 | ///
18 | /// The client to interact with the server.
19 | internal MFWSVaultExtensionMethodOperations(MFWSClientBase client)
20 | : base(client)
21 | {
22 | }
23 |
24 | #region Execute extension methods
25 |
26 | ///
27 | /// Executes an extension method on the server-side.
28 | ///
29 | /// The expected response type.
30 | /// The type of the item to send.
31 | /// The name of the extension method.
32 | /// The input (cannot be null) parameter.
33 | /// A cancellation token for the request.
34 | /// The response of the extension method, deserialised to an instance of .
35 | public async Task ExecuteVaultExtensionMethodAsync(string extensionMethodName, TB input = null, CancellationToken token = default)
36 | where TA : new()
37 | where TB : class
38 | {
39 | // Create the request.
40 | var request = new RestRequest($"/REST/vault/extensionmethod/{extensionMethodName}.aspx");
41 |
42 | // If we have a parameter then serialise it.
43 | if (null != input)
44 | {
45 | request.AddJsonBody(input);
46 | }
47 |
48 | // Make the request and get the response.
49 | var response = await this.MFWSClient.Post(request, token)
50 | .ConfigureAwait(false);
51 |
52 | // Return the data.
53 | return response.Data;
54 | }
55 |
56 | ///
57 | /// Executes an extension method on the server-side.
58 | ///
59 | /// The expected response type.
60 | /// The type of the item to send.
61 | /// The name of the extension method.
62 | /// The input (cannot be null) parameter.
63 | /// A cancellation token for the request.
64 | /// The response of the extension method, deserialised to an instance of .
65 | public TA ExecuteVaultExtensionMethod(string extensionMethodName, TB input = null, CancellationToken token = default)
66 | where TA : new()
67 | where TB : class
68 | {
69 |
70 | // Execute the async method.
71 | return this.ExecuteVaultExtensionMethodAsync(extensionMethodName, input, token)
72 | .ConfigureAwait(false)
73 | .GetAwaiter()
74 | .GetResult();
75 |
76 | }
77 |
78 | ///
79 | /// Executes an extension method on the server-side.
80 | ///
81 | /// The type of the item to send.
82 | /// The name of the extension method.
83 | /// The input (cannot be null) parameter.
84 | /// A cancellation token for the request.
85 | /// The response of the extension method.
86 | public async Task ExecuteVaultExtensionMethodAsync(string extensionMethodName, TB input = null, CancellationToken token = default)
87 | where TB : class
88 | {
89 | // Create the request.
90 | var request = new RestRequest($"/REST/vault/extensionmethod/{extensionMethodName}.aspx");
91 |
92 | // If we have a parameter then serialise it.
93 | if (null != input)
94 | {
95 | request.AddJsonBody(input);
96 | }
97 |
98 | // Make the request and get the response.
99 | var response = await this.MFWSClient.Post(request, token)
100 | .ConfigureAwait(false);
101 |
102 | // Return the data.
103 | return response.Content;
104 | }
105 |
106 | ///
107 | /// Executes an extension method on the server-side.
108 | ///
109 | /// The type of the item to send.
110 | /// The name of the extension method.
111 | /// The input (cannot be null) parameter.
112 | /// A cancellation token for the request.
113 | /// The response of the extension method.
114 | public string ExecuteVaultExtensionMethod(string extensionMethodName, TB input = null, CancellationToken token = default)
115 | where TB : class
116 | {
117 | // Execute the async method.
118 | return this.ExecuteVaultExtensionMethodAsync(extensionMethodName, input, token)
119 | .ConfigureAwait(false)
120 | .GetAwaiter()
121 | .GetResult();
122 | }
123 |
124 | ///
125 | /// Executes an extension method on the server-side.
126 | ///
127 | /// The name of the extension method.
128 | /// The input parameter.
129 | /// A cancellation token for the request.
130 | /// The response of the extension method as a string.
131 | public async Task ExecuteVaultExtensionMethodAsync(string extensionMethodName, string input = null, CancellationToken token = default)
132 | {
133 |
134 | // Create the request.
135 | var request = new RestRequest($"/REST/vault/extensionmethod/{extensionMethodName}.aspx");
136 |
137 | // If we have a parameter then send it.
138 | if (null != input)
139 | {
140 | // We need to copy the default parameters if we are adding new ones (??).
141 | foreach(var p in this.MFWSClient.DefaultParameters)
142 | {
143 | request.Parameters.AddParameter(p);
144 | }
145 |
146 | // Add the message body.
147 | request.AddJsonBody(input);
148 | }
149 |
150 | // Make the request and get the response.
151 | var response = await this.MFWSClient.Post(request, token)
152 | .ConfigureAwait(false);
153 |
154 | // Return the data.
155 | return response.Content;
156 | }
157 |
158 | ///
159 | /// Executes an extension method on the server-side.
160 | ///
161 | /// The name of the extension method.
162 | /// The input parameter.
163 | /// A cancellation token for the request.
164 | /// The response of the extension method as a string.
165 | public string ExecuteVaultExtensionMethod(string extensionMethodName, string input = null, CancellationToken token = default)
166 | {
167 | // Execute the async method.
168 | return this.ExecuteVaultExtensionMethodAsync(extensionMethodName, input, token)
169 | .ConfigureAwait(false)
170 | .GetAwaiter()
171 | .GetResult();
172 | }
173 |
174 | #endregion
175 |
176 | }
177 |
178 | }
179 |
--------------------------------------------------------------------------------
/.gitignore:
--------------------------------------------------------------------------------
1 | ## Ignore Visual Studio temporary files, build results, and
2 | ## files generated by popular Visual Studio add-ons.
3 | ##
4 | ## Get latest from https://github.com/github/gitignore/blob/master/VisualStudio.gitignore
5 |
6 | # User-specific files
7 | *.rsuser
8 | *.suo
9 | *.user
10 | *.userosscache
11 | *.sln.docstates
12 |
13 | # User-specific files (MonoDevelop/Xamarin Studio)
14 | *.userprefs
15 |
16 | # Build results
17 | [Dd]ebug/
18 | current/
19 | [Dd]ebugPublic/
20 | [Rr]elease/
21 | [Rr]eleases/
22 | x64/
23 | x86/
24 | [Aa][Rr][Mm]/
25 | [Aa][Rr][Mm]64/
26 | bld/
27 | [Bb]in/
28 | [Oo]bj/
29 | [Ll]og/
30 |
31 | # Visual Studio 2015/2017 cache/options directory
32 | .vs/
33 | # Uncomment if you have tasks that create the project's static files in wwwroot
34 | #wwwroot/
35 |
36 | # Visual Studio 2017 auto generated files
37 | Generated\ Files/
38 |
39 | # MSTest test Results
40 | [Tt]est[Rr]esult*/
41 | [Bb]uild[Ll]og.*
42 |
43 | # NUNIT
44 | *.VisualState.xml
45 | TestResult.xml
46 |
47 | # Build Results of an ATL Project
48 | [Dd]ebugPS/
49 | [Rr]eleasePS/
50 | dlldata.c
51 |
52 | # Benchmark Results
53 | BenchmarkDotNet.Artifacts/
54 |
55 | # .NET Core
56 | project.lock.json
57 | project.fragment.lock.json
58 | artifacts/
59 |
60 | # StyleCop
61 | StyleCopReport.xml
62 |
63 | # Files built by Visual Studio
64 | *_i.c
65 | *_p.c
66 | *_h.h
67 | *.ilk
68 | *.meta
69 | *.obj
70 | *.iobj
71 | *.pch
72 | *.pdb
73 | *.ipdb
74 | *.pgc
75 | *.pgd
76 | *.rsp
77 | *.sbr
78 | *.tlb
79 | *.tli
80 | *.tlh
81 | *.tmp
82 | *.tmp_proj
83 | *_wpftmp.csproj
84 | *.log
85 | *.vspscc
86 | *.vssscc
87 | .builds
88 | *.pidb
89 | *.svclog
90 | *.scc
91 |
92 | # Chutzpah Test files
93 | _Chutzpah*
94 |
95 | # Visual C++ cache files
96 | ipch/
97 | *.aps
98 | *.ncb
99 | *.opendb
100 | *.opensdf
101 | *.sdf
102 | *.cachefile
103 | *.VC.db
104 | *.VC.VC.opendb
105 |
106 | # Visual Studio profiler
107 | *.psess
108 | *.vsp
109 | *.vspx
110 | *.sap
111 |
112 | # Visual Studio Trace Files
113 | *.e2e
114 |
115 | # TFS 2012 Local Workspace
116 | $tf/
117 |
118 | # Guidance Automation Toolkit
119 | *.gpState
120 |
121 | # ReSharper is a .NET coding add-in
122 | _ReSharper*/
123 | *.[Rr]e[Ss]harper
124 | *.DotSettings.user
125 |
126 | # JustCode is a .NET coding add-in
127 | .JustCode
128 |
129 | # TeamCity is a build add-in
130 | _TeamCity*
131 |
132 | # DotCover is a Code Coverage Tool
133 | *.dotCover
134 |
135 | # AxoCover is a Code Coverage Tool
136 | .axoCover/*
137 | !.axoCover/settings.json
138 |
139 | # Visual Studio code coverage results
140 | *.coverage
141 | *.coveragexml
142 |
143 | # NCrunch
144 | _NCrunch_*
145 | .*crunch*.local.xml
146 | nCrunchTemp_*
147 |
148 | # MightyMoose
149 | *.mm.*
150 | AutoTest.Net/
151 |
152 | # Web workbench (sass)
153 | .sass-cache/
154 |
155 | # Installshield output folder
156 | [Ee]xpress/
157 |
158 | # DocProject is a documentation generator add-in
159 | DocProject/buildhelp/
160 | DocProject/Help/*.HxT
161 | DocProject/Help/*.HxC
162 | DocProject/Help/*.hhc
163 | DocProject/Help/*.hhk
164 | DocProject/Help/*.hhp
165 | DocProject/Help/Html2
166 | DocProject/Help/html
167 |
168 | # Click-Once directory
169 | publish/
170 |
171 | # Publish Web Output
172 | *.[Pp]ublish.xml
173 | *.azurePubxml
174 | # Note: Comment the next line if you want to checkin your web deploy settings,
175 | # but database connection strings (with potential passwords) will be unencrypted
176 | *.pubxml
177 | *.publishproj
178 |
179 | # Microsoft Azure Web App publish settings. Comment the next line if you want to
180 | # checkin your Azure Web App publish settings, but sensitive information contained
181 | # in these scripts will be unencrypted
182 | PublishScripts/
183 |
184 | # NuGet Packages
185 | *.nupkg
186 | # except current
187 | !/current/*.nupkg
188 | # The packages folder can be ignored because of Package Restore
189 | **/[Pp]ackages/*
190 | # except build/, which is used as an MSBuild target.
191 | !**/[Pp]ackages/build/
192 | # Uncomment if necessary however generally it will be regenerated when needed
193 | #!**/[Pp]ackages/repositories.config
194 | # NuGet v3's project.json files produces more ignorable files
195 | *.nuget.props
196 | *.nuget.targets
197 |
198 | # Microsoft Azure Build Output
199 | csx/
200 | *.build.csdef
201 |
202 | # Microsoft Azure Emulator
203 | ecf/
204 | rcf/
205 |
206 | # Windows Store app package directories and files
207 | AppPackages/
208 | BundleArtifacts/
209 | Package.StoreAssociation.xml
210 | _pkginfo.txt
211 | *.appx
212 |
213 | # Visual Studio cache files
214 | # files ending in .cache can be ignored
215 | *.[Cc]ache
216 | # but keep track of directories ending in .cache
217 | !?*.[Cc]ache/
218 |
219 | # Others
220 | ClientBin/
221 | ~$*
222 | *~
223 | *.dbmdl
224 | *.dbproj.schemaview
225 | *.jfm
226 | *.pfx
227 | *.publishsettings
228 | orleans.codegen.cs
229 |
230 | # Including strong name files can present a security risk
231 | # (https://github.com/github/gitignore/pull/2483#issue-259490424)
232 | #*.snk
233 |
234 | # Since there are multiple workflows, uncomment next line to ignore bower_components
235 | # (https://github.com/github/gitignore/pull/1529#issuecomment-104372622)
236 | #bower_components/
237 |
238 | # RIA/Silverlight projects
239 | Generated_Code/
240 |
241 | # Backup & report files from converting an old project file
242 | # to a newer Visual Studio version. Backup files are not needed,
243 | # because we have git ;-)
244 | _UpgradeReport_Files/
245 | Backup*/
246 | UpgradeLog*.XML
247 | UpgradeLog*.htm
248 | ServiceFabricBackup/
249 | *.rptproj.bak
250 |
251 | # SQL Server files
252 | *.mdf
253 | *.ldf
254 | *.ndf
255 |
256 | # Business Intelligence projects
257 | *.rdl.data
258 | *.bim.layout
259 | *.bim_*.settings
260 | *.rptproj.rsuser
261 | *- Backup*.rdl
262 |
263 | # Microsoft Fakes
264 | FakesAssemblies/
265 |
266 | # GhostDoc plugin setting file
267 | *.GhostDoc.xml
268 |
269 | # Node.js Tools for Visual Studio
270 | .ntvs_analysis.dat
271 | node_modules/
272 |
273 | # Visual Studio 6 build log
274 | *.plg
275 |
276 | # Visual Studio 6 workspace options file
277 | *.opt
278 |
279 | # Visual Studio 6 auto-generated workspace file (contains which files were open etc.)
280 | *.vbw
281 |
282 | # Visual Studio LightSwitch build output
283 | **/*.HTMLClient/GeneratedArtifacts
284 | **/*.DesktopClient/GeneratedArtifacts
285 | **/*.DesktopClient/ModelManifest.xml
286 | **/*.Server/GeneratedArtifacts
287 | **/*.Server/ModelManifest.xml
288 | _Pvt_Extensions
289 |
290 | # Paket dependency manager
291 | .paket/paket.exe
292 | paket-files/
293 |
294 | # FAKE - F# Make
295 | .fake/
296 |
297 | # JetBrains Rider
298 | .idea/
299 | *.sln.iml
300 |
301 | # CodeRush personal settings
302 | .cr/personal
303 |
304 | # Python Tools for Visual Studio (PTVS)
305 | __pycache__/
306 | *.pyc
307 |
308 | # Cake - Uncomment if you are using it
309 | # tools/**
310 | # !tools/packages.config
311 |
312 | # Tabs Studio
313 | *.tss
314 |
315 | # Telerik's JustMock configuration file
316 | *.jmconfig
317 |
318 | # BizTalk build output
319 | *.btp.cs
320 | *.btm.cs
321 | *.odx.cs
322 | *.xsd.cs
323 |
324 | # OpenCover UI analysis results
325 | OpenCover/
326 |
327 | # Azure Stream Analytics local run output
328 | ASALocalRun/
329 |
330 | # MSBuild Binary and Structured Log
331 | *.binlog
332 |
333 | # NVidia Nsight GPU debugger configuration file
334 | *.nvuser
335 |
336 | # MFractors (Xamarin productivity tool) working folder
337 | .mfractor/
338 |
339 | # Local History for Visual Studio
340 | .localhistory/
341 |
342 | # BeatPulse healthcheck temp database
343 | healthchecksdb
344 | current/MFWSClient.nupkg
345 |
--------------------------------------------------------------------------------
/MFaaP.MFWSClient/MFWSVaultExternalObjectOperations.cs:
--------------------------------------------------------------------------------
1 | using System;
2 | using System.Collections.Generic;
3 | using System.Linq;
4 | using System.Threading;
5 | using System.Threading.Tasks;
6 | using RestSharp;
7 |
8 | namespace MFaaP.MFWSClient
9 | {
10 | ///
11 | /// Methods to unteract with objects in external repositories.
12 | ///
13 | public class MFWSVaultExternalObjectOperations
14 | : MFWSVaultOperationsBase
15 | {
16 | ///
17 | /// Creates a new object.
18 | ///
19 | /// The client to interact with the server.
20 | internal MFWSVaultExternalObjectOperations(MFWSClientBase client)
21 | : base(client)
22 | {
23 | }
24 |
25 | #region Demote objects
26 |
27 | ///
28 | /// Demotes managed objects to unmanaged objects.
29 | ///
30 | /// The Ids of the objects to demote.
31 | /// A cancellation token for the request.
32 | public async Task> DemoteObjectsAsync(CancellationToken token = default, params ObjID[] objectsToDemote)
33 | {
34 | // Sanity.
35 | if (null == objectsToDemote)
36 | throw new ArgumentNullException(nameof(objectsToDemote));
37 | if (objectsToDemote.Length == 0)
38 | return new List();
39 |
40 | // Create the request.
41 | var request = new RestRequest($"/REST/objects/demotemultiobjects");
42 |
43 | // NOTE: If the ObjID collection contains external data then it fails; remove it.
44 | objectsToDemote = objectsToDemote
45 | .Select(oid => new ObjID()
46 | {
47 | Type = oid.Type,
48 | ID = oid.ID
49 | })
50 | .ToArray();
51 |
52 | // Set the request body.
53 | request.AddJsonBody(objectsToDemote);
54 |
55 | // Make the request and get the response.
56 | var response = await this.MFWSClient.Put>(request, token)
57 | .ConfigureAwait(false);
58 |
59 | // Return the object data.
60 | return response.Data;
61 | }
62 |
63 | ///
64 | /// Demotes managed objects to unmanaged objects.
65 | ///
66 | /// The Ids of the objects to demote.
67 | /// A cancellation token for the request.
68 | /// The ObjectVersion, if it is visible to the user.
69 | public List DemoteObjects(CancellationToken token = default, params ObjID[] objectsToDemote)
70 | {
71 | // Execute the async method.
72 | return this.DemoteObjectsAsync(token, objectsToDemote)
73 | .ConfigureAwait(false)
74 | .GetAwaiter()
75 | .GetResult();
76 | }
77 |
78 | ///
79 | /// Demote a managed object to an unmanaged object.
80 | ///
81 | /// The Id of the object to demote.
82 | /// A cancellation token for the request.
83 | public Task> DemoteObjectAsync(ObjID objID, CancellationToken token = default)
84 | {
85 | return this.DemoteObjectsAsync(token, objID);
86 | }
87 |
88 | ///
89 | /// Demote a managed object to an unmanaged object.
90 | ///
91 | /// The Id of the object to demote.
92 | /// A cancellation token for the request.
93 | /// The ObjectVersion, if it is visible to the user.
94 | public List DemoteObject(ObjID objID, CancellationToken token = default)
95 | {
96 | // Execute the async method.
97 | return this.DemoteObjectAsync(objID, token)
98 | .ConfigureAwait(false)
99 | .GetAwaiter()
100 | .GetResult();
101 | }
102 |
103 | #endregion
104 |
105 | #region Promote objects
106 |
107 | ///
108 | /// Promotes unmanaged objects to managed objects.
109 | ///
110 | /// Information on the objects to promote.
111 | /// A cancellation token for the request.
112 | /// The property values must be valid for the class, as they would if an object were being created.
113 | public Task> PromoteObjectsAsync(CancellationToken token = default, params ObjectVersionUpdateInformation[] objectVersionUpdateInformation)
114 | {
115 | // Use the "SetPropertiesOfMultipleObjects" method to perform this.
116 | return this.MFWSClient.ObjectPropertyOperations.SetPropertiesOfMultipleObjectsAsync(
117 | token,
118 | objectVersionUpdateInformation);
119 | }
120 |
121 | ///
122 | /// Promotes unmanaged objects to managed object.
123 | ///
124 | /// Information on the objects to promote.
125 | /// A cancellation token for the request.
126 | /// The property values must be valid for the class, as they would if an object were being created.
127 | public List PromoteObjects(CancellationToken token = default, params ObjectVersionUpdateInformation[] objectVersionUpdateInformation)
128 | {
129 | // Execute the async method.
130 | return this.PromoteObjectsAsync(token, objectVersionUpdateInformation)
131 | .ConfigureAwait(false)
132 | .GetAwaiter()
133 | .GetResult();
134 | }
135 |
136 | ///
137 | /// Promotes an unmanaged object to a managed object.
138 | ///
139 | /// The object to promote.
140 | /// The object's new properties.
141 | /// A cancellation token for the request.
142 | /// The property values must be valid for the class, as they would if an object were being created.
143 | public async Task PromoteObjectAsync(ObjVer objVer, PropertyValue[] propertyValues, CancellationToken token = default)
144 | {
145 | // Sanity.
146 | if (null == objVer)
147 | throw new ArgumentNullException(nameof(objVer));
148 | if (null == propertyValues)
149 | throw new ArgumentNullException(nameof(propertyValues));
150 |
151 | // Use the other method.
152 | var response = await this.PromoteObjectsAsync(token, new ObjectVersionUpdateInformation()
153 | {
154 | ObjVer = objVer,
155 | Properties = propertyValues.ToList()
156 | });
157 |
158 | // Return the first item from the response.
159 | if(null == response || response.Count != 1)
160 | throw new InvalidOperationException($"The call to /objects/setmultipleobjproperties returned {response?.Count ?? 0} items, but 1 was expected");
161 | return response[0];
162 | }
163 |
164 | ///
165 | /// Promotes an unmanaged object to a managed object.
166 | ///
167 | /// The object to promote.
168 | /// The object's new properties.
169 | /// A cancellation token for the request.
170 | /// The property values must be valid for the class, as they would if an object were being created.
171 | public ExtendedObjectVersion PromoteObject(ObjVer objVer, PropertyValue[] propertyValues, CancellationToken token = default)
172 | {
173 | // Execute the async method.
174 | return this.PromoteObjectAsync(objVer, propertyValues, token)
175 | .ConfigureAwait(false)
176 | .GetAwaiter()
177 | .GetResult();
178 | }
179 |
180 | #endregion
181 |
182 | }
183 | }
184 |
--------------------------------------------------------------------------------
/MFaaP.MFWSClient/ExtensionMethods/FolderContentItemExtensionMethods.cs:
--------------------------------------------------------------------------------
1 | using System;
2 | using System.Collections.Generic;
3 | using System.Linq;
4 | using System.Net;
5 | //using RestSharp.Extensions.MonoHttp;
6 |
7 | namespace MFaaP.MFWSClient.ExtensionMethods
8 | {
9 | ///
10 | /// Folder item extension methods.
11 | ///
12 | public static class FolderContentItemExtensionMethods
13 | {
14 | ///
15 | /// Retrieves the name of a folder content item for display.
16 | ///
17 | /// The folder content item to retrieve the name of.
18 | /// The name, or empty if cannot be found.
19 | public static string GetDisplayName(this FolderContentItem item)
20 | {
21 | // Sanity.
22 | if (null == item)
23 | throw new ArgumentNullException(nameof(item));
24 |
25 | // Get the name depending on type.
26 | switch (item.FolderContentItemType)
27 | {
28 | case MFFolderContentItemType.ObjectVersion:
29 | return item.ObjectVersion.Title;
30 | case MFFolderContentItemType.PropertyFolder:
31 | return item.PropertyFolder.DisplayValue;
32 | case MFFolderContentItemType.ViewFolder:
33 | return item.View.ViewLocation?.Overlapping == true
34 | ? item.View.ViewLocation.OverlappedFolder.DisplayValue
35 | : item.View.Name;
36 | case MFFolderContentItemType.TraditionalFolder:
37 | return item.TraditionalFolder.DisplayValue;
38 | case MFFolderContentItemType.ExternalViewFolder:
39 | return item.ExternalView.DisplayName;
40 | default:
41 | // Unknown.
42 | return string.Empty;
43 | }
44 | }
45 |
46 | ///
47 | /// Returns the path information to be used to retrieve items from the view.
48 | ///
49 | ///
50 | /// See: http://www.m-files.com/mfws/resources/views/path/items.html
51 | ///
52 | /// The items to return the view path for.
53 | /// The view path.
54 | public static string GetPath(this FolderContentItem[] items)
55 | {
56 | // Sanity.
57 | if (null == items || 0 == items.Length)
58 | return string.Empty;
59 |
60 | // Return the paths, separated by "/".
61 | return String.Join("/", items.Select(FolderContentItemExtensionMethods.GetPath).Where(p => false == string.IsNullOrWhiteSpace(p))) + "/";
62 |
63 | }
64 |
65 | ///
66 | /// Returns the path information to be used to retrieve items from the view.
67 | ///
68 | ///
69 | /// See: http://www.m-files.com/mfws/resources/views/path/items.html
70 | ///
71 | /// The item to return the view path for.
72 | /// The view path.
73 | public static string GetPath(this FolderContentItem item)
74 | {
75 | // Sanity.
76 | if (null == item)
77 | return string.Empty;
78 |
79 | // The return value depends on the item type.
80 | // See: http://www.m-files.com/mfws/syntax.html
81 | switch (item.FolderContentItemType)
82 | {
83 | case MFFolderContentItemType.ExternalViewFolder:
84 | // NOTE: The string should be "u", followed by the URL-encoded external repository name, followed by a colon, followed by the URL-encoded view ID.
85 | // The entire string should then be URL-encoded a second time to ensure that it is passed correctly.
86 | return WebUtility.UrlEncode($"u{WebUtility.UrlEncode(item.ExternalView.ExternalRepositoryName)}:{WebUtility.UrlEncode(item.ExternalView.ID)}");
87 | case MFFolderContentItemType.ViewFolder:
88 | return "v" + item.View.ID;
89 | case MFFolderContentItemType.TraditionalFolder:
90 | return "y" + item.TraditionalFolder.Item;
91 | case MFFolderContentItemType.PropertyFolder:
92 | {
93 | string prefix = null;
94 | string suffix = item.PropertyFolder.Value?.ToString();
95 | switch (item.PropertyFolder.DataType)
96 | {
97 | case MFDataType.Text:
98 | prefix = "T";
99 | break;
100 | case MFDataType.MultiLineText:
101 | prefix = "M";
102 | break;
103 | case MFDataType.Integer:
104 | prefix = "I";
105 | break;
106 | case MFDataType.Integer64:
107 | prefix = "J";
108 | break;
109 | case MFDataType.Floating:
110 | prefix = "R";
111 | break;
112 | case MFDataType.Date:
113 | prefix = "D";
114 | break;
115 | case MFDataType.Time:
116 | prefix = "C";
117 | break;
118 | case MFDataType.FILETIME:
119 | prefix = "E";
120 | break;
121 | case MFDataType.Lookup:
122 | prefix = "L";
123 | suffix = (item.PropertyFolder.Lookup?.Item ?? 0).ToString();
124 | break;
125 | case MFDataType.MultiSelectLookup:
126 | prefix = "S";
127 | suffix = String.Join(",", item.PropertyFolder.Lookups?.Select(l => l.Item) ?? new int[0]);
128 | break;
129 | case MFDataType.Uninitialized:
130 | prefix = "-";
131 | break;
132 | case MFDataType.ACL:
133 | prefix = "A";
134 | break;
135 | case MFDataType.Boolean:
136 | prefix = "B";
137 | break;
138 | }
139 |
140 | // Sanity.
141 | if (null == prefix || null == suffix)
142 | return null;
143 |
144 | // Return the formatted value.
145 | return $"{prefix}{WebUtility.UrlEncode(suffix)}";
146 | }
147 | default:
148 | return null;
149 | }
150 |
151 | }
152 |
153 | ///
154 | /// Compares one folder item to another, for ordering purposes.
155 | ///
156 | /// The first item.
157 | /// The second item.
158 | /// 0 means same, -1 means (x < y), 1 means (y > x)
159 | private static int CompareTo(this FolderContentItem x, FolderContentItem y)
160 | {
161 | // Sanity.
162 | if (null == x && null == y)
163 | return 0;
164 | if (null == x)
165 | return 1;
166 | if (null == y)
167 | return -1;
168 |
169 | // Compare types.
170 | var typeCompare = FolderContentItemExtensionMethods.Compare(x.FolderContentItemType, y.FolderContentItemType);
171 | if (typeCompare != 0)
172 | return typeCompare;
173 |
174 | // Same type; compare name.
175 | var xName = x.GetDisplayName();
176 | var yName = y.GetDisplayName();
177 | return String.Compare(xName, yName, StringComparison.OrdinalIgnoreCase);
178 | }
179 |
180 | ///
181 | /// Compares one folder item type to another, for ordering purposes.
182 | ///
183 | /// The first item.
184 | /// The second item.
185 | /// 0 means same, -1 means (x < y), 1 means (y > x)
186 | private static int Compare(MFFolderContentItemType x, MFFolderContentItemType y)
187 | {
188 | // Are they the same?
189 | if (x == y)
190 | return 0;
191 |
192 | switch (x)
193 | {
194 | case MFFolderContentItemType.ObjectVersion:
195 | {
196 | // Objects always at the end.
197 | return 1;
198 | }
199 | case MFFolderContentItemType.PropertyFolder:
200 | case MFFolderContentItemType.TraditionalFolder:
201 | case MFFolderContentItemType.ViewFolder:
202 | {
203 | // If y is an object, then put y is greater.
204 | if (y == MFFolderContentItemType.ObjectVersion)
205 | return -1;
206 |
207 | // Otherwise they are the same.
208 | return 0;
209 | }
210 | default:
211 | // Unknown.
212 | return -1;
213 | }
214 | }
215 |
216 | }
217 | }
218 |
--------------------------------------------------------------------------------
/MFaaP.MFWSClient/MFWSVaultPropertyDefOperations.cs:
--------------------------------------------------------------------------------
1 | using System;
2 | using System.Collections.Generic;
3 | using System.Linq;
4 | using System.Threading;
5 | using System.Threading.Tasks;
6 | using RestSharp;
7 |
8 | namespace MFaaP.MFWSClient
9 | {
10 | ///
11 | /// A group of methods for creating and modifying property definitions.
12 | ///
13 | /// ref: https://www.m-files.com/api/documentation/latest/index.html#MFilesAPI~VaultPropertyDefOperations.html
14 | public class MFWSVaultPropertyDefOperations
15 | : MFWSVaultOperationsBase
16 | {
17 |
18 | ///
19 | public MFWSVaultPropertyDefOperations(MFWSClientBase client)
20 | : base(client)
21 | {
22 | }
23 |
24 | #region Property definition alias to ID resolution
25 |
26 | ///
27 | /// Retrieves the ID for a property definition with a given alias in the vault.
28 | ///
29 | /// The alias for the property definition.
30 | /// A cancellation token for the request.
31 | /// An awaitable task for the request.
32 | /// Returns -1 if the alias cannot be resolved (e.g. no property definitions have the alias, or more than one does).
33 | /// Only available in M-Files 12.0.6768.0 upwards.
34 | public async Task GetPropertyDefIDByAliasAsync(string alias, CancellationToken token = default)
35 | {
36 | // Use the other overload.
37 | var output = await this.GetPropertyDefIDsByAliasesAsync(token, aliases: new string[] { alias });
38 | return output?.Count == 1
39 | ? output[0]
40 | : -1;
41 | }
42 |
43 | ///
44 | /// Retrieves the ID for a property definition with a given alias in the vault.
45 | ///
46 | /// The aliases for the property definition.
47 | /// A cancellation token for the request.
48 | /// An awaitable task for the request.
49 | /// Returns -1 if the alias cannot be resolved (e.g. no property definitions have the alias, or more than one does).
50 | /// Only available in M-Files 12.0.6768.0 upwards.
51 | public async Task> GetPropertyDefIDsByAliasesAsync(CancellationToken token = default, params string[] aliases)
52 | {
53 | // Sanity.
54 | if(null == aliases)
55 | throw new ArgumentNullException(nameof(aliases));
56 | if (0 == aliases.Length)
57 | return new List();
58 |
59 | // Create the request.
60 | var request = new RestRequest($"/REST/structure/properties/itemidbyalias.aspx");
61 |
62 | // Assign the body.
63 | request.AddJsonBody(aliases);
64 |
65 | // Make the request and get the response.
66 | var response = await this.MFWSClient.Post>(request, token)
67 | .ConfigureAwait(false);
68 |
69 | // Return the data.
70 | return aliases.Select(alias => response.Data.ContainsKey(alias) ? response.Data[alias] : -1).ToList();
71 | }
72 |
73 | ///
74 | /// Retrieves the ID for a property definition with a given alias in the vault.
75 | ///
76 | /// The aliases for the property definition.
77 | /// A cancellation token for the request.
78 | /// A collection of resolved IDs.
79 | /// Returns -1 if the alias cannot be resolved (e.g. no property definitions have the alias, or more than one does).
80 | public List GetPropertyDefIDsByAliases(CancellationToken token = default, params string[] aliases)
81 | {
82 | // Execute the async method.
83 | return this.GetPropertyDefIDsByAliasesAsync(token, aliases)
84 | .ConfigureAwait(false)
85 | .GetAwaiter()
86 | .GetResult();
87 | }
88 |
89 | ///
90 | /// Retrieves the ID for a property definition with a given alias in the vault.
91 | ///
92 | /// The alias for the property definition.
93 | /// A cancellation token for the request.
94 | /// An awaitable task for the request.
95 | /// Returns -1 if the alias cannot be resolved (e.g. no property definitions have the alias, or more than one does).
96 | /// Only available in M-Files 12.0.6768.0 upwards.
97 | public int GetPropertyDefIDByAlias(string alias, CancellationToken token = default)
98 | {
99 | // Use the other overload.
100 | var output = this.GetPropertyDefIDsByAliases(token, aliases: new string[] { alias });
101 | return output?.Count == 1
102 | ? output[0]
103 | : -1;
104 | }
105 |
106 | #endregion
107 |
108 | ///
109 | /// Gets all property definitions in the vault.
110 | ///
111 | /// A cancellation token for the request.
112 | /// All property definitions in the vault.
113 | /// This may be filtered by the user's permissions.
114 | public async Task> GetPropertyDefsAsync(CancellationToken token = default)
115 | {
116 | // Create the request.
117 | var request = new RestRequest($"/REST/structure/properties");
118 |
119 | // Make the request and get the response.
120 | var response = await this.MFWSClient.Get>(request, token)
121 | .ConfigureAwait(false);
122 |
123 | // Return the data.
124 | return response.Data;
125 | }
126 |
127 | ///
128 | /// Gets all property definitions in the vault.
129 | ///
130 | /// A cancellation token for the request.
131 | /// All property definitions in the vault.
132 | /// This may be filtered by the user's permissions.
133 | public List GetPropertyDefs(CancellationToken token = default)
134 | {
135 | // Execute the async method.
136 | return this.GetPropertyDefsAsync(token)
137 | .ConfigureAwait(false)
138 | .GetAwaiter()
139 | .GetResult();
140 | }
141 |
142 | ///
143 | /// Gets a single property definition in the vault.
144 | ///
145 | /// The Id of the property definition to retrieve.
146 | /// A cancellation token for the request.
147 | /// The property definition.
148 | /// This may be affected by the user's permissions.
149 | public async Task GetPropertyDefAsync(int propertyDefId, CancellationToken token = default)
150 | {
151 | // Create the request.
152 | var request = new RestRequest($"/REST/structure/properties/{propertyDefId}");
153 |
154 | // Make the request and get the response.
155 | var response = await this.MFWSClient.Get(request, token)
156 | .ConfigureAwait(false);
157 |
158 | // Return the data.
159 | return response.Data;
160 | }
161 |
162 | ///
163 | /// Gets a single property definition in the vault.
164 | ///
165 | /// The Id of the property definition to retrieve.
166 | /// A cancellation token for the request.
167 | /// The property definition.
168 | /// This may be affected by the user's permissions.
169 | public PropertyDef GetPropertyDef(int propertyDefId, CancellationToken token = default)
170 | {
171 | // Execute the async method.
172 | return this.GetPropertyDefAsync(propertyDefId, token)
173 | .ConfigureAwait(false)
174 | .GetAwaiter()
175 | .GetResult();
176 | }
177 | }
178 | }
179 |
--------------------------------------------------------------------------------
/MFaaP.MFWSClient.Tests/MFWSVaultAutomaticMetadataOperations.cs:
--------------------------------------------------------------------------------
1 | using System.Collections.Generic;
2 | using System.Linq;
3 | using System.Threading.Tasks;
4 | using Microsoft.VisualStudio.TestTools.UnitTesting;
5 | using RestSharp;
6 |
7 | namespace MFaaP.MFWSClient.Tests
8 | {
9 | [TestClass]
10 | public class MFWSVaultAutomaticMetadataOperations
11 | {
12 |
13 | #region GetAutomaticMetadataAsync
14 |
15 | ///
16 | /// Ensures that a call to
17 | /// requests the correct resource address with the correct method.
18 | ///
19 | [TestMethod]
20 | public async Task GetAutomaticMetadataAsync()
21 | {
22 | // Create our test runner.
23 | var runner = new RestApiTestRunner>(Method.Post, "/REST/objects/automaticmetadata.aspx");
24 |
25 | // Execute.
26 | await runner.MFWSClient.AutomaticMetadataOperations.GetAutomaticMetadataAsync();
27 |
28 | // Verify.
29 | runner.Verify();
30 | }
31 |
32 | ///
33 | /// Ensures that a call to
34 | /// requests the correct resource address with the correct method.
35 | ///
36 | [TestMethod]
37 | public void GetAutomaticMetadata()
38 | {
39 | // Create our test runner.
40 | var runner = new RestApiTestRunner>(Method.Post, "/REST/objects/automaticmetadata.aspx");
41 |
42 | // Execute.
43 | runner.MFWSClient.AutomaticMetadataOperations.GetAutomaticMetadata();
44 |
45 | // Verify.
46 | runner.Verify();
47 | }
48 |
49 | #endregion
50 |
51 | #region GetAutomaticMetadataForObject
52 |
53 | ///
54 | /// Ensures that a call to
55 | /// requests the correct resource address with the correct method.
56 | ///
57 | [TestMethod]
58 | public async Task GetAutomaticMetadataForObjectAsync()
59 | {
60 | // Create our test runner.
61 | var runner = new RestApiTestRunner>(Method.Post, "/REST/objects/automaticmetadata.aspx");
62 |
63 | // Set up the expected body.
64 | var body = new AutomaticMetadataRequestInfo()
65 | {
66 | ObjVer = new ObjVer()
67 | {
68 | Type = 0,
69 | ID = 43,
70 | Version = 0
71 | }
72 | };
73 | runner.SetExpectedRequestBody(body);
74 |
75 | // Execute.
76 | await runner.MFWSClient.AutomaticMetadataOperations.GetAutomaticMetadataForObjectAsync(body.ObjVer);
77 |
78 | // Verify.
79 | runner.Verify();
80 | }
81 |
82 | ///
83 | /// Ensures that a call to
84 | /// requests the correct resource address with the correct method.
85 | ///
86 | [TestMethod]
87 | public void GetAutomaticMetadataForObject()
88 | {
89 | // Create our test runner.
90 | var runner = new RestApiTestRunner>(Method.Post, "/REST/objects/automaticmetadata.aspx");
91 |
92 | // Set up the expected body.
93 | var body = new AutomaticMetadataRequestInfo()
94 | {
95 | ObjVer = new ObjVer()
96 | {
97 | Type = 0,
98 | ID = 43,
99 | Version = 0
100 | }
101 | };
102 | runner.SetExpectedRequestBody(body);
103 |
104 | // Execute.
105 | runner.MFWSClient.AutomaticMetadataOperations.GetAutomaticMetadataForObject(body.ObjVer);
106 |
107 | // Verify.
108 | runner.Verify();
109 | }
110 |
111 | #endregion
112 |
113 | #region GetAutomaticMetadataForTemporaryFiles
114 |
115 | ///
116 | /// Ensures that a call to
117 | /// requests the correct resource address with the correct method.
118 | ///
119 | [TestMethod]
120 | public async Task GetAutomaticMetadataForTemporaryFileAsync()
121 | {
122 | // Create our test runner.
123 | var runner = new RestApiTestRunner>(Method.Post, "/REST/objects/automaticmetadata.aspx");
124 |
125 | // Set up the expected body.
126 | var body = new AutomaticMetadataRequestInfo()
127 | {
128 | UploadIds = new List() { 123 }
129 | };
130 | runner.SetExpectedRequestBody(body);
131 |
132 | // Execute.
133 | await runner.MFWSClient.AutomaticMetadataOperations.GetAutomaticMetadataForTemporaryFileAsync(body.UploadIds.First());
134 |
135 | // Verify.
136 | runner.Verify();
137 | }
138 |
139 | ///
140 | /// Ensures that a call to
141 | /// requests the correct resource address with the correct method.
142 | ///
143 | [TestMethod]
144 | public void GetAutomaticMetadataForTemporaryFile()
145 | {
146 | // Create our test runner.
147 | var runner = new RestApiTestRunner>(Method.Post, "/REST/objects/automaticmetadata.aspx");
148 |
149 | // Set up the expected body.
150 | var body = new AutomaticMetadataRequestInfo()
151 | {
152 | UploadIds = new List() { 123 }
153 | };
154 | runner.SetExpectedRequestBody(body);
155 |
156 | // Execute.
157 | runner.MFWSClient.AutomaticMetadataOperations.GetAutomaticMetadataForTemporaryFile(body.UploadIds.First());
158 |
159 | // Verify.
160 | runner.Verify();
161 | }
162 |
163 | ///
164 | /// Ensures that a call to
165 | /// requests the correct resource address with the correct method.
166 | ///
167 | [TestMethod]
168 | public async Task GetAutomaticMetadataForTemporaryFilesAsync()
169 | {
170 | // Create our test runner.
171 | var runner = new RestApiTestRunner>(Method.Post, "/REST/objects/automaticmetadata.aspx");
172 |
173 | // Set up the expected body.
174 | var body = new AutomaticMetadataRequestInfo()
175 | {
176 | UploadIds = new List() { 123, 456 }
177 | };
178 | runner.SetExpectedRequestBody(body);
179 |
180 | // Execute.
181 | await runner.MFWSClient.AutomaticMetadataOperations.GetAutomaticMetadataForTemporaryFilesAsync(temporaryFileIds: body.UploadIds.ToArray());
182 |
183 | // Verify.
184 | runner.Verify();
185 | }
186 |
187 | ///
188 | /// Ensures that a call to
189 | /// requests the correct resource address with the correct method.
190 | ///
191 | [TestMethod]
192 | public void GetAutomaticMetadataForTemporaryFiles()
193 | {
194 | // Create our test runner.
195 | var runner =
196 | new RestApiTestRunner>(Method.Post, "/REST/objects/automaticmetadata.aspx");
197 |
198 | // Set up the expected body.
199 | var body = new AutomaticMetadataRequestInfo()
200 | {
201 | UploadIds = new List() { 123, 456 }
202 | };
203 | runner.SetExpectedRequestBody(body);
204 |
205 | // Execute.
206 | runner.MFWSClient.AutomaticMetadataOperations.GetAutomaticMetadataForTemporaryFiles(temporaryFileIds: body.UploadIds.ToArray());
207 |
208 | // Verify.
209 | runner.Verify();
210 | }
211 |
212 | #endregion
213 |
214 | }
215 | }
216 |
--------------------------------------------------------------------------------
/MFaaP.MFWSClient.Tests/MFWSVaultClassOperations.cs:
--------------------------------------------------------------------------------
1 | using System.Collections.Generic;
2 | using System.Threading.Tasks;
3 | using Microsoft.VisualStudio.TestTools.UnitTesting;
4 | using Newtonsoft.Json.Linq;
5 | using RestSharp;
6 |
7 | namespace MFaaP.MFWSClient.Tests
8 | {
9 | [TestClass]
10 | public class MFWSVaultClassOperations
11 | {
12 |
13 | #region Object type alias to ID resolution
14 |
15 | ///
16 | /// Ensures that a call to
17 | /// requests the correct resource address with the correct method.
18 | ///
19 | [TestMethod]
20 | public async Task GetObjectClassIDByAliasAsync()
21 | {
22 | // Create our test runner.
23 | var runner = new RestApiTestRunner>(Method.Post, "/REST/structure/classes/itemidbyalias.aspx");
24 |
25 | // Set up the expected body.
26 | var body = new JArray { "hello world" };
27 | runner.SetExpectedRequestBody(body);
28 |
29 | // Execute.
30 | await runner.MFWSClient.ClassOperations.GetObjectClassIDByAliasAsync("hello world");
31 |
32 | // Verify.
33 | runner.Verify();
34 | }
35 |
36 | ///
37 | /// Ensures that a call to
38 | /// requests the correct resource address with the correct method.
39 | ///
40 | [TestMethod]
41 | public async Task GetObjectClassIDsByAliasesAsync()
42 | {
43 | // Create our test runner.
44 | var runner = new RestApiTestRunner>(Method.Post, "/REST/structure/classes/itemidbyalias.aspx");
45 |
46 | // Set up the expected body.
47 | var body = new JArray { "hello", "world", "third option" };
48 | runner.SetExpectedRequestBody(body);
49 |
50 | // Execute.
51 | await runner.MFWSClient.ClassOperations.GetObjectClassIDsByAliasesAsync(aliases: new string[] { "hello", "world", "third option" });
52 |
53 | // Verify.
54 | runner.Verify();
55 | }
56 |
57 | ///
58 | /// Ensures that a call to
59 | /// requests the correct resource address with the correct method.
60 | ///
61 | [TestMethod]
62 | public void GetObjectClassIDsByAliases()
63 | {
64 | // Create our test runner.
65 | var runner = new RestApiTestRunner>(Method.Post, "/REST/structure/classes/itemidbyalias.aspx");
66 |
67 | // Set up the expected body.
68 | var body = new JArray { "hello", "world", "third option" };
69 | runner.SetExpectedRequestBody(body);
70 |
71 | // Execute.
72 | runner.MFWSClient.ClassOperations.GetObjectClassIDsByAliases(aliases: new string[] { "hello", "world", "third option" });
73 |
74 | // Verify.
75 | runner.Verify();
76 | }
77 |
78 | ///
79 | /// Ensures that a call to
80 | /// requests the correct resource address with the correct method.
81 | ///
82 | [TestMethod]
83 | public void GetObjectClassIDByAlias()
84 | {
85 | // Create our test runner.
86 | var runner = new RestApiTestRunner>(Method.Post, "/REST/structure/classes/itemidbyalias.aspx");
87 |
88 | // Set up the expected body.
89 | var body = new JArray { "hello world" };
90 | runner.SetExpectedRequestBody(body);
91 |
92 | // Execute.
93 | runner.MFWSClient.ClassOperations.GetObjectClassIDByAlias("hello world");
94 |
95 | // Verify.
96 | runner.Verify();
97 | }
98 |
99 | #endregion
100 |
101 | #region GetAllObjectClasses
102 |
103 | ///
104 | /// Ensures that a call to
105 | /// requests the correct resource address with the correct method.
106 | ///
107 | [TestMethod]
108 | public async Task GetAllObjectClassesAsync()
109 | {
110 | // Create our test runner.
111 | var runner = new RestApiTestRunner>(Method.Get, "/REST/structure/classes.aspx");
112 |
113 | // Execute.
114 | await runner.MFWSClient.ClassOperations.GetAllObjectClassesAsync();
115 |
116 | // Verify.
117 | runner.Verify();
118 | }
119 |
120 | ///
121 | /// Ensures that a call to
122 | /// requests the correct resource address with the correct method.
123 | ///
124 | [TestMethod]
125 | public void GetAllObjectClasses()
126 | {
127 | // Create our test runner.
128 | var runner = new RestApiTestRunner>(Method.Get, "/REST/structure/classes.aspx");
129 |
130 | // Execute.
131 | runner.MFWSClient.ClassOperations.GetAllObjectClasses();
132 |
133 | // Verify.
134 | runner.Verify();
135 | }
136 |
137 | #endregion
138 |
139 | #region GetObjectClasses
140 |
141 | ///
142 | /// Ensures that a call to
143 | /// requests the correct resource address with the correct method.
144 | ///
145 | [TestMethod]
146 | public async Task GetObjectClassesAsync()
147 | {
148 | // Create our test runner.
149 | var runner = new RestApiTestRunner>(Method.Get, "/REST/structure/classes.aspx?objtype=0");
150 |
151 | // Execute.
152 | await runner.MFWSClient.ClassOperations.GetObjectClassesAsync(0);
153 |
154 | // Verify.
155 | runner.Verify();
156 | }
157 |
158 | ///
159 | /// Ensures that a call to
160 | /// requests the correct resource address with the correct method.
161 | ///
162 | [TestMethod]
163 | public void GetObjectClasses()
164 | {
165 | // Create our test runner.
166 | var runner = new RestApiTestRunner>(Method.Get, "/REST/structure/classes.aspx?objtype=0");
167 |
168 | // Execute.
169 | runner.MFWSClient.ClassOperations.GetObjectClasses(0);
170 |
171 | // Verify.
172 | runner.Verify();
173 | }
174 |
175 | #endregion
176 |
177 | #region GetObjectClass
178 |
179 | ///
180 | /// Ensures that a call to
181 | /// requests the correct resource address with the correct method.
182 | ///
183 | [TestMethod]
184 | public async Task GetObjectClassAsync()
185 | {
186 | // Create our test runner.
187 | var runner = new RestApiTestRunner(Method.Get, "/REST/structure/classes/0.aspx");
188 |
189 | // Execute.
190 | await runner.MFWSClient.ClassOperations.GetObjectClassAsync(classId: 0);
191 |
192 | // Verify.
193 | runner.Verify();
194 | }
195 |
196 | ///
197 | /// Ensures that a call to
198 | /// requests the correct resource address with the correct method.
199 | ///
200 | [TestMethod]
201 | public void GetObjectClass()
202 | {
203 | // Create our test runner.
204 | var runner = new RestApiTestRunner(Method.Get, "/REST/structure/classes/0.aspx");
205 |
206 | // Execute.
207 | runner.MFWSClient.ClassOperations.GetObjectClass(classId: 0);
208 |
209 | // Verify.
210 | runner.Verify();
211 | }
212 |
213 | #endregion
214 |
215 | #region GetObjectClass (with templates)
216 |
217 | ///
218 | /// Ensures that a call to
219 | /// requests the correct resource address with the correct method.
220 | ///
221 | [TestMethod]
222 | public async Task GetObjectClassAsync_WithTemplates()
223 | {
224 | // Create our test runner.
225 | var runner = new RestApiTestRunner(Method.Get, "/REST/structure/classes/0.aspx?include=templates");
226 |
227 | // Execute.
228 | await runner.MFWSClient.ClassOperations.GetObjectClassAsync(classId: 0, includeTemplates: true);
229 |
230 | // Verify.
231 | runner.Verify();
232 | }
233 |
234 | ///
235 | /// Ensures that a call to
236 | /// requests the correct resource address.
237 | ///
238 | [TestMethod]
239 | public void GetObjectClass_WithTemplates()
240 | {
241 | // Create our test runner.
242 | var runner = new RestApiTestRunner(Method.Get, "/REST/structure/classes/0.aspx?include=templates");
243 |
244 | // Execute.
245 | runner.MFWSClient.ClassOperations.GetObjectClass(classId: 0, includeTemplates: true);
246 |
247 | // Verify.
248 | runner.Verify();
249 | }
250 |
251 | #endregion
252 |
253 | }
254 | }
255 |
--------------------------------------------------------------------------------
/MFaaP.MFWSClient/MFWSVaultViewOperations.cs:
--------------------------------------------------------------------------------
1 | using System.Collections.Generic;
2 | using System.Net;
3 | using System.Threading;
4 | using System.Threading.Tasks;
5 | using MFaaP.MFWSClient.ExtensionMethods;
6 | using RestSharp;
7 |
8 | namespace MFaaP.MFWSClient
9 | {
10 | ///
11 | /// View operations.
12 | ///
13 | public class MFWSVaultViewOperations
14 | : MFWSVaultOperationsBase
15 | {
16 |
17 | ///
18 | public MFWSVaultViewOperations(MFWSClientBase client)
19 | : base(client)
20 | {
21 | }
22 |
23 | ///
24 | /// Gets the contents of the root ("home") view.
25 | ///
26 | /// The contents of the view.
27 | /// A cancellation token for the request.
28 | /// Identical to calling with no parameters.
29 | public Task GetRootFolderContentsAsync(CancellationToken token = default)
30 | {
31 | // Get the root view contents.
32 | return this.GetFolderContentsAsync(token);
33 | }
34 |
35 | ///
36 | /// Gets the contents of the root ("home") view.
37 | ///
38 | /// The contents of the view.
39 | /// A cancellation token for the request.
40 | /// Identical to calling with no parameters.
41 | public FolderContentItems GetRootFolderContents(CancellationToken token = default)
42 | {
43 | // Execute the async method.
44 | return this.GetRootFolderContentsAsync(token)
45 | .ConfigureAwait(false)
46 | .GetAwaiter()
47 | .GetResult();
48 | }
49 |
50 | ///
51 | /// Gets the contents of the view specified by the .
52 | ///
53 | /// A collection representing the view depth.
54 | /// Should contain zero or more s representing the view being shown,
55 | /// then zero or more s representing the appropriate property groups being shown.
56 | /// The contents of the view.
57 | public Task GetFolderContentsAsync(params FolderContentItem[] items)
58 | {
59 | return this.GetFolderContentsAsync(CancellationToken.None, items);
60 | }
61 |
62 | ///
63 | /// Gets the contents of the view specified by the .
64 | ///
65 | /// A collection representing the view depth.
66 | /// Should contain zero or more s representing the view being shown,
67 | /// then zero or more s representing the appropriate property groups being shown.
68 | /// The contents of the view.
69 | public FolderContentItems GetFolderContents(params FolderContentItem[] items)
70 | {
71 | // Execute the async method.
72 | return this.GetFolderContentsAsync(items)
73 | .ConfigureAwait(false)
74 | .GetAwaiter()
75 | .GetResult();
76 | }
77 |
78 | ///
79 | /// Gets the contents of the view specified by the .
80 | ///
81 | /// A view path, formatted as per http://www.m-files.com/mfws/syntax.html#sect:viewpath.
82 | /// A cancellation token for the request.
83 | /// The contents of the view.
84 | public async Task GetFolderContentsAsync(CancellationToken token, string path)
85 | {
86 | // Sanity.
87 | if (false == string.IsNullOrWhiteSpace(path))
88 | {
89 | // If the path is not blank then it must end with a slash.
90 | if (false == path.EndsWith("/"))
91 | path += "/";
92 |
93 | // It cannot start with a slash.
94 | if (path.StartsWith("/"))
95 | path = path.Substring(1);
96 | }
97 |
98 | // Create the request.
99 | var request = new RestRequest($"/REST/views/{path}items");
100 |
101 | // Make the request and get the response.
102 | var response = await this.MFWSClient.Get(request, token)
103 | .ConfigureAwait(false);
104 |
105 | // Return the data.
106 | return response.Data;
107 | }
108 |
109 | ///
110 | /// Gets the contents of the view specified by the .
111 | ///
112 | /// A view path, formatted as per http://www.m-files.com/mfws/syntax.html#sect:viewpath.
113 | /// The contents of the view.
114 | public Task GetFolderContentsAsync(string path)
115 | {
116 | // Execute the async method.
117 | return this.GetFolderContentsAsync(CancellationToken.None, path);
118 | }
119 |
120 | ///
121 | /// Gets the contents of the view specified by the .
122 | ///
123 | /// A view path, formatted as per http://www.m-files.com/mfws/syntax.html#sect:viewpath.
124 | /// A cancellation token for the request.
125 | /// The contents of the view.
126 | public FolderContentItems GetFolderContents(CancellationToken token, string path)
127 | {
128 | // Execute the async method.
129 | return this.GetFolderContentsAsync(token, path)
130 | .ConfigureAwait(false)
131 | .GetAwaiter()
132 | .GetResult();
133 | }
134 |
135 | ///
136 | /// Gets the contents of the view specified by the .
137 | ///
138 | /// A view path, formatted as per http://www.m-files.com/mfws/syntax.html#sect:viewpath.
139 | /// The contents of the view.
140 | public FolderContentItems GetFolderContents(string path)
141 | {
142 | // Execute the async method.
143 | return this.GetFolderContents(CancellationToken.None, path);
144 | }
145 |
146 | ///
147 | /// Gets the contents of the view specified by the .
148 | ///
149 | /// A collection representing the view depth.
150 | /// Should contain zero or more s representing the view being shown,
151 | /// then zero or more s representing the appropriate property groups being shown.
152 | /// A cancellation token for the request.
153 | /// The contents of the view.
154 | public Task GetFolderContentsAsync(CancellationToken token, params FolderContentItem[] items)
155 | {
156 | return this.GetFolderContentsAsync(token, items.GetPath());
157 | }
158 |
159 | ///
160 | /// Gets the contents of the view specified by the .
161 | ///
162 | /// A collection representing the view depth.
163 | /// Should contain zero or more s representing the view being shown,
164 | /// then zero or more s representing the appropriate property groups being shown.
165 | /// A cancellation token for the request.
166 | /// The contents of the view.
167 | public FolderContentItems GetFolderContents(CancellationToken token, params FolderContentItem[] items)
168 | {
169 | // Execute the async method.
170 | return this.GetFolderContentsAsync(token, items)
171 | .ConfigureAwait(false)
172 | .GetAwaiter()
173 | .GetResult();
174 | }
175 |
176 | ///
177 | /// Gets the contents of a built-in view.
178 | ///
179 | /// An enumeration of the built-in view to retrieve.
180 | /// A cancellation token for the request.
181 | /// The favorited items.
182 | public async Task> GetFolderContentsAsync(MFBuiltInView builtInView, CancellationToken token = default)
183 | {
184 | // Create the request.
185 | var request = new RestRequest($"/REST/views/v{(int)builtInView}/items");
186 |
187 | // Make the request and get the response.
188 | var response = await this.MFWSClient.Get>(request, token)
189 | .ConfigureAwait(false);
190 |
191 | // Return the data.
192 | return response.Data;
193 | }
194 |
195 | ///
196 | /// Gets the contents of a built-in view.
197 | ///
198 | /// An enumeration of the built-in view to retrieve.
199 | /// A cancellation token for the request.
200 | /// The favorited items.
201 | public List GetFolderContents(MFBuiltInView builtInView, CancellationToken token = default)
202 | {
203 | // Execute the async method.
204 | return this.GetFolderContentsAsync(builtInView, token)
205 | .ConfigureAwait(false)
206 | .GetAwaiter()
207 | .GetResult();
208 | }
209 | }
210 | }
211 |
--------------------------------------------------------------------------------
/MFaaP.MFWSClient/MFWSVaultClassOperations.cs:
--------------------------------------------------------------------------------
1 | using System;
2 | using System.Collections.Generic;
3 | using System.Linq;
4 | using System.Threading;
5 | using System.Threading.Tasks;
6 | using RestSharp;
7 |
8 | namespace MFaaP.MFWSClient
9 | {
10 | ///
11 | /// Methods to create and modify objects.
12 | ///
13 | public class MFWSVaultClassOperations
14 | : MFWSVaultOperationsBase
15 | {
16 | ///
17 | /// Creates a new object.
18 | ///
19 | /// The client to interact with the server.
20 | internal MFWSVaultClassOperations(MFWSClientBase client)
21 | : base(client)
22 | {
23 | }
24 |
25 | #region Class alias to ID resolution
26 |
27 | ///
28 | /// Retrieves the ID for a class with a given alias in the vault.
29 | ///
30 | /// The alias for the class.
31 | /// A cancellation token for the request.
32 | /// An awaitable task for the request.
33 | /// Returns -1 if the alias cannot be resolved (e.g. no classes have the alias, or more than one does).
34 | /// Only available in M-Files 12.0.6768.0 upwards.
35 | public async Task GetObjectClassIDByAliasAsync(string alias, CancellationToken token = default)
36 | {
37 | // Use the other overload.
38 | var output = await this.GetObjectClassIDsByAliasesAsync(token, aliases: new string[] { alias });
39 | return output?.Count == 1
40 | ? output[0]
41 | : -1;
42 | }
43 |
44 | ///
45 | /// Retrieves the IDs for classes with given aliases in the vault.
46 | ///
47 | /// The aliases for the class.
48 | /// A cancellation token for the request.
49 | /// An awaitable task for the request.
50 | /// Returns -1 if the alias cannot be resolved (e.g. no object type have the alias, or more than one does).
51 | /// Only available in M-Files 12.0.6768.0 upwards.
52 | public async Task> GetObjectClassIDsByAliasesAsync(CancellationToken token = default, params string[] aliases)
53 | {
54 | // Sanity.
55 | if (null == aliases)
56 | throw new ArgumentNullException(nameof(aliases));
57 | if (0 == aliases.Length)
58 | return new List();
59 |
60 | // Create the request.
61 | var request = new RestRequest($"/REST/structure/classes/itemidbyalias.aspx");
62 |
63 | // Assign the body.
64 | request.AddJsonBody(aliases);
65 |
66 | // Make the request and get the response.
67 | var response = await this.MFWSClient.Post>(request, token)
68 | .ConfigureAwait(false);
69 |
70 | // Return the data.
71 | return aliases.Select(alias => response.Data.ContainsKey(alias) ? response.Data[alias] : -1).ToList();
72 | }
73 |
74 | ///
75 | /// Retrieves the IDs for classes with given aliases in the vault.
76 | ///
77 | /// The aliases for the class.
78 | /// A cancellation token for the request.
79 | /// An awaitable task for the request.
80 | /// Returns -1 if the alias cannot be resolved (e.g. no object type have the alias, or more than one does).
81 | public List GetObjectClassIDsByAliases(CancellationToken token = default, params string[] aliases)
82 | {
83 | // Execute the async method.
84 | return this.GetObjectClassIDsByAliasesAsync(token, aliases)
85 | .ConfigureAwait(false)
86 | .GetAwaiter()
87 | .GetResult();
88 | }
89 |
90 | ///
91 | /// Retrieves the ID for a class with a given alias in the vault.
92 | ///
93 | /// The alias for the class.
94 | /// A cancellation token for the request.
95 | /// An awaitable task for the request.
96 | /// Returns -1 if the alias cannot be resolved (e.g. no classes have the alias, or more than one does).
97 | /// Only available in M-Files 12.0.6768.0 upwards.
98 | public int GetObjectClassIDByAlias(string alias, CancellationToken token = default)
99 | {
100 | // Use the other overload.
101 | var output = this.GetObjectClassIDsByAliases(token, aliases: new string[] { alias });
102 | return output?.Count == 1
103 | ? output[0]
104 | : -1;
105 | }
106 |
107 | #endregion
108 |
109 | ///
110 | /// Gets a specific object class from the server, optionally including details on templates for that class.
111 | ///
112 | /// The Id of the class to load.
113 | /// If true, information on the templates will be returned.
114 | /// A cancellation token for the request.
115 | /// The class in the vault.
116 | /// This may be filtered by the user's permissions.
117 | public async Task GetObjectClassAsync(int classId, bool includeTemplates = false, CancellationToken token = default)
118 | {
119 | // Create the request.
120 | var request = new RestRequest($"/REST/structure/classes/{classId}.aspx");
121 |
122 | // Templates?
123 | if (includeTemplates)
124 | {
125 | request.Resource += "?include=templates";
126 | }
127 |
128 | // Make the request and get the response.
129 | var response = await this.MFWSClient.Get(request, token)
130 | .ConfigureAwait(false);
131 |
132 | // Return the data.
133 | return response.Data;
134 | }
135 |
136 | ///
137 | /// Gets a specific object class from the server, optionally including details on templates for that class.
138 | ///
139 | /// The Id of the class to load.
140 | /// If true, information on the templates will be returned.
141 | /// A cancellation token for the request.
142 | /// The class in the vault.
143 | /// This may be filtered by the user's permissions.
144 | public ExtendedObjectClass GetObjectClass(int classId, bool includeTemplates = false, CancellationToken token = default)
145 | {
146 | // Execute the async method.
147 | return this.GetObjectClassAsync(classId, includeTemplates, token)
148 | .ConfigureAwait(false)
149 | .GetAwaiter()
150 | .GetResult();
151 | }
152 |
153 | ///
154 | /// Gets a list of all classes in the vault.
155 | ///
156 | /// A cancellation token for the request.
157 | /// All classes in the vault.
158 | /// This may be filtered by the user's permissions.
159 | public async Task> GetAllObjectClassesAsync(CancellationToken token = default)
160 | {
161 | // Create the request.
162 | var request = new RestRequest($"/REST/structure/classes.aspx");
163 |
164 | // Make the request and get the response.
165 | var response = await this.MFWSClient.Get>(request, token)
166 | .ConfigureAwait(false);
167 |
168 | // Return the data.
169 | return response.Data;
170 | }
171 |
172 | ///
173 | /// Gets a list of all classes in the vault.
174 | ///
175 | /// A cancellation token for the request.
176 | /// All classes in the vault.
177 | /// This may be filtered by the user's permissions.
178 | public List GetAllObjectClasses(CancellationToken token = default)
179 | {
180 | // Execute the async method.
181 | return this.GetAllObjectClassesAsync(token)
182 | .ConfigureAwait(false)
183 | .GetAwaiter()
184 | .GetResult();
185 | }
186 |
187 | ///
188 | /// Gets a list of all classes in the vault for a given object type.
189 | ///
190 | /// The type of the object.
191 | /// A cancellation token for the request.
192 | /// All classes in the vault for the supplied object type.
193 | /// This may be filtered by the user's permissions.
194 | public async Task> GetObjectClassesAsync(int objectTypeId, CancellationToken token = default)
195 | {
196 | // Create the request.
197 | var request = new RestRequest($"/REST/structure/classes.aspx?objtype={objectTypeId}");
198 |
199 | // Make the request and get the response.
200 | var response = await this.MFWSClient.Get>(request, token)
201 | .ConfigureAwait(false);
202 |
203 | // Return the data.
204 | return response.Data;
205 | }
206 |
207 | ///
208 | /// Gets a list of all classes in the vault for a given object type.
209 | ///
210 | /// The type of the object.
211 | /// A cancellation token for the request.
212 | /// All classes in the vault for the supplied object type.
213 | /// This may be filtered by the user's permissions.
214 | public List GetObjectClasses(int objectTypeId, CancellationToken token = default)
215 | {
216 | // Execute the async method.
217 | return this.GetObjectClassesAsync(objectTypeId, token)
218 | .ConfigureAwait(false)
219 | .GetAwaiter()
220 | .GetResult();
221 | }
222 | }
223 |
224 | }
225 |
--------------------------------------------------------------------------------
/MFaaP.MFWSClient.Tests/MFWSVaultExtensionAuthenticationOperations.cs:
--------------------------------------------------------------------------------
1 | using System;
2 | using System.Collections.Generic;
3 | using System.Threading.Tasks;
4 | using System.Web;
5 | using Microsoft.VisualStudio.TestTools.UnitTesting;
6 | using RestSharp;
7 |
8 | namespace MFaaP.MFWSClient.Tests
9 | {
10 | [TestClass]
11 | public class MFWSVaultExtensionAuthenticationOperations
12 | {
13 |
14 | #region Retrieval of external repository information
15 |
16 | ///
17 | /// Ensures that a call to
18 | /// requests the correct resource address with the correct method.
19 | ///
20 | [TestMethod]
21 | public async Task GetExtensionAuthenticationTargetsAsync()
22 | {
23 | // Create our test runner.
24 | var runner = new RestApiTestRunner>(Method.Get, "/REST/repositories.aspx");
25 |
26 | // Execute.
27 | await runner.MFWSClient.ExtensionAuthenticationOperations.GetExtensionAuthenticationTargetsAsync();
28 |
29 | // Verify.
30 | runner.Verify();
31 | }
32 |
33 | ///
34 | /// Ensures that a call to
35 | /// requests the correct resource address with the correct method.
36 | ///
37 | [TestMethod]
38 | public void GetExtensionAuthenticationTargets()
39 | {
40 | // Create our test runner.
41 | var runner = new RestApiTestRunner>(Method.Get, "/REST/repositories.aspx");
42 |
43 | // Execute.
44 | runner.MFWSClient.ExtensionAuthenticationOperations.GetExtensionAuthenticationTargets();
45 |
46 | // Verify.
47 | runner.Verify();
48 | }
49 |
50 | #endregion
51 |
52 | #region Logging into external repository connection
53 |
54 | ///
55 | /// Ensures that a call to
56 | /// requests the correct resource address with the correct method.
57 | ///
58 | [TestMethod]
59 | public async Task LogInWithExtensionAuthenticationAsync()
60 | {
61 | // Set the target ID.
62 | var targetID = "hello world";
63 |
64 | // Create our test runner.
65 | var runner = new RestApiTestRunner(Method.Post, $"/REST/repositories/{HttpUtility.UrlEncode(targetID)}/session.aspx");
66 |
67 | // Create the body.
68 | var authentication = new RepositoryAuthentication()
69 | {
70 | ConfigurationName = "hello"
71 | };
72 |
73 | // Set the expected body.
74 | runner.SetExpectedRequestBody(authentication);
75 |
76 | // Execute.
77 | await runner.MFWSClient.ExtensionAuthenticationOperations.LogInWithExtensionAuthenticationAsync(targetID, authentication);
78 |
79 | // Verify.
80 | runner.Verify();
81 | }
82 |
83 | ///
84 | /// Ensures that a call to
85 | /// with a null target throws an exception.
86 | ///
87 | [TestMethod]
88 | [ExpectedException(typeof(ArgumentNullException))]
89 | public async Task LogInWithExtensionAuthenticationAsync_NullTarget()
90 | {
91 | // Create our test runner.
92 | var runner = new RestApiTestRunner(Method.Post, $"/REST/repositories//session.aspx");
93 |
94 | // Execute.
95 | await runner.MFWSClient.ExtensionAuthenticationOperations.LogInWithExtensionAuthenticationAsync(null, new RepositoryAuthentication());
96 |
97 | Assert.Fail("Expected exception not thrown.");
98 | }
99 |
100 | ///
101 | /// Ensures that a call to
102 | /// with an empty target throws an exception.
103 | ///
104 | [TestMethod]
105 | [ExpectedException(typeof(ArgumentException))]
106 | public async Task LogInWithExtensionAuthenticationAsync_EmptyTarget()
107 | {
108 | // Create our test runner.
109 | var runner = new RestApiTestRunner(Method.Post, $"/REST/repositories//session.aspx");
110 |
111 | // Execute.
112 | await runner.MFWSClient.ExtensionAuthenticationOperations.LogInWithExtensionAuthenticationAsync("", new RepositoryAuthentication());
113 |
114 | Assert.Fail("Expected exception not thrown.");
115 | }
116 |
117 | ///
118 | /// Ensures that a call to
119 | /// with null authentication throws an exception.
120 | ///
121 | [TestMethod]
122 | [ExpectedException(typeof(ArgumentNullException))]
123 | public async Task LogInWithExtensionAuthenticationAsync_NullAuthentication()
124 | {
125 | // Create our test runner.
126 | var runner = new RestApiTestRunner(Method.Post, $"/REST/repositories//session.aspx");
127 |
128 | // Execute.
129 | await runner.MFWSClient.ExtensionAuthenticationOperations.LogInWithExtensionAuthenticationAsync("hello world", null);
130 |
131 | Assert.Fail("Expected exception not thrown.");
132 | }
133 |
134 | ///
135 | /// Ensures that a call to
136 | /// with an empty/null authentication configuration name.
137 | ///
138 | [TestMethod]
139 | [ExpectedException(typeof(ArgumentException))]
140 | public async Task LogInWithExtensionAuthenticationAsync_EmptyAuthenticationConfiguration()
141 | {
142 | // Create our test runner.
143 | var runner = new RestApiTestRunner(Method.Post, $"/REST/repositories//session.aspx");
144 |
145 | // Execute.
146 | await runner.MFWSClient.ExtensionAuthenticationOperations.LogInWithExtensionAuthenticationAsync("hello world", new RepositoryAuthentication());
147 |
148 | Assert.Fail("Expected exception not thrown.");
149 | }
150 |
151 | ///
152 | /// Ensures that a call to
153 | /// requests the correct resource address with the correct method.
154 | ///
155 | [TestMethod]
156 | public void LogInWithExtensionAuthentication()
157 | {
158 | // Set the target ID.
159 | var targetID = "hello world";
160 |
161 | // Create our test runner.
162 | var runner = new RestApiTestRunner(Method.Post, $"/REST/repositories/{HttpUtility.UrlEncode(targetID)}/session.aspx");
163 |
164 | // Create the body.
165 | var authentication = new RepositoryAuthentication()
166 | {
167 | ConfigurationName = "hello"
168 | };
169 |
170 | // Set the expected body.
171 | runner.SetExpectedRequestBody(authentication);
172 |
173 | // Execute.
174 | runner.MFWSClient.ExtensionAuthenticationOperations.LogInWithExtensionAuthentication(targetID, authentication);
175 |
176 | // Verify.
177 | runner.Verify();
178 | }
179 |
180 | #endregion
181 |
182 | #region Logging out of external repository connection
183 |
184 | ///
185 | /// Ensures that a call to
186 | /// requests the correct resource address with the correct method.
187 | ///
188 | [TestMethod]
189 | public async Task LogOutWithExtensionAuthenticationAsync()
190 | {
191 | // Set the target ID.
192 | var targetID = "hello world";
193 |
194 | // Create our test runner.
195 | var runner = new RestApiTestRunner(Method.Delete, $"/REST/repositories/{HttpUtility.UrlEncode(targetID)}/session.aspx");
196 |
197 | // Execute.
198 | await runner.MFWSClient.ExtensionAuthenticationOperations.LogOutWithExtensionAuthenticationAsync(targetID);
199 |
200 | // Verify.
201 | runner.Verify();
202 | }
203 |
204 | ///
205 | /// Ensures that a call to
206 | /// with a null target throws an exception.
207 | ///
208 | [TestMethod]
209 | [ExpectedException(typeof(ArgumentNullException))]
210 | public async Task LogOutWithExtensionAuthenticationAsync_NullTarget()
211 | {
212 | // Create our test runner.
213 | var runner = new RestApiTestRunner(Method.Post, $"/REST/repositories//session.aspx");
214 |
215 | // Execute.
216 | await runner.MFWSClient.ExtensionAuthenticationOperations.LogOutWithExtensionAuthenticationAsync(null);
217 |
218 | Assert.Fail("Expected exception not thrown.");
219 | }
220 |
221 | ///
222 | /// Ensures that a call to
223 | /// with an empty target throws an exception.
224 | ///
225 | [TestMethod]
226 | [ExpectedException(typeof(ArgumentException))]
227 | public async Task LogOutWithExtensionAuthenticationAsync_EmptyTarget()
228 | {
229 | // Create our test runner.
230 | var runner = new RestApiTestRunner(Method.Post, $"/REST/repositories//session.aspx");
231 |
232 | // Execute.
233 | await runner.MFWSClient.ExtensionAuthenticationOperations.LogOutWithExtensionAuthenticationAsync("");
234 |
235 | Assert.Fail("Expected exception not thrown.");
236 | }
237 |
238 | ///
239 | /// Ensures that a call to
240 | /// requests the correct resource address with the correct method.
241 | ///
242 | [TestMethod]
243 | public void LogOutWithExtensionAuthentication()
244 | {
245 | // Set the target ID.
246 | var targetID = "hello world";
247 |
248 | // Create our test runner.
249 | var runner = new RestApiTestRunner(Method.Delete, $"/REST/repositories/{HttpUtility.UrlEncode(targetID)}/session.aspx");
250 |
251 | // Execute.
252 | runner.MFWSClient.ExtensionAuthenticationOperations.LogOutWithExtensionAuthentication(targetID);
253 |
254 | // Verify.
255 | runner.Verify();
256 | }
257 |
258 | #endregion
259 | }
260 | }
261 |
--------------------------------------------------------------------------------
/MFaaP.MFWSClient.Tests/MFWSVaultExtensionMethodOperations.cs:
--------------------------------------------------------------------------------
1 | using System;
2 | using System.Threading.Tasks;
3 | using Microsoft.VisualStudio.TestTools.UnitTesting;
4 | using Newtonsoft.Json;
5 | using RestSharp;
6 |
7 | namespace MFaaP.MFWSClient.Tests
8 | {
9 | [TestClass]
10 | public class MFWSVaultExtensionMethodOperations
11 | {
12 |
13 | #region Extension Method (no serialisation/deserialisation)
14 |
15 | ///
16 | /// Ensures that a call to
17 | /// requests the correct resource address with the correct method.
18 | ///
19 | [TestMethod]
20 | public async Task ExecuteExtensionMethodAsync()
21 | {
22 | // Create our test runner.
23 | var runner = new RestApiTestRunner(Method.Post, "/REST/vault/extensionmethod/HelloWorld.aspx");
24 |
25 | // Execute.
26 | await runner.MFWSClient.ExtensionMethodOperations.ExecuteVaultExtensionMethodAsync("HelloWorld");
27 |
28 | // Verify.
29 | runner.Verify();
30 | }
31 |
32 | ///
33 | /// Ensures that a call to
34 | /// requests the correct resource address with the correct method.
35 | ///
36 | [TestMethod]
37 | public void ExecuteExtensionMethod()
38 | {
39 | // Create our test runner.
40 | var runner = new RestApiTestRunner(Method.Post, "/REST/vault/extensionmethod/HelloWorld.aspx");
41 |
42 | // Execute.
43 | runner.MFWSClient.ExtensionMethodOperations.ExecuteVaultExtensionMethod("HelloWorld");
44 |
45 | // Verify.
46 | runner.Verify();
47 | }
48 |
49 | ///
50 | /// Ensures that a call to
51 | /// includes the correct request body.
52 | ///
53 | [TestMethod]
54 | public async Task ExecuteExtensionMethodAsync_CorrectRequestBody()
55 | {
56 | // Create our test runner.
57 | var runner = new RestApiTestRunner(Method.Post, "/REST/vault/extensionmethod/HelloWorld.aspx");
58 |
59 | // Set the request body.
60 | const string inputValue = "this is my test input value";
61 | runner.SetExpectedRequestBody(inputValue);
62 |
63 | // Execute.
64 | await runner.MFWSClient.ExtensionMethodOperations.ExecuteVaultExtensionMethodAsync("HelloWorld", input: inputValue);
65 |
66 | // Verify.
67 | runner.Verify();
68 | }
69 |
70 | ///
71 | /// Ensures that a call to
72 | /// includes the correct request body.
73 | ///
74 | [TestMethod]
75 | public void ExecuteExtensionMethod_CorrectRequestBody()
76 | {
77 | // Create our test runner.
78 | var runner = new RestApiTestRunner(Method.Post, "/REST/vault/extensionmethod/HelloWorld.aspx");
79 |
80 | // Set the request body.
81 | const string inputValue = "this is my test input value";
82 | runner.SetExpectedRequestBody(inputValue);
83 |
84 | // Execute.
85 | runner.MFWSClient.ExtensionMethodOperations.ExecuteVaultExtensionMethod("HelloWorld", input: inputValue);
86 |
87 | // Verify.
88 | runner.Verify();
89 | }
90 |
91 | ///
92 | /// Ensures that a call to
93 | /// returns the correct response.
94 | ///
95 | [TestMethod]
96 | public async Task ExecuteExtensionMethodAsync_CorrectOutput()
97 | {
98 | // Create our test runner.
99 | var runner = new RestApiTestRunner(Method.Post, "/REST/vault/extensionmethod/HelloWorld.aspx");
100 |
101 | // Set the request body.
102 | const string inputValue = "this is my test input value";
103 | runner.SetExpectedRequestBody(inputValue);
104 |
105 | // Set the response body.
106 | const string outputValue = "Return value";
107 | runner.ResponseData = outputValue;
108 |
109 | // Execute.
110 | var output = await runner.MFWSClient.ExtensionMethodOperations.ExecuteVaultExtensionMethodAsync("HelloWorld", input: inputValue);
111 |
112 | // Verify.
113 | runner.Verify();
114 |
115 | // Response body must be correct.
116 | Assert.AreEqual(outputValue, output);
117 | }
118 |
119 | ///
120 | /// Ensures that a call to
121 | /// returns the correct response.
122 | ///
123 | [TestMethod]
124 | public void ExecuteExtensionMethod_CorrectOutput()
125 | {
126 | // Create our test runner.
127 | var runner = new RestApiTestRunner(Method.Post, "/REST/vault/extensionmethod/HelloWorld.aspx");
128 |
129 | // Set the request body.
130 | const string inputValue = "this is my test input value";
131 | runner.SetExpectedRequestBody(inputValue);
132 |
133 | // Set the response body.
134 | const string outputValue = "Return value";
135 | runner.ResponseData = outputValue;
136 |
137 | // Execute.
138 | var output = runner.MFWSClient.ExtensionMethodOperations.ExecuteVaultExtensionMethod("HelloWorld", input: inputValue);
139 |
140 | // Verify.
141 | runner.Verify();
142 |
143 | // Response body must be correct.
144 | Assert.AreEqual(outputValue, output);
145 | }
146 |
147 | #endregion
148 |
149 | #region Extension Method (serialisation of input, no deserialisation of output)
150 |
151 | ///
152 | /// Ensures that a call to
153 | /// includes the serialised request data.
154 | ///
155 | [TestMethod]
156 | public async Task ExecuteExtensionMethodAsync_InputSerialisation()
157 | {
158 | // Create our test runner.
159 | var runner = new RestApiTestRunner(Method.Post, "/REST/vault/extensionmethod/HelloWorld.aspx");
160 |
161 | // Set the request body.
162 | var inputValue = new MySerialisableObject
163 | {
164 | a = "b",
165 | x = 7
166 | };
167 | runner.SetExpectedRequestBody(inputValue.ToSerializedString());
168 |
169 | // Set the response body.
170 | const string outputValue = "Return value";
171 | runner.ResponseData = outputValue;
172 |
173 | // Execute
174 | var output = await runner.MFWSClient.ExtensionMethodOperations.ExecuteVaultExtensionMethodAsync("HelloWorld", input: inputValue);
175 |
176 | // Verify.
177 | runner.Verify();
178 |
179 | // Response body must be correct.
180 | Assert.AreEqual(outputValue, output);
181 | }
182 |
183 | ///
184 | /// Ensures that a call to
185 | /// includes the serialised request data.
186 | ///
187 | [TestMethod]
188 | public void ExecuteExtensionMethod_InputSerialisation()
189 | {
190 | // Create our test runner.
191 | var runner = new RestApiTestRunner(Method.Post, "/REST/vault/extensionmethod/HelloWorld.aspx");
192 |
193 | // Set the request body.
194 | var inputValue = new MySerialisableObject
195 | {
196 | a = "b",
197 | x = 7
198 | };
199 | runner.SetExpectedRequestBody(inputValue.ToSerializedString());
200 |
201 | // Set the response body.
202 | const string outputValue = "Return value";
203 | runner.ResponseData = outputValue;
204 |
205 | // Execute
206 | var output = runner.MFWSClient.ExtensionMethodOperations.ExecuteVaultExtensionMethod("HelloWorld", input: inputValue);
207 |
208 | // Verify.
209 | runner.Verify();
210 |
211 | // Response body must be correct.
212 | Assert.AreEqual(outputValue, output);
213 | }
214 |
215 | #endregion
216 |
217 | #region Extension Method (serialisation and deserialisation)
218 |
219 | ///
220 | /// Ensures that a call to
221 | /// includes the deserialised response data.
222 | ///
223 | [TestMethod]
224 | public async Task ExecuteExtensionMethodAsync_OutputDeserialisation()
225 | {
226 | // Create our test runner.
227 | var runner = new RestApiTestRunner(Method.Post, "/REST/vault/extensionmethod/HelloWorld.aspx");
228 |
229 | // Set the request body.
230 | var inputValue = new MySerialisableObject
231 | {
232 | a = "b",
233 | x = 7
234 | };
235 | runner.SetExpectedRequestBody(inputValue.ToSerializedString());
236 |
237 | // Set the response body.
238 | var outputValue = new MySerialisableObject
239 | {
240 | a = "c",
241 | x = 123
242 | };
243 | runner.ResponseData = outputValue;
244 |
245 | // Execute
246 | var output = await runner.MFWSClient
247 | .ExtensionMethodOperations
248 | .ExecuteVaultExtensionMethodAsync("HelloWorld", input: inputValue);
249 |
250 | // Verify.
251 | runner.Verify();
252 |
253 | // Response must be correct.
254 | Assert.AreEqual(outputValue, output);
255 | }
256 |
257 | ///
258 | /// Ensures that a call to
259 | /// includes the deserialised response data.
260 | ///
261 | [TestMethod]
262 | public void ExecuteExtensionMethod_OutputDeserialisation()
263 | {
264 | // Create our test runner.
265 | var runner = new RestApiTestRunner(Method.Post, "/REST/vault/extensionmethod/HelloWorld.aspx");
266 |
267 | // Set the request body.
268 | var inputValue = new MySerialisableObject
269 | {
270 | a = "b",
271 | x = 7
272 | };
273 | runner.SetExpectedRequestBody(inputValue.ToSerializedString());
274 |
275 | // Set the response body.
276 | var outputValue = new MySerialisableObject
277 | {
278 | a = "c",
279 | x = 123
280 | };
281 | runner.ResponseData = outputValue;
282 |
283 | // Execute
284 | var output = runner.MFWSClient
285 | .ExtensionMethodOperations
286 | .ExecuteVaultExtensionMethod("HelloWorld", input: inputValue);
287 |
288 | // Verify.
289 | runner.Verify();
290 |
291 | // Response must be correct.
292 | Assert.AreEqual(outputValue, output);
293 | }
294 |
295 | #endregion
296 |
297 | public class MySerialisableObject
298 | {
299 | public string a { get; set; } = "b";
300 | public int x { get; set; } = 7;
301 |
302 | public string ToSerializedString()
303 | {
304 | return Newtonsoft.Json.JsonConvert.SerializeObject(this, Formatting.None);
305 | }
306 | }
307 |
308 | }
309 | }
310 |
--------------------------------------------------------------------------------