About the author

Miron Abramson
Me
Software Engineer,
CTO at PixeliT
and .NET addicted for long time.
Open source projects:
MbCompression - Compression library

Recent comments

Authors

Disclaimer

The opinions expressed herein are my own personal opinions and do not represent my employer's view in anyway.

© Copyright 2014

Creative Commons License

Blog Flux Directory
Technology Blogs - Blog Top Sites

HttpCompression on IIS7 (Using MbCompression library)

If You have full control on the server, you probably don't need my compression library MbCompression, But if you are using share hosting, sure you do.

I just uploaded the configuration for the compression library to work on IIS7.  Check the latest source code from here

Currently rated 4.6 by 7 people

  • Currently 4.571429/5 Stars.
  • 1
  • 2
  • 3
  • 4
  • 5

Posted by Miron on Thursday, July 23, 2009 8:46 AM
Permalink | Comments (5) | Post RSSRSS comment feed

Cropping image using jQuery, Jcrop and ASP.NET

Letting the client cropping his images on the site was never an easy task. With jQuery and the plugin Jcrop by Deep Liquid it is easier than ever to do it in ASP.NET site. Here is how to do it:

First we need to include jQuery library,Jcrop script file & Jquery css file in the page. Then, we need to tell Jcrop wich element is our image to crop, and what method to be fire when we are changing the cropping area:

//
//  Initialize Jcrop
//
$(function() {
$('#theImage').Jcrop({
        onChange: showCoords,
        onSelect: showCoords
    });
});

//
//  Will fire every move of the cropping area
//
function showCoords(c) {
    $('#x1').val(c.x);
    $('#y1').val(c.y);
    $('#x2').val(c.x2);
    $('#y2').val(c.y2);
    $('#w').val(c.w);
    $('#h').val(c.h);
};

x1,y1,x2,y2 are inputs from where the code behind will read the values of the cropping area.

The code behind that will actualy crop the image:

 protected void btnCrop_Click(object sender, EventArgs e)
{
    int X1 = Convert.ToInt32(Request.Form["x1"]);
    int Y1 = Convert.ToInt32(Request["y1"]);
    int X2 = Convert.ToInt32(Request.Form["x2"]);
    int Y2 = Convert.ToInt32(Request.Form["y2"]);
    int X = System.Math.Min(X1, X2);
    int Y = System.Math.Min(Y1, Y2);
    int w = Convert.ToInt32(Request.Form["w"]);
    int h = Convert.ToInt32(Request.Form["h"]);

    // That can be any image (jpg,jpeg,png,gif) from anywhere in the server
    string originalFile = Server.MapPath("~/images/miautito.jpg");


    using (Image img = Image.FromFile(originalFile))
    {
        using (System.Drawing.Bitmap _bitmap = new System.Drawing.Bitmap(w, h))
        {
            _bitmap.SetResolution(img.HorizontalResolution, img.VerticalResolution);
            using (Graphics _graphic = Graphics.FromImage(_bitmap))
            {
                _graphic.InterpolationMode = System.Drawing.Drawing2D.InterpolationMode.HighQualityBicubic;
                _graphic.SmoothingMode = System.Drawing.Drawing2D.SmoothingMode.HighQuality;
                _graphic.PixelOffsetMode = System.Drawing.Drawing2D.PixelOffsetMode.HighQuality;
                _graphic.CompositingQuality = System.Drawing.Drawing2D.CompositingQuality.HighQuality;
                _graphic.DrawImage(img, 0, 0, w, h);
                _graphic.DrawImage(img, new Rectangle(0, 0, w, h), X, Y, w, h, GraphicsUnit.Pixel);

                string extension = Path.GetExtension(originalFile);
                string croppedFileName = Guid.NewGuid().ToString();
                string path = Server.MapPath("~/cropped/");


                // If the image is a gif file, change it into png
                if (extension.EndsWith("gif", StringComparison.OrdinalIgnoreCase))
                {
                    extension = ".png";
                }

                string newFullPathName = string.Concat(path, croppedFileName, extension);

                using (EncoderParameters encoderParameters = new EncoderParameters(1))
                {
                    encoderParameters.Param[0] = new EncoderParameter(Encoder.Quality, 100L);
                    _bitmap.Save(newFullPathName, GetImageCodec(extension), encoderParameters);
                }
            }
        }
    }
}

