.NET

SQL Returns Multiple Counters

Posted on Updated on

This SQL can be used to return multiple counters in one record.

select
    (select count(*) from Courses where FacilityId = 4) as counter1,
    (select count(*) from Facilities)                   as counter2,
    (select count(*) from TeeBoxes where CourseId=9)    as counter3,
    (select count(*) from Holes)                        as counter4
Results
+---+----------+----------+----------+----------+
|   | counter1 | counter2 | counter3 | counter4 |
+---+----------+----------+----------+----------+
| 1 | 2        | 4        | 5        | 468      |
+---+----------+----------+----------+----------+

Use the following SQL to return a list of counters.

create table #tempCounters( myCounter int )
insert into #tempCounters( myCounter )
(select count(*) from Courses where FacilityId = 4) 

insert into #tempCounters( myCounter )
 (select count(*) from Facilities)
    
insert into #tempCounters( myCounter )
 (select count(*) from TeeBoxes where CourseId=9)
    
insert into #tempCounters( myCounter )
    (select count(*) from Holes)

select * from #tempCounters
drop table #tempCounters
Results
+---+-----------+
|   | myCounter |
+---+-----------+
| 1 | 2         |
+---+-----------+
| 2 | 4         |
+---+-----------+
| 3 | 5         |
+---+-----------+
| 4 | 468       |
+---+-----------+

Here’s a link to a stackoverflow posting with more examples.

Object Extensions

Posted on Updated on

Here is my class of object extensions I use.

using System;
using System.IO;
using System.Reflection;
using System.Runtime.Serialization;
using System.Runtime.Serialization.Formatters.Binary;

namespace Dahl.Core.Extensions
{
    public static partial class Extensions
    {
        public static string AsString( this object source ) { return source as string; }
        public static DateTime AsDateTime( this object source ) { return (DateTime)source; }
        public static short AsShort( this object source ) { return (short)source; }
        public static int   AsInt( this object source ) { return (int)source; }
        public static long  AsLong( this object source ) { return (long)source; }
        public static bool  AsBool( this object source ) { return (bool)source; }
        public static byte  AsByte( this object source ) { return (byte)source; }

        public static DateTime? AsNullableDateTime( this object source ) { return source as DateTime?; }
        public static short?    AsNullableShort( this object source ) { return source as short?; }
        public static int?      AsNullableInt( this object source ) { return source as int?; }
        public static long?     AsNullableLong( this object source ) { return source as long?; }
        public static bool?     AsNullableBool( this object source ) { return source as bool?; }
        public static byte?     AsNullableByte( this object source ) { return (byte?)source; }

        public static DateTime? AsDateTimeNullable( this object source ) { return source as DateTime?; }
        public static short? AsShortNullable( this object source )       { return source as short?; }
        public static int?   AsIntNullable( this object source )         { return source as int?; }
        public static long?  AsLongNullable( this object source )        { return source as long?; }
        public static bool?  AsBoolNullable( this object source )        { return source as bool?; }
        public static byte?  AsByteNullable( this object source )        { return (byte?)source; }

        public static byte AsTinyInt( this object source )               { return (byte)source; }
        public static byte? AsTinyIntNullable( this object source )       { return (byte?)source; }

        public static short AsSmallInt( this object source ) { return (short)source; }
        public static short? AsSmallIntNullable( this object source ) { return (short?)source; } 

        //-----------------------------------------------------------------------------------------
        /// <summary>
        /// Copy properties from source object into destination object.
        /// </summary>
        /// <typeparam name="T"></typeparam>
        /// <param name="src">copy data from this object into the specified dst object</param>
        /// <param name="dst">copy data into this object</param>
        public static void CopyFrom<T>( this T dst, T src )
        {
            PropertyInfo[] srcProperties = src.GetType().GetProperties( BindingFlags.Public | BindingFlags.Instance );
            foreach ( PropertyInfo srcProperty in srcProperties )
            {
                if ( srcProperty.CanRead && srcProperty.CanWrite )
                {
                    PropertyInfo dstProperty = dst.GetType().GetProperty( srcProperty.Name );
                    if ( dstProperty != null )
                    {
                        object val = srcProperty.GetValue( src, null );
                        dstProperty.SetValue( dst, val, null );
                    }
                }
            }
        }

        //-----------------------------------------------------------------------------------------
        /// <summary>
        /// Makes a new object and copies 
        /// </summary>
        /// <typeparam name="T"></typeparam>
        /// <param name="S"></param>
        /// <returns></returns>
        public static T GetCopy<T>( this T S )
        {
            T newObj = Activator.CreateInstance<T>();
            foreach ( PropertyInfo i in newObj.GetType().GetProperties() )
            {
                //"EntitySet" is specific to link and this conditional logic is optional/can be ignored
                if ( i.CanWrite && i.PropertyType.Name.Contains( "EntitySet" ) == false )
                {
                    object value = S.GetType().GetProperty( i.Name ).GetValue( S, null );
                    i.SetValue( newObj, value, null );
                }
            }

            return newObj;
        }

        //-----------------------------------------------------------------------------------------
        /// <summary>
        /// Perform a deep Copy of an object, object must be serializable.
        /// </summary>
        /// <typeparam name="T">The type of object being copied.</typeparam>
        /// <param name="source">The object instance to copy.</param>
        /// <returns>The copied object.</returns>
        public static T Clone<T>( this T source )
        {
            if ( !typeof( T ).IsSerializable )
            {
                throw new ArgumentException( "The type must be serializable.", nameof( source ) );
            }

            // Don't serialize a null object, simply return the default for that object
            if ( object.ReferenceEquals( source, null ) )
            {
                return default( T );
            }

            IFormatter formatter = new BinaryFormatter();
            Stream stream = new MemoryStream();
            using ( stream )
            {
                formatter.Serialize( stream, source );
                stream.Seek( 0, SeekOrigin.Begin );
                return (T)formatter.Deserialize( stream );
            }
        }
    }
}

