Click here to Skip to main content
11,494,785 members (61,879 online)
Click here to Skip to main content
Add your own
alternative version

Populating a business logical layer from Stored Procedures

, 22 Sep 2014 CPOL 38.7K 1.3K 66
A brief look at a technique mapping tables to a basic business layer.
doPersistence-noexe.zip
doPersistence
doPersistence.csproj.user
doPersistence.csproj.vspscc
obj
Debug
Release
Properties
doLogicCode
bin
Debug
doLogicCode.vshost.exe.manifest
doLogicCode.csproj.vspscc
obj
x86
Debug
doLogicCode.frmCodeGenerator.resources
doLogicCode.Properties.Resources.resources
Properties
Settings.settings
doPersistence.zip
Test
doLogic
bin
Debug
doLogic.dll
doLogic.pdb
doPersistence.dll
doPersistence.pdb
Release
doLogic.dll
doLogic.pdb
doPersistence.dll
doPersistence.pdb
obj
Debug
DesignTimeResolveAssemblyReferencesInput.cache
doLogic.dll
doLogic.pdb
ResolveAssemblyReference.cache
TempPE
Release
DesignTimeResolveAssemblyReferencesInput.cache
doLogic.dll
doLogic.pdb
ResolveAssemblyReference.cache
TempPE
Properties
doLogicCode
bin
Debug
doLogicCode.exe
doLogicCode.pdb
doLogicCode.vshost.exe
doLogicCode.vshost.exe.manifest
doPersistence.dll
doPersistence.pdb
obj
x86
Debug
DesignTimeResolveAssemblyReferencesInput.cache
doLogicCode.exe
doLogicCode.frmCodeGenerator.resources
doLogicCode.pdb
doLogicCode.Properties.Resources.resources
GenerateResource.read.1.tlog
GenerateResource.write.1.tlog
ResolveAssemblyReference.cache
TempPE
Properties.Resources.Designer.cs.dll
Properties
Settings.settings
doPersistence
bin
Debug
doPersistence.dll
doPersistence.pdb
Release
doPersistence.dll
doPersistence.pdb
doPersistence.csproj.vspscc
obj
Debug
DesignTimeResolveAssemblyReferencesInput.cache
doPersistence.dll
doPersistence.pdb
TempPE
Release
DesignTimeResolveAssemblyReferencesInput.cache
doPersistence.dll
doPersistence.pdb
TempPE
Properties
Test.suo
TestSite
Account
App_Data
bin
doLogic.dll
doLogic.pdb
doPersistence.dll
doPersistence.pdb
TestSite.dll
TestSite.pdb
Global.asax
obj
Debug
DesignTimeResolveAssemblyReferencesInput.cache
ResolveAssemblyReference.cache
TempPE
TestSite.dll
TestSite.pdb
Release
CSAutoParameterize
original
Account
transformed
Account
Database
DesignTimeResolveAssemblyReferencesInput.cache
Package
PackageTmp
Account
bin
doLogic.dll
doLogic.pdb
doPersistence.dll
doPersistence.pdb
TestSite.dll
TestSite.pdb
Global.asax
Scripts
Styles
ResolveAssemblyReference.cache
TempPE
TestSite.dll
TestSite.pdb
TransformWebConfig
original
transformed
Account
Properties
Scripts
Styles
TestSite.csproj.user
dopersistenceexample.zip
doLogic.dll
doPersistence.dll
doPersistence.dll
doLogic.dll
doPersistence.dll
TestSite.dll
Global.asax
TestSite.csproj.user
dopersistencepocodynamicsqlexample.zip
doLogic.dll
doLogic.pdb
doPersistence.dll
doPersistence.pdb
doLogic.dll
doLogic.pdb
doPersistence.dll
doPersistence.pdb
DesignTimeResolveAssemblyReferencesInput.cache
doLogic.dll
doLogic.pdb
ResolveAssemblyReference.cache
DesignTimeResolveAssemblyReferencesInput.cache
doLogic.dll
doLogic.pdb
ResolveAssemblyReference.cache
doPersistence.dll
doPersistence.pdb
doPersistence.dll
doPersistence.pdb
DesignTimeResolveAssemblyReferencesInput.cache
doPersistence.dll
doPersistence.pdb
DesignTimeResolveAssemblyReferencesInput.cache
doPersistence.dll
Test.suo
doLogic.dll
doLogic.pdb
doPersistence.dll
doPersistence.pdb
TestSite.dll
TestSite.pdb
Global.asax
DesignTimeResolveAssemblyReferencesInput.cache
ResolveAssemblyReference.cache
TestSite.dll
TestSite.pdb
DesignTimeResolveAssemblyReferencesInput.cache
ResolveAssemblyReference.cache
TestSite.dll
TestSite.pdb
TestSite.csproj.user
PersistenceTest20131129-noexe.zip
PersistenceTest_orig
Account
App_Code
App_Data
Bin
Persistence.pdb
Global.asax
Scripts
Styles
Persistence
bin
Debug
doPersistence.pdb
Persistence.pdb
Release
doPersistence.pdb
doPersistence.csproj.vspscc
obj
Debug
DesignTimeResolveAssemblyReferences.cache
DesignTimeResolveAssemblyReferencesInput.cache
doPersistence.csprojResolveAssemblyReference.cache
doPersistence.pdb
Persistence.pdb
TempPE
Release
DesignTimeResolveAssemblyReferencesInput.cache
doPersistence.pdb
TempPE
Persistence.csproj.user
Properties
PersistenceTest_orig.v11.suo
CodeGenerator
bin
Debug
doLogicCode.pdb
doLogicCode.vshost.exe.manifest
doPersistence.pdb
Persistence.pdb
CodeGenerator.csproj.vspscc
obj
x86
Debug
CodeGenerator.csproj.GenerateResource.Cache
CodeGenerator.csprojResolveAssemblyReference.cache
CodeGenerator.frmCodeGenerator.resources
CodeGenerator.Properties.Resources.resources
DesignTimeResolveAssemblyReferences.cache
DesignTimeResolveAssemblyReferencesInput.cache
doLogicCode.csproj.GenerateResource.Cache
doLogicCode.csprojResolveAssemblyReference.cache
doLogicCode.pdb
TempPE
Properties
Settings.settings
PersistenceTest20131129.zip
AjaxControlToolkit.dll
Persistence.dll
Persistence.pdb
Global.asax
doPersistence.dll
doPersistence.pdb
Persistence.dll
Persistence.pdb
doPersistence.dll
doPersistence.pdb
doPersistence.csproj.vspscc
DesignTimeResolveAssemblyReferences.cache
DesignTimeResolveAssemblyReferencesInput.cache
doPersistence.csprojResolveAssemblyReference.cache
doPersistence.dll
doPersistence.pdb
Persistence.dll
Persistence.pdb
DesignTimeResolveAssemblyReferencesInput.cache
doPersistence.dll
doPersistence.pdb
Persistence.csproj.user
PersistenceTest_orig.v11.suo
doLogicCode.exe
doLogicCode.pdb
doLogicCode.vshost.exe
doLogicCode.vshost.exe.manifest
doPersistence.dll
doPersistence.pdb
Persistence.dll
Persistence.pdb
CodeGenerator.csproj.vspscc
CodeGenerator.csproj.GenerateResource.Cache
CodeGenerator.csprojResolveAssemblyReference.cache
CodeGenerator.frmCodeGenerator.resources
CodeGenerator.Properties.Resources.resources
DesignTimeResolveAssemblyReferences.cache
DesignTimeResolveAssemblyReferencesInput.cache
doLogicCode.csproj.GenerateResource.Cache
doLogicCode.csprojResolveAssemblyReference.cache
doLogicCode.exe
doLogicCode.pdb
Properties.Resources.Designer.cs.dll
Settings.settings
using System;
using System.Collections.Generic;
using System.Text;

