自动标记示例 SharePoint 外接程序

ECM.AutoTagging 示例说明如何使用提供程序托管的 外接程序,使用自定义用户配置文件属性中的数据自动标记添加到 SharePoint 库的内容。

此外接程序使用托管在 Azure 网站上的远程事件接收器,以:

  • 创建字段、内容类型和文档库。
  • 检索自定义用户配置文件属性的值。
  • 设置分类字段。

如果您需要执行以下操作,请使用此解决方案:

  • 在 SharePoint Online 中实现事件接收器。
  • 创建内容时向其附加其他元数据以改进搜索结果。
  • 对您的内容进行分类。
  • 迁移到 SharePoint 新版本之前更新代码,您过去曾使用过事件接收器。

准备工作

若要开始,请从 GitHub 上的 Office 365 开发人员模式和做法项目下载 ECM.AutoTagging 示例外接程序。

注意

本文中的代码按原样提供,不提供任何明示或暗示的担保,包括对特定用途适用性、适销性或不侵权的默示担保。

在运行此外接程序之前,请执行以下操作:

  1. 创建 Azure 网站并向其部署 ECM.AutoTaggingWeb 项目。

  2. 在 Office 365 中使用 Appregnew.aspx 页面注册外接程序。

  3. 此外接程序使用仅应用程序权限。 你需要在 Office 365 中使用 AppInv.aspx 页面分配仅应用程序权限。 将以下 XML 从 AppManifest.xml 文件复制到 AppInv.aspx 页面上的“权限请求 XML”框,如下图所示。

       <AppPermissionRequests AllowAppOnlyPolicy="true">
         <AppPermissionRequest Scope="http://sharepoint/content/tenant" Right="FullControl" />
         <AppPermissionRequest Scope="http://sharepoint/taxonomy" Right="Read" />
         <AppPermissionRequest Scope="http://sharepoint/social/tenant" Right="Read" />
       </AppPermissionRequests>
    

    AppInv.aspx 页面的屏幕截图,其中突出显示了应用 ID 和权限请求 XML 框

  4. 在 ECM.AutoTaggingWeb 项目的 ReceiverHelper.cs 文件中,在 CreateEventReciever 方法中,使用你的 Azure 网站 的 URL 更新 ReceiverUrl 属性。

         public static EventReceiverDefinitionCreationInformation CreateEventReciever(string receiverName, EventReceiverType type)
             {
    
                 EventReceiverDefinitionCreationInformation _rer = new EventReceiverDefinitionCreationInformation();
                 _rer.EventType = type;
                 _rer.ReceiverName = receiverName;
                 _rer.ReceiverClass = "ECM.AutoTaggingWeb.Services.AutoTaggingService";
                 _rer.ReceiverUrl = "https://<Your domain>.azurewebsites.net/Services/AutoTaggingService.svc";
                 _rer.Synchronization = EventReceiverSynchronization.Synchronous;
                 return _rer;
             }
    
    

  5. 打包和部署你的外接程序。

当你启动外接程序时,将显示文档自动标记提供程序托管的外接程序的起始页,如下图中所示。 起始页显示了在分配或删除事件接收器之前需执行的一些额外配置步骤。

自动标记外接程序起始页的屏幕截图,其中突出显示了三个设置步骤。

使用 ECM.Autotagging 示例外接程序

此示例使用远程事件接收器,使用自定义用户配置文件属性中的数据,自动标记(将元数据添加到)添加到文档库中的文档。

自动标记文档的流程使用的远程事件接收器如下图中所示。

标记库中文档的过程的插图。在用户创建内容时,外接程序与事件接收器联系,该接收器可访问用户的配置文件并将信息提交到 SharePoint。

使用远程事件接收器将元数据分配到文档库中新创建的文档:

  1. 用户创建新内容或将新内容上载到文档库。 已分配远程事件接收器以处理此文档库上的 ItemAddingItemAdded 事件。

  2. ItemAddingItemAdded 方法调用远程事件接收器。

  3. 提供程序托管的外接程序获取该用户的 SharePoint 的 User Profile Service 中自定义用户配置文件属性的值。 在此示例外接程序中,将检索之前已添加的 Classification 自定义用户配置文件属性。

  4. 远程事件接收器使用该用户的自定义用户配置文件属性值更新新文档上的元数据。

运行方案 1 按钮

当你选择按钮“运行方案 1”时,外接程序将执行以下操作:

  1. 创建文档库。

  2. 创建 ItemAdding 事件的远程事件接收器。

    注意

    本文介绍了 ItemAdding 事件接收器类型。 一般情况下,ItemAdding 事件接收器类型的性能优于 ItemAdded 事件接收器类型。 ECM.Autotagging 示例提供同时适用于 ItemAdding 和 ItemAdded 事件接收器类型的代码。

  3. 将远程事件接收器添加到文档库。