Linq Extensions

Posted on Updated on

Here is my class of linq extensions I use.

This is an example of using the extension in a unit test.

[TestMethod]
public void Linq_OrderBy()
{
    List<User> userList = UserList.OrderBy( "FirstName"  ).ToList();
    Trace.WriteLine( "===  Order By FirstName ascending ===" );
    foreach ( User user in userList )
        Trace.WriteLine( $"FirstName: {user.FirstName},  LastName: {user.LastName}" );

    userList = UserList.OrderBy( "LastName", false ).ToList();
    Trace.WriteLine( "===  Order By LastName descending ====" );
    foreach ( User user in userList )
        Trace.WriteLine( $"FirstName: {user.FirstName},  LastName: {user.LastName}" );

}

private static readonly List<User> UserList = new List<User>() {
    new User { FirstName = "firstName03", LastName= "lastName08" },
    new User { FirstName = "firstName07", LastName= "lastName04" },
    new User { FirstName = "firstName06", LastName= "lastName05" },
    new User { FirstName = "firstName04", LastName= "lastName07" },
    new User { FirstName = "firstName10", LastName= "lastName01" },
    new User { FirstName = "firstName09", LastName= "lastName02" },
    new User { FirstName = "firstName08", LastName= "lastName03" },
    new User { FirstName = "firstName05", LastName= "lastName06" },
    new User { FirstName = "firstName02", LastName= "lastName09" },
    new User { FirstName = "firstName01", LastName= "lastName10" }
};
using System;
using System.Collections.Generic;
using System.Linq;
using System.Linq.Expressions;
using System.Reflection;

namespace Dahl.Core.Extensions
{
    public static partial class Extensions
    {
        //-----------------------------------------------------------------------------------------
        /// <summary>
        /// Sorts the elements of a sequence according to a key. 
        /// </summary>
        /// <typeparam name="TSource"></typeparam>
        /// <typeparam name="TKey"></typeparam>
        /// <param name="source"></param>
        /// <param name="keySelector"></param>
        /// <param name="descending"></param>
        /// <returns></returns>
        public static IOrderedEnumerable<TSource> OrderBy<TSource, TKey>( this IEnumerable<TSource> source,
                                                                          Func<TSource, TKey> keySelector,
                                                                          bool descending )
        {
            if ( descending )
                return source.OrderByDescending( keySelector );

            return source.OrderBy( keySelector );
        }

        //-----------------------------------------------------------------------------------------
        /// <summary>
        /// 
        /// </summary>
        /// <typeparam name="TSource"></typeparam>
        /// <typeparam name="TKey"></typeparam>
        /// <param name="source"></param>
        /// <param name="keySelector"></param>
        /// <param name="descending"></param>
        /// <returns></returns>
        public static IOrderedQueryable<TSource> OrderBy<TSource, TKey>( this IQueryable<TSource> source,
                                                                         Expression<Func<TSource, TKey>> keySelector,
                                                                         bool descending )
        {
            return descending ? source.OrderByDescending( keySelector )
                              : source.OrderBy( keySelector );
        }

        //-----------------------------------------------------------------------------------------
        /// <summary>
        /// 
        /// </summary>
        /// <typeparam name="T"></typeparam>
        /// <param name="list"></param>
        /// <param name="sortExpression"></param>
        /// <param name="sortAscending"></param>
        /// <returns></returns>
        public static IQueryable<T> OrderBy<T>( this IQueryable<T> list, string sortExpression, bool sortAscending = true )
        {
            return sortAscending ? list.OrderBy( f => OrderFunc( f, sortExpression ) )
                                 : list.OrderByDescending( f => OrderFunc( f, sortExpression ) );
        }


        //-----------------------------------------------------------------------------------------
        /// <summary>
        /// 
        /// </summary>
        /// <typeparam name="T"></typeparam>
        /// <param name="list"></param>
        /// <param name="sortExpression"></param>
        /// <param name="sortAscending"></param>
        /// <returns></returns>
        public static IEnumerable<T> OrderBy<T>( this IEnumerable<T> list, string sortExpression, bool sortAscending = true )
        {
            return sortAscending ? list.OrderBy( f => OrderFunc( f, sortExpression ) )
                                 : list.OrderByDescending( f => OrderFunc( f, sortExpression ) );
        }

        //-----------------------------------------------------------------------------------------
        /// <summary>
        /// 
        /// </summary>
        /// <typeparam name="T"></typeparam>
        /// <param name="obj"></param>
        /// <param name="propertyName"></param>
        /// <returns></returns>
        public static object GetChildObject<T>( T obj, string propertyName )
        {
            Type t = obj.GetType();
            PropertyInfo prop = t.GetProperty( propertyName );
            if ( prop == null )
            {
                string msg = $"PropertyName \"{propertyName}\" is not defined in class \"{obj.GetType().FullName}\".";
                throw new ArgumentException( msg );
            }

            return prop.GetValue( obj, null ) ?? Activator.CreateInstance( prop.PropertyType );
        }

        //-----------------------------------------------------------------------------------------
        /// <summary>
        /// 
        /// </summary>
        /// <typeparam name="T"></typeparam>
        /// <param name="obj"></param>
        /// <param name="propertyName"></param>
        /// <returns></returns>
        private static object OrderFunc<T>( T obj, string propertyName )
        {
            string propName = propertyName;
            object newObj = obj;

            if ( propertyName.Contains( '.' ) )
            {   // the requested property is contained in a child object
                string[] parts = propertyName.Split( '.' );
                int numParts = parts.Length - 1;
                for ( int i = 0; i < numParts; i++ )
                    newObj = GetChildObject( newObj, parts[i] );

                propName = parts[numParts];
            }

