Kuwait Civil ID Validator

In the following solution, I had implemented a custom Enterprise Library Validator for Kuwait Civil ID.

The validation logic has been acquired from PACI as the following:

1 /// <summary> 2 /// Represent the associated validator attribute for <see cref="CivilIdValidator"/> 3 /// </summary> 4 [AttributeUsage(AttributeTargets.Property | AttributeTargets.Field)] 5 public class CivilIdValidatorAttribute : ValidatorAttribute 6 { 7 /// <summary> 8 /// Creates the <see cref="T:Microsoft.Practices.EnterpriseLibrary.Validation.Validator" /> described by the attribute object providing validator specific 9 /// information. 10 /// </summary> 11 /// <param name="targetType">The type of object that will be validated by the validator.</param> 12 /// <returns> 13 /// The created <see cref="T:Microsoft.Practices.EnterpriseLibrary.Validation.Validator" />. 14 /// </returns> 15 /// <remarks> 16 /// This operation must be overriden by subclasses. 17 /// </remarks> 18 protected override Validator DoCreateValidator(Type targetType) 19 { 20 return new CivilIdValidator(); 21 } 22 }

and the validator class:

1 /// <summary> 2 /// MS EL Custom Validation Attribute for Civil ID validation 3 /// </summary> 4 public class CivilIdValidator : Validator<decimal> 5 { 6 7 8 /// <summary> 9 /// Initializes a new instance of the <see cref="CivilIdValidator"/> class. 10 /// </summary> 11 public CivilIdValidator() : base("","") { } 12 13 /// <summary> 14 /// Does the validate. 15 /// </summary> 16 /// <param name="objectToValidate">The object to validate.</param> 17 /// <param name="currentTarget">The current target.</param> 18 /// <param name="key">The key.</param> 19 /// <param name="validationResults">The validation results.</param> 20 protected override void DoValidate(decimal objectToValidate, object currentTarget, string key, ValidationResults validationResults) 21 { 22 if(!Utilities.IsValidCivilId(objectToValidate.ToString())) 23 { 24 LogValidationResult(validationResults, "???? ????? ??? ???? ???? ?? 12 ???", currentTarget, key); 25 return; 26 } 27 } 28 29 /// <summary> 30 /// Gets the message template to use when logging results no message is supplied. 31 /// </summary> 32 protected override string DefaultMessageTemplate 33 { 34 get 35 { 36 return ""; 37 } 38 } 39 40 41 }

The validation logic:

1 /// <summary> 2 /// Custom utilities used by the applciation 3 /// </summary> 4 public class Utilities 5 { 6 /// <summary> 7 /// Determines whether [is valid civil identifier] [the specified civil identifier]. 8 /// </summary> 9 /// <param name="civilId">The civil identifier.</param> 10 /// <returns></returns> 11 public static bool IsValidCivilId(string civilId) 12 { 13 if (string.IsNullOrEmpty(civilId)) 14 return false; 15 16 if (civilId.Length != 12) 17 return false; 18 19 decimal civilIdDecimal; 20 21 if (!decimal.TryParse(civilId, out civilIdDecimal)) 22 return false; 23 24 int calculation; 25 26 int monthPart = int.Parse(civilId.Substring(3,2)); 27 int dayPart = int.Parse(civilId.Substring(3,2)); 28 29 30 if ((monthPart > 12 || monthPart <1) || (dayPart > 31 || dayPart <1)) 31 { 32 return false; 33 } 34 35 calculation = 2 * int.Parse(civilId.Substring(0,1)) + 1 * int.Parse(civilId.Substring(1, 1)) + 6 * int.Parse(civilId.Substring(2, 1)) + 3 * int.Parse(civilId.Substring(3, 1)) + 7 * int.Parse(civilId.Substring(4, 1)) + 9 * int.Parse(civilId.Substring(5, 1)) + 10 * int.Parse(civilId.Substring(6, 1)) + 5 * int.Parse(civilId.Substring(7, 1)) + 8 * int.Parse(civilId.Substring(8, 1)) + 4 * int.Parse(civilId.Substring(9, 1)) + 2 * int.Parse(civilId.Substring(10, 1)); 36 37 calculation = calculation % 11; 38 39 calculation = 11 - calculation; 40 41 if (calculation != int.Parse(civilId.Substring(11, 1))) 42 return false; 43 else 44 return true; 45 } 46 }

