Skip to main content

Custom Actions Event Receiver

using System;
using System.Collections.ObjectModel;
using System.IO;
using System.Runtime.InteropServices;
using System.Xml;
using Microsoft.SharePoint;
using Microsoft.SharePoint.Administration;
using Nintex.Workflow;
using Nintex.Workflow.Administration;
using Nintex.Workflow.Common;
using System.Reflection;

namespace CFSP.CustomActions.Features.WebApplication___Custom_Actions
{
    [Guid("07607091-449b-422b-94e4-84e6d863eb9e")]
    public class WebApplication___Custom_ActionsEventReceiver : SPFeatureReceiver
    {
        #region Events

        public override void FeatureActivated(SPFeatureReceiverProperties properties)
        {
            SPWebApplication parent = (SPWebApplication) properties.Feature.Parent;

            AddCustomAction(parent, properties, "ReadFromPropertyBagAction.nwa");
        }

        public override void FeatureDeactivating(SPFeatureReceiverProperties properties)
        {
            SPWebApplication parent = (SPWebApplication) properties.Feature.Parent;

            RemoveCustomAction(parent, properties,
                "CFSP.CustomActions.ReadFromPropertyBag.ReadFromPropertyBagAdapter",
                Assembly.GetExecutingAssembly().FullName);

        }
        #endregion

        #region Methods

        /// <summary>
        /// Adds a nintex custom action to SharePoint
        /// </summary>
        /// <param name="parent"></param>
        /// <param name="properties"></param>
        /// <param name="pathToNWAFile"></param>
        protected void AddCustomAction(SPWebApplication parent, SPFeatureReceiverProperties properties,
            string pathToNWAFile)
        {

            // First step is register the action to the Nintex Workflow database
            XmlDocument nwaXml = GetNWADefinition(properties, pathToNWAFile);

            ActivityReference newActivityReference = ActivityReference.ReadFromNWA(nwaXml);

            ActivityReference action = ActivityReferenceCollection.FindByAdapter(newActivityReference.AdapterType,
                newActivityReference.AdapterAssembly);

            if (action != null)
            {
                // update the details if the adapter already exists
                ActivityReferenceCollection.UpdateActivity(action.ActivityId, newActivityReference.Name,
                    newActivityReference.Description, newActivityReference.Category,
                    newActivityReference.ActivityAssembly, newActivityReference.ActivityType,
                    newActivityReference.AdapterAssembly, newActivityReference.AdapterType,
                    newActivityReference.HandlerUrl, newActivityReference.ConfigPage,
                    newActivityReference.RenderBehaviour, newActivityReference.Icon, newActivityReference.ToolboxIcon,
                    newActivityReference.WarningIcon, newActivityReference.QuickAccess,
                    newActivityReference.ListTypeFilter);
            }
            else
            {
                ActivityReferenceCollection.AddActivity(newActivityReference.Name, newActivityReference.Description,
                    newActivityReference.Category, newActivityReference.ActivityAssembly,
                    newActivityReference.ActivityType, newActivityReference.AdapterAssembly,
                    newActivityReference.AdapterType, newActivityReference.HandlerUrl, newActivityReference.ConfigPage,
                    newActivityReference.RenderBehaviour, newActivityReference.Icon, newActivityReference.ToolboxIcon,
                    newActivityReference.WarningIcon, newActivityReference.QuickAccess,
                    newActivityReference.ListTypeFilter);
                action = ActivityReferenceCollection.FindByAdapter(newActivityReference.AdapterType,
                    newActivityReference.AdapterAssembly);
            }

            // Second step is to modify the web.config file to allow use of the activity in declarative workflows
            string activityTypeName = string.Empty;
            string activityNamespace = string.Empty;
            Utility.ExtractNamespaceAndClassName(action.ActivityType, out activityTypeName, out activityNamespace);
            AuthorisedTypes.InstallAuthorizedWorkflowTypes(parent, action.ActivityAssembly, activityNamespace,
                activityTypeName);

            // Third step is to activate the action for the farm
            ActivityActivationReference reference = new ActivityActivationReference(action.ActivityId, Guid.Empty,
                Guid.Empty);
            reference.AddOrUpdateActivationReference();
        }