            PropertyInfo propertyGetter = newObj.GetType()
                                                .GetProperty( propName, BindingFlags.Public | BindingFlags.Instance | BindingFlags.IgnoreCase );
            if ( propertyGetter == null )
            {
                string msg = @"Sort Expression could not find property name provided<br />" + $"PropertyName: {propertyName}";
                throw new ArgumentException( msg );
            }

            return propertyGetter.GetValue( newObj, null );
        }

        //-----------------------------------------------------------------------------------------
        /// <summary>
        /// 
        /// </summary>
        /// <typeparam name="TSrc"></typeparam>
        /// <typeparam name="TKey"></typeparam>
        /// <param name="src"></param>
        /// <param name="selector"></param>
        /// <returns></returns>
        public static IEnumerable<TSrc> DistinctBy<TSrc, TKey>( this IEnumerable<TSrc> src, Func<TSrc, TKey> selector )
        {
            HashSet<TKey> keys = new HashSet<TKey>();
            return src.Where( element => keys.Add( selector( element ) ) );
        }
    }
}

String Extensions

Posted on Updated on

Here is my class of string extensions I like to use. It allows me to write code that is easier for me to read. For me, I find the following two examples a lot easier to read and allows me to be more consistent in writing code.

// Test if two string are not equal
string s1 = "this is string #1";
string s2 = "this is string #2";

if ( s1.IsNotEqualIgnoreCase( s2 ) )
    DoSomething();
// convert a string to an integer
string s = "12356";
int x = s.ToInt();

C# class Extensions:

using System;
using System.Globalization;
using System.Text.RegularExpressions;

namespace Dahl.Core.Extensions
{
    public static class StringExt
    {
        ///----------------------------------------------------------------------------------------
        /// <summary>
        /// Trims whitespace from the string.
        /// </summary>
        /// <param name="source"></param>
        /// <returns></returns>
        public static string TrimWhiteSpace( this string source )
        {
            if ( string.IsNullOrEmpty( source ) )
                return string.Empty;

            return source.Trim();
        }

        ///----------------------------------------------------------------------------------------
        /// <summary>
        /// Determines whether two T:string objects have the same value ignoring case,
        /// uses StringComparison.OrdinalIgnoreCase 
        /// </summary>
        /// <param name="source">the string to compare</param>
        /// <param name="val">the value to compare</param>
        /// <returns></returns>
        public static bool IsEqualIgnoreCase( this string source, string val )
        {
            if ( string.IsNullOrEmpty( source ) && string.IsNullOrEmpty( val ) )
                return false;

            if ( string.IsNullOrEmpty( source ) )
                return false;

            return string.Equals( source, val, StringComparison.OrdinalIgnoreCase );
        }

        ///----------------------------------------------------------------------------------------
        /// <summary>
        /// Determines whether 2 specified T:String objects have the same value ignoring case,
        /// uses StringComparison.OrdinalIgnoreCase 
        /// </summary>
        /// <param name="source">the string to compare</param>
        /// <param name="val">the value to compare</param>
        /// <returns></returns>
        public static bool IsNotEqual( this string source, string val )
        {
            if ( string.IsNullOrEmpty( source ) && !string.IsNullOrEmpty( val ) )
                return true;

            if ( string.IsNullOrEmpty( val ) )
                return true;

            return !string.Equals( source, val );
        }

        ///----------------------------------------------------------------------------------------
        /// <summary>
        /// Determines whether 2 specified T:String objects have the same value ignoring case,
        /// uses StringComparison.OrdinalIgnoreCase 
        /// </summary>
        /// <param name="source">the string to compare</param>
        /// <param name="val">the value to compare</param>
        /// <returns></returns>
        public static bool IsNotEqualIgnoreCase( this string source, string val )
        {
            if ( string.IsNullOrEmpty( source ) && !string.IsNullOrEmpty( val ) )
                return true;

            if ( string.IsNullOrEmpty( val ) )
                return true;

            return !string.Equals( source, val, StringComparison.OrdinalIgnoreCase );
        }

        ///----------------------------------------------------------------------------------------
        /// <summary>
        /// Returns a value indicating whether the specified String object occurs within this string ignoring case,
        /// uses StringComparison.OrdinalIgnoreCase 
        /// </summary>
        /// <param name="source">the string to compare</param>
        /// <param name="val">the value to find</param>
        /// <returns></returns>
        public static bool ContainsIgnoreCase( this string source, string val )
        {
            if ( string.IsNullOrEmpty( source ) || string.IsNullOrEmpty( val ) )
                return false;

            return source.IndexOf( val, StringComparison.OrdinalIgnoreCase ) >= 0;
        }

        ///----------------------------------------------------------------------------------------
        /// <summary>
        /// Returns a value indicating whether the specified String object contains anything
        /// </summary>
        /// <param name="source">the string to compare</param>
        /// <returns></returns>
        public static bool IsNullOrEmpty( this string source )
        {
            return string.IsNullOrEmpty( source );
        }

        ///----------------------------------------------------------------------------------------
        /// <summary>
        /// Returns a value indicating whether the specified String object contains anything
        /// </summary>
        /// <param name="source">the string to compare</param>
        /// <returns></returns>
        public static bool IsNotNullOrEmpty( this string source )
        {
            return !string.IsNullOrEmpty( source );
        }

        ///----------------------------------------------------------------------------------------
        /// <summary>
        /// Determines whether the beginning of this string instance matches the specified string ignoring case,
        /// uses StringComparison.OrdinalIgnoreCase 
        /// </summary>
        /// <param name="source">the string to compare</param>
        /// <param name="val">the value to find</param>
        /// <returns></returns>
        public static bool StartsWithIgnoreCase( this string source, string val )
        {
            if ( string.IsNullOrEmpty( source ) || string.IsNullOrEmpty( val ) )
                return false;

            return source.StartsWith( val, StringComparison.OrdinalIgnoreCase );
        }