I hope that helped.

Ahmed

Advertisements

Using Enterprise Library to Map Data Into Objects (Simple ORM)

In a recent project – working with developers just started using MS Enterprise Library – I had the need to implement a simple framework for them to deal with relational database as objects in a simple ORM.

The idea was to create a layer utilizing Enterprise Library 6.0 to encapsulate the database objects mapping plus having a way for validation.

The solution can be highlighted as below:

 image

First, we have implemented a base Adapter of T – T is the object type – as the following:

1 /// <summary> 2 /// The base class for the adapter 3 /// </summary> 4 /// <typeparam name="T">The type of the associated object</typeparam> 5 public class AdapterBase<T> 6 { 7 /// <summary> 8 /// Gets the object. 9 /// </summary> 10 /// <param name="objectData">The object data.</param> 11 /// <returns>One instance of the associated object</returns> 12 protected static T GetObject(DataRow objectData) 13 { 14 var objectInstance = (T)Activator.CreateInstance(typeof(T)); 15 16 var databaseDefinedProperties = ExploreDatabaseDefinedProperties(objectInstance); 17 18 return GetObject(objectData, databaseDefinedProperties); 19 } 20 21 /// <summary> 22 /// Gets the collection. 23 /// </summary> 24 /// <param name="collectionData">The collection data.</param> 25 /// <returns>Collection of the associated object</returns> 26 protected static Collection<T> GetCollection(DataTable collectionData) 27 { 28 var objectCollection = (Collection<T>)Activator.CreateInstance(typeof(Collection<T>)); 29 30 var objectInstance = (T)Activator.CreateInstance(typeof(T)); 31 32 var databaseDefinedProperties = ExploreDatabaseDefinedProperties(objectInstance); 33 34 foreach (DataRow row in collectionData.Rows) 35 { 36 objectCollection.Add(GetObject(row, databaseDefinedProperties)); 37 } 38 39 return objectCollection; 40 } 41 42 /// <summary> 43 /// Gets the object. 44 /// </summary> 45 /// <param name="objectData">The object data.</param> 46 /// <param name="databaseDefinedProperties">The database defined properties.</param> 47 /// <returns></returns> 48 private static T GetObject(DataRow objectData, Collection<PropertyInfo> databaseDefinedProperties) 49 { 50 var objectInstance = (T)Activator.CreateInstance(typeof(T)); 51 52 foreach (PropertyInfo propertyInfo in databaseDefinedProperties) 53 { 54 if (Attribute.IsDefined(propertyInfo, typeof(DbField))) 55 { 56 var dbAttribute = propertyInfo.CustomAttributes.Single(p => p.AttributeType == typeof(DbField)); 57 58 if (dbAttribute != null) 59 { 60 var dbFieldName = dbAttribute.NamedArguments.Single(p => p.MemberName == "DbfieldName").TypedValue.Value.ToString(); 61 62 if (objectData.Table.Columns.Contains(dbFieldName)) 63 { 64 var dbFieldValue = objectData[dbFieldName]; 65 66 if (dbFieldValue != DBNull.Value) 67 { 68 propertyInfo.SetValue(objectInstance, objectData[dbFieldName]); 69 } 70 } 71 } 72 73 } 74 } 75 return objectInstance; 76 } 77 78 /// <summary> 79 /// Explores the database defined properties. 80 /// </summary> 81 /// <param name="objectInstance">The object instance.</param> 82 /// <returns></returns> 83 private static Collection<PropertyInfo> ExploreDatabaseDefinedProperties(T objectInstance) 84 { 85 var databaseDefinedProperties = new Collection<PropertyInfo>(); 86 87 var info = objectInstance.GetType().GetTypeInfo(); 88 89 foreach (PropertyInfo propertyInfo in info.DeclaredProperties) 90 { 91 if (Attribute.IsDefined(propertyInfo, typeof(DbField)) && propertyInfo.CanWrite) 92 { 93 databaseDefinedProperties.Add(propertyInfo); 94 } 95 } 96 97 return databaseDefinedProperties; 98 } 99 100 /// <summary> 101 /// Validates the specified object to validate. 102 /// </summary> 103 /// <param name="objectToValidate">The object to validate.</param> 104 /// <returns></returns> 105 public static ValidationResults Validate(T objectToValidate) 106 { 107 return Validation.Validate<T>(objectToValidate); 108 } 109 110 /// <summary> 111 /// Validates the specified object to validate. 112 /// </summary> 113 /// <param name="objectToValidate">The object to validate.</param> 114 /// <param name="ruleSet">The rule set.</param> 115 /// <returns></returns> 116 public static ValidationResults Validate(T objectToValidate, string[] ruleSet) 117 { 118 return Validation.Validate<T>(objectToValidate, ruleSet); 119 } 120 121 public static string ToXml(T objectToConvert) 122 { 123 var objectXml = new XmlDocument(); 124 125 var parentNode = objectXml.CreateElement("ObjectData"); 126 127 var info = objectToConvert.GetType().GetTypeInfo(); 128 129 foreach (PropertyInfo propertyInfo in info.DeclaredProperties) 130 { 131 var xmlNode = objectXml.CreateElement(propertyInfo.Name); 132 var nodeValue = propertyInfo.GetValue(objectToConvert); 133 xmlNode.InnerText = nodeValue == null ? "" : nodeValue.ToString(); 134 parentNode.AppendChild(xmlNode); 135 } 136 137 objectXml.AppendChild(parentNode); 138 139 return objectXml.InnerXml; 140 } 141 142 143 }