using System.Data;
using System.Data.SqlClient;

using System.Collections;
using System.Configuration;

/*
 * todo:
 * verify all datatypes
 * Copy to DataTable from SP resultset
 * pagination from sql or within list?
 * change List to generic?
*/

namespace doPersistence
{
	internal class SqlServer
    {
        private static readonly string _SpPrefix;
        private static readonly bool _AllowsDynamicSql;
        internal static readonly string ConnectionString;

        static SqlServer()
        {
            try
			{
				_SpPrefix = ConfigurationManager.AppSettings["doPersistenceSpPrefix"];
                _AllowsDynamicSql = Convert.ToBoolean(ConfigurationManager.AppSettings["AllowsDynamicSql"]);
				ConnectionString = ConfigurationManager.ConnectionStrings["doPersistence"].ConnectionString;
			}
            catch { }
        }

        public static bool AllowsDynamicSql { get { return _AllowsDynamicSql; } }

        public static string SpPrefix { get { return _SpPrefix; } }

        public static DataTable GetTableStructure(string tableName)
        {
            DataTable table = new DataTable();
			table.TableName = tableName;

            using (SqlConnection conn = new SqlConnection(SqlServer.ConnectionString))
            {
                conn.Open();

                SqlCommand cmd = new SqlCommand("sys_StructureForTable", conn);
				cmd.CommandType = CommandType.StoredProcedure;
				cmd.Parameters.AddWithValue("@TableName", tableName);
                SqlDataReader reader = cmd.ExecuteReader();
				if (!reader.HasRows)
					throw new ApplicationException(String.Format("Unable to retrieve schema information on table {0} in {1}.  {2} '{3}' returned 0 rows.", cmd.Parameters[0].Value, cmd.Connection.Database, cmd.CommandText, cmd.Parameters[0].Value));
				
				while (reader.Read())
                {
                    DataColumn col = new DataColumn();
                    col.ColumnName = reader["Name"].ToString();
                    col.DataType = SqlServer.SqlStringToType(reader["Type"].ToString());
                    col.AllowDBNull = Convert.ToBoolean(reader["IsNullable"]);
                    table.Columns.Add(col);
                }
            }
            return table;
        }

