tisdag 29 maj 2018

Dynamic serverside validation of form data

public class FormValidationHelper
{
    public TValidationResult DoDynamicValidation(TModel model, string methodBody)
    {
        var result = CompileWebFormValidationScript(methodBody);
        return result.Assembly == null ? default(TValidationResult) : result.Assembly.ExecuteFromAssembly("DynamicValidator", "Validate", new object[] { model });
    }

    public static CompilationResult CompileWebFormValidationScript(string script)
    {
        var references = new[]
        {
            MetadataReference.CreateFromFile(typeof (object).Assembly.Location),
            MetadataReference.CreateFromFile(typeof (TValidationResult).Assembly.Location),
            MetadataReference.CreateFromFile(typeof (TModel).Assembly.Location)
        };
        var dynamicCompiler = new DynamicCompiler();
        var result = dynamicCompiler.CompileSourceRoslyn(references,
            @"using " + typeof (TModel).Namespace + @";
                    using " + typeof (TValidationResult).Namespace + @";

                    public class DynamicValidator
                    {
                        public " + typeof (TValidationResult).Name + @" Validate(" + typeof (TModel).Name + @" model)
                        {
                            " + script + @"
                        }
                    }
                ");
        return result;
    }
}

public class FormValidationResult
{
    public bool HasError { get; }
    public string Message { get; }
    public string FieldName { get; }

    public WebFormValidationResult()
    {
        HasError = false;
        Message = string.Empty;
        FieldName = string.Empty;
    }

    public WebFormValidationResult(bool hasError, string message, string fieldName)
    {
        HasError = hasError;
        Message = message;
        FieldName = fieldName;
    }

    public override string ToString()
    {
        return $"HasError: {HasError}, Message: {Message}, FieldName: {FieldName}";
    }
}
Use like so:
var validationScript = "return new FormValidationResult(model.FirstName == \"John\");"
var model = new FormModel { FirstName = "Lars", LastName = "Doe", Age = 61 };
var validationHelper = new FormValidationHelper();
var result = validationHelper.DoDynamicValidation(model, validationScript);