Sunday, November 26, 2023
Windows Server 2016 / IIS Cannot Disable for site:
signalr/negotiate?clientProtocol
<system.webServer>
<ModSecurity enabled="false" />
</system.webServer>
Sunday, December 24, 2017
WCF services don’t run on IIS 8 with the default configuration, because the webserver doesn’t know, how to handle incoming requests targeting .svc files. You can teach it in two steps:
1. Add a new MIME type:
Extension: .svc MIME type: application/octet-stream
2. Add a new Managed HTTP Handler:
Go itRequest path: *.svc
Type: System.ServiceModel.Activation.HttpHandler
Name: svc-Integrated
Thursday, January 5, 2017
Google's reCaptcha system is very effective at preventing spam, but unlike other systems, does not require you to squint at a screen for ages to work out whether that wobbly circle is an o, O or a 0. With Google's captcha system, all you have to do is click on the 'I am not a robot' checkbox. If someone tries too many times to fill your form in, or the system detects a suspicious response, then it will pop up a series of images and ask to you to identify which image contains pasta or an aeroplane for example. It's quite simple and clever in the way it works.
The way it works is quite straightforward: when you embed the reCaptcaha javascript tag, the captcha code inserts a hidden form field with a pre-generated string created by Google's servers, and then when the form is posted, you send back the contents of this field, plus a secret key to google's web service. The reCaptcha server then looks at the secret key and hidden field string and checks whether the string was generated by its own system using your site key, and if so, it returns a 'true' or if not it returns 'false'.
Version 1 of the reCatpcha included sample code for ASP.net however the newer version does not, so I had to work out how to do this myself. Heres how I added reCaptcha v2 using ASP.net. The code below is written in C# and built using web forms, but it can easily be modified of MVC based applications:
STEP 1 - sign up for your secret key
To do this, go to https://www.google.com/recaptcha and click on the 'get recaptcha' button in the top right.
If you already have a google account, you can log in with this, or if you don't (and who doesn't have one?) then you'll have to register a google account.
Once done, you then add your website domain names to get 2 unique keys: a Site Key and a Secret Key. The site key is used in your code's script tag in your web form, and the secret key is used by your site to create a verification request to the reCaptcha web service.
STEP 2 Integrating the code in your form
Integrating the code into the front end web form is really easy. All you have to do is add 2 lines of code:
- paste the following into the section of your page:
- paste the following into the body of your html, where you want the captcaha button to appear:
STEP 3. Server Side Validation
When the form is generated in a browser, Google's recaptcha script adds a hidden field element called 'g-recaptcha-response'. To validate the form, you need to send an ajax call to google's web service with the contents of this field, and your secret key - this will return success:true if the response and key are valid, or otherwise will return success:false.
Here's the code for doing this. Note, this code uses Json.NET which is just used for a shortcut to parse JSON responses - in this case the reponse is serialised into the CaptchaResponse object but if you want to create a simple convertor yourself, it's not very hard to do that. The only slight complication is that If you want to use json.net, then you'll need to download the dll files from the newtonsoft site and copy then to the bin folder of your web application.
HTML code (contactform.aspx):
<%@ Master Language="C#" AutoEventWireup="true" CodeFile="contactform.cs" Inherits="contactform" %>
C# code (contactform.cs):
using Newtonsoft.Json;
using System;
using System.IO;
using System.Net;
public partial class contactform:System.Web.UI.Page {
protected void Page_Load(object sender, EventArgs e) {
}protected void btnSend_Click(object sender, EventArgs e) {
string reCaptchaSecret = "[SECRET KEY HERE]";
string reCaptchaRequest = "";
if (Request.Form["g-recaptcha-response"] != null) {reCaptchaRequest = Request.Form["g-recaptcha-response"].ToString();}
if (CheckReCaptcha(reCaptchaSecret, reCaptchaRequest)) {
// catpcha request is validated, do the form proccessing here...
string mName=txtName.Text;
string mMessage=txtMessage.Text;
// Add code here to save messages to database or send via email.
} else {
litMessage.Text = "Please confirm that you are not a robot.
";
}
}
public bool CheckReCaptcha(string captchaSecret, string captchaRequest) {
bool cValidated = false;
if (captchaRequest != null) {
string captchaURL = String.Format("https://www.google.com/recaptcha/api/siteverify?secret={0}&response={1}", captchaSecret, captchaRequest);
HttpWebRequest wrq = (HttpWebRequest)WebRequest.Create(captchaURL);
wrq.ContentType = "application/json";
wrq.Method = "POST";
using (var streamWriter = new StreamWriter(wrq.GetRequestStream())) {
try {
var wrs = (HttpWebResponse)wrq.GetResponse();
using (var streamReader = new StreamReader(wrs.GetResponseStream())) {
var result = streamReader.ReadToEnd();
if (result != "") {
CaptchaResponse capResp = JsonConvert.DeserializeObject(result);
cValidated = capResp.success;
}
}
} catch (WebException ex) {
if (ex.Status == WebExceptionStatus.ProtocolError) {
litDebug.Text = "ERROR : " + ex.Response.ToString() + "\r\n\r\nexception = " + ex.Message + "\r\n"; // debugging code
}
}
}
}
return cValidated;
}
public class CaptchaResponse {
public bool success { get; set; }
public string challenge_ts { get; set; }
public string hostname { get; set; }
public string errorCodes { get; set; }
}
}
Summary
Before adding this code to my website, I used to get about 20-30 spam messages per day. I installed this code about a week ago and to date I have not received a single spam submission.
Thursday, November 10, 2016
I want to take this thought a step further, and as implied by the post title, do a group by.
Starting, here is an order by % 2 giving us a list of even and then odd numbers:
- int[] numbers = { 5, 4, 1, 3, 9, 8, 6, 7, 2, 0 };
- var orderedNumbers = from n in numbers
- orderby n % 2 == 0 descending
- select n;
- foreach (var g in orderedNumbers)
- {
- Console.Write("{0},", g);
- }
This is all pretty straight forward, order by numbers that when modded by 2 are 0 and we have the numbers 4,8,6,2,0,5,1,3,9,7.
But what if I want to simply have two lists, one with evens and one with odds? That’s where group by comes in.
- int[] numbers = { 5, 4, 1, 3, 9, 8, 6, 7, 2, 0 };
- var numberGroups = from n in numbers
- group n by n % 2 into g
- select new { Remainder = g.Key, Numbers = g };
- foreach (var g in numberGroups)
- {
- if(g.Remainder.Equals(0))
- Console.WriteLine("Even Numbers:", g.Remainder);
- else
- Console.WriteLine("Odd Numbers:", g.Remainder);
- foreach (var n in g.Numbers)
- {
- Console.WriteLine(n);
- }
- }
with the output:
- Odd Numbers:
- 5
- 1
- 3
- 9
- 7
- Even Numbers:
- 4
- 8
- 6
- 2
- 0
What’s happening here is that LINQ is using anonymous types to create new dictionary (actually a System.Linq.Enumerable.WhereSelectEnumerableIterator>).
It is important to note here that the key here that everything is keyed on is the first value after the “by”.
Taking this one simple step forward let’s group a bunch of words. The following doesn’t work quite right:
- string[] words = { "blueberry", "Chimpanzee", "abacus", "Banana", "apple", "cheese" };
- var wordGroups = from w in words
- group w by w[0] into g
- select new { FirstLetter = g.Key.ToString().ToLower(), Words = g };
- foreach (var g in wordGroups)
- {
- Console.WriteLine("Words that start with the letter '{0}':", g.FirstLetter);
- foreach (var w in g.Words)
- {
- Console.WriteLine(w);
- }
- }
giving us the output:
- Words that start with the letter 'b':
- blueberry
- Words that start with the letter 'c':
- Chimpanzee
- Words that start with the letter 'a':
- abacus
- apple
- Words that start with the letter 'b':
- Banana
- Words that start with the letter 'c':
- cheese
That’s because there is a bit of a red herring here. Remember that the first value after the by is what is used to group by. In our case w[0] for Chimpanzee is “C”, not c. If we change it to:
- string[] words = { "blueberry", "Chimpanzee", "abacus", "Banana", "apple", "cheese" };
- var wordGroups = from w in words
- group w by w[0].ToString().ToLower() into g
- select new { FirstLetter = g.Key.ToString().ToLower(), Words = g };
- foreach (var g in wordGroups)
- {
- Console.WriteLine("Words that start with the letter '{0}':", g.FirstLetter);
- foreach (var w in g.Words)
- {
- Console.WriteLine(w);
- }
- }
then we get the results we expect with:
- Words that start with the letter 'b':
- blueberry
- Banana
- Words that start with the letter 'c':
- Chimpanzee
- cheese
- Words that start with the letter 'a':
- abacus
- apple
Taking this even one step further we can throw an orderby above the group and order things alphabetically:
- var wordGroups = from w in words
- orderby w[0].ToString().ToLower()
- group w by w[0].ToString().ToLower() into g
- select new { FirstLetter = g.Key.ToString().ToLower(), Words = g };
So let’s now make this a bit over the top complex. Given the classes:
- public class Customer
- {
- public List<Order> Orders { get; set; }
- }
- public class Order
- {
- public DateTime Date { get; set; }
- public int Total { get; set; }
- }
lets group a customer list by customer, then by year, then by month:
- List<Customer> customers = GetCustomerList();
- var customerOrderGroups = from c in customers
- select
- new {c.CompanyName,
- YearGroups = from o in c.Orders
- group o by o.OrderDate.Year into yg
- select
- new {Year = yg.Key,
- MonthGroups = from o in yg
- group o by o.OrderDate.Month into mg
- select new { Month = mg.Key, Orders = mg }
- }
- };
Whew! that took a lot to copy and paste from MSDN’s sample library!
As mentioned previously the important part here is that the keys for these are the first value after the “by”. This just creates a bunch of dictionarys keyed embeded together keyed on the values after the “by”.
As mentioned previously the important part here is that the keys for these are the first value after the “by”. This just creates a bunch of dictionarys keyed embeded together keyed on the values after the “by”.
The GroupBy method that is a part of Linq can also take an IEqualityComparer. Given the comparer:
- public class AnagramEqualityComparer : IEqualityComparer
- {
- public bool Equals(string x, string y)
- {
- return getCanonicalString(x) == getCanonicalString(y);
- }
- public int GetHashCode(string obj)
- {
- return getCanonicalString(obj).GetHashCode();
- }
- private string getCanonicalString(string word)
- {
- char[] wordChars = word.ToCharArray();
- Array.Sort
(wordChars); - return new string(wordChars);
- }
- }
we can find all the matching anagrams. This is possible because the IEqualityComparer compares words based on a sorted array of characters. If you take “meat” and “team” they both become “aemt” when sorted by their characters.
- string[] anagrams = { "from", "salt", "earn", "last", "near", "form" };
- var orderGroups = anagrams.GroupBy(
- w => w.Trim(),
- a => a.ToUpper(),
- new AnagramEqualityComparer()
- );
- foreach (var group in orderGroups)
- {
- Console.WriteLine("For the word "{0}" we found matches to:", group.Key);
- foreach (var word in group)
- {
- Console.WriteLine(word);
- }
- }
Subscribe to:
Posts (Atom)