        public static void StoreBulk(string tableName, DataTable table)
        {
            using (SqlConnection conn = new SqlConnection(SqlServer.ConnectionString))
            {
                conn.Open();

                //create temporary table
                string sql = String.Format("select * into #{0} from {0} where 1=0", tableName);
                SqlCommand cmd = new SqlCommand(sql, conn);
                cmd.ExecuteNonQuery();

                //bulk copy
                using (SqlBulkCopy bulk = new SqlBulkCopy(conn))
                {
                    bulk.DestinationTableName = "#" + tableName;
                    bulk.WriteToServer(table);
                }

                //merge temp table into production
                cmd = new SqlCommand(SpPrefix + "merge_" + tableName, conn);
                cmd.ExecuteNonQuery();
            }
        }

		public static int LoadAll(PersistentList list, string action)
		{
			return LoadAll(list, action, SqlServer.ConnectionString);
		}

        public static int LoadAll(PersistentList list, string action, string connString)
        {
            string spName = SpPrefix + "list_" + list.GetItemType().Name + action;

            SqlCommand cmd = GetCommand(spName, connString);
            SetParameterValues(cmd, list);

            using (SqlConnection cn = new SqlConnection(connString))
            {
                int rowCount = 0;
                cmd.Connection = cn;
                cn.Open();
                SqlDataReader reader = cmd.ExecuteReader();
                while (reader.Read())
                {
                    IPersistable newItem = list.CreateNewItem();
                    MapToInstance(reader, newItem);
                    list.Add(newItem);
                    rowCount++;
                }
                return rowCount;
            }
        }

		public static void Load(IPersistable o)
		{
			Load(o, "");
		}

		public static void Load(IPersistable o, string action)
		{
			Load(o, action, SqlServer.ConnectionString);
		}

		public static void Load(IPersistable o, string action, string connString)
        {
			if (Database.AllowsDynamicSql && o.UseDynamicSql)
			{
				LoadViaDynamicSql(o, connString);
				return;
			}

			string spName = SpPrefix + "load_" + o.GetType().Name + action;

			SqlCommand cmd = GetCommand(spName, connString);
			SetParameterValues(cmd, o);

            using (SqlConnection cn = new SqlConnection(connString))
            {
                cmd.Connection = cn;
                cn.Open();
                SqlDataReader reader = cmd.ExecuteReader();
                if (reader.Read())
                    MapToInstance(reader, o);
                else
                    throw new ApplicationException("No single result returned by " + spName);
            }
		}

		public static void LoadViaDynamicSql(IPersistable o, string connString)
		{
			string sql = String.Format("select * from {0} where {1}={2}", o.GetType().Name, o.PrimaryKeyName, o.PrimaryKeyValue);

			using (SqlConnection cn = new SqlConnection(connString))
			{
				SqlCommand cmd = new SqlCommand(sql);
				cmd.Connection = cn;
				cn.Open();
				SqlDataReader reader = cmd.ExecuteReader();
				if (reader.Read())
					MapToInstance(reader, o);
				else
					throw new ApplicationException("No single result returned by " + sql);
			}
		}

