2009-08-26

Execute Commands Remotely

Using the pstools available here: http://technet.microsoft.com/en-us/sysinternals/bb897553.aspx, and this command:

psexec \\RemoteComputer cmd.exe

Execute commands on a remote computer. Please view this blog post for more details:

http://computer-vet.com/weblog/2008/01/28/remote-command-line-on-windows.html

Notably, you will need to have admin access on the remote machine.

Zoidberg Away!

2009-08-25

Vista MSTSC -C

Quickie. Vista's RDP (Remote Desktop Connection) switch -c (console) has been eliminated. Use /admin instead:

mstsc /admin

Deploying to SharePoint

I've read some pretty lousy reads about deploying web parts and WSP packages to SharePoint. This is one of the best ones:

http://www.k2distillery.com/2009/06/deploy-web-part-as-feature-with-cas.html

Long story short, here are the commands that get you 90% of what you need.

stsadm.exe -o addsolution -filename C:\WSSDistillery\Deploy\WSSDistillery.Deploy\WSSDistillery.Deploy.WebPart.wsp

stsadm.exe -o deploysolution -name WSSDistillery.Deploy.WebPart.wsp -url http://mossserver:28921 -immediate -force

stsadm.exe -o execadmsvcjobs

----

stsadm.exe -o installfeature -filename WSSDistillery.Deploy.WebPart\Feature.xml -force

stsadm.exe -o activatefeature -filename WSSDistillery.Deploy.WebPart\Feature.xml -url http://mossserver:28921 –force

Jason Apergis, the author of this post, has written probably the single best article about Deploying to SharePoint, and you're doing yourself a disservice by not clicking on that link.

2009-08-24

Attribute-based Validation

I've always been a bit miffed by Validation in .NET and a lot of 3(+)-tiered models. In a lot of cases, your front end is doing a lot of things that your business layer should manage--ASP.NET Validator controls, I'm looking at you.

Don't get me wrong, ASP.NET Validator controls are great! A field is required? RequiredFieldValidator. A field needs to be greater than x and less than y? RangeValidator. A fields needs to match a certain pattern, like a phone number (NNN-NNN-NNNN)? RegularExpressionValidator. These controls are great!

Unfortunately, they fail at one important OOP principle... the Separation of Concerns. All of a sudden, you've gotten business rules built into your presentation layer. It makes me feel... dirty. Which brings me to the other pattern I've seen--a haphazard pattern in which there's a Validate method of some sort that is a dozen or so if statements defined within each entity that checks for basic rules as follows:

public class Employee
{
  public int EmployeeID
  { get; set; }

      public string EmployeeName
  { get; set; }

  public void Save()
  {
    if (Validate())
    {
      EmployeeDataLayer.Save(this.EmployeeID, this.EmployeeName);
    }
  }

  public bool Validate()
  {
    if (EmployeeID <= 0)
    { // EmployeeID must be set.
      return false;
    }
    if (EmployeeID >= int.MaxValue)
    {
      return false;
    }
    if (string.IsNullOrEmpty(EmployeeName))
    { // It's a required field in the database, and empty string isn't valid.
      return false;
    }
    if (EmployeeName.Length < 3)
    { // You don't want to hire anyone named Jo, Bo, Di, or Ed.
      return false;
    }
    if (EmployeeName.Length > 50)
    { // Maybe this field is defined as a [n][var]char(50)
      return false;
    }
    return true;
  }
}

Now, I'm not saying this is a bad idea. In fact, it's a decent idea to have this type of validation on your business objects. But it's very verbose. And with just a dozen or so entities, (each of which with half a dozen or more properties), and you see it quickly becomes very time consuming to write. Also annoying--let's say you change the length of EmployeeName in the database from VARCHAR(50) to VARCHAR(100). Now you need to remember to go back in to your Validate function and update it--albeit, it's one tick easier than updating a validator control

