Function to validate Html Fragment

My code generate some dynamic HTML fragments and I want to know does the html valid.

Thanks to HtmlAgilityPack it is easy:

 Debug.Assert(IsValidHtmlFragment(pricesTable));      

public static bool IsValidHtmlFragment(string html)

       {

           HtmlAgilityPack.HtmlDocument doc = new HtmlAgilityPack.HtmlDocument();

                  doc.LoadHtml(html);

               return (doc.ParseErrors.Count==0);

      }

An error “An entry with the same key already exists” when assigning ImageButton.ImageUrl

We have the following code,

            ImageButton btn = buttonLookupTable[buttonName] as ImageButton;

            if (btn != null)

            {

                btn.ImageUrl = sUrl;

            }
It is almost always works fine, but sometimes we’ve got the error:

System.ArgumentException: An entry with the same key already exists.

Stack Trace :    at System.Collections.Specialized.ListDictionary.Add(Object key, Object value)

   at System.Collections.Specialized.HybridDictionary.Add(Object key, Object value)

   at System.Web.UI.StateBag.Add(String key, Object value)

   at System.Web.UI.WebControls.Image.set_ImageUrl(String value)

I was puzzled, why assigning the value calls Add method.
However despite the ADD name, it is documented that if the item already exists in the StateBag object,
this method updates the value of the item.
And Reflector shows valid code in System.Web.UI.StateBag.Add: 

StateItem item = this.bag[key] as StateItem;
    if (item == null)
    {
        if ((value != null) || this.marked)
        {
            item = new StateItem(value);
            this.bag.Add(key, item);
        }
    }
I’ve noticed a few similar errors in event logs:
System.ArgumentException:An entry with the same key already exists.
Stack Trace :    at System.Collections.Specialized.ListDictionary.Add(Object key, Object value)  
at System.Collections.Specialized.HybridDictionary.Add(Object key, Object value)
   at System.Web.UI.StateBag.Add(String key, Object value)
   at System.Web.UI.AttributeCollection.Add(String key, String value)

It was noticed, that usually the error happened for the first user openning the site after ASP application pool recycle.

It could be caused by multi-threaded access to the same function during ASP.NET precompilation.

The similar problem was reported here.
UPDATE: I beleive that problem is related to the user control’s EnableViewState=false, which we set in Page_Load, and then call btn.ImageUrl=value .

My workaround is to add extra try/catch:  <!–

.csharpcode, .csharpcode pre
{
font-size: small;
color: black;
font-family: Consolas, “Courier New”, Courier, Monospace;
background-color: #ffffff;
/*white-space: pre;*/
}

.csharpcode pre { margin: 0em; }

