# 10 Kasım 2008 Pazartesi
I'm sure someone did this before, but I'm too lazy to search for it :)

Model Binders in MVC is a cool concept to map your form values to parameter objects of your Action. There's also this automatic error message display capabilities in MVC. All explained by The Gu here.

Here's my take on validating a model object during the binding process. Castle project has a validation framework and a range of validators which can be used standalone. It would be cool to use it with MVC to ease the validation pain a bit, huh?

First, we need a binder to validate the object using Castle's ValidatorRunner:

    using System.Web.Mvc;
    using Castle.Components.Validator;
 
    public class ValidatingModelBinder : DefaultModelBinder
    {
        public override ModelBinderResult BindModel(ModelBindingContext bindingContext)
        {
            var result = base.BindModel(bindingContext);
 
            if (result != null && result.Value != null)
            {
                var runner = new ValidatorRunner(new CachedValidationRegistry());
                if (!runner.IsValid(result.Value))
                {
                    var summary = runner.GetErrorSummary(result.Value);
                    foreach (var invalidProperty in summary.InvalidProperties)
                    {
                        foreach (var error in summary.GetErrorsForProperty(invalidProperty))
                        {
                            bindingContext.ModelState.AddModelError(bindingContext.ModelName + "." + invalidProperty, error);
                        }
                    }
                }
            }
 
            return result;
        }
    }

And an object to validate:

    using Castle.Components.Validator;
 
    public class CreateUser
    {
        [ValidateNonEmpty("Please enter user name.")]
        public string UserName { get; set; }
        [ValidateNonEmpty("Please enter password.")]
        public string Password  { get; set; }
        [ValidateEmail("Email is not valid.")]
        [ValidateNonEmpty("Please enter email address.")]
        public string Email { get; set; }
    }

And an action to use the object:

        public ActionResult CreateUser(CreateUser createUser)
        {
            if (ViewData.ModelState.IsValid)
            {
                ViewData["Message"] = "Done.";
            }
 
            return View();
        }

Please note that, when the action is invoked, parameter is already validated. We just check ViewData.ModelState.IsValid and act accordingly.

Next, we'll tell the MVC engine to bind CreateUser objects through ValidatingModelBinder, in Application_Start() of Global.asax.cs:

        ModelBinders.Binders.Add(typeof(CreateUser), new ValidatingModelBinder());

So, whenever the engine is bindign to a CreateUser, our binder will execute (and validate) the object. Finally, code below for the view:

<asp:Content ID="Content1" ContentPlaceHolderID="MainContent" runat="server">
    <%if (ViewData["Message"] != null)
      {%>
        <%=ViewData["Message"]%>
    <%} %>
    <%=Html.ValidationSummary() %>
    <form method="post" action="/Home/CreateUser">
        User name: <br />
        <%=Html.TextBox("CreateUser.UserName")%>  <%=Html.ValidationMessage("CreateUser.UserName", "*")%><br />
        Password: <br />
        <%=Html.Password("CreateUser.Password")%> <%=Html.ValidationMessage("CreateUser.Password", "*")%><br />
        Email: <br />
        <%=Html.TextBox("CreateUser.Email")%> <%=Html.ValidationMessage("CreateUser.Email", "*")%><br />
        <input type="submit" value="Submit" />
    </form>
</asp:Content>

Here's the result:

posted on 10 Kasım 2008 Pazartesi 10:40:43 UTC  #   
# 28 Ağustos 2006 Pazartesi
I use CodeDom to generate ActiveRecord classes in ActiveWriter. Quite fancy, but gets complicated easily. To generate something like this:

        public override bool Equals(object obj)

        {

            if (obj == this) return true;

            if (obj == null || obj.GetType() != this.GetType()) return false;

            MyCompositeKey test = (MyCompositeKey)obj;

            return (_keyA == test.KeyA || (_keyA != null && _keyA.Equals(test.KeyA))) &&

              (_keyB == test.KeyB || (_keyB != null && _keyB.Equals(test.KeyB)));

        }


