Extension method to trim all string fields in a C# object

/// <summary>
/// This does NOT go into sub objects, only the top level object
/// i.e. if you have a class with a string field, it will trim that string field value
/// but not trim any string fields on sub-objects inside the containing class
/// </summary>
/// <param name="currentObject"></param>
        public static void SafeTrimAllStringFields(this object currentObject)
        {
            if (currentObject == null)
            {
                return;
            }

            var type = currentObject.GetType();
            var stringFields = type.GetFields(BindingFlags.Instance | BindingFlags.Public | BindingFlags.NonPublic)
                .Where(f => f.FieldType == typeof(string));

            foreach (var field in stringFields)
            {
                var value = (string)field.GetValue(currentObject);
                if (value != null)
                {
                    field.SetValue(currentObject, value.SafeTrim());
                }
            }
        }
 }

   public static string SafeTrim(this string value)
        {
            return value == null ? string.Empty : value.Trim();
        }

NHibernate ‘IN’ clause with linq

NHibernate was giving me fits, not letting me use ‘.In’ in the linq statements.

Here is how I got it to go:

 IQueryable<int?> idsForOrgList = _repo.Get<OrganizationThingyXref>().Where(thingy => thingy.OrganizationID == orgId && thingy.IdICareAbout != null).Select(_=>_.IdICareAbout);
           
List<People> ThingysInOrg = _repo.Get<Thingy>().Where(_ => idsForOrgList.Contains(_.IdICareAbout)).ToList();

Selenium test .net webforms with data-attributes

I was struggling to E2E Selenium test a repeater, in a user control, in an old .net webforms page – tall ask right?

Here is the solution I came up with:

I added a custom attribute (“data-serviceid”) to the element the repeater is drawing – inside the code behind of the user control (a link button in this case):

var lbNewReport = (LinkButton)args.Item.FindControl("lbNewReport");
lbNewReport.Attributes.Add("data-serviceid", myServiceId);

Then I used this static helper method for selenium:

public static By SelectorByAttributeValue(string attributeName, string attributeValue)
{
return (By.XPath($"//*[@{attributeName} = '{attributeValue}']"));
}

With This call:

var linkIWant = _driver.FindElement(SelectorByAttributeValue("data-serviceid", myServiceId));

And voila – I have the control in hand that I want to interact with(clicking in this case for me).

Reading hidden field values with Selenium

I have a need to hide a guid used for an index on a .cshtml so I can get model binding on controls dynamically added with ajax (it’s a long story) (that was a mouthful)

I had a hard time finding the value in the hidden field; as it turns out, you can just get it by the attribute on the Selenium element like this:


IWebElement hiddenIndex = driver.FindElement(By.Id("MyControlName_0__Index"));
var indexValueToUse = hiddenIndex.GetAttribute("value");

 

Implementing reCAPTCHA in a Razor MVC view

Setup in your Google account

You will have to have a Google account to use reCAPTCHA.

Log into the google account you want to tie your reCAPTCHA keys to and navigate to:

https://www.google.com/recaptcha/admin#list

Under the ‘Register a new site’ section of that page,follow the instructions and set up a separate key set for each of your development,test, and production environments – including one specifically for ‘localhost’ or 127.0.0.1 so you can test locally.

Web config changes

Add the public and private keys you just created on the Google site to your web.config:

<add key="ReCaptchaPrivateKey" value="yourPrivateKey"/> 
<add key="ReCaptchaPublicKey" value="yourPublicKey"/>

HttpGet action in the controller

Add a property for yourPublicKey to your viewmodel and load it from the web.config in the get controller action, passing it into the view.

Changes in the head section

Add this script in the head section of your layout or view page:

<script src="https://www.google.com/recaptcha/api.js?render=@layoutModel.yourPublicKey"></script>

Changes on the .cshtml view page

There are two steps for the view page where you want to display the reCaptcha box:

Add this to the view where you want the reCaptcha box to display:

<div class="g-recaptcha" data-sitekey="@Model.YourPublicKey">

And add this script at the bottom of that view:

<script src='https://www.google.com/recaptcha/api.js'></script>

HttpPost action in the controller

You will need some code in the post action of your controller to hit the Google reCaptcha service and get a response if it appears this is a valid person – something like this:

var response = Request["g-recaptcha-response"];
var reCaptchaSecretKey = ConfigurationManager.AppSettings["yourPrivateKey"];
var webClient = new WebClient();
var resultFromGoogle = webClient.DownloadString(string.Format("https://www.google.com/recaptcha/api/siteverify?secret={0}&response={1}", reCaptchaSecretKey , response));
var parsedResponseFromGoogle = JObject.Parse(resultFromGoogle);
var thisIsARealPersonNotARobot = (bool)parsedResponseFromGoogle.SelectToken("success");

With that result in hand, you can decide how to handle a success or failure.

Gotchas:

I noticed that reCAPTCHA tried to send it’s request through TLS1.1 and our site will not allow it – we require TLS 1.2, so I had to add a directive to force it to only use 1.2 with this setting at the top of the HTTPPost controller action:

  ServicePointManager.SecurityProtocol = SecurityProtocolType.Tls12;

Thanks for reading and happy coding,
-Jim

Idempotent (run twice safe) sql statements

if (select count(*) from neatoSchema.YourTable where SomeColumnYouCanCheckDataOn = 2018)> 0
begin
print 'That row is already inserted'
end
else
begin
INSERT into neatoSchema.[ConferenceDate]
(... your data ...)
end

You can also interrogate information_schema.tables or information_schema.columns if you are doing a change to a table to ensure that doesn’t run twice!