To avoid this extra manual coding, I've come up with a different solution: Attribute-based Validation using Reflection and Custom Attributes. In a nutshell here's what I'm doing:

  • All business entities inherit from a base entity.
  • The base entity has a few new methods, properties, including Validate and ErrorMessages
  • There is no restriction to only use the defined Validation Rules--you can easily add your own. New Validation Rules are created by inheriting from a custom attribute, ValidationAttribute and implementing an interface called IValidationRule. (Though, technically, you could probably just use one or the other.)
  • You need to modify your Business Entity's behaviour to call it's (parent's) Validate() Method from an appropriate location such as the Save() Method--or from higher up the stack, such as your presentation layer, etc. Whatever makes the best sense.
  • You must decorate all of the properties you wish to validate with the Validation Rules [Attributes] that you want to use. Many of these rules, although not all of them, can be added using a code generation tool--if your tool supports more in-depth information of your Entity's Properties (such as Max length, nullable, etc.)
  • At runtime, the Validate() method in the BaseEntity uses Reflection do the following...
    • All of the properties in the Entity
      • All of the attributes on each property that inherits from ValidationAttribute
      • Execute the ValidationAttribute's Validate() method (which is virtual, and should be overridden by the custom Validation Rule)

Now the solution that I've come up with--has advantages and disadvantages. I, however, feel it will save me quite a bit of time, and will be worth the disadvantages, but here are the weaknesses that I've thus far identified. By no means, is this the full list:

  • Reflection has a cost associated with it and therefore there is overhead in using this Attribute based Validation System
  • I am looping through all properties in your Entity--and all Attributes (that inherit from ValidationAttribute) for each property. There is overhead in this.
  • This Validation is _not_ done client side. This does not, at this time, replace client side validation--such as ASP.NET Validators, javascript/jquery custom validators. While it currently requires a post back to execute the Validate() method, a clever, clever coder could use these attributes to build validation code on the client side on Page_Load or PreRender, etc. (TODO: figure out how to automatically engage the WebForm/WinForm with client-side validation)

Here's why I'm using it, though:

  • By interrogating a properties attributes, I can learn about it--via Validation or otherwise. For example, to make this validation work well, you need friendly error messages. I've added a friendly name for each property. Now that I've added this, I can use this to populate other information such as tooltips, labels, and auto-generated help files.
  • This decisive move to declarative programming--as the architect of this solution, yeah, there's an implementation for this solution--but the developers, for the most part don't care how it happens. And while there's definitely some ramifications to this solution, there are obvious advantages. ROI over one or two classes is nonexistent. Payback over a dozen classes is very quickly seen. Especially since I've done most of the legwork for you. ;)
  • Processing power is cheap. Truth be told, development time is one of the most costly things in a development house. If your app's not performing well... you can throw $20,000 at it in new  hardware and be done with it. Or $40,000 in development time to get 'er done right. The number I've heard, for an in house developer, the fully-loaded hourly rate (that is, benefits, software and hardware, administrative overhead, and salary) is about $65 or $70 an hour on average. Consultants? Easily a lot more than that.

Anyway! Here's what I've done:

ValidationAttribute.cs

public abstract class ValidationAttribute : Attribute
    {
        public virtual string ErrorMessage
        {
            get;
            protected set;
        }
        public virtual bool Validate(string Value)
        {
            return true;
        }
    }

IValidationRule.cs

public interface IValidationRule
    {
        string ErrorMessage { get; }
        bool Validate(object value);
    }

MinimumLength.cs

public class MinimumLength : ValidationAttribute, IValidationRule
{
    public int Length
    {
        private set;
        get;
    }
    const string _DefaultErrorMessage = "The Minimum Length for [PropertyName] is {0}";
    public MinimumLength(int Length)
    {
        this.ErrorMessage = _DefaultErrorMessage;
        this.Length = Length;
    }
    public MinimumLength(int Length, string ErrorMessage)
    {
        this.Length = Length;
        this.ErrorMessage = ErrorMessage;
    }
    public bool Validate(object Value)
    {
        bool returnValue = false;
        if (Value is string)
        {
            returnValue = ((string)Value).Length >= this.Length;
        }
        if (!returnValue)
        {
            this.ErrorMessage = string.Format
                (
                    string.IsNullOrEmpty(this.ErrorMessage) ? _DefaultErrorMessage : this.ErrorMessage
                ,   this.Length
                );
        }
        return returnValue;
    }
}

MaximumLength.cs

public class MaximumLength : ValidationAttribute, IValidationRule
{
    public int Length
    {
        private set;
        get;
    }
    const string _DefaultErrorMessage = "The Maximum Length for [PropertyName] is {0}";
    public MaximumLength(int Length)
    {
        this.Length = Length;
        this.ErrorMessage = _DefaultErrorMessage;
    }
    public MaximumLength(int Length, string ErrorMessage)
    {
        this.Length = Length;
        this.ErrorMessage = ErrorMessage;
    }
    public bool Validate(object Value)
    {
        bool returnValue = false;
        if (Value is string)
        {
            returnValue = ((string)Value).Length <= this.Length;
        }
        if (!returnValue)
        {
            this.ErrorMessage = string.Format
                (
                    string.IsNullOrEmpty(this.ErrorMessage) ? _DefaultErrorMessage : this.ErrorMessage
                , this.Length
                );
        }
        return returnValue;
    }
}