        public static int StoreViaDynamicSql(IPersistable o, string connString)
        {
            string sql = "";

            if (o.PrimaryKeyValue < 1)
                sql = Database.GetInsertSql(o);
            else
                sql = Database.GetUpdateSql(o);

            using (SqlConnection cn = new SqlConnection(connString))
            {
                SqlCommand cmd = new SqlCommand(sql);
                cmd.Connection = cn;
                cn.Open();
                if (o.PrimaryKeyValue < 1)
                {
                    int newId = Convert.ToInt32(cmd.ExecuteScalar());
                    o.PrimaryKeyValue = newId;
                    return 1;
                }
                else
                    return cmd.ExecuteNonQuery();
            }
        }

		public static bool DeleteViaDynamicSql(IPersistable o, string connString)
		{
			string sql = String.Format("delete from {0} where {1}={2}", o.GetType().Name, o.PrimaryKeyName, o.PrimaryKeyValue);
			using (SqlConnection cn = new SqlConnection(connString))
			{
				SqlCommand cmd = new SqlCommand(sql);
				cmd.Connection = cn;
				cn.Open();
				return (cmd.ExecuteNonQuery() > 0);
			}
		}

		public static int Store(IPersistable o)
		{
			return Store(o, SqlServer.ConnectionString);
		}

        public static int Store(IPersistable o, string connString)
        {
            if (Database.AllowsDynamicSql && o.UseDynamicSql)
            {
                return StoreViaDynamicSql(o, connString);
            }

            string spName = SpPrefix + "store_" + o.GetType().Name;

            SqlCommand cmd = GetCommand(spName, connString);
            SetParameterValues(cmd, o);

            int rowsAffected = 0;
            using (SqlConnection cn = new SqlConnection(connString))
            {
                cmd.Connection = cn;
                cn.Open();
                rowsAffected = cmd.ExecuteNonQuery();

                //set output parameter on object (eg. identity key)
                foreach (SqlParameter p in cmd.Parameters)
                {
                    if (p.ParameterName.ToLower() == "@" + o.PrimaryKeyName.ToLower()
                            && p.Direction == ParameterDirection.Input)
                        throw new ApplicationException("Primary key must be set as an output parameter in the stored procedure: " + spName);
                    if (p.Direction != ParameterDirection.Input)
                    {
                        string name = p.ParameterName;
                        if (name.StartsWith("@"))
                            name = name.Substring(1);

						Class.SetPropertyValueByName(o, name, p.Value);
                    }
                }
            }
            return rowsAffected;
        }

		public static bool Delete(IPersistable o)
		{
			return Delete(o, SqlServer.ConnectionString);
		}

        public static bool Delete(IPersistable o, string connString)
        {
			if (Database.AllowsDynamicSql && o.UseDynamicSql)
				return DeleteViaDynamicSql(o, connString);
			
			string spName = SpPrefix + "delete_" + o.GetType().Name;

            SqlCommand cmd = GetCommand(spName, connString);
            SetParameterValues(cmd, o);

            using (SqlConnection cn = new SqlConnection(connString))
            {
                cmd.Connection = cn;
                cn.Open();
                return cmd.ExecuteNonQuery() > 0;
            }
        }

        public static int ExecuteUpdate(SqlCommand cmd, string connString, out int newId)
		{
            throw new NotImplementedException();
		}


        public static void MapToInstance(IDataReader reader, object o)
        {
			for (int i = 0; i < reader.FieldCount; i++)
            {
                if (reader.IsDBNull(i))
                    continue;

				string colName = reader.GetName(i);
                object value = reader.GetValue(i);
                Type t = SqlStringToType(reader.GetDataTypeName(i));

                if (t == typeof(string))
					Class.SetPropertyValueByName(o, colName, reader.GetString(i));
                else if (t == typeof(int))
					Class.SetPropertyValueByName(o, colName, reader.GetInt32(i));
                else if (t == typeof(bool))
					Class.SetPropertyValueByName(o, colName, reader.GetBoolean(i));
                else if (t == typeof(long))
					Class.SetPropertyValueByName(o, colName, reader.GetInt64(i));
                else if (t == typeof(DateTime))
					Class.SetPropertyValueByName(o, colName, reader.GetDateTime(i));
                else if (t == typeof(Double))
					Class.SetPropertyValueByName(o, colName, Convert.ToSingle(reader.GetDouble(i)));
                else if (t == typeof(Single))
					Class.SetPropertyValueByName(o, colName, Convert.ToSingle(reader.GetValue(i)));
                else if (t == typeof(byte))
					Class.SetPropertyValueByName(o, colName, reader.GetByte(i));
                else if (t == typeof(Decimal))
					Class.SetPropertyValueByName(o, colName, reader.GetDecimal(i));
                //else if (t == typeof(byte[]))
				//    Object.SetPropertyValueByName(o, colName, reader.GetBytes(i));
                else
					Class.SetPropertyValueByName(o, colName, (string)reader.GetValue(i));
			}
		}

