Code Sample - Custom Content Handler Class File
- Last UpdatedJun 10, 2024
- 7 minute read
using System;
using System.Web.Caching;
using System.Collections;
using System.Xml;
using System.Xml.XPath;
using System.IO;
using System.Data;
using System.Text.RegularExpressions;
using Workflow.NET.Interfaces;
using Workflow.NET;
using Workflow.NET.Engine.Interfaces;
using Workflow.NET.Storage;
using Skelta.Core;
using Workflow.NET.Engine;
namespace CustomContentHandler
{
public class DatabaseContentHandler : IContentHandler, ISkeltaAddInProvider
{
CacheWrapper cache;
string sConnectionString;
string sConnectionAssembly;
string sConnectionClass;
string sConnectionParam;
DataSet data;
string dataSourceType = null;
string connectionString = null;
SortedList ContentCollection;
AppContentsCollection filteredContent;
Context ctx;
Log logger;
string name;
public virtual string Name
{
get
{
return this.name;
}
set
{
this.name = value;
}
}
public DatabaseContentHandler()
{
logger = new Log();
}
IContentHandler IContentHandler.Clone()
{
DatabaseContentHandler contentHandler = new DatabaseContentHandler();
contentHandler.connectionString = this.connectionString;
contentHandler.dataSourceType = this.dataSourceType;
contentHandler.data = this.data;
contentHandler.ctx = this.ctx;
contentHandler.connectedPreviously = this.connectedPreviously;
contentHandler.filteredContent = this.filteredContent;
contentHandler.ContentCollection = this.ContentCollection;
contentHandler.logger = this.logger;
contentHandler.name = this.name;
return contentHandler;
}
public virtual void InitializeContent(Context ctx, string Param)
{
try
{
filteredContent = new AppContentsCollection();
this.ctx = ctx;
string applicationName = "";
string[] temp = Param.ToString().Split(new string[] { "#SKC#" }, StringSplitOptions.None);
if(temp.Length > 0)
{
Param = temp[0];
applicationName = temp[1];
}
ContentCollection = new SortedList();
data = new DataSet("content");
XPathDocument doc;
//Get the data source type and connection string
if (!File.Exists(Param))
{
doc = new XPathDocument(new StringReader(Param));
}
else
{
doc = new XPathDocument(Param);
}
XPathNavigator nav = doc.CreateNavigator();
XPathNodeIterator iterator = nav.Select("//datasource");
if (iterator.MoveNext())
{
dataSourceType = iterator.Current.GetAttribute("type", "");
connectionString = iterator.Current.GetAttribute("connectionString", "");
sConnectionClass = iterator.Current.GetAttribute("class", "");
sConnectionAssembly = iterator.Current.GetAttribute("assembly", "");
sConnectionParam = iterator.Current.GetAttribute("param", "");
connectionString = iterator.Current.Value;
sConnectionString = connectionString;
if (ctx != null)
{
cache =
new CacheWrapper();
bool showLog = (ctx.ProcessDefinition.ActionsDefinition.WorkflowConfigFile.DebugLevel == "111") ? true : false;
string application = ctx.ProcessDefinition.ApplicationName;
string cacheKeyName = (sConnectionParam == null || sConnectionParam == "") ? application : sConnectionParam;
if ((sConnectionClass != null && sConnectionClass != "") &&
sConnectionAssembly != null && sConnectionAssembly != "")
{
if (cache.Cache["ContentHandlerConnString" + cacheKeyName] != null)
{
connectionString = cache.Cache["ContentHandlerConnString" + cacheKeyName].ToString();
if (showLog)
logger.LogInformation("Getting connection string from Cache (Content Handler):" + connectionString);
}
else
{
//Set the dependency files to invalidate the cache.
System.Web.Caching.CacheDependency fileDependency;
if (Param != null && Param != "" && Param.ToUpperInvariant().IndexOf(".XML") >= 0)
fileDependency = new CacheDependency(new string[] { Config.GetConfigFilePath() + "WorkflowNET.Config.Xml", Param });
else
fileDependency = new CacheDependency(Config.GetConfigFilePath() + "WorkflowNET.Config.Xml");
connectionString = CommonFunctions.GetConnectionString("Content Handler", sConnectionClass, sConnectionAssembly, sConnectionParam, sConnectionString, application);
cache.Cache.Add("ContentHandlerConnString" + cacheKeyName, connectionString, fileDependency, DateTime.MaxValue,
TimeSpan.Zero, System.Web.Caching.CacheItemPriority.Normal, null);
if (showLog)
logger.LogInformation("Getting connection string from DLL(Content Handler):" + connectionString);
}
}
}
}
else
{
throw new Exception("Datasource not configured in the file " + Param);
}
//Read the tables
iterator = nav.Select("/content/tables/table");
while (iterator.MoveNext())
{
XPathNavigator table = iterator.Current;
try
{
ParseTable(table);
}
catch (Exception e)
{
logger.LogError(e, "Could not parse the xml for table " + table + ".");
throw e;
}
}
}
catch (Exception e)
{
logger.LogError(e, "Could not initialize the application content handler");
throw e;
}
}
public virtual void Clear()
{
filteredContent.Clear();
}
void ParseTable(XPathNavigator Table)
{
string tableName = Table.GetAttribute("name", "");
FilterDataTable dt = new FilterDataTable(tableName);
data.Tables.Add(dt);
//Console.WriteLine(tableName);
//Prase the fields
XPathNodeIterator fields = Table.Select("//tables/table[@name='" + tableName + "']/fields/*");
while (fields.MoveNext())
{
string fldName = fields.Current.GetAttribute("name", "");
//Console.WriteLine(fldName);
string fldType = fields.Current.GetAttribute("type", "");
string fldSize = fields.Current.GetAttribute("size", "");
if (fields.Current.GetAttribute("identifier", "") != null && fields.Current.GetAttribute("identifier", "") == "true")
{
dt.Identifier = fldName;
}
string contentName = fields.Current.GetAttribute("contentName", "");
string canUpdate = fields.Current.GetAttribute("canUpdate", "");
ContentField field = new ContentField(fldName, fldType);
field.CanUpdate = canUpdate.ToLowerInvariant() == "true" ? true : false;
dt.Columns.Add(field);
ContentCollection.Add(contentName, field);
//Can populate the content collection in this method if required.
}
((FilterDataTable)dt).FilterCondition = Table.SelectChildren("filter", "").Current.Value.Trim();
}
bool connectedPreviously = false;
IDataHandler GetConnection(string DatasourceType, string ConnectionString)
{
IDataHandler dataHandler = null;
if (connectedPreviously)
{
dataHandler = DataHandlerFactory.GetDataHandler(
ConnectionString, DatasourceType);
}
else
{
dataHandler = DataHandlerFactory.GetDataHandler(
ConnectionString, DatasourceType, 3);
}
connectedPreviously = true;
return dataHandler;
}
public virtual AppContent GetContent(string ContentName)
{
if (filteredContent[ContentName] != null && filteredContent[ContentName].Value != null)
{
return filteredContent[ContentName];
}
else
{
AppContent content = GetContent(new string[] { ContentName })[ContentName];
if (content != null && content.Value != null)
{
return content;
}
else
{
return null;
}
}
}
public virtual AppContentsCollection GetContent(params string[] ContentNames)
{
AppContentsCollection tempContentCollection = new AppContentsCollection();
IDataReader reader = null;
IDataHandler dataHandler = null;
try
{
bool firstIteration = true;
string sql = null;
string tableName = null;
foreach (string contentName in ContentNames)
{
//Get the field for the content.
ContentField field = (ContentField)ContentCollection[contentName];
string fieldName = field.ColumnName;
tableName = field.Table.TableName;
if (firstIteration)
{
string identifier = ((FilterDataTable)data.Tables[tableName]).Identifier;
sql = "select " + identifier + " as identifier, " + fieldName;
firstIteration = false;
}
else
{
sql += ", " + fieldName;
}
}
sql += " from " + tableName;
while (true)
{
try
{
dataHandler = GetConnection(dataSourceType, connectionString);
string tempSql = sql;
string filter = ((FilterDataTable)data.Tables[tableName]).FilterCondition;
if (filter != null && filter != "")
{
Regex regex = new Regex("<%#([a-zA-Z0-9]*).([a-zA-Z0-9]*)%>");
MatchCollection matches = regex.Matches(filter);
ArrayList parameters = new ArrayList(matches.Count);
int i = 1;
if (matches != null)
{
foreach (Match match in matches)
{
string strToBeReplaced = match.Value;
string type = match.Groups[1].Value;
string key = match.Groups[2].Value;
object val = null;
if (type.ToLowerInvariant() == "content")
{
if (ctx.Contents[key].Value != null)
{
val = ctx.Contents[key].Value;
}
}
else if (type.ToLowerInvariant() == "variable")
{
if (ctx.Variables.Contains(key) && ctx.Variables[key].Value != null)
{
val = ctx.Variables[key].Value;
}
}
else
{
val = "";
}
filter = filter.Replace(strToBeReplaced, "@param" + i);
IDataParameter param = dataHandler.GetParameter("@param" + i, val);
parameters.Add(param);
i++;
}
}
tempSql += " where " + filter;
reader = dataHandler.ExecuteReader(tempSql, (IDataParameter[])parameters.ToArray(typeof(IDataParameter)));
}
else
{
reader = dataHandler.ExecuteReader(sql, null);
}
if (reader.Read())
{
object identifierValue = reader["identifier"];
//Read the values
foreach (string contentName in ContentNames)
{
AppContent content = new AppContent();
ContentField field = (ContentField)ContentCollection[contentName];
content.Name = contentName;
content.Identifier = identifierValue;
content.Value = reader[field.ColumnName];
content.Type = field.Type;
content.CanUpdate = field.CanUpdate;
filteredContent[content.Name] = content;
tempContentCollection[content.Name] = content;
}
reader.Close();
}
break;
}
catch (Exception e)
{
if (dataHandler != null && dataHandler.ConnectionState == ConnectionState.Open)
{
logger.LogError(e, "Could not get the content from " + name);
throw e;
}
else
{
logger.LogWarning("Database connection lost abruptly, will try to connect again");
}
}
finally
{
try
{
dataHandler.Dispose();
}
catch { }
}
}
}
catch (Exception e)
{
logger.LogError(e, "Could not get the content " + String.Join(",", ContentNames, 0, ContentNames.Length) + ".");
}
return tempContentCollection;
}
public virtual AppContent GetContent(object Identifier, string ContentName)
{
AppContent content = GetContent(Identifier, new string[] { ContentName })[ContentName];
if (content != null && content.Value != null)
{
return content;
}
else
{
return null;
}
}
public virtual AppContentsCollection GetContent(object Identifier, params string[] ContentNames)
{
AppContentsCollection contentValues = new AppContentsCollection();
try
{
string sql = "select ";
bool firstIteration = true;
string tableName = "";
string identifierFieldName = "";
foreach (string contentName in ContentNames)
{
ContentField field = (ContentField)ContentCollection[contentName];
string fieldName = field.ColumnName;
if (firstIteration)
{
tableName = field.Table.TableName;
FilterDataTable table = (FilterDataTable)data.Tables[tableName];
identifierFieldName = table.Identifier;
firstIteration = false;
sql += identifierFieldName + " as identifier," + fieldName;
}
else
{
sql += "," + fieldName;
}
}
sql += " from " + tableName + " where " + identifierFieldName + "=@paramId";
IDataHandler dataHandler = null;
while (true)
{
try
{
dataHandler = GetConnection(this.dataSourceType, this.connectionString);
IDataParameter paramId = dataHandler.GetParameter("@paramId", Identifier);
IDataReader reader = dataHandler.ExecuteReader(sql, paramId);
if (reader.Read())
{
object identifierValue = reader["identifier"];
foreach (string contentName in ContentNames)
{
AppContent content = new AppContent();
content.Name = contentName;
content.Identifier = identifierValue;
content.Value = reader[((ContentField)ContentCollection[contentName]).ColumnName];
contentValues.Add(contentName, content);
}
}
reader.Close();
break;
}
catch (Exception e)
{
if (dataHandler != null && dataHandler.ConnectionState == ConnectionState.Open)
{
logger.LogError(e, "Could not get the content from " + name);
throw e;
}
else
{
logger.LogWarning("Database connection lost abruptly, will try to connect again");
}
}
finally
{
try
{
dataHandler.Dispose();
}
catch { }
}
}
}
catch (Exception e)
{
logger.LogError(e, "Could not get the content " + String.Join(",", ContentNames, 0, ContentNames.Length) + " with identifier " + Identifier + ".");
throw e;
}
return contentValues;
}
public virtual object[] FilterContent(string FullyProcessedQuery, params object[] Parameters)
{
IDataHandler dataHandler = null;
while (true)
{
try
{
ArrayList identifiers = new ArrayList();
dataHandler = GetConnection(this.dataSourceType, this.connectionString);
ArrayList contentParameters = new ArrayList();
if (Parameters != null)
{
foreach (object param in Parameters)
{
object[] paramArray = (object[])param;
contentParameters.Add(dataHandler.GetParameter((string)paramArray[0], paramArray[1]));
}
}
IDataReader reader = dataHandler.ExecuteReader(FullyProcessedQuery, (IDataParameter[])contentParameters.ToArray(typeof(IDataParameter)));
while (reader.Read())
{
identifiers.Add(reader[0]);
}
reader.Close();
return identifiers.ToArray();
}
catch (Exception e)
{
if (dataHandler != null && dataHandler.ConnectionState == ConnectionState.Open)
{
logger.LogError(e, "Could not filter the content using the query \"" + FullyProcessedQuery + "\".");
throw e;
}
else
{
logger.LogWarning("Database connection lost abruptly. Will try to connect to the database again.");
}
}
finally
{
try
{
dataHandler.Dispose();
}
catch { }
}
}
}
public virtual AppContentsCollection GetContentDetails()
{
AppContentsCollection contents = new AppContentsCollection();
foreach (string contentName in ContentCollection.Keys)
{
ContentField field = (ContentField)ContentCollection[contentName];
AppContent content = new AppContent();
content.Name = contentName;
content.Type = field.Type;
contents.Add(contentName, content);
}
return contents;
}
public virtual bool UpdateContent(AppContent Content)
{
return UpdateContent(new AppContent[] { Content });
}
public virtual bool UpdateContent(params AppContent[] ContentList)
{
IDataHandler dataHandler = null;
int rowsUpdated = 0;
while (true)
{
try
{
using (System.Transactions.TransactionScope TScope = Skelta.Core.DS.SingleTableObject.GetTransactionScope())
{
dataHandler = GetConnection(this.dataSourceType, this.connectionString);
using (dataHandler)
{
bool firstIteration = true;
string sql = null;
string tableName = null;
object identifierValue = null;
ArrayList parameters = new ArrayList();
int i = 1;
foreach (AppContent content in ContentList)
{
if (!((ContentField)ContentCollection[content.Name]).CanUpdate)
{
throw new Exception("Can not update the content that is not updatable.");
}
//Get the field for the content.
ContentField field = (ContentField)ContentCollection[content.Name];
string fieldName = field.ColumnName;
if (firstIteration)
{
tableName = field.Table.TableName;
identifierValue = content.Identifier;
sql = "update " + tableName + " set " + fieldName + "=@param" + i;
firstIteration = false;
}
else
{
sql += ", " + fieldName + "=@param" + i;
}
parameters.Add(dataHandler.GetParameter("@param" + i, content.Value));
i++;
filteredContent[content.Name] = content;
}
string identifier = ((FilterDataTable)data.Tables[tableName]).Identifier;
sql += " where " + identifier + "=@paramId";
parameters.Add(dataHandler.GetParameter("@paramId", identifierValue));
rowsUpdated = dataHandler.ExecuteUpdate(sql, (IDataParameter[])parameters.ToArray(typeof(IDataParameter)));
}
if (rowsUpdated > 0)
{
return true;
}
else
{
return false;
}
TScope.Complete();
}
}
catch (Exception e)
{
if (dataHandler != null && dataHandler.ConnectionState == ConnectionState.Open)
{
logger.LogError(e, "Could not update the content values.");
filteredContent.Clear();
throw e;
}
else
{
logger.LogWarning("Database connection lost abruptly. Will try to connect to the database again.");
}
}
}
}
public virtual void Dispose()
{
//ctx.Close();
}
class FilterDataTable : DataTable
{
internal FilterDataTable(string TableName)
: base(TableName)
{
}
internal string FilterCondition = null;
internal string Identifier = null;
}
public class ContentField : DataColumn
{
public string Type = "string";
internal ContentField(string FieldName, string DbType)
{
this.Type = DbType;
Type dbType = typeof(string);
switch (DbType)
{
case "int":
dbType = typeof(int);
break;
case "float":
dbType = typeof(double);
break;
case "varchar":
break;
case "datetime":
dbType = typeof(DateTime);
break;
default:
break;
}
this.ColumnName = FieldName;
this.DataType = dbType;
}
public bool CanUpdate;
}
#region ISkeltaAddInProvider Members
string _Settings = "";
Guid _Id = Guid.Empty;
void ISkeltaAddInProvider.InitializeProvider(string settings, Guid id)
{
_Settings = settings;
_Id = id;
}
string ISkeltaAddInProvider.Settings
{
get { return _Settings; }
}
Guid ISkeltaAddInProvider.Id
{
get { return _Id; }
}
#endregion
}
}