.csharpcode .rem { color: #008000; }

.csharpcode .kwrd { color: #0000ff; }

.csharpcode .str { color: #006080; }

.csharpcode .op { color: #0000c0; }

.csharpcode .preproc { color: #cc6633; }

.csharpcode .asp { background-color: #ffff00; }

.csharpcode .html { color: #800000; }

.csharpcode .attr { color: #ff0000; }

.csharpcode .alt
{
background-color: #f4f4f4;
width: 100%;
margin: 0em;
}

.csharpcode .lnum { color: #606060; }

  	catch (ArgumentException exc)
            {
                string sKnownErrorToIgnore="An entry with the same key already exists";
                if(!exc.Message.Contains(sKnownErrorToIgnore))
                {
                    throw;
                }
                else
                  {
                    //ignore in production
                    Debug.Assert(false, "just debug when it happens" +exc.ToString());
                  }
            }

Reading AppSettings to be Unit Test friendly.

My application uses a lot of AppSettings to enable/disable different function and I wanted to created unit tests for different combination. I found the simplest way is to create static class data field, that is set to null by default, and loaded from config file if it is null. This allows in unit test methods to explicitely assign values, and when you want return to reading from config file, just reset it to null.

        static private bool? st_bAPIEnabled;

        public static bool IsAPIEnabled()

        {

            st_bAPIDomesticEnabled = AppSettingsHelper.GetIsTrueIfNull(st_bAPIEnabled, “EnableAPI”);

            return (bool)st_bAPIEnabled;

        }

     #region  “set enabled flags- use from Unit tests”

        public static void SetAPIEnabled(bool value)

        {

            st_bAPIEnabled = value;

        }

        public static void ResetAPIEnabledFlag()

        {

            st_bAPIEnabled =null;

        }

        #endregion  //”set API enabled flags- use from Unit tests”

 

      public class AppSettingsHelper

      {

 

        public static bool GetIsTrueIfNull(bool? bEnabled, string AppSettingsKey)

        {

            if (bEnabled == null)

            {

                bEnabled = AppSettingsHelper.ConfigurationIsTrue(AppSettingsKey);

            }

            return (bool)bEnabled;

        }

            public static bool ConfigurationIsTrue(string key)

            {

            string setting = WebConfigurationManager.AppSettings[key];

            bool bRet=false;

            if(!string.IsNullOrEmpty(setting))

                  {

                bRet =(setting.ToLower() == “true”);

            }

            return bRet;

            }

­­­­}

 

Alternative option described in the posts Abstract Class with Template Method – Testing Different Application Configuration Settings – App.Config – Web.Config  and Unit tests – Changing app.config values at runtime.

 

By the way, the post How NUnit Finds Config Files describes, how to make config files available during unit tests. If you are using MS Team System, see Loading appsettings or custom settings from MSTest.exe  

Debug.Assert vs Unit Testing Assert. class

I have quite complicated class and I wanted during debugging/testing to validate that the data in the class is consistent. So I created a method Validate and used it in unit testing class

MyComplexClass oClass= MyComplexClass.CreateClass();
Assert.IsTrue(Validate(oClass);

But then I understood, that it would be better to call this function in the code to ensure that validation happens in the application, not only in unit testing.
So I’ve added Validate method to the end of my  CreateClass() method like the following:

public MyComplexClass CreateClass()
{
  //code omitted
  Debug.Assert(Validate());

This approach is better, because it will work for every call. Also the method belongs to the same class and keeps a knowledge about the class in one place.

Note that there are different options depending how you are using unit test and how critical is validation you perform.
If you are going to use validation only during debugging and running unit tests for debug only, the Validate() method could be private.
If you run Unit Tests in Release mode(for continuous integration), it’s better to make the  Validate()  method public(or use unit test accessor approach to call private methods).
If the validation is important not only during debugging, but in production, you need to log validation errors or throw exception instead of simple  Debug.Assert(). In this case Validate should return not  just bool, but return failure message (or list of error messages).

So my recommendation is the following: If your unit tests methods have not-trivial code to validate results, consider to move it to Validate class method and call it inside the class functions, that create/manipulate the objects.

By the way, if you don’t want to see Debug.Assert messages during Unit Testing, add

When I wrote this post, I found the post with similar opinion- see Myths about Debug.Assert! post.

Passing Exception details in Session to Custom Error page.

In my recent post ASP.NET Exception Handling links  I wondered why in the article Rich Custom Error Handling with ASP.NET    Session is not considered to pass Exception details between global.asax: Application_Error  and Rich Custom Error Pages with Redirect method.
The article compare different state possibilities : Application, Context, Cookies, and QueryString.

The application that I am working with used Cache(which technically works as the same way as Application) with SessionID as a key and Response.Redirect()  to open a custom error page. The problem with Cache( and with Application) state is that it doesn’t work in a web farm  environment, because Exception obeject saved on one farm server is not available after Redirect on another farm server(unless farm support session affinity). So if you have 4 web farm servers, only one of 4 errors are shown in  the custom error page(which is not good). And the problem is not noticable on development machines(which is very bad).
OK, but if SessionID was used as a key in both Application_Error  and custom error page, why not to use Session to pass Exception details. It didn’t work for me initially. Post Don’t redirect after setting a Session variable (or do it right)  describes that it is required to use  Response.Redirect overload with endResponse =false. However even after this I wasn’t able to retrieve in custom error page object, that was saved to Session in Application_Error .
The problem is that after Application_Error  function finished, ASP.NET still considered Exception as not handled, and handles it by logging “Unhandled Exception” to the Application Event Log and interrupting normal event life cycle, which prevents to save the latest Session state changes. 
The fix is simple: if you handle Exception in Application_Error  , don’t forget to call Server.ClearError();  

By the way, this is important difference between catch block and Application_Error  handler.
In catch block If you do NOT want to “swallow” exception , you should explicitely specify throw.
In Application_Error , if you want to “swallow” exception, you need to call Server.ClearError();  

To summarize below is the code, that I am using to pass Exception info from Application_Error to  custom error page using Session(actually it is the almost the same code as posted by  kurtsune in comments on Bertrand Le Roy‘s post .


void Application_Error(object sender, EventArgs e)
{
Exception ex = Server.GetLastError();
HttpContext.Current.Session[“Error”] = ex.Message;
Response.Redirect(“error.aspx”,false);
Server.ClearError();  
}

My CollectionsHelper class

Previously I’ve posted a few Helper Classes . This post describes my CollectionsHelper class.

    ///<summary>
    ///</summary>
    ///<example>
    ///<code>
    ///</code>
    ///</example>
    public static class CollectionsHelper
    {
        /*When C# extensions will be available( promised in C# 3, add this keyword to parameter
         * public static bool IsNullOrEmpty(this ICollection c)
        */
 

<!–

.csharpcode{font-size: 10pt;color: black;font-family: Courier New , Courier, Monospace;background-color:Transparent;}.csharpcode pre { margin: 0px; }.rem { color: #008000; }.kwrd { color: #0000ff; }.str { color: #006080; }.op { color: #0000c0; }.preproc { color: #cc6633; }.asp { background-color: #ffff00; }.html { color: #800000; }.attr { color: #ff0000; }.alt{background-color: #f4f4f4;width: 100%;margin: 0px;}.lnum { color: #606060; }

        ///<summary>
        ///
        ///</summary>
        ///<param name="c"></param>
        ///<returns></returns>
        public static bool IsNullOrEmpty(ICollection c)
        {
           return (c == null || c.Count == 0);
        }
        ///<summary>
        ///
        ///</summary>
        ///<param name="c"></param>
        ///<returns></returns>
        public static bool IsNullOrEmpty(Object[] myArr)
        {
            return (myArr == null || myArr.Length == 0);
        }
  
        //created based on http://www.kirupa.com/net/removingDuplicates2.htm
        //Why it is not in .Net Framework yet? Why HashSet<T> is only in Orcas(http://blogs.msdn.com/bclteam/archive/2006/11/09/introducing-hashset-t-kim-hamilton.aspx)
        public static List<GenericType> removeDuplicates<GenericType>(List<GenericType> inputList)
        {
            Dictionary<GenericType, int> uniqueStore = new Dictionary<GenericType, int>();
            List<GenericType> finalList = new List<GenericType>();
 
            foreach (GenericType currValue in inputList)
            {
                if (!uniqueStore.ContainsKey(currValue))
                {
                    uniqueStore.Add(currValue, 0);
                    finalList.Add(currValue);
                }
            }
            return finalList;
        }
        //Why it is not in .Net Framework yet? Why HashSet<T> is only in Orcas(http://blogs.msdn.com/bclteam/archive/2006/11/09/introducing-hashset-t-kim-hamilton.aspx)
        public static bool AreValuesUnique<GenericType>(List<GenericType> inputList)
        {
            foreach (GenericType currValue in inputList)
            {
                if (inputList.IndexOf(currValue) != inputList.LastIndexOf(currValue))
                    return false;
            }
            return true;
        }
        //Why it is not in .Net Framework yet? Why HashSet<T> is only in Orcas(http://blogs.msdn.com/bclteam/archive/2006/11/09/introducing-hashset-t-kim-hamilton.aspx)
        public static List<GenericType> FindDuplicates<GenericType>(List<GenericType> inputList)
        {
            Dictionary<GenericType, int> uniqueStore = new Dictionary<GenericType, int>();
            List<GenericType> finalList = new List<GenericType>();
 
            foreach (GenericType currValue in inputList)
            {
                if (uniqueStore.ContainsKey(currValue))
                {
                    finalList.Add(currValue);
                }
                else
                {
                    uniqueStore.Add(currValue, 0);
                }
            }
            return finalList;
        }
 
        public static string ToCSVString(List<String> inputList)
        {
            string [] arrStrs=inputList.ToArray();
            return string.Join(",", arrStrs);
        }
        public static string ToCSVString<GenericType>(List<GenericType> inputList)
        {
            StringBuilder sb = new StringBuilder();
            foreach (GenericType currValue in inputList)
            {
                sb.AppendFormat("{0},",currValue.ToString());
            }
            return sb.ToString().TrimEnd(',');
        } 
    }// class CollectionsHelper

Error: “Cannot perform ‘Like’ operation on System.Int64 and System.String”

I’ve had a code similar to the following:

string sSql = String.Format(“Column1 LIKE ‘%{0}%'”, StringValue);
fareRows = dataset.Table.Select(sSql);

And DataTable.Select method returned me  “Cannot perform ‘Like’ operation on System.Int64 and System.String”.

System.Data.EvaluateException: Cannot perform ‘Like’ operation on System.Int64 and System.String.

   at System.Data.BinaryNode.SetTypeMismatchError(Int32 op, Type left, Type right)

   at System.Data.LikeNode.Eval(DataRow row, DataRowVersion version)

   at System.Data.Select.AcceptRecord(Int32 record)

   at System.Data.Select.GetLinearFilteredRows(Range range)

   at System.Data.Select.SelectRows()

   at System.Data.DataTable.Select(String filterExpression)

 I’ve checked http://msdn.microsoft.com/library/default.asp?url=/library/en-us/cpref/html/frlrfSystemDataDataColumnClassExpressionTopic.asp and it  didn’t help.
After some debugging I recognized that I’ve used incorrect Column1  name and the column that I’ve used for filtering had integer type. So the error description is not obvious, but gives a mearningful hint.

I am not sure, that I should post this, but it could help people, who “Google first” instead of “think first”(like me in this case).  
Update: I was surprised that there are guite a few hits to this post from Google searches for the error.