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

Dependency Injection in SharePoint with Ninject

by Michael Ciba 20. April 2010 07:46

 

A while ago I was having a discussion with one of my fellow developers at EMC Consulting about SharePoint and getting dependency injection working with it. Well finally after a few weeks I have found the time to produce a quick example of just how easy it is to get dependency injection working in SharePoint using a great tool called Ninject. You can find additional information about Ninject at http://ninject.org/. So this get started!
First off Ninject works by providing you with something it calls a kernel which it uses for returning an instance of a specific type. You can think about the kernel as a big brother to the factory pattern we all know and love. Because the kernel is so important the first things you need to do to get Ninject working in SharePoint is create an instance of a kernel and a simple way to do this in SharePoint is through the use of a HttpModule.

1:  public class SharePointNinjectHttpModule: IHttpModule, IDisposable
2:  {
3:         private readonly HttpApplication _httpApplication;
4: 
5:         public void Init(HttpApplication context)
6:         {
7:             if (context == null)
8:                 throw new ArgumentException("context");
9: 
10:             if(FrameworkHelper.Kernel == null)
11:             {
12:                 FrameworkHelper.Kernel = GetKernel();
13:             }
14:         }
15: 
16:         public void Dispose()
17:         {
18:             if(_httpApplication == null) return;
19:             _httpApplication.Dispose();
20:         }
21: 
22:         #region Private methods
23:         
24:         /// <summary>
25:         /// Gets the kernel.
26:         /// </summary>
27:         /// <returns></returns>
28:         private static IKernel GetKernel()
29:         {           
30:             IKernel result = new StandardKernel();
31:             result.Bind<IWarrior>().To<Samurai>();
32:             result.Bind<IWeapon>().To<Sword>();
33:             return result;
34:         }
35: 
36:         #endregion
37: }



As you can see from the code the module is very simple and straightforward and all it does is create an instance of the kernel and sets it's bindings so Ninject knows which instance of a type to return when a request for “IWarrior” or “IWeapon” is made. Remember that you will need to add an entry to the “httpModules” section of your web.config (see below) which in a real world application would be done using the SPWebConfigModification class. However, as this is just a demo I have added it by hand to save myself sometime.

1: <add name="SharePointNinjectHttpModule" type="Blog.IOC.Source.HttpModules.SharePointNinjectHttpModule,Blog.IOC, Version=1.0.0.0, Culture=neutral, PublicKeyToken=bf2ebb07a9bc44ba" />



Now to allow Ninject to actually do it's dependency injection magic there are a few things you must do. The first of these is to modify the “AssemblyInfo.cs” file for all of your projects (well the ones using Ninject at least) so they will allow partially trusted callers. If you don't do this then a security exception is thrown when you inject your object into the Ninject kernel.

1: using System.Security;
2: 
3: [assembly: AllowPartiallyTrustedCallers]



The next thing you need to do is inject the actual instance of the object you want Ninject to apply dependency injection to into the kernel you created. The way I did this was to create a number of base classes which inherit from commonly used items in SharePoint like Web Parts, User Controls and Application Pages. Then within the constructor for each base class I inject the instance of that object into the Ninject kernel.


This is the web part base class:

1: public abstract class WebPartBase : Microsoft.SharePoint.WebPartPages.WebPart
2: {
3:       protected WebPartBase()
4:       {
5:           FrameworkHelper.Kernel.Inject(this);
6:       }
7: }



This is the application page base class:

1: public class LayoutsBase : LayoutsPageBase
2: {
3:         protected LayoutsBase()
4:         {
5:             FrameworkHelper.Kernel.Inject(this);
6:         }
7: }



And finally the user control base class:

1: public abstract class UserControlBase : UserControl
2: {
3:         protected UserControlBase()
4:         {
5:             FrameworkHelper.Kernel.Inject(this);
6:         }
7: }



You can see all the bases classes shown below in the “Blog.IOC” project.

Blog.IOC.BaseClasses


Once you have done this Ninject will work and happily inject any dependencies you have marked up with the “[Inject]” attribute into your objects.

1: [Inject]
2: public IWarrior Warrior { get; set; }


So does this all work you ask? Well yes indeed it does and to prove it below is the code for a very simple application page which inherits off “LayoutsBase” and a screen shot of it’s rendered output.


[ Notice the use of the inject attribute on the Warrior property so Ninject knows this is something it is responsible for ]

1: public class BlogCustomApplicationPage : LayoutsBase
2: {
3:         protected Literal litWarrior;
4: 
5:         [Inject]
6:         public IWarrior Warrior { get; set; }
7: 
8:         protected override void OnLoad(EventArgs e)
9:         {
10:             base.OnLoad(e);
11: 
12:             SetUpWarrior();
13:         }
14: 
15:         private void SetUpWarrior()
16:         {
17:             litWarrior.Text = Warrior.Name;
18:         }
19: }



[ The fully rendered output ]
ApplicationPage


The full source code for the dependency injection example using Ninject can be download from: http://cid-468e9f9e14e99f80.skydrive.live.com/self.aspx/.Public/Blog.IOC.zip

PS. In order to get all this working you will need Visual Studio 2008, WSPBuilder and SharePoint 2007 enjoy :-)

Categories: ASP.NET | Ninject | Sharepoint

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