Good Links
Building distributed systems provides great benefits in terms of reliability, scalability, deployment flexibility, decoupling of disparate services and apps, and so on. Actually realizing these benefits can be a challenge. It requires architects and developers pay a lot of attention to app and service boundaries, messaging patterns, and data ownership. This session is an architecture-focused dive into distributed systems design, including the creation of microservices, apps, and the messaging patterns used to communicate between them. You will learn: •About the challenges you’ll face when trying to realize the benefits of distributed systems •How to manage service and app boundaries to achieve practical decoupling •About messaging patterns key to successful interaction across the services and apps in a distributed system/
The SOLID principles are the five commandments of the software world. They have been forgotten for years, as developers focused on JavaScript frameworks with stupid names and complicated patterns. The SOLID principles transcend frameworks and patterns. They are the foundation of building good software, the breakers of monoliths, the decouplers of coupling, and the squashers of regression bugs. One might even say they’re the creators of maintainable code. Unless you’re already a believer, you need to attend this session and get on the right path. You’ll work through each of the principles, learn what they mean, what they will do for you, and why you should stop breaking them. You will even check out some C# code that explains how they can help you; and problems that will haunt you if you ignore them and are face their wrath.
Over the last couple of years Microsoft has offered a wide array of new data access products and technologies. Learn about which technology you should choose in a given situation: LINQ to SQL, the Entity Framework, DataSets, SQL Server stored procedures, ADO.NET, Access, REST based services, and third party ORMs? This interactive session features audience participation with industry experts.
Web Site: .NET Multi Web Application Development – Part 2
Web Site: .NET Multi Web Application Development – Part 2
Multi-web Application Development – Part 2
To continue from part 1, this post describes the setup for a Visual Studio Solution with multiple projects. I’m using Visual Studio 2015, but the concepts can be used with almost any version of Visual Studio.
I always start with a solution containing a couple of projects. The number of projects will grow to many projects, but can be broken apart into multiple solutions for each WebApi or Web application. (The ideal setup would be to put common libraries on a local nuget server).
My current philosophy for .NET systems (Web, WinForms, Wpf, UWP, or whatever) is to break the system apart and create multiple applications for back end access through restful web services. The front end can be any flavor of MVC, WinForms, Wpf, UWP, JavaScript, etc.
In the following example the application is for teacher certification and is based from a similar system created at Texas Education Agency. To begin, the following image is a set of projects I created as one naming convention of projects and how a system may be structured.
I use Solution Folders to group projects together and will discuss each of the groups and how they relate to the overall solutions. This particular solution uses five Solution Folders, Core Libraries, Database Libraries, Model Libraries, WebApi Applications, and WebApps Applications.
Core Libraries
This set of libraries is a set of common libraries that may be used by any application project being developed within the organization. It contains the extension methods for string, StringBuilder, Linq, object, dictionary, and etc classes. There are also library projects for core database classes, Mvc, and WebApi classes.
Database Libraries
This set of set of library projects are for accessing specific databases within the organization. I use one library project per database. Notice each of the database projects contain folders for data storage models (Dsm), data view models (Dvm) and the database repository classes and interfaces used for accessing the database. My current preference is to use Dapper because it is small, lightweight, and pretty fast compared to Entity Frameworks and nHibernate. Using Dapper, you need to write the SQL for database CRUD operations which some may consider a negative.
The Dsm folder contains the classes that are a direct mapping or one to one relationship for each of the database tables. The Dvm is for classes that are used for result sets when joins between two or more tables are needed. The classes in these libraries are a direct result of accessing the database.
Model Libraries
The model libraries are going to contain a combination of data transfer objects, or other model classes that are special for this solution. It might contains some view models for moving data from an MVC controller and/or an WebApi controller. These classes may also be smart or intelligent classes with a fair amount of logic.
WebApi Applications
This folder holds all of the WebApi applications or web services applications used by this system and/or other solution projects. They may be specialized for this current solution but it’s also acceptable to bring in WebApi applications from other solutions. For example, the Access Panel Application (Apa) may have some WebApi services that may be used by the current system. These applications contain the restful web services for the entire website and can be used by any web application. In general, the web services could be broken off into a separate solution or even be created by a different group of developers as long as they provide the api required by the web applications.
WebApps Applications
This folder contains the web applications used by this system and they work together to form one system or at least the appearance of a single system. The applications share a common look and feel for the user interface and also have the ability to share session state. Once the security is estabished the user will not notice when they go from one application to another. They act as one application, even though this example shows three web applications.
This example provides a methodology on how a system can be organized to use several webapi and mvc applications to give the appearance as one application. It also shows the building blocks that can be used to promote code reuse and a methodogoly for developing all applications within an organization. Another side benefit of doing it this way is it promotes consistency between how systems are developed and allows developers to work on more than one system without getting lost when they move on to a different project.
We’re currently using this methodology at the Texas Education Agency and it’s the methodology I used while I was a developer at the Texas Water Development Board. While at TWDB, this process allowed a handful(4) of programmers to create over 25 web applications in less than five years. I believe most of the applications are still in production at the time of this writing.
In my first post on this topic, I showed how to setup multiple applications in IIS so on my next post on this topic (several months away), I’ll dive deeper into the system and start with the development of an Access Panel Application used for logging into the system and displays applications a user has access to within the entire system.
As I’ve been writing this, .NET Core has been released for a while and I’ve experimented with it some. It does change things a bit and not all of it for the better. Setting up and using IIS (localhost) is still doable but you can’t just build and test, instead you have to publish and test even when you make a change to a javascript or css file. I’m not sure yet how this is going to affect using common css or javascript files between projects, perhaps this is where a nuget server for common libraries becomes a big benefit.
Are Great Employees Replaceable?
I’ve seen several posts on the web that refer to the original post by Amy Rees Anderson which led me to other posts that plagiarized parts of the article. The links below are what I believe is the original and some others are based on what she wrote. I’ll let you be the judge on who is original and who is taking credit for other people’s ideas.
Great Employees Are Not Replaceable
by Amy Rees Anderson.
Key Employees You Can’t Afford to Lose
by staff editor.
Great Employees Are Not Replaceable by
by Hira Jha.
Good Leaders Are Invaluable To A Company. Bad Leaders Will Destroy It
by Amy Rees Anderson.
Object Extensions
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
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
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 ); } } }