		public static void SetParameterValues(SqlCommand cmd, object o)
		{
			foreach (SqlParameter parm in cmd.Parameters)
			{
				string name = parm.ParameterName;
                if (name.StartsWith("@"))
                    name = name.Substring(1);

				object value = Class.GetPropertyValueByName(o, name);

                if (value is DateTime && (DateTime)value == new DateTime(1, 1, 1))
                    value = DBNull.Value;
                else if (value == null)
                    value = DBNull.Value;

                if (value == DBNull.Value && !parm.IsNullable)
                    throw new ApplicationException(String.Format("Property value cannot be null on {0}: {1}.", o.GetType().Name, name));

                parm.Value = value;
            }
		}

		private static Hashtable cmds = new Hashtable();

        public static SqlCommand GetCommand(string spName, string connString)
        {
			SqlCommand cmd = null;
			if (cmds.ContainsKey(spName))
            {
				cmd = ((SqlCommand)cmds[spName]).Clone();   //thread safety
			}
            else
            {
				cmd = new SqlCommand(spName);
				cmd.CommandType = CommandType.StoredProcedure;
				CreateParameters(cmd, spName, connString);
				cmds.Add(spName, cmd);
			}
			return cmd;
		}

        public static void CreateParameters(SqlCommand cmd, string spName, string connString)
        {
			using (SqlConnection cn = new SqlConnection(connString))
            {
				SqlCommand parmCmd = new SqlCommand("sys_ParametersForSP", cn);
                parmCmd.CommandType = CommandType.StoredProcedure;
                parmCmd.Parameters.AddWithValue("@SPName", spName);

				cn.Open();
				SqlDataReader reader = parmCmd.ExecuteReader();

				while (reader.Read())
                {
                    SqlParameter parm = new SqlParameter();
                    parm.ParameterName = "@" + Convert.ToString(reader["Name"]);
                    parm.IsNullable = Convert.ToBoolean(reader["IsOptional"]);
                    parm.Precision = Convert.ToByte(reader["XPrec"]);
                    parm.Size = Convert.ToInt32(reader["Length"]);
                    parm.SqlDbType = SqlStringToSqlDbType(Convert.ToString(reader["Type"]));
                    if (Convert.ToBoolean(reader["IsOutParam"]))
						parm.Direction = ParameterDirection.InputOutput;
					else
						parm.Direction = ParameterDirection.Input;

					cmd.Parameters.Add(parm);
				}
			}
		}

		public static SqlDbType SqlStringToSqlDbType(string typeName)
        {
            if (typeName=="varchar")
				return SqlDbType.VarChar;
            else if (typeName == "int")
				return SqlDbType.Int;
            else if (typeName == "datetime")
				return SqlDbType.DateTime;
            else if (typeName == "uniqueidentifier")
				return SqlDbType.UniqueIdentifier;
            else if (typeName == "float")
                return SqlDbType.Float;
            else if (typeName == "bit")
                return SqlDbType.Bit;
            else if (typeName == "binary")
                return SqlDbType.Binary;
            else if (typeName == "char")
                return SqlDbType.Char;
            else if (typeName == "decimal")
                return SqlDbType.Decimal;
            else if (typeName == "image")
                return SqlDbType.Image;
            else if (typeName == "bigint")
                return SqlDbType.BigInt;
            else if (typeName == "money")
                return SqlDbType.Decimal;
            else if (typeName == "nchar")
                return SqlDbType.NChar;
            else if (typeName == "ntext")
                return SqlDbType.NText;
            else if (typeName == "nvarchar")
                return SqlDbType.NVarChar;
            else if (typeName == "real")
                return SqlDbType.Real;
            else if (typeName == "smalldatetime")
                return SqlDbType.SmallDateTime;
            else if (typeName == "smallint")
                return SqlDbType.SmallInt;
            else if (typeName == "smallmoney")
                return SqlDbType.SmallMoney;
            else if (typeName == "text")
                return SqlDbType.Text;
            else if (typeName == "timestamp")
                return SqlDbType.Timestamp;
            else if (typeName == "tinyint")
                return SqlDbType.TinyInt;
            else if (typeName == "varbinary")
                return SqlDbType.VarBinary;
            else if (typeName == "variant")
                return SqlDbType.Variant;
            else if (typeName == "xml")
                throw new NotImplementedException();
            else if (typeName == "udt")
				throw new NotImplementedException();
            else if (typeName == "structured")
				throw new NotImplementedException();
            else if (typeName == "date")
                return SqlDbType.Date;
            else if (typeName == "time")
                return SqlDbType.Time;
            else if (typeName == "DateTime2")
                return SqlDbType.DateTime2;
            else if (typeName == "DateTimeOffset")
                return SqlDbType.DateTimeOffset;
            else
                return SqlDbType.Binary;
        }