The base adapter have the needed functions to convert relational data – Data Tables or Data Rows – into the respective objects, also have the function to do validation which will be described later in this post.

Next, the DBField class which is required to do the actual mapping between the class property and the field name from the relational database:

1 /// <summary> 2 /// Custom attribute to hold the databse field name for a defined object property 3 /// </summary> 4 [AttributeUsage(AttributeTargets.Property)] 5 public class DbField : Attribute 6 { 7 /// <summary> 8 /// Gets or sets the name of the dbfield. 9 /// </summary> 10 /// <value> 11 /// The name of the dbfield. 12 /// </value> 13 public string DbfieldName { get; set; } 14 15 /// <summary> 16 /// Initializes a new instance of the <see cref="DbField"/> class. 17 /// </summary> 18 public DbField() 19 { 20 } 21 }

Last part of the mapping solution is the object itself which can be as the following:

1 /// <summary> 2 /// Represent the bank object 3 /// </summary> 4 public class Bank 5 { 6 /// <summary> 7 /// Gets or sets the identifier. 8 /// </summary> 9 /// <value> 10 /// The identifier. 11 /// </value> 12 [DbField(DbfieldName="BNK_MGR_ID")] 13 public Nullable<int> Id {get; set;} 14 15 /// <summary> 16 /// Gets or sets the name. 17 /// </summary> 18 /// <value> 19 /// The name. 20 /// </value> 21 [StringLengthValidator(1, 255, MessageTemplate = "???? ????? ??? ?????")] 22 [DbField(DbfieldName="BNK_NMA")] 23 public string Name { get; set; } 24 25 /// <summary> 26 /// Gets or sets the telephone. 27 /// </summary> 28 /// <value> 29 /// The telephone. 30 /// </value> 31 [DbField(DbfieldName="BNK_TEL")] 32 public string Telephone { get; set; } 33 34 /// <summary> 35 /// Gets or sets the fax. 36 /// </summary> 37 /// <value> 38 /// The fax. 39 /// </value> 40 [DbField(DbfieldName="BNK_FAX")] 41 public string Fax { get; set; } 42 43 /// <summary> 44 /// Gets or sets the email. 45 /// </summary> 46 /// <value> 47 /// The email. 48 /// </value> 49 [DbField(DbfieldName="BNK_EMAIL")] 50 public string Email { get; set; } 51 52 /// <summary> 53 /// Gets or sets the address. 54 /// </summary> 55 /// <value> 56 /// The address. 57 /// </value> 58 public string Address { get; set; } 59 /// <summary> 60 /// Gets or sets the note. 61 /// </summary> 62 /// <value> 63 /// The note. 64 /// </value> 65 [DbField(DbfieldName="BNK_NOTE")] 66 public string Note { get; set; } 67 68 /// <summary> 69 /// Initializes a new instance of the <see cref="Bank"/> class. 70 /// </summary> 71 public Bank() { } 72 }

As you can notice, DbField attribute is used to tell the adapter of the actual field name which comes from the data source.

Finally, the adapter itself to be created as the following:

1 /// <summary> 2 /// Bank adapter 3 /// </summary> 4 public class BankAdapter : AdapterBase<Bank> 5 { 6 /// <summary> 7 /// Gets the by identifier. 8 /// </summary> 9 /// <param name="id">The identifier.</param> 10 /// <returns></returns> 11 public static Bank GetById(int id) 12 { 13 return GetObject(BankRef.GeById(id).Tables[0].Rows[0]); 14 } 15 16 /// <summary> 17 /// Gets all. 18 /// </summary> 19 /// <returns></returns> 20 public static Collection<Bank> GetAll() 21 { 22 return GetCollection(BankRef.GetAll().Tables[0]); 23 } 24 25 /// <summary> 26 /// Adds the specified new bank. 27 /// </summary> 28 /// <param name="newBank">The new bank.</param> 29 /// <returns></returns> 30 public static string Add(Bank newBank) 31 { 32 return BankRef.Insert(newBank.Name, newBank.Telephone, newBank.Fax, newBank.Email, newBank.Address, newBank.Note); 33 } 34 35 /// <summary> 36 /// Updates the specified edited bank. 37 /// </summary> 38 /// <param name="editedBank">The edited bank.</param> 39 /// <returns></returns> 40 public static bool Update(Bank editedBank) 41 { 42 if (BankRef.Update(editedBank.Id.Value, editedBank.Name, editedBank.Telephone, editedBank.Fax, editedBank.Email, editedBank.Address, editedBank.Note) > 0) 43 return true; 44 else 45 return false; 46 } 47 48 /// <summary> 49 /// Gets all lite. 50 /// </summary> 51 /// <returns></returns> 52 public static Collection<Bank> GetAllLite() 53 { 54 return GetCollection(BankRef.GetAllLite().Tables[0]); 55 } 56 57 public static Collection<Bank> GetAllLiteForElevation() 58 { 59 return GetCollection(BankRef.GetAllLiteForElevation().Tables[0]); 60 } 61 62 }

You can notice the usage of the GetCollection and GetObject methods which is inherited from the base adapter class.

The solution can be used to teach starters the basics of ORM and the usage of Enterprise Library.

I hope that helped

Ahmed

Visual Studio 2012 Report Project: Using dataset web service data source step by step

Recently I was working on a project which involves creating SSRS reports using a web service which returns dataset as data source, after searching a lot and tries different bites of techniques, here is the final working solution step by step:

Problem definition:

You can’t get the actual values of the returned dataset fields or you are new to XML data sources and you need the step by step guide.

Solution:

Install Microsoft SQL Server Data Tools – Business Intelligence for Visual Studio 2012 from the following link: http://www.microsoft.com/en-us/download/details.aspx?id=36843 .

Once installed you can now see the following project types as below:

image

Install Fiddler from the following link http://fiddler2.com/get-fiddler (Fiddler helps you to inspect the web service output in real time in case your have no access to the local server which has the service hosted).

Install XMLQuire from the following link http://qutoric.com/xmlquire/ (XMLQuire helps you to get the exact ElemenPath which will be explained soon).

Now, get back to VS and create a new “Report Server Project” and then create a new “Shared Data Source” as shown below:

image

Replace the “Connection String” with the actual path of your service and supply credentials if required.

Now create a new “Shared Dataset”, select the data source created above and then add the following query:

<Query xmlns=”http://tempuri.org/”>
<SoapAction>http://tempuri.org/GetReportIFTSB07</SoapAction>
<Method Namespace=”http://tempuri.org/” Name=”GetReportIFTSB07″>
    <Parameters>
      <Parameter Name=”FiscalYear”>
        <DefaultValue>2013</DefaultValue>
      </Parameter>
      <Parameter Name=”Agency”>
        <DefaultValue>141</DefaultValue>
      </Parameter>
      <Parameter Name=”AccountPeriod1″>
        <DefaultValue>03</DefaultValue>
      </Parameter>
      <Parameter Name=”AccountPeriod2″>
        <DefaultValue>04</DefaultValue>
      </Parameter>
    </Parameters>
  </Method>
<ElementPath IgnoreNameSpace=”True”>*</ElementPath>
</Query>

Modify the query with the method name and required method parameters.

Run the query and get back to Fiddler (Fiddler will keep monitoring all the events while running), click on the web service call to get the XML results as shown below:

image 

Switch to TextView and copy the whole response.

Open XMLQuire and copy the whole XML from previous step into the editor.