        ///----------------------------------------------------------------------------------------
        /// <summary>
        /// Determines whether the end of this string instance matches the specified string ignoring case,
        /// uses StringComparison.OrdinalIgnoreCase 
        /// </summary>
        /// <param name="source">the string to compare</param>
        /// <param name="val">the value to find</param>
        /// <returns></returns>
        public static bool EndsWithIgnoreCase( this string source, string val )
        {
            if ( string.IsNullOrEmpty( source ) || string.IsNullOrEmpty( val ) )
                return false;

            return source.EndsWith( val, StringComparison.OrdinalIgnoreCase );
        }

        ///----------------------------------------------------------------------------------------
        /// <summary>
        /// Replaces the old value with the specified new value ignoring case.
        /// </summary>
        /// <param name="source"></param>
        /// <param name="oldValue">The part of the string to be replaced by the newValue</param>
        /// <param name="newValue">The new string to replace the old value</param>
        /// <returns></returns>
        public static string ReplaceIgnoreCase( this string source, string oldValue, string newValue )
        {
            string s;
            try
            {
                if ( source == null )
                    source = string.Empty;

                if ( oldValue == null )
                    oldValue = string.Empty;

                s = Regex.Replace( source, oldValue, newValue, RegexOptions.IgnoreCase );
            }
            catch ( Exception )
            {
                s = oldValue;
            }

            return s;
        }

        ///----------------------------------------------------------------------------------------
        /// <summary>
        /// 
        /// </summary>
        /// <param name="source"></param>
        /// <returns></returns>
        public static string ToString( this string source )
        {
            if ( source == null )
                return string.Empty;

            return source.ToString( CultureInfo.InvariantCulture );
        }

        ///----------------------------------------------------------------------------------------
        /// <summary>
        /// Returns a string up to the maxLen specified.
        /// </summary>
        /// <param name="source"></param>
        /// <param name="maxLen">The maximum length of the sting</param>
        /// <returns></returns>
        public static string ToString( this string source, int maxLen )
        {
            if ( string.IsNullOrEmpty( source ) )
                return string.Empty;

            if ( source.Length > maxLen )
                return source.Substring( 0, maxLen );

            return source.TrimEnd();
        }

        ///----------------------------------------------------------------------------------------
        /// <summary>
        /// Takes a string and if its length is greater than maxLen it trims it to maxLen-3 and 
        /// appends three periods to the string.
        /// </summary>
        /// <param name="source">the string to compare</param>
        /// <param name="maxLen">maximum length of string to return</param>
        /// <returns></returns>
        public static string ToEllipsis( this string source, int maxLen )
        {
            if ( string.IsNullOrEmpty( source ) )
                return string.Empty;

            maxLen -= 3;
            if ( source.Length > maxLen )
                return string.Format( "{0}...", source.Substring( 0, maxLen ) );

            return source.TrimEnd();
        }

        ///----------------------------------------------------------------------------------------
        /// <summary>
        /// If possible makes a Guid from the string provided, otherwise it returns an Empty Guid.
        /// </summary>
        /// <param name="source"></param>
        /// <returns></returns>
        public static Guid ToGuid( this string source )
        {
            Guid result;
            try
            {
                result = new Guid( source );
            }
            catch ( Exception )
            {
                result = Guid.Empty;
            }

            return result;
        }

        ///----------------------------------------------------------------------------------------
        /// <summary>
        /// Converts string to title case by first changing all characters to lower case.
        /// </summary>
        /// <param name="source"></param>
        /// <returns></returns>
        public static string ToTitleCase( this string source )
        {
            CultureInfo cultureInfo = System.Threading.Thread.CurrentThread.CurrentCulture;
            return cultureInfo.TextInfo.ToTitleCase( source.ToLower() );
        }

        ///----------------------------------------------------------------------------------------
        /// <summary>
        /// Convert string to DateTime, if null or empty then returns defaultValue
        /// </summary>
        /// <param name="source"></param>
        /// <param name="defaultValue"></param>
        /// <returns></returns>
        public static DateTime ToDateTime( this string source, DateTime defaultValue = default( DateTime ) )
        {
            if ( string.IsNullOrEmpty( source ) )
                return defaultValue;

            DateTime result;
            if ( !DateTime.TryParse( source, out result ) )
                result = defaultValue;

            return result;
        }

        ///----------------------------------------------------------------------------------------
        /// <summary>
        /// Convert string to DateTime, if null or empty then returns defaultValue
        /// </summary>
        /// <param name="source"></param>
        /// <param name="defaultValue"></param>
        /// <returns></returns>
        public static DateTime ToDate( this string source, DateTime defaultValue = default( DateTime ) )
        {
            if ( string.IsNullOrEmpty( source ) )
                return defaultValue;

            DateTime result;
            if ( !DateTime.TryParse( source, out result ) )
                result = defaultValue;

            return new DateTime( result.Year, result.Month, result.Day );
        }

        ///----------------------------------------------------------------------------------------
        /// <summary>
        /// Converts string into a boolean value.
        /// </summary>
        /// <param name="source">Valid values are "f" or "false" and "t" or "true"</param>
        /// <param name="defaultValue">If parameter is not specified, false is returned.</param>
        /// <returns></returns>
        public static bool ToBool( this string source, bool defaultValue = default( bool ) )
        {
            if ( string.IsNullOrEmpty( source ) )
                return defaultValue;

            string s = source.ToLower().Trim();
            if ( s.Equals( "false" ) || s.Equals( "f" ) || s == "0" )
                return false;

            if ( s.Equals( "true" ) || s.Equals( "t" ) || s == "1" )
                return true;

            return defaultValue;
        }