在下面的代码中,ECM.AutoTaggingWeb 项目中 Default.aspx.cs 页面的 btnScenario1_Click 方法展示了这些步骤。

protected void btnScenario1_Click(object sender, EventArgs e)
        {
            var _libraryToCreate = this.GetLibaryInformationItemAdding();
 
            var spContext = SharePointContextProvider.Current.GetSharePointContext(Context);
            using (var ctx = spContext.CreateUserClientContextForSPHost())
            {
                try 
                { 
                    if(!ctx.Web.ListExists(_libraryToCreate.Title))
                    {
                        ScenarioHandler _scenario = new ScenarioHandler();
                        _scenario.CreateContosoDocumentLibrary(ctx, _libraryToCreate);
                    }
                    List _list = ctx.Web.Lists.GetByTitle(_libraryToCreate.Title);
                    EventReceiverDefinitionCreationInformation _rec = ReceiverHelper.CreateEventReciever(ScenarioHandler.AUTOTAGGING_ITEM_ADDING_RERNAME, EventReceiverType.ItemAdding);
                    ReceiverHelper.AddEventReceiver(ctx, _list, _rec);
                }
                catch(Exception _ex)
                {

                }
            }
        }  

将调用 CreateContosoDocumentLibrary 方法。 ScenarioHandler.cs 文件的以下代码使用 OfficeDevPnP.Core 中的方法,使用自定义内容类型创建自定义文档库。 文档库中的默认内容类型将删除。

public void CreateContosoDocumentLibrary(ClientContext ctx, Library library)
        {
            // Check the fields.
            if (!ctx.Web.FieldExistsById(FLD_CLASSIFICATION_ID))
            {
                ctx.Web.CreateTaxonomyField(FLD_CLASSIFICATION_ID,
                                            FLD_CLASSIFICATION_INTERNAL_NAME,
                                            FLD_CLASSIFICATION_DISPLAY_NAME,
                                            FIELDS_GROUP_NAME,
                                            TAXONOMY_GROUP,
                                            TAXONOMY_TERMSET_CLASSIFICATION_NAME);
            }

            // Check the content type.
            if (!ctx.Web.ContentTypeExistsById(CONTOSODOCUMENT_CT_ID))
            {
                ctx.Web.CreateContentType(CONTOSODOCUMENT_CT_NAME,
                                          CT_DESC, CONTOSODOCUMENT_CT_ID,
                                          CT_GROUP);
            }

            // Associate fields to content types.
            if (!ctx.Web.FieldExistsByNameInContentType(CONTOSODOCUMENT_CT_NAME, FLD_CLASSIFICATION_INTERNAL_NAME))
            {
                ctx.Web.AddFieldToContentTypeById(CONTOSODOCUMENT_CT_ID,
                                                  FLD_CLASSIFICATION_ID.ToString(),
                                                  false);
            }

            
            CreateLibrary(ctx, library, CONTOSODOCUMENT_CT_ID);
        }

private void CreateLibrary(ClientContext ctx, Library library, string associateContentTypeID)
        {
            if (!ctx.Web.ListExists(library.Title))
            {
                ctx.Web.AddList(ListTemplateType.DocumentLibrary, library.Title, false);
                List _list = ctx.Web.GetListByTitle(library.Title);
                if (!string.IsNullOrEmpty(library.Description))
                {
                    _list.Description = library.Description;
                }

                if (library.VerisioningEnabled)
                {
                    _list.EnableVersioning = true;
                }

                _list.ContentTypesEnabled = true;
                _list.RemoveContentTypeByName("Document");
                _list.Update();
                
     
                ctx.Web.AddContentTypeToListById(library.Title, associateContentTypeID, true);
                ctx.Web.Context.ExecuteQuery();
               
            }
            else
            {
                throw new Exception("A list, survey, discussion board, or document library with the specified title already exists in this website.  Please choose another title.");
            }
        }

此代码运行后,将在 Site Contents4 中创建 AutoTaggingSampleItemAdding 文档库。

显示具有新的 AutoTaggingSampleItemAdd 文档库的“网站内容”页面的屏幕截图。


在 ECM.AutoTaggingWeb 项目的 ReceiverHelper.cs 文件中,CreateEventReciever 方法将创建 ItemAdding 事件接收器定义。 在 ECM.AutoTaggingWeb 项目中,Services 文件夹包括一项称为 AutoTaggingService.svc 的 Web 服务。 将 ECM.AutoTaggingWeb 项目发布到你的 Azure 网站之后,此 Web 服务也已部署到网站中。 CreateEventReciever 方法将此 Web 服务指定为文档库上的远程事件接收器。

CreateEventReciever 方法中的以下代码说明如何将 Web 服务分配到远程事件接收器。