RegexMatch.cs

public class RegexMatch : ValidationAttribute, IValidationRule
{
    public string RegularExpression
    {
        get;
        private set;
    }
    public RegexOptions RegexOptions
    {
        get;
        private set;
    }
    const string _DefaultErrorMessage = "Format does not match expected format";
    public RegexMatch(string RegularExpression)
    {
        this.ErrorMessage = _DefaultErrorMessage;
        this.RegularExpression = RegularExpression;
        RegexOptions = RegexOptions.IgnoreCase;
    }
    public RegexMatch(string RegularExpression, string ErrorMessage)
    {
        this.ErrorMessage = ErrorMessage;
        this.RegularExpression = RegularExpression;
        RegexOptions = RegexOptions.IgnoreCase;
    }
    public RegexMatch(string RegularExpression, RegexOptions Options, string ErrorMessage)
    {
        this.ErrorMessage = ErrorMessage;
        this.RegexOptions = Options;
        this.RegularExpression = RegularExpression;
    }
    public bool Validate(object Value)
    {
        return Regex.IsMatch(Convert.ToString(Value), this.RegularExpression, this.RegexOptions);
    }
}

BaseEntity.cs

public abstract partial class BaseEntity
    {

#region Validate
        public virtual IList<string> ErrorMessages
        {
            get;
            set;
        }
        public virtual bool Validate()
        {
            // Loop through each of the properties in this entity.
            PropertyInfo[] properties = this.GetType().GetProperties();
            foreach (PropertyInfo property in properties)
            {
                object[] attributesOfTypeValidationRules =
                  property.GetCustomAttributes(typeof(IValidationRule), false);
                if (attributesOfTypeValidationRules != null)
                {
                    for (int i = 0; i < attributesOfTypeValidationRules.GetLength(0); i++)
                    {
                        IValidationRule rule = attributesOfTypeValidationRules[i] as IValidationRule;                       
                        object[] propertyNameAttribute =
                          property.GetCustomAttributes(typeof(PropertyName), false);
                        string propertyName =
                          propertyNameAttribute != null
                            &&
                          propertyNameAttribute.GetLength(0) > 0
                          ?
                            ((PropertyName)propertyNameAttribute[0]).Name
                          : property.Name;

                        if (!rule.Validate(property.GetValue(this, null)))
                        {
                            if (this.ErrorMessages == null)
                            {
                                this.ErrorMessages = new List<string>();
                            }
                            this.ErrorMessages.Add(rule.ErrorMessage.Replace("[PropertyName]", propertyName));
                        }
                    }
                }
            }
            if (this.ErrorMessages == null || this.ErrorMessages.Count == 0)
            {
                return true;
            }
            else
            {
                return false;
            }
        }

        #endregion Validate

}

Employee.cs

public class Employee : BaseEntity
{
  public int EmployeeId { get; set; }

  [MinimumLength(3)]
  [MaximumLength(50)]
  public string Name { get; set; }

  public bool Save()
  {
    if (this.Validate())
    {
      EmployeeDataService.Save(this);
      return true;
    }
    return false;
  }
}

Using the Employee Object

Employee e = new Employee() { EmployeeID = 1, Name="Jamal Khan" };
if (e.Save())
{
  Console.WriteLine("Employee Saved");
}
else
{
  foreach (string errMsg in e.ErrorMessages)
  {
    Console.WriteLine(errMsg);
  }
}

And Viola! Attribute based validation that just works. Oh, I suppose I should let you in on a few details... I've noticed that my Min/Max Length (and I'm guessing Regex, too) Validations don't play nice with nullable/blank data. You may wish to add code to handle this.

Also, as I may have said, you can add any new Validators that you can dream of--just follow the inheritance rules set above.

This is a very versatile solution, and it can save you quite a bit of time coding. If you use it clever, with MVC, WinForms, ASP.NET, or WPF/Silverlight, you can very elegantly deliver automatic validation on the client side, too. An ubercoder might, for example, auto-add Required, RegEx, and Range Validators to an ASP.NET form by extrapolating these properties. Be warned, that this particular solution relies _heavily_ an Reflection, which adds overhead. To overcome the overhead--you could dynamically compile your objects at runtime into wrapper classes similar to NHIbernate. Also, while this solution is powerful, does add overhead and a certain level of abstraction (read: black box) for your development team.

Also, I hear this is due out in the next major EntityFramework release... if you care to use that pile o'...

Alas, Zoidberg Away!