Shouldn’t validating a checkbox be easier than this?

by Michael Ciba 6. April 2011 08:51

 

Well it's been a while since I have done a post but with changing jobs recently and life in general getting in the way I just couldn’t seem to find the time. However, now I have a spare five minutes I thought I would fire off a post :)

So what's the post about? Validating a checkbox web control. Now I know your reading this thinking that's easy all you need is a custom validator and a event handler in your code behind and job done? Well in most cases yes I would agree with you. However, my latest project (a legacy application) uses code generation to create the vast majority of the ASP.NET pages and user controls. Therefore it’s difficult for me to include anything other than the standard set of ASP.NET validators or something which inherits off the “BaseValidator” and get it working correctly in the XSLT templates generating the code. Because of this I decided to create my own validator for the checkbox web control.

So how do we get started? Well first off you need to inherit off the “BaseValidator” and then override the required "EvaluateIsValid" method. Once done you can then write some simple logic to ensure your checkbox has been checked. As shown below.

   1:  public class CheckBoxValidator : BaseValidator
   2:  {
   3:      protected override bool EvaluateIsValid()
   4:      {
   5:          var controlValue = this.GetControlValidationValue(this.ControlToValidate);
   6:          bool checkBoxValue;
   7:          var hasBeenParsed = bool.TryParse(controlValue, out checkBoxValue);
   8:   
   9:          var result = hasBeenParsed && checkBoxValue;
  10:          return result;
  11:      }
  12:  }

 

So is that it all done? Well no because the out of the box checkbox control is missing an important thing. The "ValidationProperty" attribute. This attribute is used within the base validator to work out which property on the control being validated should to used when getting the control validation value. In order to solve this problem you will need to create your own version of the checkbox control by inheriting from it and adding the required attribute as shown below.

   1:  [ValidationProperty("Checked")]
   2:  public class ValidationCheckBox : CheckBox
   3:  {
   4:  }

 

Ok so now we have our own custom checkbox and checkbox validator we can finally validate those lovely checkboxes. However, if you recall from a bit earlier I said this is a legacy application and although it is to a large degree generated for me I'm not sure I really want to find all the places where a standard checkbox web control should be switched out for my super custom one. So what's the answer? Tag mapping.

Now tag mapping if you haven't heard of it before enables you to define within the web.config that tag "A" should instead be mapped to tag "B". You can see below how I used it to always return my custom checkbox whether a standard asp.net checkbox should be used.

  1: <pages controlRenderingCompatibilityVersion="3.5" clientIDMode="AutoID">
  2:   <tagMapping>
  3:     <add tagType="System.Web.UI.WebControls.CheckBox" mappedTagType="Demo.Web.Code.Controls.ValidationCheckBox" />
  4:   </tagMapping>
  5: </pages>
Now that’s done I don’t have to change a single line of code to get my new checkbox control in place and get my validations working. One finial point though or really a question is why haven’t Microsoft just created this type of validator and given it to me straight out of the box? Yes I know I could change the checkbox to some radio buttons to achieve a similar thing, but sometimes I don’t get the finial say in the design of a page and this type of validator would come in handy I think for a lot of people.
Tags:
Categories: ASP.NET | C# | VS2010 | IIS

Downloading Microsoft office files under SSL with CacheControl=no-cache

by Naeem Khedarun 15. April 2010 05:05

 

My current project involves an ASP.NET application which need to be able to send some protected data. SSL was used to encrypt the sensitive pages, and the rest of the site has encryption turned off. The reporting side of the application, which allows the user to download dynamically generated reports was resulting in the following error:

image

This seemed to be happening in the following circumstances:

  1. Internet Explorer had the Internet Options > Advanced > Do not save encrypted pages to disk.
  2. The application was modifying a response (POST).
  3. It was sending an office document.

Now this particular page had encryption turned off, but it was still being accessed via HTTPS. Taking a look a look through fiddler was showing that CacheControl was being set to no-cache:

POST /Something.com/Reports/UserReports.aspx HTTP/1.1
Accept: application/x-ms-application, application/vnd.ms-excel
Referer: https://something.com/Something/Reports/UserReports.aspx
Content-Type: application/x-www-form-urlencoded
Accept-Encoding: gzip, deflate
Host: usermanager.something.com
Content-Length: 265
Connection: Keep-Alive
Cache-Control: no-cache

After some investigation it turns out this was a known issue from Microsoft which has persisted through Internet Explorer versions; Opera and Firefox apparently do not share this issue.

There are a number of possible solutions, and out of them we could not:

  1. Change the group policy around caching files under SSL.
  2. Run the reports under HTTP.
  3. Follow the support article and hack the registry (why is this even noted as a resolution?) as this overrides the group policy.

The solution in this circumstance was to remove the Cache-Control:no-cache portion of the header and set it to something Internet Explorer will be able to consume. The following code was causing this issue:

private static void SendExcelReport(string filename, MemoryStream stream)
{
    var response = HttpContext.Current.Response;

    response.ContentType = "application/vnd.ms-excel";
    
    response.AddHeader(
        "Content-Disposition", 
        string.Format("attachment;filename={0}", filename));

    response.Clear();
    stream.Seek(0, 0);
    byte[] bytes = stream.GetBuffer();
    response.BinaryWrite(bytes);
    response.Flush();
    response.End();
}

When using IIS and integrated pipeline mode, you can manipulate the header programatically:

response.Headers["Cache-Control"] = "private";

However if you try this with IIS6 or when running in Classic Pipeline mode, you will get the following error:

This operation requires IIS integrated pipeline mode.

Oh dear, however the solution wasn’t too bad:

private static void SendExcelReport(string filename, MemoryStream stream)
{
    var response = HttpContext.Current.Response;

    response.ClearHeaders(); // Clear the header, including no-cache
    response.ContentType = "application/vnd.ms-excel";
    response.AddHeader(
        "Content-Disposition", 
        string.Format("attachment;filename={0}", filename));

    response.Clear();
    stream.Seek(0, 0);
    byte[] bytes = stream.GetBuffer();
    response.BinaryWrite(bytes);
    response.Flush();
    response.End();
}

Internet Explorer was now happily allowing the Open / Save / Cancel dialog without the error message.

HTTP/1.1 200 OK
Cache-Control: private
Transfer-Encoding: chunked
Content-Type: application/vnd.ms-excel
Server: Microsoft-IIS/7.5
X-AspNet-Version: 2.0.50727
Content-Disposition: attachment;filename=Report.xls
X-Powered-By: ASP.NET
Date: Wed, 14 Apr 2010 14:53:25 GMT

 

IIS has defaulted the Cache-Control to private, but this could be set to whatever you decide based on the IIS configuration or the AddHeader method.

Tags:
Categories: C# | ASP.NET | IIS | Internet Explorer