        ///----------------------------------------------------------------------------------------
        /// <summary>
        /// Convert string to short, if null or empty then returns defaultValue
        /// </summary>
        /// <param name="source"></param>
        /// <param name="defaultValue"></param>
        /// <returns></returns>
        public static short ToShort( this string source, short defaultValue = default( short ) )
        {
            if ( string.IsNullOrEmpty( source ) )
                return defaultValue;

            short result;
            source = source.Replace( ",", "" );
            if ( short.TryParse( source, out result ) )
                return result;

            return defaultValue;
        }

        ///----------------------------------------------------------------------------------------
        /// <summary>
        /// Convert string to Int, if null or empty then returns defaultValue
        /// </summary>
        /// <param name="source"></param>
        /// <param name="defaultValue"></param>
        /// <returns></returns>
        public static int ToInt( this string source, int defaultValue = default( int ) )
        {
            if ( string.IsNullOrEmpty( source ) )
                return defaultValue;

            int result;
            source = source.Replace( ",", "" );
            if ( int.TryParse( source, out result ) )
                return result;

            return defaultValue;
        }

        ///----------------------------------------------------------------------------------------
        /// <summary>
        /// Trys to converts an object to an integer
        /// </summary>
        /// <param name="source"></param>
        /// <param name="defaultValue"></param>
        /// <returns></returns>
        public static int ToInt( this object source, int defaultValue = default( int ) )
        {
            int target = defaultValue;
            if ( source is string )
                target = IntParse( source.ToString() );
            else if ( source is int )
                target = (int)source;

            return target;
        }

        ///----------------------------------------------------------------------------------------
        /// <summary>
        /// Converts a string to an integer 
        /// </summary>
        /// <param name="source">The string to parse</param>
        /// <param name="defaultValue">If provided, a value to return if the string cannot be parsed, 
        ///                   if not provided zero will be used as the default value</param>
        /// <returns>The parsed value if string represents a legal integer, otherwise the default value</returns>
        public static int IntParse( this string source, int defaultValue = default( int ) )
        {
            int target;
            int.TryParse( source, out target );
            return target;
        }

        ///----------------------------------------------------------------------------------------
        /// <summary>
        /// Convert string to long, if null or empty then returns defaultValue
        /// </summary>
        /// <param name="source"></param>
        /// <param name="defaultValue"></param>
        /// <returns></returns>
        public static long ToLong( this string source, long defaultValue = default( long ) )
        {
            if ( string.IsNullOrEmpty( source ) )
                return defaultValue;

            long result;
            source = source.Replace( ",", "" );
            if ( long.TryParse( source, out result ) )
                return result;

            return defaultValue;
        }

        ///----------------------------------------------------------------------------------------
        /// <summary>
        /// Convert string to double, if null or empty then returns defaultValue
        /// </summary>
        /// <param name="source"></param>
        /// <param name="defaultValue"></param>
        /// <returns></returns>
        public static double ToDouble( this string source, double defaultValue = default( double ) )
        {
            if ( string.IsNullOrEmpty( source ) )
                return defaultValue;

            double result;
            source = source.Replace( ",", "" );
            if ( double.TryParse( source, out result ) )
                return result;

            return defaultValue;
        }

        ///----------------------------------------------------------------------------------------
        /// <summary>
        /// Convert string to float, if null or empty then returns defaultValue
        /// </summary>
        /// <param name="source"></param>
        /// <param name="defaultValue"></param>
        /// <returns></returns>
        public static float ToFloat( this string source, float defaultValue = default( float ) )
        {
            if ( string.IsNullOrEmpty( source ) )
                return defaultValue;

            float result;
            source = source.Replace( ",", "" );
            if ( float.TryParse( source, out result ) )
                return result;

            return defaultValue;
        }

        ///----------------------------------------------------------------------------------------
        /// <summary>
        /// Converts string to decimal, if null or empty then uses default value
        /// </summary>
        /// <param name="source"></param>
        /// <param name="defaultValue"></param>
        /// <returns></returns>
        public static decimal ToDecimal( this string source, decimal defaultValue = default( decimal ) )
        {
            if ( string.IsNullOrEmpty( source ) )
                return defaultValue;

            decimal result;
            source = source.Replace( ",", "" );
            if ( decimal.TryParse( source, out result ) )
                return result;

            return defaultValue;
        }

        ///----------------------------------------------------------------------------------------
        /// <summary>
        /// 
        /// </summary>
        private static readonly Regex NonDigit = new Regex( "\\D" );

        ///----------------------------------------------------------------------------------------
        /// <summary>
        /// Returns only Digits
        /// </summary>
        /// <param name="number"></param>
        /// <returns></returns>
        public static string OnlyDigits( this string number )
        {
            return NonDigit.Replace( number, string.Empty );
        }

        ///----------------------------------------------------------------------------------------
        /// <summary>
        /// Returns a short date string
        /// </summary>
        /// <param name="date"></param>
        /// <returns></returns>
        public static string ToShortDateString( this DateTime? date )
        {
            return date?.ToShortDateString() ?? string.Empty;
        }

        ///----------------------------------------------------------------------------------------
        /// <summary>
        /// Returns a long date string
        /// </summary>
        /// <param name="date"></param>
        /// <returns></returns>
        public static string ToLongDateString( this DateTime? date )
        {
            return date?.ToLongDateString() ?? string.Empty;
        }

        ///----------------------------------------------------------------------------------------
        /// <summary>
        /// Provide a string to test pattern to see if email address is probably in a valid format.
        /// </summary>
        /// <param name="source"></param>
        /// <returns></returns>
        public static bool IsValidEmailFormat( this string source )
        {
            const string pattern = @"^[a-zA-Z0-9._%+-]+@[a-zA-Z0-9.-]+\.[a-zA-Z]{2,6}$";
            return Regex.IsMatch( source, pattern );
        }
    }
}

Web Site: .NET Multi Web Application Development

Aside Posted on Updated on

Multi-web Application Development – Part I

This post describes how to create, setup and configure multiple web applications to appear as one application. It shows how to setup a development environment that uses localhost to works similar to dev, test and production environments. The only difference between the environments is the domain name in the URL. The following table is an example showing the difference in URL’s between different environments used in an organization.