you code this:

        private CodeTypeMember GetCompositeClassEqualsMethod(string className,  List<CodeMemberField> fields)

        {

            CodeMemberMethod equals = new CodeMemberMethod();

            equals.Attributes = MemberAttributes.Public | MemberAttributes.Override;

            equals.ReturnType = new CodeTypeReference(typeof(Boolean));

            equals.Name = "Equals";

 

            CodeParameterDeclarationExpression param = new CodeParameterDeclarationExpression(typeof(Object), "obj");

            equals.Parameters.Add(param);

 

            equals.Statements.Add(new CodeConditionStatement(

                                      new CodeBinaryOperatorExpression(

                                          new CodeFieldReferenceExpression(null, "obj"),

                                          CodeBinaryOperatorType.ValueEquality, new CodeThisReferenceExpression()

                                          ), new CodeMethodReturnStatement(new CodePrimitiveExpression(true))

                                      )

                );

 

            equals.Statements.Add(new CodeConditionStatement

                                      (

                                      new CodeBinaryOperatorExpression

                                          (

                                          new CodeBinaryOperatorExpression(

                                              new CodeFieldReferenceExpression(null, "obj"),

                                              CodeBinaryOperatorType.ValueEquality, new CodePrimitiveExpression(null)),

                                          CodeBinaryOperatorType.BooleanOr,

                                          new CodeBinaryOperatorExpression(

                                              new CodeMethodInvokeExpression(new CodeFieldReferenceExpression(null, "obj"), "GetType"),

                                              CodeBinaryOperatorType.IdentityInequality,

                                              new CodeMethodInvokeExpression(new CodeThisReferenceExpression(), "GetType"))

                                          )

                                      , new CodeMethodReturnStatement(new CodePrimitiveExpression(false))

                                      )

                );

 

            equals.Statements.Add(

                new CodeVariableDeclarationStatement(new CodeTypeReference(className), "test",

                                                    new CodeCastExpression(new CodeTypeReference(className),

                                                                            new CodeFieldReferenceExpression(null, "obj"))));

 

            List<CodeExpression> expressions = new List<CodeExpression>();

            foreach (CodeMemberField field in fields)

            {

                expressions.Add(

                    new CodeBinaryOperatorExpression(

                        //_keyA == test.KeyA

                        new CodeBinaryOperatorExpression(

                            new CodeFieldReferenceExpression(null, field.Name),

                            CodeBinaryOperatorType.ValueEquality,

                            new CodeFieldReferenceExpression(new CodeFieldReferenceExpression(null, "test"), field.Name)),

                        CodeBinaryOperatorType.BooleanOr, // ||

                        new CodeBinaryOperatorExpression(

                            //_keyA != null

                            new CodeBinaryOperatorExpression(

                                new CodeFieldReferenceExpression(null, field.Name),

                                CodeBinaryOperatorType.IdentityInequality,

                                new CodePrimitiveExpression(null)

                                ),

                            CodeBinaryOperatorType.BooleanAnd, // &&

                            // _keyA.Equals( test.KeyA )  

                            new CodeMethodInvokeExpression(

                                new CodeFieldReferenceExpression(null, field.Name), "Equals",

                                new CodeFieldReferenceExpression(

                                    new CodeFieldReferenceExpression(null, "test"), field.Name))

                            )

                        )

                    );

            }

 

            CodeExpression expression = null;

            if (expressions.Count > 2)

                expression =

                    new CodeBinaryOperatorExpression(expressions[0], CodeBinaryOperatorType.BooleanAnd, GetBooleanAnd(expressions, 1));

            else

                expression = new CodeBinaryOperatorExpression(expressions[0], CodeBinaryOperatorType.BooleanAnd, expressions[1]);

 

 

            equals.Statements.Add(new CodeMethodReturnStatement(expression));

 

            return equals;

        }


Strangely, there's no CodeBinaryOperatorType.ValueInequality operator defined. (a==b)==false will do the trick, but how about not having an XOR? I find CodeDom's lack of completeness... disturbing.

posted on 28 Ağustos 2006 Pazartesi 21:46:29 UTC  #   
# 09 Şubat 2006 Perşembe

Please Note: If you're using VS 2008, you don't need this tool anymore. 2008 has this functionality built-in, look for the dropdown on top of the resource editor.

Introduction

In Visual Studio 2005, strongly-typed code for resource files (.resx files) are automatically generated when you save them. The generated class, however, cannot be accessed externally since the class is marked as internal.

This little add-in just instructs the generation process to build a Public class. To use it, just change the Custom Tool property of any resource file from ResXFileCodeGenerator to ResXFilePublicCodeGenerator.

After you make any changes and save the file, IDE will auto-generate a Public strongly-typed class for your resource.

Licence

The component and source is provided "as is" and there are neither warranties to the quality of the work nor any expressed or implied agreements that the programmer will release any updates. The programmer will release updates and provide any support at his own discretion.

External code mentioned in credits may subject to their own licence terms.

1.0.0.1 Update:
Fixed the issue with VB.Net root namespaces. This is, in fact, reported months ago but I totally forgot to fix it. I apoligize from all VB.Net users for the trouble.

Download

v1.0.0.1

Credits

Includes some code from Daniel Cazzulino’s XSD -> Classes Generator Custom Tool article.

VS Integration classes from http://www.gotdotnet.com/Community/UserSamples/Details.aspx?SampleGuid=4AA14341-24D5-45AB-AB18-B72351D0371C

posted on 09 Şubat 2006 Perşembe 00:10:42 UTC  #