Step 5: Create Custom Role Entity Data Source Provider
- Last UpdatedJun 10, 2024
- 8 minute read
The custom role entity provider fetches the role information from the same table "SqlUsers". The column Role in this table contains role information for a user.
The below configuration is mandatory for the Role Provider.
-
The EntityIdentifierType method should always return string as the user entity provider value type is always a string (Ex: "<Provider Instance Name>::<User Unique Identifier>").
-
The instance for User entity data source provider & Role entity data source provider should be same. The role provider does not exist by itself and is always mapped to a user provider. The users returned by the role needs to be mapped to a user provider to be used within AVEVA Work Tasks. Due to this behavior it's mandatory to have the providers having same instance name. For this sample the instance name used is "sqlproviderCustom".
-
The identifier type for Role provider is always string as the Role name itself is considered as unique identifier.
PROCEDURE
DLL REFERENCE
Workflow.NET.NET2 .dll
Skelta.Repository.Web.dll
System.Transactions.dll
NAMESPACE USED
System
System.Collections.Generic
System.Text
System.Xml
System.Xml.XPath
System.Transactions
System.Data
Workflow.NET
Workflow.NET.Interfaces
Skelta.Entity
System.Collections.Specialized
Workflow.NET.Storage
Skelta.Entity.RoleEntityProvider
System.IO
API Configuration
The Role Entity Data Source Provider should:
Inherit Skelta.Entity.DataSourceProviderBase class
Or
Implement Skelta.Entity.IEntityDataSourceProvider, Skelta.Core.ISkeltaAddInProvider
Implement interface Skelta.Entity.RoleEntityProvider.IRoleEntityDataSourceProvider
The only method which is accessed from IEntityDataSourceProvider for Role Provider is GetEntityItem (object entityId). Since there is no specific UI for role provider the other interface methods will be used for future release.
Skelta.Entity.RoleEntityProvider.IRoleEntityDataSourceProvider: The methods in this interface provide information related to Roles & Users related to each role.
Sample code
/// <summary>
/// Role entityt data source provider.
/// </summary>
class RoleEntityDataSourceProvider : DataSourceProviderBase,
Skelta.Entity.RoleEntityProvider.IRoleEntityDataSourceProvider
{
bool _IsConnectionValid = false;
string _ConnectionString;
string _ApplicationName;
private Log logger = new Log();
#region IRoleEntityDataSourceProvider Members
/// <summary>
/// Repository name.
/// </summary>
public string ApplicationName
{
get
{
return this._ApplicationName;
}
set
{
this._ApplicationName = value;
}
}
/// <summary>
/// Connection string for role provider
/// </summary>
public string ConnectionString
{
get
{
return this._ConnectionString;
}
set
{
this._ConnectionString = 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>
/// Return all the roles for the provider, Get called from Role look up provider (Queue, Security)
/// </summary>
/// <returns>Collection of roles as string array</returns>
public string[] GetAllRoles()
{
// When search is performed on role lookup , the context information 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 SqlUsers WHERE Role is not NULL ORDER BY Role";
else
StrSQl = "SELECT DISTINCT Role FROM SqlUsers WHERE Role is not NULL AND Role like '%" + searchContextInfo.RoleSearchString + "%' ORDER BY Role";
IDataHandler dbHandler = DataHandlerFactory.GetDataHandler(this.ConnectionString, "sql server");
using (dbHandler)
{
idrRoles = dbHandler.ExecuteReader(StrSQl);
while (idrRoles.Read())
{
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");
throw;
}
return StrRolesArray;
}
/// <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">resource </param>
/// <returns>Arrays of Roles</returns>
public string[] GetRolesForUser(Resource resource)
{
StringCollection StrRoleForUserCollection = new StringCollection();
System.Data.IDataReader idrRolesForUser;
string[] StrRolesForUserArray = { };
string StrSql = "";
StrSql = " SELECT Role";
StrSql += " FROM SqlUsers ";
StrSql += " WHERE UserId =@UserId";
try
{
if (_IsConnectionValid)
{
IDataHandler dbHandler = DataHandlerFactory.GetDataHandler(this.ConnectionString, "sql server");
using (dbHandler)
{
System.Data.IDataParameter iparmUserId = dbHandler.GetParameter("@UserId", resource.Properties.Identifier.Value);
idrRolesForUser = dbHandler.ExecuteReader(StrSql, iparmUserId);
while (idrRolesForUser.Read())
{
StrRoleForUserCollection.Add(idrRolesForUser.GetString(0));
}
idrRolesForUser.Close();
}
StrRolesForUserArray = new string[StrRoleForUserCollection.Count];
StrRoleForUserCollection.CopyTo(StrRolesForUserArray, 0);
}
}
catch (Exception ex)
{
logger.LogError(ex, "@@SkeltaRoleProvider@GetRolesForUser");
throw;
}
return StrRolesForUserArray;
}
/// <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="roleName"></param>
/// <returns></returns>
public Dictionary<object, string> GetUsersInRole(string roleName)
{
string StrSql = string.Empty;
Dictionary<object, string> StrUsersInRoleArray = new Dictionary<object, string>();
System.Data.IDataReader idrUsersInRole;
try
{
if (_IsConnectionValid)
{
StrSql = " SELECT UserId , Name";
StrSql += " FROM SqlUsers ";
StrSql += " WHERE Role=@Role";
IDataHandler dbHandler = DataHandlerFactory.GetDataHandler(this.ConnectionString, "sql server");
using (dbHandler)
{
System.Data.IDataParameter iparmUserId = dbHandler.GetParameter("@Role", roleName);
idrUsersInRole = dbHandler.ExecuteReader(StrSql, iparmUserId);
while (idrUsersInRole.Read())
{
StrUsersInRoleArray.Add(idrUsersInRole.GetGuid(0), idrUsersInRole.GetString(1));
}
idrUsersInRole.Close();
}
}
}
catch (Exception ex)
{
logger.LogError(ex, "@@SkeltaRoleProvider@GetUsersInRole");
throw;
}
return StrUsersInRoleArray;
}
/// <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(Resource resource, string roleName)
{
string StrSql = string.Empty;
bool IsUserInRole = false;
System.Data.IDataReader idrUserInRole;
try
{
if (_IsConnectionValid)
{
StrSql = " SELECT * FROM SqlUsers";
StrSql += " WHERE UserId = @UserId AND Role = @Role";
IDataHandler dbHandler = DataHandlerFactory.GetDataHandler(this.ConnectionString, "sql server");
using (dbHandler)
{
System.Data.IDataParameter iparmRolesAppid = dbHandler.GetParameter("@UserId", resource.Properties.Identifier.Value);
System.Data.IDataParameter iparmUserId = dbHandler.GetParameter("@Role", roleName);
idrUserInRole = dbHandler.ExecuteReader(StrSql, iparmRolesAppid, iparmUserId);
while (idrUserInRole.Read())
{
IsUserInRole = true;
break;
}
idrUserInRole.Close();
}
}
}
catch (Exception ex)
{
logger.LogError(ex, "@@SkeltaRoleProvider@IsUserInRole");
IsUserInRole = true;
}
return IsUserInRole;
}
void IRoleEntityDataSourceProvider.Initialize(string definition)
{
if (!_IsConnectionValid)
Initialize(definition);
}
/// <summary>
/// Checks if a role exists in the provider.
/// </summary>
/// <param name="roleName">Role name.</param>
/// <returns></returns>
public bool RoleExists(string roleName)
{
bool CheckRoleStatus = false;
try
{
if (_IsConnectionValid)
{
string StrRoleName = roleName;
string StrSQl = "SELECT distinct role FROM SqlUsers WHERE Role =@Role";
IDataHandler dbHandler = DataHandlerFactory.GetDataHandler(this.ConnectionString, "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();
}
}
}
}
catch
{
CheckRoleStatus = true;
}
return CheckRoleStatus;
}
#endregion
#region "DataSourceProviderBase"
/// <summary>
/// Loads the configuration info
/// </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);
_ConnectionString = xnc.InnerText;
_IsConnectionValid = true;
}
catch (System.Exception ex)
{
logger.LogError(ex, "Cannot get required information.");
throw ex;
}
}
catch (Exception ex)
{
logger.LogError(ex, "@@SkeltaMembershipDataProvider@Initialize");
throw ex;
}
}
/// <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="entityId">Id of the EntityItem</param>
/// <returns></returns>
public override EntityItem GetEntityItem(object entityId)
{
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(entityId);
if (!string.IsNullOrEmpty(ProviderPrefix))
entityId = entityId.ToString().Replace(ProviderPrefix, "");
tempResProperties["RoleName"].Values.Add(entityId);
entityItem.Properties = tempResProperties;
return entityItem;
//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;
//}
}
public override IEntityDataSourceProvider Clone()
{
//Create a shallow clone of the instance
RoleEntityDataSourceProvider roleProvider = new RoleEntityDataSourceProvider();
roleProvider = this;
return roleProvider;
}
#endregion
}
-
Configure Custom Role Entity Data Source Provider
Configuring custom role entity data source provider involves entries in two tables of the Repository
-
Table : SKAddInProviders , Object : Skelta.Core.AddInProvider
-
Table : SKEntityDataSourceProvider, Object : Skelta.Entity.DataSourceProvider
I. Adding Assembly information in SKAddInProvider table
API for Adding Role provider in SKAddInProvider table: Create an entry in SKAddInProviders for the role provider.
ApplicationObject applicationObject = new ApplicationObject("Sample Repository");
Skelta.Core.AddInProvider addInProvider = new Skelta.Core.AddInProvider(applicationObject);
addInProvider.Type = "Role";
addInProvider.Name = "customsqlroleprovider";
#warning : Make sure to change the assembly path
addInProvider.Description = "Sample Custom Role Entity Data Source Provider";
addInProvider.ClassName = "CustomUserEntityDataSourceProvider.RoleEntityDataSourceProvider";
addInProvider.AssemblyNameWithAbsoluteOrRelativePath = @"M:\Michelle\CustomUserEntityDataSourceProvider\CustomUserEntityDataSourceProvider\bin\Debug\CustomUserEntityDataSourceProvider.dll";
addInProvider.IsGacAssembly = false;
addInProvider.IsGlobal = true;
addInProvider.IsDefault = true; // The properties IsGacAssembly, IsGlobal, IsDefault is not currently in use. The value used in sample should be used "as is"
addInProvider.Save();
Database script for adding Role provider in SKAddInProviders table
INSERT INTO SKAddInProviders VALUES (newid(),'Role','customsqlroleprovider','Sample Custom Role Entity Data Source Provider','CustomUserEntityDataSourceProvider.RoleEntityDataSourceProvider','M:\Michelle\CustomUserEntityDataSourceProvider\CustomUserEntityDataSourceProvider\bin\Debug\CustomUserEntityDataSourceProvider.dll',null,0,1,1,getutcdate())
Note: Assembly path should be changed.
Verification:
The above code creates an entry in SKAddInProviders table with type as Role. The entry in Repository DB can be verified in database by running the query select * from SKAddInProviders Where Name='customsqlroleprovider '
|
Column Name |
Value |
|---|---|
|
ID |
Auto Generated |
|
Type |
Role |
|
Name |
customsqlroleprovider |
|
Description |
Sample Custom Role Entity Data Source |
|
ClassName |
CustomUserEntityDataSourceProvider. RoleEntityDataSourceProvider |
|
Assembly |
M:\Michelle\ CustomUserEntityDataSourceProvider\ CustomUserEntityDataSourceProvider\ bin\Debug \CustomUserEntityDataSourceProvider.dll |
|
Settings |
Null |
|
IsGacAssembly |
False |
|
Isdefault |
True |
|
IsGlobal |
True |
|
LastUpdatedDateTime |
Date time value |
II. Creating an Entry in SKEntityDataSourceProvider table
API for updating the List Role Provider with Custom Role Provider.
Update the role entry created for the list with custom role provider in SKEntityDataSourceProvider table.
Skelta.Entity.Entity entity = Skelta.Entity.Entity.GetEntity(applicationObject, "RoleEntity");
Skelta.Entity.DataSourceProvider roleEntitySourceProvider = null;
roleEntitySourceProvider = new Skelta.Entity.DataSourceProvider(applicationObject, "skeltalist");
//Role entity definition
string roleProviderDefinitionXML = "";
roleProviderDefinitionXML += "<dataproviders>";
roleProviderDefinitionXML += "<provider name=\"customsqlprovider\" type=\"Custom Role Provider\">";
roleProviderDefinitionXML += "<properties>";
roleProviderDefinitionXML += "<property name=\"Role\" type=\"string\" purpose=\"identifier\"/>";
roleProviderDefinitionXML += "<property name=\"RoleName\" type=\"string\" persist=\"true\" persistcolumn=\"rolename\"/>";
roleProviderDefinitionXML += "</properties>";
roleProviderDefinitionXML += "<datasource>server=localhost;database=SkeltaUsers;User Id=sa;pwd=XXXX;</datasource>";
roleProviderDefinitionXML += "</provider>";
roleProviderDefinitionXML += "</dataproviders>";
roleEntitySourceProvider.DefinitionXml = roleProviderDefinitionXML;
//Change the role provider name.
roleEntitySourceProvider.Provider = "customsqlroleprovider";
roleEntitySourceProvider.InstanceName = "sqlproviderCustom"; // Instance Name should be same as the instance name set for the user provider.
roleEntitySourceProvider.DisplayName = "Custom Role Provider";
// adding an entry in SKEntityDataSourceProvider fro Role provider
roleEntitySourceProvider.Entity = entity;
roleEntitySourceProvider.Save();
Database script for updating the Skelta list Role Provider with Custom Role Provider.
Make sure to update the connection string information in the definition XML with appropriate value. The provider column value should be same as the name column value inserted in SKAddInProviders table.
Note: Also, ensure that the query given below updates the row for the List Role Entity Data Source Provider and not the User Entity Data Source Provider.
//For Windows Authentication
Update SKEntityDataSourceProvider
Set
DefinitionXML =' <dataproviders><provider name="customsqlprovider" type="Custom Role Provider"><properties><property name="Role" type="string" purpose="identifier"/><property name="RoleName" type="string" persist="true" persistcolumn="rolename"/></properties>
<datasource>server=localhost; database=SkeltaUsers;Integrated Security=true;</datasource></provider></dataproviders>',
DisplayName='Custom Role Provider',Provider='customsqlroleprovider', InstanceName='sqlproviderCustom' Where InstanceName='skeltalist' and EntityId=(Select Id from SKEntity where Name='RoleEntity')
//SQL SERVER Authentication
Update SKEntityDataSourceProvider
Set
DefinitionXML =' <dataproviders><provider name="customsqlprovider" type="Custom Role Provider"><properties><property name="Role" type="string" purpose="identifier"/><property name="RoleName" type="string" persist="true" persistcolumn="rolename"/></properties>
<datasource>server=localhost; database=SkeltaUsers;User Id=sa;pwd=XXXX;</datasource></provider></dataproviders>',
DisplayName='Custom Role Provider',Provider='customsqlroleprovider',
InstanceName='sqlproviderCustom' Where InstanceName='skeltalist' and EntityId=(Select Id from SKEntity where Name='RoleEntity')
Note: Connection string should be changed.
The provider name value customsqlroleprovider should be same as the AddInProvider Name column value.
Verification:
The above code creates an entry in SKEntityDataSourceProvider table. The entry in Repository DB can be verified in database by running the query select * from SKEntityDataSourceProvider Where DisplayName='Custom Role Provider
|
Column Name |
Value |
|---|---|
|
ID |
Auto generated |
|
Application |
Sample Repository |
|
Entity ID |
Copy the Id Column value of SKEntity of RoleEntity row here. |
|
DisplayName |
Custom Role Provider |
|
DefinitionXML |
<dataproviders><provider name="customsqlprovider" type="Custom Role Provider"><properties><property name="Role" type="string" purpose="identifier"/><property name="RoleName" type="string" persist="true" persistcolumn="rolename"/></properties> <datasource>server=localhost; database=SkeltaUsers;User Id=sa;pwd=XXXX;</datasource></provider></dataproviders> |
|
Provider |
customsqlroleprovider |
|
Instance Name |
sqlproviderCustom |
|
LastUpdatedDateTime |
Date Time Value |
Verification:
Now we should be able to access role & respective user information from the role provider. Sample code to check role information is listed below.
AddInProviderCollection addInProviderCollection = new AddInProviderCollection(applicationObject);
Dictionary<string, ISkeltaAddInProvider> addinProviders = addInProviderCollection.GetProvidersForType(true, "Role");
ISkeltaRoleProvider iSkeltaRoleProvider;
//Addin provider added with name as RoleProvider is the entity provider and should be used to access the role entity data source provider.
iSkeltaRoleProvider = (ISkeltaRoleProvider)addinProviders["RoleProvider"];
iSkeltaRoleProvider.ApplicationName = "Sample Repository";
string[] rolesCollection = iSkeltaRoleProvider.GetAllRoles();
Dictionary<object,string> usersInRole = iSkeltaRoleProvider.GetUsersInRole(rolesCollection[0]);
The above code displays all the roles configured.
Code below creates an entry in SkVirtualRole table.
//For each role, a virtual role id gets created which is used internally for reference with in AVEVA Work Tasks.
Skelta.Core.VirtualRole virtualRole = new VirtualRole(applicationObject);
Guid virtualRoleId = virtualRole.GetVirtualRoleId(rolesCollection[0]);
The script below can be used to check the entries in respective tables.
select * from SKAddInProviders Where Name='customsqlprovider'
select * from SKEntityDataSourceProvider Where DisplayName='Custom Role Provider'
select * from SKVirtualRole where ResourceHandler='Sample Repository'