Environment URL
Local https://localhost/apps/app1
Development https://dev/apps/app1
Test https://test/apps/app1
Production https://prod/apps/app1

Why is all this important? Have you ever had multiple versions of an application and needed to debug an older version? Or, have you ever developed an application using IIS Express (F5) only to have it look and work different once it’s deployed to dev?

A common reason for deployment problems developing locally on IIS Express (F5) is because it’s a different web server and physical paths don’t always match to the same relative path as the deployment server’s path, especially if you’re using virtual directories. This usually happens when there are common JavaScript and CSS files used in multiple web applications. I’m not an expert with IIS Express but it seems to use a location that is tied to where the project is located and is not the same as the IIS Web Site physical path.

Here the main question is, is there any way to setup and configure a development environment to provide consistent results when deployed to dev, test, and prod. My answer is yes, if you use IIS and localhost instead of IIS Express.

Advantages to using IIS instead of IIS Express

  1. Modify JavaScript, CSS, cshmtl, and html files without rebuilding the web application,
  2. Unnecessary to close browser each time for code, build, debug cycle during development of web application,
  3. Access web applications in separate browser anytime, even when Visual Studio is closed,
  4. Debug multiple web applications in one instance of Visual Studio

Step 1: Setting up physical directory structure
IIS configuration uses inheritance through the use of its web.config file. Knowing how to take advantage of it is important during development and deployment.

The default directory for IIS is C:\inetput\wwwroot, but it doesn’t have to be that directory. It can point anywhere. I like using the following structure because it allows me to create multiple websites on my development system.

In this example, the website physical path is D:\IISWebsites\localhost\wwwroot.

+- D:\IISWebsites
   +- localhost
      +- AdminScripts
      +- custerr
      +- logs
      +- temp
      +- wwwroot
          +- appName
          |  +- api
          |  +- apps
          |  +- web.config
          +- aspnet_client
          |  +- cdn
          |  |  +- angular
          |  |  +- bootstrap
          |  |  +- SmartAdmin
          |  +- css
          |  +- js
          +- Content

In IIS, the above folders show up under the Default Web Site as shown in the following image. While the folder structure looks the same, we’re putting the applications in a different physical location that separates them from the website.

+- E:\IISApps
   +- appName
      +- api
      |  +- WebApi01
      |     +- bin
      |     +- Areas
      |  +- WebApi02
      |     +- bin
      |     +- Areas
      |  +- WebApi03
      |     +- bin
      |     +- Areas
      |  +- WebApi04
      |     +- bin
      |     +- Areas
      +- apps
         +- WebApp01
            +- bin
            +- Areas
         +- WebApp02
            +- bin
            +- Areas
         +- WebApp03
            +- bin
            +- Areas

In IIS, the left pane looks similar to the following tree. The aspnet_client folder in each application is a virtual directory that points to the physical location defined by the web site, in this case D:\IISWebsites\localhost\wwwroot\aspnet_client. So far, this is they only way I’ve been able to share bundles between the web applications.

+- Default Web Site
   +- aspnet_client
   +- api
   |  +- WebApi01
   |  |	+- aspnet_client
   |  |	+- Views
   |  +- WebApi02
   |  |	+- aspnet_client
   |  |	+- Views
   |  +- WebApi03
   |  |	+- aspnet_client
   |  |	+- Views
   |  +- WebApi04
   |  	+- Views
   +- apps
      +- WebApp01
      |	 +- aspnet_client
      |	 +- Views
      +- WebApp02
      |  +- aspnet_client
      |  +- Views
      +- WebApp03
         +- aspnet_client
	 +- Views

So far, I’ve been able to use these concepts to work with TFS and SVN successfully. It’s helped me with my development of multiple web applications.

Share Bundles in ASP.NET Applications

Posted on Updated on

I’m working on a system that needs to work and look as one web application. They share the same css styles and several JavaScript files. In an MVC application, Microsoft provides the ability to bundle styles and javascript, but everything I’ve seen and read so far puts the stylesheets and javascripts files in the applications /Content or /Scripts folder. In the past I used the aspnet_client folder to share common stylesheets and javascript files and it was not a problem because I was doing Web Forms and not using the bundling capabilities in .NET.

The current project is three .NET MVC 5 applications and they use the same stylesheets and share some custom javascript files, not to mention Angular, Bootstrap, and so on. For Angular and Bootstrap I can use the CDN but I’d like to really just bundle everything into a couple of bundles. I did figure out a way to share everything and store the files it the aspnet_client folder, but came across a few problems when I started to do the builds in Release mode.

The default location for the IIS website is C:\inetpub\wwwwroot and aspnet_client directory is there as a place where usually third party libraries will install their software. The aspnet_client directory is a global location for all web applications in the website. I think this is a good place to put common css and javascript files, even the ones from angular, bootstrap and so on if you don’t want to use the CDN for those third party packages.

To make shared bundling work, each application needs to create a virtual directory to point to the aspnet_client physical location. For three applications, let’s call them app1, app2, and app3. We need to create a virtual directory called aspnet_client in each of the applications.

This is one configuration that works:

C:\inetpub\wwwroot +-- aspnet_client | +-- | +-- angular | | +-- 1.5.5 | +-- angular.uigrid | +-- 3.1.0.1 | +-- bootstrap | | +-- 3.3.1 | | +-- 3.3.6 | +-- custom | | +-- 1.0.0 | +-- custom | | +-- 1.0.0 | +-- jquery | | +-- 2.1.1 | +-- jquery.validation | +-- 1.14.0 +-- Dahl (this is the primary path for a family of applications in the website) +-- api +-- apps

On the D: drive I put each of the applications in their own folder. The aspnet_client below is a virtual directory in the application. The physical directory doesn’t exist on the D: drive, but instead points to c:\inetpub\wwwroot\aspnet_client.

