Custom Role Provider Fetching Roles from SQL and Users from Active Directory
- Last UpdatedJun 10, 2024
- 11 minute read
Setup: Open a new .NET Class Library project, provide the namespace and class name for the project accordingly and add reference to "Workflow.NET.NET2.dll" from [AVEVA Work Tasks Installed Path]\AVEVA\Work Tasks\Bin folder.
PROCEDURE
DLL REFERENCE
Workflow.NET.NET2
System.DirectoryServices
NAMESPACE USED
System
System.IO
System.Collections.Generic
System.Text
System.Collections
System.Collections.Specialized
System.Data
System.Xml
System.DirectoryServices
System.Security.Cryptography
System.Text.RegularExpressions
Sample Code
To support various type of Active Directory, you need to use appropriate APIs. Example, for RODC use ReadonlyServer authenticationType while creating instance of DirectoryEntry.
using Skelta.Core;
using Skelta.Entity;
using Skelta.Entity.RoleEntityProvider;
using System;
using System.Collections;
using System.Collections.Generic;
using System.Collections.Specialized;
using System.DirectoryServices;
using System.IO;
using System.Xml;
using Workflow.NET;
using Workflow.NET.Interfaces;
using Workflow.NET.Storage;
namespace CustomUserEntityProvider
{
public class Roles : DataSourceProviderBase, IRoleEntityDataSourceProvider, ISkeltaAddInProvider
{
bool _IsConnectionValid = false;
string _ConnectionString;
string _SQLConnectionString;
string _LDAPConnectionString;
string _ApplicationName;
private string _UserID, _Password, sDataSourceType;
private bool _IsPasswordEncrypted = false;
private Workflow.NET.Log log = new Workflow.NET.Log();
private string _LDAPServer, _LDAPSearchBase, _LDAPBaseFilter;
private SearchScope _SearchScope;
string _ProviderPrefix = "";
private Config config = new Config();
private ReferralChasingOption _ReferralChasing;
private int _SizeLimit;
private TimeSpan _TimeOut;
private Log logger = new Log();
#region IRoleEntityDataSourceProvider Members
/// <summary>
/// Name of the Repository
/// </summary>
public string ApplicationName
{
get
{
return this._ApplicationName;
}
set
{
this._ApplicationName = value;
}
}
/// <summary>
/// Connection string
/// </summary>
public string ConnectionString
{
get
{
return this._ConnectionString;
}
set
{
this._ConnectionString = value;
}
}
/// <summary>
/// SQL Connection string
/// </summary>
public string SQLConnectionString
{
get
{
return this._SQLConnectionString;
}
set
{
this._SQLConnectionString = value;
}
}
/// <summary>
/// LDAP Connection string
/// </summary>
public string LDAPConnectionString
{
get
{
return this._LDAPConnectionString;
}
set
{
this._LDAPConnectionString = value;
}
}
/// <summary>
/// The identifier type value should always be string.
/// It's always string as the type for user entity provider will always be /// string.
/// </summary>
public string EntityIdentifierType
{
get
{
return "string";
}
}
/// <summary>
/// Getting the information like SizeLimit,Timeout,Referral Chasing from the /// definition xml
/// </summary>
internal class XmlPropertyHandler
{
private XmlDocument xmlDoc;
/// <summary>
/// Loads the definition xml value to the xml document
/// </summary>
/// <param name="xmlString">Definition xml is passed as string</param>
public XmlPropertyHandler(string xmlString)
{
xmlDoc = new XmlDocument();
xmlDoc.Load(new StringReader(xmlString));
}
/// <summary>
/// Getting the value of Searchscope[Subtree,base etc] from the xml document
/// </summary>
/// <returns></returns>
internal SearchScope GetSearchScope()
{
XmlNodeList xnl = xmlDoc.GetElementsByTagName("SearchScope");
if (xnl == null || xnl.Count == 0)
return SearchScope.Subtree; //Default Search Scope;
string SearchScopeString = xnl.Item(0).InnerText.ToUpperInvariant().Trim();
if (SearchScopeString == "BASE")
{
return SearchScope.Base;
}
else
{
if (SearchScopeString == "ONELEVEL")
return SearchScope.OneLevel;
else
return SearchScope.Subtree;
}
}
/// <summary>
/// Checks whether password is encrypted or not
/// </summary>
/// <returns></returns>
internal bool IsPasswordEncrypted()
{
XmlNodeList xnl = xmlDoc.GetElementsByTagName("AuthenticationPassword");
if (xnl == null || xnl.Count == 0)
return false; //Default Settings;
if (xnl.Item(0).Attributes["IsEncrypted"] == null)
{
return false;
}
string IsPasswordEncryptedString = xnl.Item(0).Attributes["IsEncrypted"].Value.ToUpperInvariant().Trim();
if (IsPasswordEncryptedString == "TRUE")
{
return true;
}
else
{
return false;
}
}
//Getting the sizelimit from the xml document
internal int GetSizeLimit()
{
XmlNodeList xnl = xmlDoc.GetElementsByTagName("SizeLimit");
if (xnl == null || xnl.Count == 0)
return 0;
string PageSizeString = xnl.Item(0).InnerText.ToUpperInvariant().Trim();
int PageSize = 0;
try
{
PageSize = int.Parse(PageSizeString);
}
catch { }
return PageSize;
}
//Getting the referral chasing value from the xml document
internal ReferralChasingOption GetReferralChasing()
{
XmlNodeList xnl = xmlDoc.GetElementsByTagName("ReferralChasing");
if (xnl == null || xnl.Count == 0)
return ReferralChasingOption.External; //Default Referral Chasing Value;
string RCString = xnl.Item(0).InnerText.ToUpperInvariant().Trim();
if (RCString == "NONE")
{
return ReferralChasingOption.None;
}
else
{
if (RCString == "ALL")
return ReferralChasingOption.All;
else
{
if (RCString == "SUBORDINATE")
return ReferralChasingOption.Subordinate;
else
return ReferralChasingOption.External;
}
}
}
//Getting Timeout value from the xml document
internal TimeSpan GetTimeOut()
{
XmlNodeList xnl = xmlDoc.GetElementsByTagName("TimeOut");
if (xnl == null || xnl.Count == 0)
return TimeSpan.FromSeconds(-1.0);
string TimeOutString = xnl.Item(0).InnerText.ToUpperInvariant().Trim();
double Seconds;
try
{
Seconds = double.Parse(TimeOutString);
}
catch
{
Seconds = -1.0;
}
return TimeSpan.FromSeconds(Seconds);
}
//Getting LDAPServer value from the xml document
internal string GetLDAPServer()
{
XmlNodeList xnl = xmlDoc.GetElementsByTagName("LDAPServer");
if (xnl == null || xnl.Count == 0)
return "LDAP://";
string s = xnl.Item(0).InnerText.Trim();
if (!s.EndsWith("/"))
{
s += "/";
}
return s;
}
//Getting LDAPSearchBase value from the xml document
internal string GetLDAPSearchBase()
{
XmlNodeList xnl = xmlDoc.GetElementsByTagName("LDAPSearchBase");
if (xnl == null || xnl.Count == 0)
return "";
return xnl.Item(0).InnerText.Trim();
}
//Getting Domain name from the xml document
internal string GetDomainName()
{
XmlNodeList xnl = xmlDoc.GetElementsByTagName("DomainName");
if (xnl == null || xnl.Count == 0)
return "";
return xnl.Item(0).InnerText.Trim();
}
//Getting Base filter value from the xml document
internal string GetBaseFilter()
{
XmlNodeList xnl = xmlDoc.GetElementsByTagName("LDAPBaseFilter");
if (xnl == null || xnl.Count == 0)
return "";
return xnl.Item(0).InnerText.Trim();
}
}
/// <summary>
/// Getting all the roles from sql table
/// </summary>
/// <returns> string i.e. all the roles from the table</returns>
public string[] GetAllRoles()
{
// When search is performed on role lookup , the context informaiton of search can be got using ther object
Skelta.Repository.Web.Lookup.RoleExecutionContextInfo searchContextInfo = Skelta.Repository.Web.Lookup.RoleExecutionContext.GetRoleExecutionContext();
string[] StrRolesArray = { };
StringCollection StrRoleCollection = new StringCollection();
System.Data.IDataReader idrRoles;
try
{
if (_IsConnectionValid)
{
// Modify the query as per your table details
string StrSQl = "";
if (searchContextInfo == null)
StrSQl = "SELECT DISTINCT Role FROM users WHERE Role is not NULL ORDER BY Role";
else
StrSQl = "SELECT DISTINCT Role FROM users WHERE Role is not NULL AND Role like '%" + searchContextInfo.RoleSearchString + "%' ORDER BY Role";
using (IDataHandler dbHandler = DataHandlerFactory.GetDataHandler(this.SQLConnectionString, "sql server"))
{
idrRoles = dbHandler.ExecuteReader(StrSQl);
while (idrRoles.Read())
{
int il1 = StrRoleCollection.Add(idrRoles.GetString(0));
}
idrRoles.Close();
StrRolesArray = new string[StrRoleCollection.Count];
StrRoleCollection.CopyTo(StrRolesArray, 0);
}
}
}
catch (Exception ex)
{
logger.LogError(ex, "@@Error while getting the SkeltaRoleProvider GetAllRoles");
}
return StrRolesArray;
}
//Getting DirectoryEntry object
private DirectoryEntry GetDirectoryEntry(string Path)
{
// To access an RODC environment appropriate flag need to be set or use alternate active directory API's. As an example
AuthenticationTypes authenticationTypesForSearch = AuthenticationTypes.Secure | AuthenticationTypes.ReadonlyServer | AuthenticationTypes.ServerBind;
DirectoryEntry de = new DirectoryEntry(Path,null,null, authenticationTypesForSearch);
return de;
}
/// <summary>
/// Collection of unique users id's which belongs to the Role.
/// The Keys for the colleciton hold the unique identifier of the user & the value could be name or any custom value.
/// </summary>
/// <param name="resource"></param>
/// <returns></returns>
public Dictionary<object, string> GetUsersInRole(string roleName)
{
Dictionary<object, string> StrUsersInRoleArray = new Dictionary<object, string>();
try
{
using (DirectoryEntry entry = GetDirectoryEntry(_LDAPConnectionString))
{
using (DirectorySearcher deSearch = new DirectorySearcher())
{
deSearch.SearchRoot = entry;
deSearch.Filter = "(&(objectClass=group) (cn=" + roleName + "))";
SearchResultCollection results = deSearch.FindAll();
if (results.Count > 0)
{
try
{
using (DirectoryEntry group = GetDirectoryEntry(results[0].Path))
{
object members = group.Invoke("Members", null);
foreach (object member in (IEnumerable)members)
{
try
{
using (DirectoryEntry x = new DirectoryEntry(member))
{
string user = x.Properties["sAMAccountName"].Value.ToString();
StrUsersInRoleArray.Add(user, user);
}
}
catch (Exception e)
{
throw e;
}
}
}
}
catch (Exception e)
{
throw e;
}
}
}
}
}
catch (Exception ex)
{
throw new Workflow.NET.ActiveDirectoryException(Skelta.Core.DS.SeverityLevel.Information, "Error while retrieving users from role (" + roleName + ")" + ex.Message, new Skelta.Core.ApplicationObject(RepositoryName));
}
return StrUsersInRoleArray;
}
/// <summary>
/// Get the roles associated to a user.
/// Called from Queue or security for getting the users associated to a role after role selection
/// </summary>
/// <param name="resource"></param>
/// <returns></returns>
public string[] GetRolesForUser(Workflow.NET.Resource resource)
{
StringCollection StrRoleForUserCollection = new StringCollection();
string[] StrRolesForUserArray = { };
try
{
using (DirectoryEntry entry = GetDirectoryEntry(_LDAPConnectionString))
{
using (DirectorySearcher mySearcher = new DirectorySearcher(entry))
{
mySearcher.Filter = "(&(objectClass=user) (cn=" + ((resource.Properties.Name.Value != null && resource.Properties.Name.Value.ToString() != "") ? resource.Properties.Name.Value.ToString().ToLowerInvariant() : resource.Properties.Identifier.Value.ToString().ToLowerInvariant()) + "))";
mySearcher.PropertiesToLoad.Add("memberOf");
int propertyCount;
SearchResult myresult = mySearcher.FindOne();
propertyCount = myresult.Properties["memberOf"].Count;
string dn;
int equalsIndex = 0;
for (int i = 0; i <= propertyCount - 1; i++)
{
dn = (string)myresult.Properties["memberOf"][i];
string strRoles = dn.Trim("CN=".ToCharArray()).Split(',')[0];
if (equalsIndex == -1)
{
return null;
}
StrRoleForUserCollection.Add(strRoles);
}
}
}
StrRolesForUserArray = new string[StrRoleForUserCollection.Count];
StrRoleForUserCollection.CopyTo(StrRolesForUserArray, 0);
}
catch (Exception ex)
{
if (ex.GetType() == typeof(System.NullReferenceException))
{
throw new Workflow.NET.ActiveDirectoryException(Skelta.Core.DS.SeverityLevel.Information, "User does not have a role assigned", new Skelta.Core.ApplicationObject(RepositoryName));
}
else
{
throw new Workflow.NET.ActiveDirectoryException(Skelta.Core.DS.SeverityLevel.Information, "Error while retrieving roles for the user" + ex.Message, new Skelta.Core.ApplicationObject(RepositoryName));
}
}
return StrRolesForUserArray;
}
/// <summary>
/// Checks if the user belongs to a specific role.
/// </summary>
/// <param name="resource">User object</param>
/// <param name="roleName">Role name</param>
/// <returns></returns>
public bool IsUserInRole(Workflow.NET.Resource resource, string roleName)
{
bool isGroupMember = false;
try
{
using (DirectoryEntry entry = new DirectoryEntry(_LDAPConnectionString))
{
DirectorySearcher deSearch = new DirectorySearcher();
deSearch.SearchRoot = entry;
deSearch.Filter = "(&(objectClass=group) (cn=" + roleName + "))";
SearchResultCollection results = deSearch.FindAll();
if (results.Count > 0)
{
DirectoryEntry group = null;
try
{
group = GetDirectoryEntry(results[0].Path);
object members = group.Invoke("Members", null);
foreach (object member in (IEnumerable)members)
{
DirectoryEntry x = null;
try
{
x = new DirectoryEntry(member);
if (x.Properties[EntityItemProperties.Identifier.PropertyName].Value.ToString().ToLowerInvariant() == resource.Properties.Identifier.Value.ToString().ToLowerInvariant())
{
isGroupMember = true;
break;
}
}
catch (Exception e)
{
throw e;
}
finally
{
if (x != null)
{
x.Close();
x.Dispose();
}
}
}
}
catch (Exception e)
{
throw e;
}
}
}
}
catch (Exception ex)
{
log.LogInformation("Error while checking user from role (" + roleName + ") for domain(" + _ConnectionString + ")" + ex.Message);
}
return isGroupMember;
}
/// <summary>
/// Verify whether role exists in the sql provider
/// </summary>
/// <param name="roleName">role name </param>
/// <returns></returns>
public bool RoleExists(string roleName)
{
bool CheckRoleStatus = false;
if (_IsConnectionValid)
{
string StrRoleName = roleName;
string StrSQl = "SELECT distinct role FROM users WHERE role =@role";
IDataHandler dbHandler = DataHandlerFactory.GetDataHandler(this._SQLConnectionString, "sql server");
System.Data.IDataReader idrRoles;
if (!string.IsNullOrEmpty(StrRoleName))
{
using (dbHandler)
{
System.Data.IDataParameter iparmRole = dbHandler.GetParameter("@role", roleName);
idrRoles = dbHandler.ExecuteReader(StrSQl, iparmRole);
while (idrRoles.Read())
{
CheckRoleStatus = true;
}
idrRoles.Close();
}
}
}
return CheckRoleStatus;
}
#endregion
#region ISkeltaAddInProvider Members
Guid _Id = Guid.Empty;
string _Settings = "";
Guid ISkeltaAddInProvider.Id
{
get { return _Id; }
}
//Initializing the provider
void ISkeltaAddInProvider.InitializeProvider(string settings, Guid id)
{
_Id = id;
_Settings = settings;
}
string ISkeltaAddInProvider.Settings
{
get { return _Settings; }
}
#endregion
#region "DataSourceProviderBase"
/// <summary>
/// Initializing the preferences [ReferralChasing,SearchScope,SizeLimit, LDAPBaseFilter] of Active directory
/// </summary>
/// <param name="definitionXml"></param>
public override void Initialize(string definitionXml)
{
try
{
XmlDocument xDoc;
xDoc = new XmlDocument();
try
{
xDoc.Load(new StringReader(definitionXml));
}
catch (System.Exception ex)
{
logger.LogError(ex, "Could not open the document ()");
throw ex;
}
//Get connection string
try
{
XmlNode xnc = xDoc.GetElementsByTagName("datasource").Item(0);
_SQLConnectionString = xnc.InnerText;
sDataSourceType = "sql server";
_IsConnectionValid = true;
if (string.IsNullOrEmpty(_LDAPServer))
{
XmlPropertyHandler xmlHandler = new XmlPropertyHandler(definitionXml);
_SearchScope = xmlHandler.GetSearchScope();
_ReferralChasing = xmlHandler.GetReferralChasing();
_SizeLimit = xmlHandler.GetSizeLimit();
_TimeOut = xmlHandler.GetTimeOut();
//_UserID = xmlHandler.GetUserID();
// _Password = xmlHandler.GetPassword();
_LDAPBaseFilter = xmlHandler.GetBaseFilter();
_LDAPSearchBase = xmlHandler.GetLDAPSearchBase();
_LDAPServer = xmlHandler.GetLDAPServer();
_ProviderPrefix = xmlHandler.GetDomainName();
if (!string.IsNullOrEmpty(_LDAPSearchBase)
&& string.IsNullOrEmpty(_ProviderPrefix))
_ProviderPrefix = _LDAPSearchBase.Split(',')[0].Split('=')[1] + "\\";
_IsPasswordEncrypted = xmlHandler.IsPasswordEncrypted();
_LDAPConnectionString = _LDAPServer + _LDAPSearchBase;
}
}
catch (System.Exception ex)
{
logger.LogError(ex, "Cannot get required information.");
throw ex;
}
}
catch (Exception ex)
{
logger.LogError(ex, "@@SkeltaMembershipDataProvider@Initialize");
throw ex;
}
}
internal delegate string GetDistiguisedNameFromCommonNameHandler(string CN);
internal class QueryToSearchFilterConversion
{
Hashtable Expressions = new Hashtable();
Hashtable Brackets = new Hashtable();
ArrayList BracketsArray = new ArrayList();
public string Output = "";
private Hashtable ParamHashTable = new Hashtable();
}
public override IEntityDataSourceProvider Clone()
{
//Clone the instance
Roles roleProvider = new Roles();
roleProvider = this;
return roleProvider;
}
/// <summary>
/// GetEntityItem is the only interface method of IEntityDataSourceProvider which will be used. This method call is initiated after Role is selected from UI and the virtual id for the role gets created.
/// This method does not get called while listing different roles for the provider.
/// </summary>
/// <param name="entityItemId"></param>
/// <returns></returns>
public override EntityItem GetEntityItem(object entityItemId)
{
string Identifier = EntityItemProperties.Identifier.PropertyName;
//It's role provider, so return single property value
EntityItemPropertiesCollection tempResProperties = EntityItemProperties.CreateDeepClone();
EntityItem entityItem = new EntityItem();
//We need to consider role itself as unique identifier.
tempResProperties[Identifier].Values.Add(entityItemId);
if (!string.IsNullOrEmpty(ProviderPrefix))
entityItemId = entityItemId.ToString().Replace(ProviderPrefix, "");
//It's mandatory for the role provider to perisist the RoleName in db, if a property named RoleName is not
//specfified or coded to be perissted in DB then the below code can be used to add or set the same
if (!tempResProperties.ContainsKey("RoleName"))
{
EntityItemProperty roleProperty = new EntityItemProperty();
roleProperty.PropertyName = "RoleName";
roleProperty.PropertyDisplayName = "Role";
roleProperty.PersistColumn = "RoleName";
roleProperty.Persist = true;
tempResProperties.Add(roleProperty.PropertyName, roleProperty);
}
else
{
tempResProperties["RoleName"].PersistColumn = "RoleName";
tempResProperties["RoleName"].Persist = true;
}
tempResProperties["RoleName"].Values.Add(entityItemId);
entityItem.Properties = tempResProperties;
return entityItem;
}
#endregion
}
}
Table Configuration:
Roles Database:
The roles database used in this example, has a single table called Users, which uses a column "Role" to assign/identify roles for the users.
Configuring custom roles involves entries in three tables of Skelta Repository database, namely:
-
SKAddInProviders
-
SKEntity
-
SKEntityDataSourceProvider
The order and the detailed steps of configuration is listed below:
In the SKAddInProvider insert a new record with the following field values:
|
Column Name |
Value |
|---|---|
|
ID |
Auto Generated |
|
Type |
Roles |
|
Name |
Name for the Custom roles |
|
Description |
Any description / Null |
|
ClassName |
Name of the class implementing |
|
Assembly |
Path of the DLL built. |
|
IsGacAssembly |
False |
|
Isdefault |
False |
|
LastUpdatedDateTime |
Date time value |
Example
Insert into SKAddInProviders (Type,Name,Description,ClassName,Assembly,IsGacAssembly,Isdefault,LastUpdatedDateTime)VALUES('Role','NewRoles','try mapping','NewRoles.Roles','bin\NewRoles.dll','False','False','5/12/2008 7:01:01 AM')
-
Open the SKEntity table. No entries are required. Copy the Entity table "Id" column value of the RoleEntity row , for the entry to be made in SKEntityDataSourceProvider table.
-
Open the SKEntityDataSourceProvider table, you will have a row with the default user provider "activedirectory". Now insert a new entry for our custom roles as defined.
Column
Value
ID
Auto generated
Application
Name of the Repository
Entity ID
Copy the Id Column value of SKEntity of RoleEntity row here.
DisplayName
Forms
DefinitionXML
The definition xml should have details related to both sql provider and Active directory.
for example, in the following definition xml the data source
<dataproviders><provider name="sqlprovider" type="sql server"><properties><property name="role" type="string" displayname="Role" purpose="identifier"/></properties><datasource>Data Source=SKELTADTP38;Initial Catalog=DS3;Integrated Security=True</datasource><Preferences><SearchScope>SubTree</SearchScope><ReferralChasing>External</ReferralChasing><TimeOut>60</TimeOut><SizeLimit>0</SizeLimit><AuthenticationUser></AuthenticationUser><AuthenticationPassword ></AuthenticationPassword></Preferences><LDAPServer>LDAP://</LDAPServer><LDAPSearchBase>DC=skelta,DC=dom</LDAPSearchBase><LDAPBaseFilter>(objectCategory=Person)</LDAPBaseFilter><DomainName>SKELTA\</DomainName></provider></dataproviders>
Provider
column must have the same name given in the "Name" column of SKAddInProviders table.
Instance Name
activedirectory
Example:
insert into SKEntityDataSourceProvider(Application,EntityID,DisplayName,DefinitionXML,Provider,InstanceName) VALUES('ADSQLRep','69b60890-c24d-4ae5-8f03-cdd709a50d17','Forms','<dataproviders><provider name="sqlprovider" type="sql server"><properties><property name="role" type="string" displayname="Role" purpose="identifier"/></properties><datasource>Data Source=SKELTADTP38;Initial Catalog=DS3;Integrated Security=True</datasource><Preferences><SearchScope>SubTree</SearchScope><ReferralChasing>External</ReferralChasing><TimeOut>60</TimeOut><SizeLimit>0</SizeLimit><AuthenticationUser></AuthenticationUser><AuthenticationPassword ></AuthenticationPassword></Preferences><LDAPServer>LDAP://</LDAPServer><LDAPSearchBase>DC=skelta,DC=dom</LDAPSearchBase><LDAPBaseFilter>(objectCategory=Person)</LDAPBaseFilter><DomainName>SKELTA\</DomainName></provider></dataproviders>','NewRoles','activedirectory').
-
In the SKEntityDatasourceProvider table, every repository will have two entries. One with the display name "user provider name" for example, "activedirectory" and the other with the "user provider role" for example, "Active Directory role". Delete the row corresponding to the display name " Active Directory role". This is done to avoid the roles to be listed in the Enterprise Console from the active directory.
The Classes and Interfaces that need to be used to implement Custom Roles in AVEVA Work Tasks are:
-
The Custom Roles Class has to be derived over "DataSourceProviderBase" part of Skelta.Entity namespace.
-
The Interface to be implemented by the Custom roles are:
-
IRoleEntityDataSourceProvider – [Skelta.Entity.RoleEntityProvider]
-
ISkeltaAddInProvider – [Skelta.Core]
-
Key Methods and Properties:
IRoleEntityDataSourceProvider Members
-
public string IRoleEntityDataSourceProvider.EntityIdentifierType() - This property returns the "identifier" type for the resources, which is "string" by default.
-
void IRoleEntityDataSourceProvider.Initialize() - This method is used to initialize the XML definition of the roles entity.
ISkeltaAddInProvider Members
-
Guid ISkeltaAddInProvider.Id - This property returns the AddInProviderId of the default role provider.
-
void ISkeltaAddInProvider.InitializeProvider(string settings, Guid id) - This method is used to initialize the provider.
DataSourceProviderBase Class Members
-
public override void Initialize(string definitionXml) - This method reads the XML definition.
-
public override EntityItem GetEntityItem(object entityId) - This returns the entity type, which is role and returns single property value.
After defining the methods and the properties as per the custom roles definition being used, build the project that generates <custom roles name>. DLL. This DLL needs to be now copied to the AVEVA Work Tasks bin folder.
Troubleshooting
You will get the "Object reference not set to an instance of an object" error when you try to open the Enterprise Console. One of the reason for this could be the access to the assembly path [that you have mentioned in the SKAddInProviders tables] is denied. To avoid this:
-
Copy the dll ( NewRoles.dll ) which you have created and put it in the folder where you have full access.
-
In SKAddInProviders table's Assembly column, update the assembly path.
Example:
-
If your dll is in C:\, then in the Assembly column of the SKAddInProviders table, update the url as C:\NewRoles.dll.
-
If your dll is in D:\Sample, then in the Assembly column of the SKAddInProviders table, update the url as D:\Sample\NewRoles.dll.