        /// <summary>
        /// Removes a nintex custom action from SharePoint
        /// </summary>
        /// <param name="parent"></param>
        /// <param name="properties"></param>
        /// <param name="adapterType"></param>
        /// <param name="adapterAssembly"></param>
        protected void RemoveCustomAction(SPWebApplication parent, SPFeatureReceiverProperties properties,
            string adapterType, string adapterAssembly)
        {
            ActivityReference action = ActivityReferenceCollection.FindByAdapter(adapterType, adapterAssembly);
            if (action != null)
            {
                // Remove the action definition from the workflow configuration database if the Feature is not activated elsewhere
                if (!IsFeatureActivatedInAnyWebApp(parent, properties.Definition.Id))
                    ActivityReferenceCollection.RemoveAction(action.ActivityId);

                string activityTypeName = string.Empty;
                string activityNamespace = string.Empty;
                Utility.ExtractNamespaceAndClassName(action.ActivityType, out activityTypeName, out activityNamespace);

                // Remove the web.config entry
                Collection<SPWebConfigModification> modifications = parent.WebConfigModifications;
                foreach (SPWebConfigModification modification in modifications)
                {
                    if (modification.Owner == AuthorisedTypes.OWNER_TOKEN)
                        // OWNER_TOKEN is the owner for any web config modification added by Nintex Workflow
                    {
                        if (IsAuthorizedTypeMatch(modification.Value, action.ActivityAssembly, activityTypeName,
                            activityNamespace))
                        {
                            modifications.Remove(modification);
                            parent.Farm.Services.GetValue<SPWebService>().ApplyWebConfigModifications();
                            break;
                        }
                    }
                }

            }
        }

        private bool IsAuthorizedTypeMatch(string modification, string activityAssembly, string activityType,
            string activityNamespace)
        {
            XmlDocument doc = new XmlDocument();
            doc.LoadXml(modification);
            if (doc.FirstChild.Name == "authorizedType")
            {
                return (doc.SelectSingleNode("//@TypeName").Value == activityType
                        && doc.SelectSingleNode("//@Namespace").Value == activityNamespace
                        && doc.SelectSingleNode("//@Assembly").Value == activityAssembly);

            }

            return false;
        }

        private bool IsFeatureActivatedInAnyWebApp(SPWebApplication thisWebApplication, Guid thisFeatureId)
        {
            SPWebService webService = SPWebService.ContentService;
            if (webService == null)
                throw new ApplicationException("Cannot access ContentService");

            SPWebApplicationCollection webApps = webService.WebApplications;
            foreach (SPWebApplication webApp in webApps)
            {
                if (webApp != thisWebApplication)
                    if (webApp.Features[thisFeatureId] != null)
                        return true;
            }

            return false;
        }

        private XmlDocument GetNWADefinition(SPFeatureReceiverProperties properties, string pathToNWAFile)
        {
            using (Stream stream = properties.Definition.GetFile(pathToNWAFile))
            {
                XmlDocument nwaXml = new XmlDocument();
                nwaXml.Load(stream);
                return nwaXml;
            }
        }

        #endregion
    }
}

Comments

Popular posts from this blog

Update user language and regional settings with CSOM

Following my previous post around multilingual aspects of SharePoint Online:  Modify Site Regional and Language settings with JSOM and JavaScript Here is some CSOM code which updates the personal regional settings of the current user or another user (if you are a tenant admin and have the rights to update user profiles) Before update: The code: using Microsoft.SharePoint.Client ; using Microsoft.SharePoint.Client.UserProfiles ; using System.Security ; namespace UpdateLanguagePreference { class Program { static void Main ( string[] args ) { //Tenant Admin Details string tenantAdministrationUrl = " https://yoursite-admin.sharepoint.com/ " ; string tenantAdminLoginName = " tenantadmin@yoursite.onmicrosoft.com " ; string tenantAdminPassword = " password " ; //AccountName of the user whos property you want to update. ...

Power shell Script to get External Users on Office 365

Hello Everyone,  Below is the Powershell script to get all external users from office 365 tenant. #--------------------------------------------------------------------------------------------------------------------------- $host.Runspace.ThreadOptions = "ReuseThread" #Definition of the function that gets all the external users in a SharePoint Online Tenant. function Get-SPOExternalUsers {     param ($sUserName,$sMessage,$sSPOAdminCenterUrl)     try     {             Write-Host "----------------------------------------------------------------------------"  -foregroundcolor Green         Write-Host "Getting all the external users in a SharePoint Online Tenant" -foregroundcolor Green         Write-Host "----------------------------------------------------------------------------"  -foregroundcolor Green         $msolcred = Get-Credential -UserName...

Build and Deploy a custom theme in SharePoint 2019: Using C# and Site features

Custom Theme and Branding are common to use cases and all kinds of business users like to have the personalized team and collaboration sites. today I am posting C# code that will help to build custom features for SharePoint 2019 site.   If need any assistance, I would be happy to help: kamal_pandey@outlook.com  ----------------------------- Code to build  custom features---------- using System; using System.Collections.Generic; using System.Globalization; using System.Linq; using System.Text; using System.Threading.Tasks; using Microsoft.SharePoint; using Microsoft.SharePoint.Utilities; namespace SharePointBranding.Code {     public class BrandingManager     {         public SPWeb Web { get; set; }         public BrandingManager(SPWeb web)         {             Web = web;         }         public void SetMasterPage(stri...