D:\ +-- Dahl +-- api | +-- api1 (web api application #1) | +-- api2 (web api application #2) | +-- api3 (web api application #2) +-- apps +-- app1 (mvc application #1) | +-- aspnet_client | (physical path is c:\inetpub\wwwroot\aspnet_client) +-- app2 (mvc application #2) | +-- aspnet_client | (physical path is c:\inetpub\wwwroot\aspnet_client) +-- app3 (mvc application #3) +-- aspnet_client (physical path is c:\inetpub\wwwroot\aspnet_client)

The default Bundling in .NET doesn’t allow you to use an absolute path. The path needs to be relative to the application it’s being used in, so /aspnet_client/… doesn’t work, you get an error. Using ~/aspnet_client works, even if aspnet_client is a virtual directory in the application. This is just one example, but there is a lot of different ways to configure this and make it work. In the RegisterBundles, I coded it as follows. Notice the bundle path mirrors the virtual path from aspnet_client/… to the last part in the bundle name.

I’ve read on stackoverflow where some say it’s a hack because the virtual path needs to mimic the actual path in the application and they shouldn’t have to do it this way. Technically they’re correct, but we have to live with it until Microsoft decides to fix it. For angular, bootstrap, and jquery files, using the CDN option is probably more appropriate but this shows how to do it without using a CDN.

public static void RegisterBundles(BundleCollection bundles)
{
    bundles.Add( new ScriptBundle( "~/aspnet_client/jquery/js" ).Include( 
                                   "~/aspnet_client/jquery/2.1.1/jquery.js",
                                   "~/aspnet_client/jquery.validation/1.14.0/jquery.validate.js" ) );

    bundles.Add( new ScriptBundle( "~/aspnet_client/angular/js" ).Include(
                                   "~/aspnet_client/angular/1.5.5/angular.js",
                                   "~/aspnet_client/angular/1.5.5/angular-animate.js",
                                   "~/aspnet_client/angular/1.5.5/angular-route.js",
                                   "~/aspnet_client/angular/1.5.5/angular-touch.js",
                                   "~/aspnet_client/angular/1.5.5/angular-mocks.js" ) );

   bundles.Add( new ScriptBundle( "~/aspnet_client/angular.ui-grid/js" ).Include( 
                                  "~/aspnet_client/angular.ui-grid/3.1.0.1/Scripts/ui-grid.js",
                                  "~/aspnet_client/angular.ui-grid/3.1.0.1/grunt-scripts/csv.js",
                                  "~/aspnet_client/angular.ui-grid/3.1.0.1/grunt-scripts/pdfmake.js",
                                  "~/aspnet_client/angular.ui-grid/3.1.0.1/grunt-scripts/vfs_fonts.js" ) );

    // Use the development version of Modernizr to develop with and learn from. Then, when you're
    // ready for production, use the build tool at http://modernizr.com to pick only the tests you need.
    bundles.Add( new ScriptBundle( "~/aspnet_client/js/js" ).Include( 
                                   "~/aspnet_client/js/respond/1.2.0/respond.js",
                                   "~/aspnet_client/js/modernizr/2.6.2/modernizr-2.6.2.js" ) );

    //-------------------------------------------------------------------------------------
    //- Styles section
    bundles.Add( new StyleBundle( "~/aspnet_client/bootStrap/css" ).Include( 
                                  "~/aspnet_client/bootStrap/3.3.6/respond.js",
                                  "~/aspnet_client/bootStrap/3.3.6/bootstrap.css",
                                  "~/aspnet_client/bootStrap/3.3.6/bootstrap-theme.css" ) );

    bundles.Add( new StyleBundle( "~/aspnet_client/Custom/css" ).Include( 
                                  "~/aspnet_client/Custom/1.0.0/Custom.css",
                                  "~/aspnet_client/Custom/1.0.0/CustomLeftNav.css",
                                  "~/aspnet_client/Custom/1.0.0/dashboard.css" ) );

    bundles.Add( new StyleBundle( "~/aspnet_client/angular.ui-grid/3.1.0.1/Content/css" ).Include( 
                                  "~/aspnet_client/angular.ui-grid/3.1.0.1/Content/ui-grid.css" ) );

In the cshtml master layout file I used the following, content removed to keep it shorter.

<head>
    <meta charset="utf-8" />
    <meta name="viewport" content="width=device-width, initial-scale=1.0">
    <title>@ViewBag.Title - My ASP.NET Application</title>
    @Styles.Render( "~/aspnet_client/bootStrap/css" )
    @Styles.Render( "~/aspnet_client/Custom/css" )
    @RenderSection( "styles", required: false )
</head>
<body>
    <div>
        @RenderBody()
    </div>

@Scripts.Render( "~/aspnet_client/jquery/js" )
@Scripts.Render( "~/aspnet_client/angular/js" )
@Scripts.Render( "~/aspnet_client/js/js" )
@RenderSection( "scripts", required: false )
</body>

In one of the view pages where the angular grid is used, include the following.

@section styles {
@Styles.Render("~/aspnet_client/angular.ui-grid/3.1.0.1/Content/css")

<div>
   page content...
</div>

@sections scripts {
@Scripts.Render("~/aspnet_client/angular.ui-grid/js")
}

Sharing Session State between Classic ASP and .NET

Posted on Updated on

At work, we are starting to upgrade/migrate a Classic ASP application to multiple ASP.NET MVC Web and WebApi 2.x applications. One of the requirements is the need to share session state between old and new web applications.

  1. Required to access the Classic ASP session state variable.
  2. Required to share session state between multiple web applications.

Step #1:
The following code is in a page called AspSession.asp in the classic asp application.

<% 
'------------------------------------------------------------------------------
if Session.Contents.Count = 0 then
    response.Write "Session.Contents.Count = 0"
    response.End
end if

'------------------------------------------------------------------------------
Dim values,remoteAddr,localAddr

remoteAddr = Request.ServerVariables("REMOTE_ADDR")
localAddr = Request.ServerVariables("LOCAL_ADDR")

'------------------------------------------------------------------------------
if remoteAddr = localAddr then
    strMode = Request.QueryString( "mode" )
    strName = Request.QueryString( "name" )

    if strMode = "get" then
        response.Write GetSessionVar( strName )
    elseif strMode = "getall" then
        response.Write GetAllSessionVars()
    elseif strMode = "set" then
        strValue = Request.QueryString( "value" )
        Session( strName ) = strValue
    end if
end if

'------------------------------------------------------------------------------
function GetAllSessionVars()
    dim sessionVars

    sessionVars = ""
    for each key in Session.Contents
        sessionVars = sessionVars & "{" & GetSessionVar( key ) & "}"
    next

    GetAllSessionVars = sessionVars
end function

'------------------------------------------------------------------------------
' returns a single session variable
function GetSessionVar( byval name )

    If IsArray(Session.Contents(name)) Then
        GetSessionVar = GetArrayVar
    ElseIf IsObject( Session.Contents(name) ) Then
        GetSessionVar = GetObjectDictionaryVar( name )
    Else
        GetSessionVar = name & "|" & Session.Contents(name)
    End If

end function

'------------------------------------------------------------------------------
' assumes this is an object/dictionary session variable.
function GetObjectDictionaryVar( byval name )
    dim values

    values = name & "[Object/Dictionary]"
    for each key in Session.Contents(name)
        values = values & key & ":" & Session.Contents(name)(key) & "|"
    next

    GetObjectDictionaryVar = values
end function

'------------------------------------------------------------------------------
' assumes this is an array session variable.
function GetArrayVar( byval name )
    dim values

    values = name & "[Array]"
    for each key in Session.Contents(name)
        values = values & key & ":" & Session.Contents(name)(key) & "|"
    next

    GetArrayVar = values
end function
%>

Step #2:
In the ASP.NET MVC web application, create a class SessionStateManager.cs. This is a generic class using .NET Session State Management. We are developing a system that uses multiple ASP.NET MVC web applications and this class is used by all of the applications and placed into a separate class library.

The appName in the URL is the path where the AspSession.asp file is located.

// Contains properties, etc for session state management. This class needs to be
// serializable so it can be saved in session state.
[Serializable]
public class SessionStateManager
{
    //-------------------------------------------------------------------------
    // This calls a web page in the classic asp application to get it's 
    // current session variables.
    public static object Get( string name )
    {
        HttpContext context = HttpContext.Current;
        if ( context == null )
            return string.Empty;

        string value = null;
        foreach ( string key in context.Request.Cookies.AllKeys )
        {
            HttpCookie cookie = context.Request.Cookies[key];
            if ( cookie != null )
            {
                if ( cookie.Name.StartsWith( "ASPSESSION" ) )
                {
                    System.Uri uri = context.Request.Url;
                    string url = string.Format( "{0}://{1}/appName/aspSession.asp?mode=get&name={2}",
                                                 uri.Scheme, uri.Host, name );
                    HttpWebRequest request = (HttpWebRequest)WebRequest.Create( url );
                    request.Headers.Add( "Cookie: " + cookie.Name + "=" + cookie.Value );
                    HttpWebResponse response = (HttpWebResponse)request.GetResponse();
                    Stream responseStream = response.GetResponseStream();
                    if ( responseStream != null )
                    {
                        System.Text.Encoding encode = System.Text.Encoding.GetEncoding( "utf-8" );
                        StreamReader readStream = new StreamReader( responseStream, encode );
                        value = readStream.ReadToEnd();
                        response.Close();
                        readStream.Close();

                        // if true then it is either the wrong cookie or an expired cookie
                        // and will eventually be removed by the system.
                        if ( value.Equals( "Session.Contents.Count = 0" ) )
                        {
                            value = null;
                            continue;
                        }

                        string[] item;
                        if ( value.StartsWith( name + "[Object/Dictionary]" ) )
                        {
                            value = value.Replace( name + "[Object/Dictionary]", "" );
                            Dictionary<string,string> dictionary = new Dictionary<string, string>();
                            string[] dictionaryItems = value.Split( '|' );
                            foreach ( string s in dictionaryItems )
                            {
                                item = s.Split( ':' );
                                if ( item.Length == 2 )
                                    dictionary.Add( item[0], item[1] );
                            }
                            return dictionary;
                        }

                        item = value.Split( '|' );
                        if ( item.Length == 2)
                            value = (item.Length == 2) ? item[1] : string.Empty;
                    }
                }
            }
        }
        return value;
    }

    //-------------------------------------------------------------------------
    //  Disclaimer: This method hasn't been tested.
    //  Use this to set a session variable in the classic asp application. 
    public static void Set( string name, object value )
    {
        HttpContext context = HttpContext.Current;
        String[] cookies = context.Request.Cookies.AllKeys;

        foreach ( string key in context.Request.Cookies.AllKeys )
        {
            HttpCookie cookie = context.Request.Cookies[key];
            if ( cookie != null && cookie.Name.StartsWith( "ASPSESSION" ) )
            {
                System.Uri uri = context.Request.Url;
                string url = string.Format( "{0}://{1}/appName/aspSession.asp?mode=set&name={2}&value={3}",
                                            uri.Scheme, uri.Host,
                                            context.Server.UrlEncode( name ),
                                            context.Server.UrlEncode( value.ToString() ) );
                HttpWebRequest request = (HttpWebRequest)WebRequest.Create( url );
                request.Headers.Add( "Cookie: " + cookie.Name + "=" + cookie.Value );
                HttpWebResponse response = (HttpWebResponse)request.GetResponse();
                Stream responseStream = response.GetResponseStream();
                break;
            }
        }
    }
}