Click on the part of the XML response which contains the data as shown below:

image 

Notice in XMLQuire in the XSD pane, it shows an element path like: /soap:Envelope/soap:Body/GetReportIFTSB07Response/GetReportIFTSB07Result/diffgr:diffgram/NewDataSet/Table[1]

Copy and edit the XSD to something like  GetReportIFTSB07Response/GetReportIFTSB07Result/diffgr:diffgram/NewDataSet/Table{MINUS_LINE_AMT}

So the final query will be:

<Query xmlns=”http://tempuri.org/”>
<SoapAction>http://tempuri.org/GetReportIFTSB07</SoapAction>
<Method Namespace=”http://tempuri.org/” Name=”GetReportIFTSB07″>
    <Parameters>
      <Parameter Name=”FiscalYear”>
        <DefaultValue>2013</DefaultValue>
      </Parameter>
      <Parameter Name=”Agency”>
        <DefaultValue>141</DefaultValue>
      </Parameter>
      <Parameter Name=”AccountPeriod1″>
        <DefaultValue>03</DefaultValue>
      </Parameter>
      <Parameter Name=”AccountPeriod2″>
        <DefaultValue>04</DefaultValue>
      </Parameter>
    </Parameters>
  </Method>
<ElementPath IgnoreNameSpace=”True”>GetReportIFTSB07Response/GetReportIFTSB07Result/diffgr:diffgram/NewDataSet/Table{MINUS_LINE_AMT}</ElementPath>
</Query>

Now you can see the actual data from the dataset instead of the first results.

Notes:

  1. http://tempuri.org/ is the default xmlns replace it with the one from your web service response.
  2. You can edit the required fields to be retrieved by modifying the “MINUS_LINE_AMT” within the “ElementPath” to include more fields separated by “,” example <ElementPath IgnoreNameSpace=”True”>GetReportIFTSB07Response/GetReportIFTSB07Result/diffgr:diffgram/NewDataSet/Table{PLUS_LINE_AMT,MINUS_LINE_AMT}</ElementPath>.
  3. Parameters must be passed as shown in the query to retrieve the right data.

I hope that helped.

Ahmed

SharePoint 2010 Field Formulas (In Arabic)

Just came cross an issue lately with SharePoint 2010 field (Column) formulas.

The issues is when I was applying formulas on Arabic culture sites, SharePoint kept giving me errors parsing the formula.

For example:

I have 2 fields [Start Date] and [End Date]

To calculate the days between the two dates and display “-” if the [End Date] is empty, you can use something like:

=IF(ISBLANK([End Date]),”-“,DATEDIF([End Date],[Start Date],”d”))

This will calculate the days between the two dates only if the [End Date] is blank and works perfectly in English based sites.

If you want to do the same in Arabic Language sites (Even if the column names in English), simple you need to replace the comma “,” with semi column “;”, the result will be something this:

=IF(ISBLANK(النهاية);”-“;DATEDIF(البداية;النهاية;”d”))

As stated in this MSDN article, this must be done for specific languages/cultures and if the website culture changed back again to English, the formula will be changed automatically to use the comma model (Didn’t test this).

I hope that helped

Ahmed

Solve Silverlight Arabic text issue in SharePoint 2010 Organization Browser and Media Web parts

Just came across the following solution to solve the common SharePoint 2010 Silverlight web parts (Org Browser and Media Web parts) Arabic display issue.

The solution is very simple:

  1. Locate the following 2 files [HierarchyChart.xap] and [MediaPlayer.xap] in [14 hive]\TEMPLATE\LAYOUTS\ClientBin
  2. Do the following for the 2 files:
    1. Very important to backup the 2 files first, just in case.
    2. The [.xap] file is basically a compressed folder (Archive), so open the file using a compression tool like [7-Zip]
    3. Open the [AppManifest.xaml] file using notepad, make sure that you open the file from the archive to make sure that the changes will be saved to the archive as well.
    4. Change the [RunTimeVersion] to [5.0.61118.0]
    5. Save the [AppManifest.xaml] (Inside the archive).
    6. Open your browser.
    7. Make sure that you clear the browser cache.
    8. Enjoy your organization browser in Arabic.

image

The idea beyond the solution is to force the Silverlight runtime to the newest version which has the proper RTL support.

Please, try this and submit your feedback.

I hope that helped

Ahmed