.. _dotcmis: DotCMIS ======================================= Apache Chemistry DotCMIS is a CMIS client library for .NET. It is loosely based on the OpenCMIS client architecture .. sidebar:: Download https://chemistry.apache.org/dotnet/dotcmis.html CMIS 1.1 compatibility """"""""""""""""""""""" DotCMIS does not fully support CMIS 1.1 when using AtomPub. Specifically, it does not recognise item types and will throw an exception if they are encountered. Item types are used in Technology One’s implementation of CMIS in order to define indexes and index entries. The issue will initially present itself as a parsing exception when attempting to retrieve the servicedoc. For example: .. _authentication-samples: .. code-block:: C# // Using Standard Authentication Dictionary parameters = new Dictionary(); parameters[DotCMIS.SessionParameter.BindingType] = BindingType.AtomPub; parameters[DotCMIS.SessionParameter.AtomPubUrl] = @"https://ecmpartner.onespresso.net/T1Dev/CiAnywhere/Web/Dev/Api/CMIS/T1/servicedoc"; parameters[DotCMIS.SessionParameter.RepositoryId] = "T1"; parameters[DotCMIS.SessionParameter.User] = "XXX"; parameters[DotCMIS.SessionParameter.Password] = "YYY"; SessionFactory factory = SessionFactory.NewInstance(); ISession session = factory.GetRepositories(parameters)[0].CreateSession(); To use OAuth authentication requires adding the bearer token to the session. The User and Password parameters must not be set when using OAuth. .. code-block:: C# // Using OAuth Authentication Dictionary parameters = new Dictionary(); parameters[DotCMIS.SessionParameter.BindingType] = BindingType.AtomPub; parameters[DotCMIS.SessionParameter.AtomPubUrl] = @"https://ecmpartner.onespresso.net/T1Dev/CiAnywhere/Web/Dev/Api/CMIS/T1/servicedoc"; parameters[DotCMIS.SessionParameter.RepositoryId] = "T1"; parameters[DotCMIS.SessionParameter.BearerToken] = "8ef76744-9544-4fa4-9933-12569d88a340"; SessionFactory factory = SessionFactory.NewInstance(); ISession session = factory.GetRepositories(parameters)[0].CreateSession(); In order to circumvent this issue it is recommended that the DotCMIS source code be referenced directly instead of the compiled source. This will allow for changes to be made so that item types can be supported and significantly improves the debugging process. The DotCmis.dll provided with the :ref:`sample application` contains all the changes documented on this page. *The compiled source provided with the sample application should only be used for prototypes.* As of DotCMIS version 0.7 the following changes will be required to allow the servicedoc to be retrieved: **CMIS-Core.xsd (line #54)** .. code-block:: Xml **Reference.cs (line #6814)** .. code-block:: C# [System.Xml.Serialization.XmlEnumAttribute("cmis:item")] cmisitem Item Type Implementation ^^^^^^^^^^^^^^^^^^^^^^^^ If using the DotCMIS source for version 0.7, additional changes are required to directly handle items and custom parameters. Code snippets and screenshots have been provided here. *The code changes provided here are valid for implementing item types with DotCMIS version 0.7 only.* **enums.cs** - Add CmisItem to the BaseTypeId enumeration. (line #41) .. code-block:: C# public enum BaseTypeId { [CmisValue("cmis:document")] CmisDocument, [CmisValue("cmis:folder")] CmisFolder, [CmisValue("cmis:relationship")] CmisRelationship, [CmisValue("cmis:policy")] CmisPolicy, // line 41 (Add CmisItem to the BaseTypeId enumeration) [CmisValue("cmis:item")] CmisItem } **Reference.cs** - Add the createItem method to the ObjectServicePortClient class (line #4965). .. code-block:: C# // line 4965 public string createItem(string repositoryId, DotCMIS.CMISWebServicesReference.cmisPropertiesType properties, string folderId) { DotCMIS.CMISWebServicesReference.createDocumentRequest inValue = new DotCMIS.CMISWebServicesReference.createDocumentRequest(); inValue.repositoryId = repositoryId; inValue.properties = properties; inValue.folderId = folderId; DotCMIS.CMISWebServicesReference.createDocumentResponse retVal = ((DotCMIS.CMISWebServicesReference.ObjectServicePort)(this)).createDocument(inValue); return retVal.objectId; } - Create the cmisTypeItemDefinitionType partial class attribute (line #8469) .. code-block:: C# // line 8469 [System.CodeDom.Compiler.GeneratedCodeAttribute("System.Xml", "4.0.30319.233")] [System.SerializableAttribute()] [System.Diagnostics.DebuggerStepThroughAttribute()] [System.ComponentModel.DesignerCategoryAttribute("code")] [System.Xml.Serialization.XmlTypeAttribute(Namespace="http://docs.oasis-open.org/ns/cmis/core/200908/")] public partial class cmisTypeItemDefinitionType : cmisTypeDefinitionType { } - Add the cmisTypeItemDefinitionType attribute (line #6962). .. image:: /_static/img/reference-cmistypeitem-attribute.png **atompub.cs** - Add the customParameters dictionary to the GetChildren method (line #1108, 1129) .. code-block:: C# // line 1108 (Add the customParameters dictionary parameter to GetChildren method declaration) public IObjectInFolderList GetChildren(string repositoryId, string folderId, string filter, Dictionary customParameters, string orderBy, bool? includeAllowableActions, IncludeRelationshipsFlag? includeRelationships, string renditionFilter, bool? includePathSegment, long? maxItems, long? skipCount, IExtensionsData extension) { ... // line 1129 (iterate custom parameters dctionary. if/else statement replaces ParamMaxItems and ParamSkipCount "addparameter" lines) // T1 Added: Loop through the custom parameters if (customParameters != null) { foreach (var param in customParameters) { url.AddParameter(param.Key, param.Value); } } else { url.AddParameter(AtomPubConstants.ParamMaxItems, maxItems); url.AddParameter(AtomPubConstants.ParamSkipCount, skipCount); } ... .. image:: /_static/img/atompub-customparamaters.png - Add the CreateItem method to the ObjectService class (line #1652). .. code-block:: C# // line 1652 public string CreateItem(string repositoryId, IProperties properties, string folderId) { CheckCreateProperties(properties); // find the link string link = null; if (folderId == null) { link = LoadCollection(repositoryId, AtomPubConstants.CollectionUnfiled); if (link == null) { throw new CmisObjectNotFoundException("Unknown respository or unfiling not supported!"); } } else { link = LoadLink(repositoryId, folderId, AtomPubConstants.RelDown, AtomPubConstants.MediatypeChildren); if (link == null) { ThrowLinkException(repositoryId, folderId, AtomPubConstants.RelDown, AtomPubConstants.MediatypeChildren); } } UrlBuilder url = new UrlBuilder(link); // set up object and writer cmisObjectType cmisObject = CreateObject(properties, null, null);//policies); string mediaType = null; Stream stream = null; string filename = null; var entryWriter = new AtomEntryWriter(cmisObject, mediaType, filename, stream); // post the new folder object var resp = Post(url, AtomPubConstants.MediatypeEntry, entryWriter.Write); // parse the response var entry = Parse(resp.Stream); // handle ACL modifications //HandleAclModifications(repositoryId, entry, addAces, removeAces); return entry.Id; } **webservices.cs** - Add the customParameters dictionary parameter to GetChildren method declaration (line #549). .. image:: /_static/img/webservices-customparameters.png - Add the CreateItem method to the ObjectService class (line #752). .. code-block:: C# // line 752 public string CreateItem(string repositoryId, IProperties properties, string folderId) { var port = Provider.GetObjectService(); try { var objectId = port.createItem(repositoryId, Converter.Convert(properties), folderId); //Converter.ConvertExtension(cmisExtension, extension); return objectId; } catch (FaultException fe) { throw ConvertException(fe); } catch (Exception e) { throw new CmisRuntimeException("Error: " + e.Message, e); } } **data-intf.cs** - Add the Item type definition interface (line #116). .. code-block:: C# // line 116 (Add the Item type definition class) public interface IItemTypeDefinition : ITypeDefinition { } - Allow Updatability to be set for Property definition interface (line #155). .. image:: /_static/img/data-intf-updatability.png **data-impl.cs** - Add the Item type definition class (line #202). .. code-block:: C# // line 202 (Add the Item type definition class) public class ItemTypeDefinitionType : AbstractTypeDefinition, IItemTypeDefinition { } **converter.cs** - Add check for Item type definition in Convert method (line #293). .. code-block:: C# // line 293 (check if typeDef is Item type) else if (typeDef is cmisTypeItemDefinitionType) { result = new ItemTypeDefinitionType(); } .. image:: /_static/img/converter-itemtype-definition.png - Parsing Integer properties must throw exception if invalid (line #1209). .. code-block:: C# // line 1209 (throw exception on parse failure) long value; if(long.TryParse(property.Values[i].ToString(), out value)) { ((cmisPropertyInteger)result).value[i] = value.ToString(); } else { throw new Exception("Invalid long value provided for integer field."); } .. image:: /_static/img/converter-propertytype-integer.png **services.cs** - Add the customParameters dictionary parameter to GetChildren method declaration (line #43). .. image:: /_static/img/services-customparamaters.png - Add CreateItem method to ObjectService interface (line #71). .. code-block:: C# // line 71 string CreateItem(string repositoryId, IProperties properties, string folderId); **client-intf.cs** - Add dictionary parameter customParameters to CreateOperationContext (line #145). .. image:: /_static/img/client-intf-customParameters.png - Add CreateItem method definition to ISession interface (line #255). .. code-block:: C# // line 255 (CreateItem method definition) IObjectId CreateItem(IDictionary properties, IObjectId folderId); - Add CustomParameters dictionary definition to IOperationContext interface (line #336). .. code-block:: C# public interface IOperationContext { /// /// Gets and sets the property filter. /// /// /// This is a set of query names. /// HashSet Filter { get; set; } // line 334 (CustomParameters dictionary definition) Dictionary CustomParameters { get; set; } ... - Define IItem interface (line #1107). .. code-block:: C# // line 1107 (IItem interface) /// /// Item interface. /// public interface IItem : IFileableCmisObject, IPolicyProperties { } **client-utils.cs** - Define and Initialize customParameters dictionary for OperationContext class (lines #36, 51, 68, 82, 87). .. image:: /_static/img/client-utils-customParameters.1.png .. image:: /_static/img/client-utils-customParameters.2.png - Define CustomParameter dictionary property for OperationContext class (line #141). .. code-block:: C# // line 141 (CustomParameters dictionary property) public Dictionary CustomParameters { get { return customParameters; } set { customParameters = value; } } **client-impl.cs** - Set customParameters to null for FallbackContext operation context (line #186). .. image:: /_static/img/client-impl-fallback-customparameters.png - Add customParameters to CreateOperationContext method (line #339, 343). .. image:: /_static/img/client-impl-create-customparameters.png - Add CreateItem method to Session class (line #787). .. code-block:: C# // line 787 (Add CreateItem method to Session class) public IObjectId CreateItem(IDictionary properties, IObjectId folderId) { if (properties == null || properties.Count == 0) { throw new ArgumentException("Properties must not be empty!"); } var newId = Binding.GetObjectService().CreateItem( RepositoryId, ObjectFactory.ConvertProperties( properties, null, null ), folderId.Id ); return newId == null ? null : CreateObjectId(newId); } **client-types.cs** - Item type implementation (line #128). .. code-block:: C# // line 128 (add Item class implementation) /// /// Item type implementation. /// public class ItemType : FolderTypeDefinition, IFolderType { private ObjectTypeHelper helper; public ItemType(ISession session, IItemTypeDefinition typeDefinition) { Initialize(typeDefinition); helper = new ObjectTypeHelper(session, this); } public IObjectType GetBaseType() { return helper.GetBaseType(); } public IItemEnumerable GetChildren() { return helper.GetChildren(); } public IList> GetDescendants(int depth) { return helper.GetDescendants(depth); } public IObjectType GetParentType() { return helper.GetParentType(); } public bool IsBaseType { get { return helper.IsBaseType; } } } **client-object.cs** - Pass customParameters to NavigationService GetChildren method (line #1124). .. image:: /_static/img/client-object-getchildren-customparameters.png - Item class implementation (line #1304). .. code-block:: C# // line 1304 (add Item class implementation) /// /// Item implementation /// public class Item : AbstractCmisObject, IFileableCmisObject { public Item(ISession session, IObjectType objectType, IObjectData objectData, IOperationContext context) { Initialize(session, objectType, objectData, context); } public void AddToFolder(IObjectId folderId, bool allVersions) { throw new NotImplementedException(); if (folderId == null || folderId.Id == null) { throw new ArgumentException("Folder Id must be set!"); } Binding.GetMultiFilingService().AddObjectToFolder(RepositoryId, ObjectId, folderId.Id, allVersions, null); } public virtual IList Paths { get { throw new NotImplementedException(); // get object paths of the parent folders IList parents = Binding.GetNavigationService().GetObjectParents( RepositoryId, ObjectId, GetPropertyQueryName(PropertyIds.Path), false, IncludeRelationshipsFlag.None, null, true, null); IList paths = new List(); foreach (IObjectParentData p in parents) { if (p == null || p.Object == null || p.Object.Properties == null) { // should not happen... throw new CmisRuntimeException("Repository sent invalid data!"); } // get path property IPropertyData pathProperty = p.Object.Properties[PropertyIds.Path]; if (pathProperty == null || pathProperty.PropertyType != PropertyType.String) { // the repository sent a folder without a valid path... throw new CmisRuntimeException("Repository sent invalid data! No path property!"); } if (p.RelativePathSegment == null) { // the repository didn't send a relative path segment throw new CmisRuntimeException("Repository sent invalid data! No relative path segement!"); } string folderPath = pathProperty.FirstValue as string; paths.Add(folderPath + (folderPath.EndsWith("/") ? "" : "/") + p.RelativePathSegment); } return paths; } } public IFileableCmisObject Move(IObjectId sourceFolderId, IObjectId targetFolderId) { throw new NotImplementedException(); string objectId = ObjectId; if (sourceFolderId == null || sourceFolderId.Id == null) { throw new ArgumentException("Source folder id must be set!"); } if (targetFolderId == null || targetFolderId.Id == null) { throw new ArgumentException("Target folder id must be set!"); } Binding.GetObjectService().MoveObject(RepositoryId, ref objectId, targetFolderId.Id, sourceFolderId.Id, null); if (objectId == null) { return null; } IFileableCmisObject movedObject = Session.GetObject(Session.CreateObjectId(objectId)) as IFileableCmisObject; if (movedObject == null) { throw new CmisRuntimeException("Moved object is invalid!"); } return movedObject; } public virtual IList Parents { get { throw new NotImplementedException(); // get object ids of the parent folders IList bindingParents = Binding.GetNavigationService().GetObjectParents(RepositoryId, ObjectId, GetPropertyQueryName(PropertyIds.ObjectId), false, IncludeRelationshipsFlag.None, null, false, null); IList parents = new List(); foreach (IObjectParentData p in bindingParents) { if (p == null || p.Object == null || p.Object.Properties == null) { // should not happen... throw new CmisRuntimeException("Repository sent invalid data!"); } // get id property IPropertyData idProperty = p.Object.Properties[PropertyIds.ObjectId]; if (idProperty == null || idProperty.PropertyType != PropertyType.Id) { // the repository sent an object without a valid object id... throw new CmisRuntimeException("Repository sent invalid data! No object id!"); } // fetch the object and make sure it is a folder IObjectId parentId = Session.CreateObjectId(idProperty.FirstValue as string); IFolder parentFolder = Session.GetObject(parentId) as IFolder; if (parentFolder == null) { // the repository sent an object that is not a folder... throw new CmisRuntimeException("Repository sent invalid data! Object is not a folder!"); } parents.Add(parentFolder); } return parents; } } public void RemoveFromFolder(IObjectId folderId) { throw new NotImplementedException(); Binding.GetMultiFilingService().RemoveObjectFromFolder(RepositoryId, ObjectId, folderId == null ? null : folderId.Id, null); } } **client-objectfactory.cs** - Add Item type to ConvertTypeDefinition method (line #129). .. code-block:: C# // line 129 (Add Item type to definition) case BaseTypeId.CmisItem: return new ItemType(session, (IItemTypeDefinition) typeDefinition); .. image:: /_static/img/client-objectfactory-itemtypedef.png - Update ConvertProperties method for definition and comment out updatability (line #253, 260). .. code-block:: C# // line 253 (default Property definition to string property type if not set) definition = new PropertyStringDefinition() { PropertyType = PropertyType.String, Cardinality = Cardinality.Single }; .. image:: /_static/img/client-objectfactory-convertproperties.png - Add Item type to ConvertObject method (line #344). .. code-block:: C# // line 344 (Convert object to Item) case BaseTypeId.CmisItem: return new Item(session, type, objectData, context); .. image:: /_static/img/client-objectfactory-itemdef.png Implementing Bulk Update """""""""""""""""""""""" Document to Index linking and Index to Index linking in bulk has been implemented using BulkUpdate. The following changes will be required for this implementation. **binding\\atompub\\atompub.cs** .. code-block:: c# // inserted at line 1832 public IEnumerable BulkUpdate(string repositoryId, IProperties properties, IList policies, IAcl addAces, IAcl removeAces, IExtensionsData extension) { // CheckCreateProperties(properties); // find the link var link = LoadTemplateLink(repositoryId, AtomPubConstants.TemplateBulkUpdate, null); if (link == null) { ThrowLinkException(repositoryId, "ROOTFOLDER", AtomPubConstants.RelDown, AtomPubConstants.MediatypeChildren); } var url = new UrlBuilder(link); // set up object and writer cmisObjectType cmisObject = CreateObject(properties, null, policies); AtomEntryWriter entryWriter = new AtomEntryWriter(cmisObject); // post the new folder object HttpUtils.Response resp = Post(url, AtomPubConstants.MediatypeEntry, new HttpUtils.Output(entryWriter.Write)); // parse the response var entries = Parse(resp.Stream); var ids = new List(); foreach (var entry in entries.GetEntries()) { // handle ACL modifications HandleAclModifications(repositoryId, entry, addAces, removeAces); ids.Add(entry.Id); } return ids; } **binding\\webservices\\webservices.cs** .. code-block:: c# // inserted at line 880 public IEnumerable BulkUpdate(string repositoryId, IProperties properties, IList policies, IAcl addAces, IAcl removeAces, IExtensionsData extension) { var port = Provider.GetObjectService(); try { var cmisExtension = Converter.ConvertExtension(extension); var objectIds = port.bulkUpdate(repositoryId, Converter.Convert(properties), Converter.ConvertList(policies), Converter.Convert(addAces), Converter.Convert(removeAces), ref cmisExtension); Converter.ConvertExtension(cmisExtension, extension); return objectIds; } catch (FaultException fe) { throw ConvertException(fe); } catch (Exception e) { throw new CmisRuntimeException("Error: " + e.Message, e); } } **binding\\services.cs** .. code-block:: c# // inserted at line 85 IEnumerable BulkUpdate(string repositoryId, IProperties properties, IList policies, IAcl addAces, IAcl removeAces, IExtensionsData extension); **client\\client-impl.cs** .. code-block:: c# // inserted at line 908 public IEnumerable BulkUpdate(IDictionary properties, IList policies, IList addAces, IList removeAces) { if (properties == null || properties.Count == 0) { throw new ArgumentException("Properties must not be empty!"); } var newIds = Binding.GetObjectService().BulkUpdate(RepositoryId, ObjectFactory.ConvertProperties(properties, null, CreateUpdatability), ObjectFactory.ConvertPolicies(policies), ObjectFactory.ConvertAces(addAces), ObjectFactory.ConvertAces(removeAces), null); var idList = new List(); foreach (var newId in newIds) { idList.Add(CreateObjectId(newId)); } return idList; } public IEnumerable BulkUpdate(IDictionary properties) { return BulkUpdate(properties, null, null, null); } **client\\client-intf.cs** .. code-block:: c# // inserted at line 270 IEnumerable BulkUpdate(IDictionary properties, IList policies, IList addAces, IList removeAces); IEnumerable BulkUpdate(IDictionary properties); **client\\client-objectfactory.cs** .. code-block:: c# // comment out the following lines starting at line 282 // if (definition.Cardinality != Cardinality.Multi) // { // throw new ArgumentException("Property '" + id + "' is not a multi value property!"); // } **Service References\\CMISWebServicesReference\\CMIS-Messaging.xsd** .. code-block:: xml This is an extension element to hold any repository or vendor-specific extensions This is an extension element to hold any repository or vendor-specific extensions **Service References\\CMISWebServicesReference\\CMIS-Messaging.xsd** .. code-block:: xml .. code-block:: xml .. code-block:: xml **Service References\\CMISWebServicesReference\\reference.cs** .. code-block:: c# // inserted at line 3596 [System.ServiceModel.OperationContractAttribute(Action="", ReplyAction="*")] [System.ServiceModel.FaultContractAttribute(typeof(DotCMIS.CMISWebServicesReference.cmisFaultType), Action="", Name="cmisFault", Namespace="http://docs.oasis-open.org/ns/cmis/messaging/200908/")] [System.ServiceModel.XmlSerializerFormatAttribute(SupportFaults=true)] [System.ServiceModel.ServiceKnownTypeAttribute(typeof(cmisProperty))] DotCMIS.CMISWebServicesReference.bulkUpdateResponse bulkUpdate(DotCMIS.CMISWebServicesReference.bulkUpdateRequest request); .. code-block:: c# // inserted at line 4161 [System.Diagnostics.DebuggerStepThroughAttribute()] [System.CodeDom.Compiler.GeneratedCodeAttribute("System.ServiceModel", "4.0.0.0")] [System.ComponentModel.EditorBrowsableAttribute(System.ComponentModel.EditorBrowsableState.Advanced)] [System.ServiceModel.MessageContractAttribute(WrapperName="bulkUpdate", WrapperNamespace="http://docs.oasis-open.org/ns/cmis/messaging/200908/", IsWrapped=true)] internal partial class bulkUpdateRequest { [System.ServiceModel.MessageBodyMemberAttribute(Namespace="http://docs.oasis-open.org/ns/cmis/messaging/200908/", Order=0)] public string repositoryId; [System.ServiceModel.MessageBodyMemberAttribute(Namespace="http://docs.oasis-open.org/ns/cmis/messaging/200908/", Order=1)] public DotCMIS.CMISWebServicesReference.cmisPropertiesType properties; [System.ServiceModel.MessageBodyMemberAttribute(Namespace="http://docs.oasis-open.org/ns/cmis/messaging/200908/", Order=3)] [System.Xml.Serialization.XmlElementAttribute("policies", IsNullable=true)] public string[] policies; [System.ServiceModel.MessageBodyMemberAttribute(Namespace="http://docs.oasis-open.org/ns/cmis/messaging/200908/", Order=4)] [System.Xml.Serialization.XmlElementAttribute(IsNullable=true)] public DotCMIS.CMISWebServicesReference.cmisAccessControlListType addACEs; [System.ServiceModel.MessageBodyMemberAttribute(Namespace="http://docs.oasis-open.org/ns/cmis/messaging/200908/", Order=5)] [System.Xml.Serialization.XmlElementAttribute(IsNullable=true)] public DotCMIS.CMISWebServicesReference.cmisAccessControlListType removeACEs; [System.ServiceModel.MessageBodyMemberAttribute(Namespace="http://docs.oasis-open.org/ns/cmis/messaging/200908/", Order=6)] [System.Xml.Serialization.XmlElementAttribute(IsNullable=true)] public DotCMIS.CMISWebServicesReference.cmisExtensionType extension; public bulkUpdateRequest() { } public bulkUpdateRequest(string repositoryId, DotCMIS.CMISWebServicesReference.cmisPropertiesType properties, string[] policies, DotCMIS.CMISWebServicesReference.cmisAccessControlListType addACEs, DotCMIS.CMISWebServicesReference.cmisAccessControlListType removeACEs, DotCMIS.CMISWebServicesReference.cmisExtensionType extension) { this.repositoryId = repositoryId; this.properties = properties; this.policies = policies; this.addACEs = addACEs; this.removeACEs = removeACEs; this.extension = extension; } } [System.Diagnostics.DebuggerStepThroughAttribute()] [System.CodeDom.Compiler.GeneratedCodeAttribute("System.ServiceModel", "4.0.0.0")] [System.ComponentModel.EditorBrowsableAttribute(System.ComponentModel.EditorBrowsableState.Advanced)] [System.ServiceModel.MessageContractAttribute(WrapperName="bulkUpdateResponse", WrapperNamespace="http://docs.oasis-open.org/ns/cmis/messaging/200908/", IsWrapped=true)] internal partial class bulkUpdateResponse { [System.ServiceModel.MessageBodyMemberAttribute(Namespace="http://docs.oasis-open.org/ns/cmis/messaging/200908/", Order=0)] public string[] objectId; [System.ServiceModel.MessageBodyMemberAttribute(Namespace="http://docs.oasis-open.org/ns/cmis/messaging/200908/", Order=1)] [System.Xml.Serialization.XmlElementAttribute(IsNullable=true)] public DotCMIS.CMISWebServicesReference.cmisExtensionType extension; public bulkUpdateResponse() { } public bulkUpdateResponse(string[] objectId, DotCMIS.CMISWebServicesReference.cmisExtensionType extension) { this.objectId = objectId; this.extension = extension; } } .. code-block:: c# // inserted at line 5121 [System.ComponentModel.EditorBrowsableAttribute(System.ComponentModel.EditorBrowsableState.Advanced)] DotCMIS.CMISWebServicesReference.bulkUpdateResponse DotCMIS.CMISWebServicesReference.ObjectServicePort.bulkUpdate(DotCMIS.CMISWebServicesReference.bulkUpdateRequest request) { return base.Channel.bulkUpdate(request); } public string[] bulkUpdate(string repositoryId, DotCMIS.CMISWebServicesReference.cmisPropertiesType properties, string[] policies, DotCMIS.CMISWebServicesReference.cmisAccessControlListType addACEs, DotCMIS.CMISWebServicesReference.cmisAccessControlListType removeACEs, ref DotCMIS.CMISWebServicesReference.cmisExtensionType extension) { DotCMIS.CMISWebServicesReference.bulkUpdateRequest inValue = new DotCMIS.CMISWebServicesReference.bulkUpdateRequest(); inValue.repositoryId = repositoryId; inValue.properties = properties; inValue.policies = policies; inValue.addACEs = addACEs; inValue.removeACEs = removeACEs; inValue.extension = extension; DotCMIS.CMISWebServicesReference.bulkUpdateResponse retVal = ((DotCMIS.CMISWebServicesReference.ObjectServicePort)(this)).bulkUpdate(inValue); extension = retVal.extension; return retVal.objectId; } **const.cs** .. code-block:: c# // inserted at line 248 public const string TemplateBulkUpdate = "bulkupdate"; **DotCMIS.csproj (updating project to .net v4.0)** .. code-block:: xml v4.0 Implementing OAuth Authentication """"""""""""""""""""""""""""""""" The followng changes are required to teh DotCMIS.dll As DotCMIS dosn't support OAuth authentication. **binding\\binding-intf.cs** .. code-block:: c# // inserted at line 90 into "public class StandardAuthenticationProvider" private string GetBearerToken() { return Session.GetValue(SessionParameter.BearerToken) as string; } // Inserted at line 124 adding else condition to "if (user != null || password != null)" statement. else { var bearerToken = GetBearerToken(); if (!string.IsNullOrEmpty(bearerToken)) request.Headers["Authorization"] = $"Bearer {bearerToken}"; } **const.cs** .. code-block:: c# // inserted at line 27 into "public static class SessionParameter" public const string BearerToken = "org.apache.chemistry.dotcmis.bearertoken"; **DotCMIS.csproj (Update project to c# language version 7.3)** .. code-block:: xml 7.3