Introduction
Many a times, while coding, we need to determine if two objects are the same, if not, do some processing further.
Mostly, we write comparison logic to achieve the same. Presented here is one of the many ways, this could be achieved in many other possible ways as well.
Background
In our project page, we had many Kendo UI TextBox
es, that had decimal amounts (called Overrides) - now depending upon whether the Overrides changed from the last time it was edited (i.e., needed to compare the existing Overrides with the ones saved in Database last time around), the requirement was to show a label in Red color to notify the user, that Billing Overrides have been changed, when the page loaded and also when the "Approve" button was clicked.
I had to send all existing values from the text box (UI), make a database call to get the last saved values, compare them to come up with a boolean flag to show the notification. In order to achieve this, formatted my Overrides each with an id with a combination of "override_item.Key
" and value as "@item.Value
". Before making an Ajax call, added "#
" as a separator to each of the Key/Value pair, on the controller side- split the string with "#
" values to get splitString
, put it in a dictionary of string
, string
as Key/Value pairs, pass it compare function.
Using the Code
//code in cshtml file
var index = 0;
foreach (var item in @Model.AllOverrides)
{
<input type="hidden" value="@item.Value"
id="override_@item.Key" name="@item.Key" />
index++;
}
//spinner div
<div id="divSpinner"
style="position:absolute;z-index:10;border-style:none;
margin-left:413px;height:48px;width:48px;">
<img src="~/Content/images/loading-image.gif" /></div>
//div for Notification Message
<table class="xxx" style="margin-left: 20px;
margin-right: 20px;width:93.7%">
<tr>
<td colspan="4" class="xxx" id="billingChangeTd">
Billing Overrides:
@(Html.DisplayFor(m => m.BillingOverridesChanged))
</td>
</tr>
</table>
// ui for btnApproval
<table class="xxx" style="margin-left: 20px;
margin-right: 20px;width:95%">
<tr>
<td>
@(Html.Kendo().ToolBar().Name("OrderApproveToolBar")
.HtmlAttributes(new { style = "font-size:10px;
line-height:2em", padding = "2px 0px 2px" })
.Items(items =>
{
items.Add().Type(CommandType.Button).ImageUrl
("../../Content/images/approve.jpg").Text("Approve").HtmlAttributes
(new { id = "btnApproval", padding = "2px 0px 2px" }).Click
("clientApproval").Enable(true);//call clientApproval on click
}))
</td>
</tr>
</table>
<script>
$(document).ready(function ()
{
var billingChanged = if(billingChanged == {
$("#billingChangeTd").attr("style",
"color:red !important"); //show Text in Red color if Overrides changed
}
});
function clientApproval()
{
var overridesStringData = "";
var overrideKeyList = $( for (var i = 0; i < overrideKeyList.length; i++)
{
overridesStringData = overridesStringData + overrideKeyList[i].id +
":" + overrideKeyList[i].value + "#"
}
var dataToSend =
{
Note: $( Overrides: overridesStringData,
};
$( $.ajax({
url: "/Order/ApprovalOrderTrue", //call to Controller method
data: dataToSend,
type: "POST",
success: function (result)
{
if (result == "True")
{
//Add delay
clientCloseSubmitWindow(3); //custom logic to have a delay
}
else if (result == "False")
{
//code here for stop propagation show message
}
}
});
}
</script>
//Controller code
[AcceptVerbs(HttpVerbs.Post)]
public bool ApprovalOrderTrue(string Note, string Overrides)
{
_iOrderBusinessService = new OrderBusinessService();
Guid selectedOpportunity = (Guid)OMSSession.SessionProperties.SelectedOpportunityId;
if(! string.IsNullOrEmpty(Overrides) && Overrides.EndsWith("#"))
{
Overrides = Overrides.Substring(0,Overrides.Length-1);
}
var splitString = Overrides.Split('#').ToList();
Dictionary<string, string> existingOverrides = new Dictionary<string, string>();
if(splitString != null && !string.IsNullOrEmpty(splitString[0]))
{
foreach (var stringItem in splitString)
{
existingOverrides.Add(stringItem.Split(':')[0].ToString(),
stringItem.Split(':')[1].ToString());
}
}
bool overridesMatch =
_iOrderBusinessService.ValidateAllOverrides(existingOverrides, selectedOpportunity);
if (overridesMatch)
{
//custom logic
}
return overridesMatch;
}
// Order Business Service
public bool ValidateAllOverrides(Dictionary<string,
string> existingOverrides,Guid opportunityId)
{
bool allOverridesMatched = false;
Dictionary<string, string> latestOverrides = GetAllOverrides(opportunityId);
if(latestOverrides.Count == 0 && existingOverrides.Count == 0
&& latestOverrides.Count == existingOverrides.Count)
{
allOverridesMatched = true;
}
else if (latestOverrides.Count != existingOverrides.Count)
{
allOverridesMatched = false;
}
else //both counts not Zero now compare actual data
{
StringBuilder sbExistingOverrides = new StringBuilder();
StringBuilder sbLatestOverrides = new StringBuilder();
foreach (var existingItem in existingOverrides)
{
if (existingItem.Key.Contains("override_"))
{
sbExistingOverrides.Append(existingItem.Key.Remove(0, 9) +
":" + existingItem.Value + "#");
}
}
string existingOverridesHash = GetMd5Hash(sbExistingOverrides.ToString()); //Getting hashed string
foreach (var latestItem in latestOverrides)
{
sbLatestOverrides.Append(latestItem.Key+":"+
latestItem.Value+"#");
}
allOverridesMatched = VerifyMd5Hash(sbLatestOverrides.ToString(),
existingOverridesHash); //call to compare passes strings
}
return allOverridesMatched;
}
//Utility Functions
public static string GetMd5Hash(string input)
{
StringBuilder sBuilder = new StringBuilder();
using (MD5 md5Hash = MD5.Create())
{
// Convert the input string to a byte array and compute the hash.
byte[] data = md5Hash.ComputeHash(Encoding.UTF8.GetBytes(input));
// Loop through each byte of the hashed data
// and format each one as a hexadecimal string.
for (int i = 0; i < data.Length; i++)
{
sBuilder.Append(data[i].ToString("x2"));
}
}
// Return the hexadecimal string
return sBuilder.ToString();
}
public static bool VerifyMd5Hash(string input, string hash)
{
// Hash the input.
string hashOfInput = GetMd5Hash(input);
// Create a StringComparer an compare the hashes.
StringComparer comparer = StringComparer.OrdinalIgnoreCase;
if (0 == comparer.Compare(hashOfInput, hash))
{
return true;
}
else
{
return false;
}
}
Points of Interest
By just calling the Utility functions and passing what it needed, I was able to infer whether passed string
s were the same or different and then accordingly act thereon.