public static EventReceiverDefinitionCreationInformation CreateEventReciever(string receiverName, EventReceiverType type)
        {

            EventReceiverDefinitionCreationInformation _rer = new EventReceiverDefinitionCreationInformation();
            _rer.EventType = type;
            _rer.ReceiverName = receiverName;
            _rer.ReceiverClass = "ECM.AutoTaggingWeb.Services.AutoTaggingService";
            _rer.ReceiverUrl = "https://<Your domain>.azurewebsites.net/Services/AutoTaggingService.svc";
            _rer.Synchronization = EventReceiverSynchronization.Synchronous;
            return _rer;
        }


AddEventReceiver 方法中的以下代码将远程事件接收器分配到文档库。

public static void AddEventReceiver(ClientContext ctx, List list, EventReceiverDefinitionCreationInformation eventReceiverInfo)
        {
            if (!DoesEventReceiverExistByName(ctx, list, eventReceiverInfo.ReceiverName))
            {
                list.EventReceivers.Add(eventReceiverInfo);
                ctx.ExecuteQuery();
            }
        }


现在,将远程事件接收器添加到文档库。 将文档上载到 AutoTaggingSampleItemAdding 文档库时,文档标记了该用户的 Classification 自定义用户配置文件属性值。

下图显示如何查看文档中的属性。

库中属性已展开的测试文档的屏幕截图。


下图显示有 Classification 字段的文档的元数据。

显示测试文档的元数据(Classification 字段中为 HBI)的屏幕截图。


AutoTaggingService.svc.cs 文件中的 HandleAutoTaggingItemAdding 方法使用 GetProfilePropertyFor 方法检索 Classification 用户配置文件属性的值。

public void HandleAutoTaggingItemAdding(SPRemoteEventProperties properties,SPRemoteEventResult result)
        {
            using (ClientContext ctx = TokenHelper.CreateRemoteEventReceiverClientContext(properties))
            {
                if (ctx != null)
                {
                    var itemProperties = properties.ItemEventProperties;
                    var _userLoginName = properties.ItemEventProperties.UserLoginName;
                    var _afterProperites = itemProperties.AfterProperties;
                    if(!_afterProperites.ContainsKey(ScenarioHandler.FLD_CLASSIFICATION_INTERNAL_NAME))
                    {
                        string _classficationToSet = ProfileHelper.GetProfilePropertyFor(ctx, _userLoginName, Constants.UPA_CLASSIFICATION_PROPERTY);
                        if(!string.IsNullOrEmpty(_classficationToSet))
                        { 
                            var _formatTaxonomy = AutoTaggingHelper.GetTaxonomyFormat(ctx, _classficationToSet);
                            result.ChangedItemProperties.Add(ScenarioHandler.FLD_CLASSIFICATION_INTERNAL_NAME, _formatTaxonomy);
                        }
                    }
                }
            }
        }


> [!IMPORTANT] > 从 GetProfilePropertyFor** 方法检索 **Classification** 值后,必须先以某种方式设置分类值的格式,然后才能将其存储为文档中的元数据。 AutoTaggingHelper.cs 文件中的 GetTaxonomyFormat 方法演示如何设置分类值的格式。
public static string GetTaxonomyFormat(ClientContext ctx, string term)
        { 
            if(string.IsNullOrEmpty(term))
            {
                throw new ArgumentException(string.Format(EXCEPTION_MSG_INVALID_ARG, "term"));
            }
            string _result = string.Empty;
            var _list = ctx.Web.Lists.GetByTitle(TAXONOMY_HIDDEN_LIST_NAME);
            CamlQuery _caml = new CamlQuery();

            _caml.ViewXml = string.Format(TAXONOMY_CAML_QRY, term);
            var _listItemCollection = _list.GetItems(_caml);

            ctx.Load(_listItemCollection,
                eachItem => eachItem.Include(
                    item => item,
                    item => item.Id,
                    item => item[TAXONOMY_FIELDS_IDFORTERM]));
            ctx.ExecuteQuery();

            if (_listItemCollection.Count > 0)
            {
                var _item = _listItemCollection.FirstOrDefault();
                var _wssId = _item.Id;
                var _termId = _item[TAXONOMY_FIELDS_IDFORTERM].ToString(); ;
                _result = string.Format(TAXONOMY_FORMATED_STRING, _wssId, term, _termId);
            }

            return _result;
        }

删除事件方案 1 按钮

选择“删除事件方案 1”按钮时,便会运行以下代码,从文档库中删除事件接收器。

public static void RemoveEventReceiver(ClientContext ctx, List list, string receiverName)
        {
            ctx.Load(list, lib => lib.EventReceivers);
            ctx.ExecuteQuery();

            var _rer = list.EventReceivers.Where(e => e.ReceiverName == receiverName).FirstOrDefault();
            if(_rer != null)
            {
                _rer.DeleteObject();
                ctx.ExecuteQuery();
            }
        }

另请参阅