Method to find the right codec to save the image in the maximum quality:

/// <summary>
/// Find the right codec
/// </summary>
/// <param name="extension"></param>
/// <returns></returns>
public static ImageCodecInfo GetImageCodec(string extension)
{
    extension = extension.ToUpperInvariant();
    ImageCodecInfo[] codecs = ImageCodecInfo.GetImageEncoders();
    foreach (ImageCodecInfo codec in codecs)
    {
        if (codec.FilenameExtension.Contains(extension))
        {
            return codec;
        }
    }
    return codecs[1];
}

You can see some demos of the Jquery Here, and actual demo using the above code in here: ASP.NET Demo.

Complete working source is available in the link below:

Crop.zip (165.24 kb)

Currently rated 4.6 by 17 people

  • Currently 4.647059/5 Stars.
  • 1
  • 2
  • 3
  • 4
  • 5

Categories: ASP.NET | C# | Client side | Server side
Posted by Miron on Monday, April 20, 2009 8:17 AM
Permalink | Comments (5) | Post RSSRSS comment feed

Create your own new Type and use it on run-time (C#)

It is not something you will use on daily bases. It doesn't have good performance. But one day, you will have to use it so it's good to know that it is possible. As you can understand from the title, I'm talking about creating a new type with fields and properties (it can also have methods), create instance/s from it and use it. It will not be 'type safe', of course, and you will be able to use it - read and set its values only with reflection. but, all the DataBindingControls (GridView, FormView etc...) are binding the data using reflection, so they will be happy to bind and use your new created objects from your own type you created on run-time.

Lets cut the crap and jump into the code:

Let's say you got an xml from a webservice. and you want to create an object from it. Something like that:

You receive an xml like this:

<root>
    <column name="Name">Miron</column>
    <column name="LastName">Abramson</column>
    <column name="Blog">www.blog.mironabramson.com</column>
</root> 

You want to make a 'match' type that looks like this:

public class MyType
{
    public string Name{ get; set; }
    public string LastName{ get; set; }
    public string Blog{ get; set; }
}

and than create an object from that type and fill it with your data. The prolem is that you don't know what will be the values of the xml attributes and fields. So you need to create the object on run-time:

private object CreateOurNewObject()
{
    string _xml = "<root>" +
        "<column name=\"Name\">Miron</column>" +
        "<column name=\"LastName\">Abramson</column>" +
        "<column name=\"Blog\">www.blog.mironabramson.com</column>" +
        "</root>";

    XmlDocument xmlDoc = new XmlDocument();
    xmlDoc.LoadXml(_xml);

    // create a dynamic assembly and module
    AssemblyName assemblyName = new AssemblyName();
    assemblyName.Name = "tmpAssembly";
    AssemblyBuilder assemblyBuilder = Thread.GetDomain().DefineDynamicAssembly(assemblyName, AssemblyBuilderAccess.Run);
    ModuleBuilder module = assemblyBuilder.DefineDynamicModule("tmpModule");

    // create a new type builder
    TypeBuilder typeBuilder = module.DefineType("BindableRowCellCollection", TypeAttributes.Public | TypeAttributes.Class);

    // Loop over the attributes that will be used as the properties names in out new type
    foreach (XmlNode node in xmlDoc.SelectSingleNode("root").ChildNodes)
    {
        string propertyName = node.Attributes["name"].Value;

        // Generate a private field
        FieldBuilder field = typeBuilder.DefineField("_" + propertyName, typeof(string), FieldAttributes.Private);
        // Generate a public property
        PropertyBuilder property =
            typeBuilder.DefineProperty(propertyName,
                             PropertyAttributes.None,
                             typeof(string),
                             new Type[] { typeof(string) });

        // The property set and property get methods require a special set of attributes:

        MethodAttributes GetSetAttr =
            MethodAttributes.Public |
            MethodAttributes.HideBySig;

        // Define the "get" accessor method for current private field.
        MethodBuilder currGetPropMthdBldr =
            typeBuilder.DefineMethod("get_value",
                                       GetSetAttr,
                                       typeof(string),
                                       Type.EmptyTypes);

        // Intermediate Language stuff...
        ILGenerator currGetIL = currGetPropMthdBldr.GetILGenerator();
        currGetIL.Emit(OpCodes.Ldarg_0);
        currGetIL.Emit(OpCodes.Ldfld, field);
        currGetIL.Emit(OpCodes.Ret);

        // Define the "set" accessor method for current private field.
        MethodBuilder currSetPropMthdBldr =
            typeBuilder.DefineMethod("set_value",
                                       GetSetAttr,
                                       null,
                                       new Type[] { typeof(string) });

        // Again some Intermediate Language stuff...
        ILGenerator currSetIL = currSetPropMthdBldr.GetILGenerator();
        currSetIL.Emit(OpCodes.Ldarg_0);
        currSetIL.Emit(OpCodes.Ldarg_1);
        currSetIL.Emit(OpCodes.Stfld, field);
        currSetIL.Emit(OpCodes.Ret);

        // Last, we must map the two methods created above to our PropertyBuilder to
        // their corresponding behaviors, "get" and "set" respectively.
        property.SetGetMethod(currGetPropMthdBldr);
        property.SetSetMethod(currSetPropMthdBldr);
    }

    // Generate our type
    Type generetedType = typeBuilder.CreateType();

    // Now we have our type. Let's create an instance from it:
    object generetedObject = Activator.CreateInstance(generetedType);

    // Loop over all the generated properties, and assign the values from our XML:
    PropertyInfo[] properties = generetedType.GetProperties();

    int propertiesCounter = 0;

    // Loop over the values that we will assign to the properties
    foreach (XmlNode node in xmlDoc.SelectSingleNode("root").ChildNodes)
    {
        string value = node.InnerText;
        properties[propertiesCounter].SetValue(generetedObject, value, null);
        propertiesCounter++;
    }
  
    //Yoopy ! Return our new genereted object.
    return generetedObject;
}

Mazal Tov!!!

We create our type and instance from it on run-time !!!

In the file bellow, there is full working exmple of the code

 

MyTypeRunTime.zip (4.15 kb)

Currently rated 4.4 by 29 people

  • Currently 4.379311/5 Stars.
  • 1
  • 2
  • 3
  • 4
  • 5

Posted by Miron on Monday, June 09, 2008 10:43 AM
Permalink | Comments (24) | Post RSSRSS comment feed

Sorting a collection using Linq and 'SortExpression' string

Already happened to you that you had a collection of object from type 'X' with some properties, and you had to sort it one time by property 'ID', and another time by property 'Name' ? You wished that you can sort it by just using a 'Sort Expression' ? If still not, I'm sure this moment will arrive sooner or later. Let me save you some time and an headache.

This is how it can be done: 

 public static IEnumerable<T> Sort<T>(this IEnumerable<T> source, string sortExpression)
{
    string[] sortParts = sortExpression.Split(' ');
    var param = Expression.Parameter(typeof(T), string.Empty);
    try
    {
        var property = Expression.Property(param, sortParts[0]);
        var sortLambda = Expression.Lambda<Func<T, object>>(Expression.Convert(property, typeof(object)), param);

        if (sortParts.Length > 1 && sortParts[1].Equals("desc", StringComparison.OrdinalIgnoreCase))
        {
            return source.AsQueryable<T>().OrderByDescending<T, object>(sortLambda);
        }
        return source.AsQueryable<T>().OrderBy<T, object>(sortLambda);
    }
    catch (ArgumentException)
    {
        return source;
    }
}

Just drop it in a static class, and you will be able to sort any collection that implement the interface IEnumerable.

Lets say you have a class 'User':

public class User
{
    public int ID { get; set; }
    public string Name { get; set; }
}

and a List<User> collection: users. You can sort it however you want:

IEnumerable<User> sortedUsersIEnumerable = users.Sort<User>("ID desc"); 

Or

List<User> sortedUsersList = users.Sort<User>("Name").ToList();

I really think this extension should be 'built-in' part of the 'Linq'. 

Extensions.cs (1.08 kb)

Currently rated 4.5 by 10 people

  • Currently 4.500001/5 Stars.
  • 1
  • 2
  • 3
  • 4
  • 5

Categories: ASP.NET | C# | Server side
Posted by Miron on Wednesday, May 07, 2008 1:59 PM
Permalink | Comments (7) | Post RSSRSS comment feed

Update to my compression module to compress third party scripts

My last version of the compression module was working great and able to compress and cache pages, WebResources, CSS and JavaScripts files. It have one problem (that similiar to most of the compression modules you can find). To compress the javascripts files, you have to modify the way you register them and change their links to something like that: 

<script type="text/javascript" src="/Scripts/utils.js">

needs to became 

<script type="text/javascript" src="Scripts/jslib.axd?d=~/Scripts/utils.js">

It is not so hard work to do, but it became useless when you use third party controls as 'Telerik' (RadControls)  and force it to doesn't use it's scripts as WebResources. In such case, the controls 'Injects' their scripts links into the HTML code and you can't modify them as needed to let the compression handler to compress it.  In the new version of my compression component, I added a ResponseFilter that parse the Scripts links in the HTML and convert them into 'compressable' links. By default, this option is disabled in the compression module. To enable it (if you use such third party controls), just add the attribute compressThirdParityScripts="true" to the compression configuration.

Full implementation instructions can be found here: Compression module implementation 

Latest code can be downloaded from: http://www.codeplex.com/MbCompression

Currently rated 4.8 by 5 people

  • Currently 4.8/5 Stars.
  • 1
  • 2
  • 3
  • 4
  • 5

Posted by Miron on Friday, February 22, 2008 4:15 AM
Permalink | Comments (7) | Post RSSRSS comment feed

Simple Generic Business Entities

"Business Entites" are widly commonly use everywhere. Sometimes the entities are very big and contains a lot of methods and properties, but most of the time, they are basicly objects that holds data in easier and cleaner way than DataTables/DataSets. Sometimes you have entity for specific type such "Customer", "Laboratory", "Shop" or whatever, but lots of time you just need to load and hold data that is not from spesific type. Good way to hold such "un typed data" is using Generic. A "Generic Entity" that can hold any kind of data you need in the moment. For example, I create Generic entity called "Quadruple" that have 4 properties that will be from type you choose. If you create an instance of this entity like this:

Quadruplet<int,string,int,string> q1 = new Quadruplet<int,string,int,string>();

Quadruplet<bool,bool,Array,string> q2 = new Quadruplet<bool,bool,Array,string>();

q1 will be entity that can hold int, string, int & string and q2 will be entity that hold bool, bool, Array, string. No casting is needed.

List<Quadruplet<int, string, int, string>> quadrupletList = new List<Quadruplet<int, string, int, string>>();

quadrupletList  will be List of object from type Quadruplet<int,string,int,string>.  This kind of entitis can be very usuful in any kind of application, and it very reusable from application to another. 

In the file below, there are 4 entites: Duplet - hold 2 objects from any kind, Triplet 3 object (I know there is such class in 'System.Web.UI' but it holds 3 objects from the type 'Object' and casting will be needed),  Quadruplet for 4 objects and Quintet for 5. All those entities contains basic needed methods as Equals(object), operator ==, operator != and GetHashCode().

Those entities are NOT comming to replace the  "Customer", "Laboratory", "Shop" or any other specific needed entity. They are to help working with "un type" of data. Where the data is not from specific type or you don't want to make specific entitiy for that data.

SimpleGenericBusinessEntities.zip (4.26 kb)

Currently rated 4.4 by 7 people

  • Currently 4.428571/5 Stars.
  • 1
  • 2
  • 3
  • 4
  • 5

Posted by Miron on Saturday, February 16, 2008 6:57 AM
Permalink | Comments (1) | Post RSSRSS comment feed

Collect all controls from specific type

I got a simple "mission" to make a method that collect all the TextBox controls from any given control on the page (or from the Page itself).  As I like to do things in the most 'Generic' way, I finished with a simple method that collect all contols from any type you want.

This is the method that run recursive and collect all the controls from type T: 

        /// <summary>
        /// Loot recursive and collect the controls
        /// </summary>
        /// <typeparam name="T"></typeparam>
        /// <param name="contol"></param>
        /// <param name="list"></param>
        private static void LoopControls<T>(Control parentContol, List<T> list) where T : Control
        {
            foreach (Control ctrl in parentContol.Controls)
            {
                if (ctrl is T)
                {
                    list.Add(ctrl as T);
                }
                else
                {
                    if (ctrl.Controls.Count > 0)
                    {
                        LoopControls(ctrl, list);
                    }
                }
            }
        }

To start the 'collecting' process:

        /// <summary>
        /// Collect all the controls from type 'T'
        /// </summary>
        /// <typeparam name="T"></typeparam>
        /// <param name="contol"></param>
        /// <returns></returns>
        public static List<T> CollectControls<T>(Control parent) where T : Control
        {
            List<T> list = new List<T>();
            LoopControls(parent, list);
            return list;
        }

Drop this method in your 'Utilities' class, and its ready to go.  Now, To collect  all the TextBox in the page, just us it like this:

System.Collections.Generic.List<TextBox> l = Utils.CollectControls<TextBox>(Page);

and to collect all the Labels, just change the  '<TextBox>' to '<Label>'.

Using 'Generic' is very goot thing, and a lot of times, if you thing on the feutre and not focus only on the current mission when you write any method, you will end up using the Generic namespace.

Be the first to rate this post

  • Currently 0/5 Stars.
  • 1
  • 2
  • 3
  • 4
  • 5

Tags:
Categories: ASP.NET | C# | Server side
Posted by Miron on Wednesday, February 06, 2008 8:50 PM
Permalink | Comments (3) | Post RSSRSS comment feed

Highlight search results in any page in the application

Recently I was working on part of an existing big project that one of it's main feature is searching (in this case it was medical info). There is search option in some different pages.  I was asked to add feature that 'highlight' the searching word/s in the search results. To do it with minimum changes for the existing code, I decided to do it using a 'Response Filter' that get the search word/s from the query and highligh it in the page. The 'highlight' is not more than to replace the 'searching word' with '<span style='background-color:yellow;color:black;'>searching word</span>'.

The idea was to get the html before it been send to the client, look for the 'searching words' and just replace them. The 'problem' is that we need to search the 'searching word' only in the text that is between the HTML tags and not within the tags. for that I used RegularExpression (ofcourse)and the not well know but powerfull class 'MatchEvaluator'.

How is it work:

First, we need to get the list of the searching words and concat them into one string seperates by '|' char.  The searching words are taken from the query string using the parameter 'highligh', and seperates by spaces (%20), or if it is exact phrase, it need to be between " (inverted commas).  For exmple, to highlight all the words 'searching' and 'words' in this article use this url: http://mironabramson.com/blog/post/2008/01/Highlight-search-results-in-any-page-in-the-application.aspx?highlight=searching%20words . To highligh the exact match 'searching words' use the url: http://mironabramson.com/blog/post/2008/01/Highlight-search-results-in-any-page-in-the-application.aspx?highlight=%22searching%20words%22 .   (To parse the searching words from the query string I used an old method I did long time ago 'GetSearchingWordsList' I'm sure it can be replace with RegularExpression version easly)

Second, we needs to find all the text that is not HTML tags. This will be done using RegularExpression:

 private static readonly Regex REGEX_TEXT_BETWEEN_TAGS = new Regex(@">\s*[^<]*<(?!/script)", RegexOptions.Compiled | RegexOptions.IgnoreCase);

 private static string HighlightText(string html, string hightlightWords)
 {
        MatchEvaluatorWithParameter matchEvulator = new MatchEvaluatorWithParameter(hightlightWords);
        return REGEX_TEXT_BETWEEN_TAGS.Replace(html, new MatchEvaluator(matchEvulator.Found));
 }

 The 'MatchEvaluator' in this case means that for every match of the regular expression, excute the method matchEvulator.Found

Third, we needs to find in every match our search words and replace it with '<span style='background-color:yellow;color:black;'>match</span>''

 private class MatchEvaluatorWithParameter
 {
      string _parameter;
      public MatchEvaluatorWithParameter(string parameter)

      {
           _parameter = parameter;
      }
      public string Found(Match m)
      {
           Regex replace = new Regex(_parameter, RegexOptions.IgnoreCase);
           return replace.Replace(m.Value, new MatchEvaluator(this.Replace));
       }
       private String Replace(Match m)
       {
           return "<span style='background-color:yellow;color:black;'>" + m.Value + "</span>";
       }
 }

To implement this ResponseFilter, you can use a new HttpModule or you can just assign the filter in an existing module in your application.  Note that like every other ResponseFilter you use, it must be exclude and not be performed if the request come from MS-AJAX control. 

To add it to an existing module, just add the 'HighlighterFilter' class, and in your module event, add:

  if (!IsAjaxPostBackRequest(app.Context) && app.Request.QueryString["highlight"] != null) {
         app.Response.Filter = new HighlighterFilter(app.Response.Filter, app.Server.UrlDecode(app.Request.QueryString["highlight"]));
  }

(If you are using compression module as I do, note that the highlight filter must come after you assign the compression filter, so it will be excute before.)  Downloading the code will help undersdand the concept more easly (as always, see the code always help to understand)

Maybe you will not find this Highlight filter usefull for your needs, but I guess some people saw a nice and useful example of using the powerfull of RegularExpression with the class 'MatchEvaluator'.

HighlighterFilter.cs (8.52 kb)

Currently rated 4.0 by 4 people

  • Currently 4/5 Stars.
  • 1
  • 2
  • 3
  • 4
  • 5

Posted by Miron on Saturday, January 12, 2008 5:55 AM
Permalink | Comments (1) | Post RSSRSS comment feed

Remove white spaces using HttpModule

Few weeks ago, Mads Kristens poseted a very usefull post about removing white spaces from your pages. For me, he found the best Regular Expression for this job.  He was using the Render method to do it, and it means that if you want to use it in existing site, you need to edit your base page and compile your site again.

I wanted to use it in some sites I have/manage, so I just insert his code into a new ResponseFilter and assign this filter in my Compression component, compile again this dll and replace it in all my sites. Importent thing is, that using this 'remove spaces metho' must folows the rule of that the current request is not made by MS-AJAX component/control, because the ViewState will be corrupted. This check can be easly made by this simple method:

internal static bool IsAjaxPostBackRequest(HttpContext context)
{
      return context.Request.Headers["X-MicrosoftAjax"] != null;
 }

Also note, that RequestFilters are excuted in order LIFO (the last added filter is the first one to be performed) , so if you use any compression filter (like me), make sure you register the compression filter before this one.

The ResponseFilter code can be download from here:

RemoveWhiteSpaces.cs (2.34 kb)

The compression module with this filter included can be download from this post: Compression component.  In this component you can control in wich pages you want to anable or disable the remove spaces option. (exclude specified pages from compression and remove spaces)

Currently rated 4.0 by 1 people

  • Currently 4/5 Stars.
  • 1
  • 2
  • 3
  • 4
  • 5

Categories: ASP.NET | C# | Server side
Posted by Miron on Thursday, December 27, 2007 1:00 PM
Permalink | Comments (3) | Post RSSRSS comment feed

A Custom Length Validator with server & client side validation

Almost evey TextBox input is going to be stored in Database (if it is not based on XML).  In the DB we need to define a maximum length for any characters field, so, we need to be sure that the input text in the TextBox in not longer then the maximum defined length in the DB where it going to be stored.

We all use Validators. I don't understand why MS didn't include in the built in controls a simple length validator (yes, I know it can be done by the RegularExpressionValidator, but why complicate things?) that simply validate maximum or minimum length of input text. Luckly, creating our custom validation control is much simplier then it sound. All we need to do is a class that inhirite from CustomValidator, override some methods, add some properties, create a JavaScript validation method, compile it into DLL and use it as any other Validator.

Override the ControlPropertiesValid() method:

private TextBox _textBox; 

 /// <summary>
 /// Check if the control is valid for validation
 /// </summary>
 /// <returns></returns>
  protected override bool ControlPropertiesValid()
  {
      Control ctrl = FindControl(ControlToValidate);
      if (ctrl != null)
      {
          _textBox = ctrl as TextBox;
          return (_textBox != null);
      }
      else
          return false;
  }

 override the EvaluateIsValid() method:

  /// <summary>
  /// Perform the validation
  /// </summary>
  /// <returns></returns>
  protected override bool EvaluateIsValid()
  {
      if ( string.IsNullOrEmpty(_textBox.Text) )
      {
          if (MinLength > 0)
              return false;
          else
              return true;
      }
      if (_textBox.Text.Length < MinLength || _textBox.Text.Length > MaxLength)
      {
          return false;
      }
      return true;
  }

 Override the AddAttributesToRender(HtmlTextWriter writer) method to support the client side validation:

  /// <summary>
  /// Add the maximum and minimum attribute for the control
  /// </summary>
  /// <param name="writer"></param>
  protected override void AddAttributesToRender(HtmlTextWriter writer)
  {
      base.AddAttributesToRender(writer);
      if (base.RenderUplevel)
      {
          writer.AddAttribute("MinLength", this.MinLength.ToString());
          writer.AddAttribute("MaxLength", this.MaxLength.ToString());
      }
  }

Register in the OnLoad event our client site script file:

  /// <summary>
  /// Add the controls script file to the page
  /// </summary>
  /// <param name="e"></param>
  protected override void OnLoad(EventArgs e)
  {
      if (Enabled && base.EnableClientScript)
      {
          Page.ClientScript.RegisterClientScriptResource(typeof(LengthValidator), "LengthValidator.LengthValidator.js");
      }
      base.OnLoad(e);
  }

 and ofcourse the client side validation method:

function ValidateLength(source, args) {
    var control = document.getElementById(source.controltovalidate);
    if( control )
    {
         args.IsValid = ( control.value.length >= source.getAttribute('MinLength') && control.value.length <= source.getAttribute('MaxLength') );
    }
}

The full class library project source  can be downloaded below. Just compile it, add it to the toolbox and use it as any other Validator

LengthValidator.zip (2.96 kb)

Currently rated 4.0 by 1 people

  • Currently 4/5 Stars.
  • 1
  • 2
  • 3
  • 4
  • 5

Posted by Miron on Saturday, December 08, 2007 7:52 AM
Permalink | Comments (2) | Post RSSRSS comment feed