        public static Type SqlStringToType(string sqlTypeName)
        {
			sqlTypeName = sqlTypeName.ToLower();

			if (sqlTypeName == "uniqueidentifier")
				return typeof(string);
			else if (sqlTypeName == "int" || sqlTypeName == "Int32")
				return typeof(int);
			else if (sqlTypeName == "varchar" || sqlTypeName == "String")
				return typeof(string);
			else if (sqlTypeName == "datetime")
				return typeof(DateTime);
			else if (sqlTypeName == "float" || sqlTypeName == "Single")
				return typeof(Single);
			else if (sqlTypeName == "bit" || sqlTypeName == "Boolean")
				return typeof(bool);
			else if (sqlTypeName == "money" || sqlTypeName == "Decimal")
				return typeof(Decimal);
			else if (sqlTypeName == "bigint")
				return typeof(long);
			else if (sqlTypeName == "binary")
				return typeof(Byte[]);
			else if (sqlTypeName == "char")
				return typeof(string);
			else if (sqlTypeName == "decimal")
				return typeof(Decimal);
			else if (sqlTypeName == "image")
				return typeof(Byte[]);
			else if (sqlTypeName == "money")
				return typeof(Decimal);
			else if (sqlTypeName == "nchar")
				return typeof(String);
			else if (sqlTypeName == "ntext")
				return typeof(String);
			else if (sqlTypeName == "nvarchar")
				return typeof(String);
			else if (sqlTypeName == "real")
				return typeof(Single);
			else if (sqlTypeName == "smalldatetime")
				return typeof(DateTime);
			else if (sqlTypeName == "smallint")
				return typeof(Byte);
			else if (sqlTypeName == "smallmoney")
				return typeof(Decimal);
			else if (sqlTypeName == "text")
				return typeof(string);
			else if (sqlTypeName == "timestamp")
				return typeof(Byte[]);
			else if (sqlTypeName == "tinyint")
				return typeof(Byte);
			else if (sqlTypeName == "varbinary")
				return typeof(Byte[]);
			else if (sqlTypeName == "variant")
				return typeof(Class);
			else if (sqlTypeName == "xml")
				throw new NotImplementedException();
			else if (sqlTypeName == "udt")
				throw new NotImplementedException();
			else if (sqlTypeName == "structured")
				throw new NotImplementedException();
			else if (sqlTypeName == "date")
				return typeof(DateTime);
			else if (sqlTypeName == "time")
				return typeof(DateTime);
			else if (sqlTypeName == "DateTime2")
				return typeof(DateTime);
			else if (sqlTypeName == "DateTimeOffset")
				return typeof(DateTime);
			else
				return typeof(string);
        }
	}
}

By viewing downloads associated with this article you agree to the Terms of Service and the article's licence.

If a file you wish to view isn't highlighted, and is a text file (not binary), please let us know and we'll add colourisation support for it.

License

This article, along with any associated source code and files, is licensed under The Code Project Open License (CPOL)

Share

About the Author

andrewbb@gmail.com
Architect
United States United States
No Biography provided

| Advertise | Privacy | Terms of Use | Mobile
Web02 | 2.8.150520.1 | Last Updated 22 Sep 2014
Article Copyright 2012 by andrewbb@gmail.com
Everything else Copyright © CodeProject, 1999-2015
Layout: fixed | fluid