DotCMIS

Apache Chemistry DotCMIS is a CMIS client library for .NET. It is loosely based on the OpenCMIS client architecture

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:

// Using Standard Authentication
Dictionary<string, string> parameters = new Dictionary<string, string>();
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.

// Using OAuth Authentication
Dictionary<string, string> parameters = new Dictionary<string, string>();
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 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)

<xs:enumeration value="cmis:item" />

Reference.cs (line #6814)

[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)
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).
// 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)
// 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).
../_images/reference-cmistypeitem-attribute.png

atompub.cs

  • Add the customParameters dictionary to the GetChildren method (line #1108, 1129)
// line 1108 (Add the customParameters dictionary parameter to GetChildren method declaration)
public IObjectInFolderList GetChildren(string repositoryId, string folderId, string filter, Dictionary<string, string> 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);
    }

    ...
../_images/atompub-customparamaters.png
  • Add the CreateItem method to the ObjectService class (line #1652).
// 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<AtomEntry>(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).
../_images/webservices-customparameters.png
  • Add the CreateItem method to the ObjectService class (line #752).
// 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<cmisFaultType> 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).
// line 116 (Add the Item type definition class)
public interface IItemTypeDefinition : ITypeDefinition
{

}
  • Allow Updatability to be set for Property definition interface (line #155).
../_images/data-intf-updatability.png

data-impl.cs

  • Add the Item type definition class (line #202).
// 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).
// line 293 (check if typeDef is Item type)
else if (typeDef is cmisTypeItemDefinitionType)
{
    result = new ItemTypeDefinitionType();
}
../_images/converter-itemtype-definition.png
  • Parsing Integer properties must throw exception if invalid (line #1209).
// 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.");
}
../_images/converter-propertytype-integer.png

services.cs

  • Add the customParameters dictionary parameter to GetChildren method declaration (line #43).
../_images/services-customparamaters.png
  • Add CreateItem method to ObjectService interface (line #71).
// line 71
string CreateItem(string repositoryId, IProperties properties, string folderId);

client-intf.cs

  • Add dictionary parameter customParameters to CreateOperationContext (line #145).
../_images/client-intf-customParameters.png
  • Add CreateItem method definition to ISession interface (line #255).
// line 255 (CreateItem method definition)
IObjectId CreateItem(IDictionary<string, object> properties, IObjectId folderId);
  • Add CustomParameters dictionary definition to IOperationContext interface (line #336).
public interface IOperationContext
{
    /// <summary>
    /// Gets and sets the property filter.
    /// </summary>
    /// <remarks>
    /// This is a set of query names.
    /// </remarks>
    HashSet<string> Filter { get; set; }

    // line 334 (CustomParameters dictionary definition)
    Dictionary<string, string> CustomParameters { get; set; }

    ...
  • Define IItem interface (line #1107).
// line 1107 (IItem interface)
/// <summary>
/// Item interface.
/// </summary>
public interface IItem : IFileableCmisObject, IPolicyProperties
{
}

client-utils.cs

  • Define and Initialize customParameters dictionary for OperationContext class (lines #36, 51, 68, 82, 87).
../_images/client-utils-customParameters.1.png ../_images/client-utils-customParameters.2.png
  • Define CustomParameter dictionary property for OperationContext class (line #141).
// line 141 (CustomParameters dictionary property)
public Dictionary<string, string> CustomParameters { get { return customParameters; } set { customParameters = value; } }

client-impl.cs

  • Set customParameters to null for FallbackContext operation context (line #186).
../_images/client-impl-fallback-customparameters.png
  • Add customParameters to CreateOperationContext method (line #339, 343).
../_images/client-impl-create-customparameters.png
  • Add CreateItem method to Session class (line #787).
// line 787 (Add CreateItem method to Session class)
public IObjectId CreateItem(IDictionary<string, object> 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).
// line 128 (add Item class implementation)
/// <summary>
/// Item type implementation.
/// </summary>
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<IObjectType> GetChildren() { return helper.GetChildren(); }

    public IList<ITree<IObjectType>> 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).
../_images/client-object-getchildren-customparameters.png
  • Item class implementation (line #1304).
// line 1304 (add Item class implementation)
/// <summary>
/// Item implementation
/// </summary>
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<string> Paths
    {
        get
        {
            throw new NotImplementedException();
            // get object paths of the parent folders
            IList<IObjectParentData> parents = Binding.GetNavigationService().GetObjectParents(
                    RepositoryId, ObjectId, GetPropertyQueryName(PropertyIds.Path), false, IncludeRelationshipsFlag.None,
                    null, true, null);

            IList<string> paths = new List<string>();

            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<IFolder> Parents
    {
        get
        {
            throw new NotImplementedException();
            // get object ids of the parent folders
            IList<IObjectParentData> bindingParents = Binding.GetNavigationService().GetObjectParents(RepositoryId, ObjectId,
                GetPropertyQueryName(PropertyIds.ObjectId), false, IncludeRelationshipsFlag.None, null, false, null);

            IList<IFolder> parents = new List<IFolder>();

            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).
// line 129 (Add Item type to definition)
case BaseTypeId.CmisItem:
    return new ItemType(session, (IItemTypeDefinition) typeDefinition);
../_images/client-objectfactory-itemtypedef.png
  • Update ConvertProperties method for definition and comment out updatability (line #253, 260).
// line 253 (default Property definition to string property type if not set)
definition = new PropertyStringDefinition()
    {
        PropertyType = PropertyType.String,
        Cardinality = Cardinality.Single
    };
../_images/client-objectfactory-convertproperties.png
  • Add Item type to ConvertObject method (line #344).
// line 344 (Convert object to Item)
case BaseTypeId.CmisItem:
    return new Item(session, type, objectData, context);
../_images/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

// inserted at line 1832
public IEnumerable<string> BulkUpdate(string repositoryId, IProperties properties, IList<string> 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<AtomFeed>(resp.Stream);
    var ids = new List<string>();
    foreach (var entry in entries.GetEntries())
    {
        // handle ACL modifications
        HandleAclModifications(repositoryId, entry, addAces, removeAces);
        ids.Add(entry.Id);
    }
    return ids;
}

binding\webservices\webservices.cs

// inserted at line 880
public IEnumerable<string> BulkUpdate(string repositoryId, IProperties properties, IList<string> 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<cmisFaultType> fe)
    {
        throw ConvertException(fe);
    }
    catch (Exception e)
    {
        throw new CmisRuntimeException("Error: " + e.Message, e);
    }
}

binding\services.cs

// inserted at line 85
IEnumerable<string> BulkUpdate(string repositoryId, IProperties properties, IList<string> policies,
    IAcl addAces, IAcl removeAces, IExtensionsData extension);

client\client-impl.cs

// inserted at line 908
public IEnumerable<IObjectId> BulkUpdate(IDictionary<string, object> properties, IList<IPolicy> policies, IList<IAce> addAces,
    IList<IAce> 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<IObjectId>();
    foreach (var newId in newIds)
    {
        idList.Add(CreateObjectId(newId));
    }
    return idList;
}
public IEnumerable<IObjectId> BulkUpdate(IDictionary<string, object> properties)
{
    return BulkUpdate(properties, null, null, null);
}

client\client-intf.cs

// inserted at line 270
IEnumerable<IObjectId> BulkUpdate(IDictionary<string, object> properties, IList<IPolicy> policies, IList<IAce> addAces, IList<IAce> removeAces);
IEnumerable<IObjectId> BulkUpdate(IDictionary<string, object> properties);

client\client-objectfactory.cs

// 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

<!-- inserted at line 634 -->
<xs:element name="bulkUpdate">
  <xs:complexType>
    <xs:sequence>
      <xs:element minOccurs="1" maxOccurs="1" name="repositoryId" type="xs:string" />
      <xs:element minOccurs="1" maxOccurs="1" name="properties" type="cmis:cmisPropertiesType" />
      <xs:element minOccurs="0" maxOccurs="unbounded" name="policies" nillable="true" type="xs:string" />
      <xs:element minOccurs="0" maxOccurs="1" name="addACEs" nillable="true" type="cmis:cmisAccessControlListType" />
      <xs:element minOccurs="0" maxOccurs="1" name="removeACEs" nillable="true" type="cmis:cmisAccessControlListType" />
      <xs:element minOccurs="0" maxOccurs="1" name="extension" nillable="true" type="cmism:cmisExtensionType">
        <xs:annotation>
          <xs:documentation>
                                                      This is an extension element to hold any
                                                      repository or
                                                      vendor-specific extensions
                                              </xs:documentation>
        </xs:annotation>
      </xs:element>
    </xs:sequence>
  </xs:complexType>
</xs:element>
<xs:element name="bulkUpdateResponse">
  <xs:complexType>
    <xs:sequence>
      <xs:element minOccurs="1" maxOccurs="unbounded" name="objectId" type="xs:string" />
      <xs:element minOccurs="0" maxOccurs="1" name="extension" nillable="true" type="cmism:cmisExtensionType">
        <xs:annotation>
          <xs:documentation>
                                                      This is an extension element to hold any
                                                      repository or
                                                      vendor-specific extensions
                                              </xs:documentation>
        </xs:annotation>
      </xs:element>
    </xs:sequence>
  </xs:complexType>
</xs:element>

Service References\CMISWebServicesReference\CMIS-Messaging.xsd

<!-- inserted at line 114 -->
<message name="bulkUpdateRequest">
  <part name="parameters" element="cmism:bulkUpdate" />
</message>
<message name="bulkUpdateResponse">
  <part name="parameters" element="cmism:bulkUpdateResponse" />
</message>
<!-- inserted at line 364 -->
<operation name="bulkUpdate">
  <input message="cmisw:bulkUpdateRequest" />
  <output message="cmisw:bulkUpdateResponse" />
  <fault name="cmisException" message="cmisw:cmisException" />
</operation>
<!-- inserted at line 716 -->
<operation name="bulkUpdate">
  <soap:operation soapAction="" />
  <input>
    <soap:body use="literal" />
  </input>
  <output>
    <soap:body use="literal" />
  </output>
  <fault name="cmisException">
    <soap:fault use="literal" name="cmisException" namespace="" />
  </fault>
</operation>

Service References\CMISWebServicesReference\reference.cs

// 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);
// 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;
    }
}
// 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

// inserted at line 248
public const string TemplateBulkUpdate = "bulkupdate";

DotCMIS.csproj (updating project to .net v4.0)

<!-- updated at line 13 -->
<TargetFrameworkVersion>v4.0</TargetFrameworkVersion>

Implementing OAuth Authentication

The followng changes are required to teh DotCMIS.dll As DotCMIS dosn’t support OAuth authentication.

binding\binding-intf.cs

// 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

// 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)

<LangVersion>7.3</LangVersion>
<!-- Remove <TargetFrameworkProfile>Client</TargetFrameworkProfile> -->