1

I'm trying to use custom remote validation to validate 2 properties based on one another with no success.

Action

Edit only, no insert

Properties

Both properties are free text (no dropdownlist)

  • FolderName
  • FileName

Validation conditions

  • FileName can be empty even if folder name is present

  • FileName can only be filled in if folder name is present

  • Filename is unique for each unique folder

  • When edit page is loaded and in case if there are already data present then no check should be done unless the user modifies theses values.

Code

1- Json function in the controller

public JsonResult IsFileValid(string folderName, string fileName)
    {
        if (!folderName.IsNullOrEmpty() && fileName.IsNullOrEmpty())
        {
            // FileName can be empty even if Folder name is present
            return Json(true, JsonRequestBehavior.AllowGet);
        }

        if (folderName.IsNullOrEmpty() && fileName.IsNullOrEmpty())
        {
            //FileName can be empty even if Folder name is present
            return Json(true, JsonRequestBehavior.AllowGet);
        }

        if (folderName.IsNullOrEmpty() && !fileName.IsNullOrEmpty())
        {
            //FileName can only be filled in if Folder name is present
            return Json(false, JsonRequestBehavior.AllowGet);
        }

        var Folder =
            Uow.Folders.GetAll()
                .FirstOrDefault(x => x.Name.ToLower().Trim() == folderName.Trim().ToLower());



        if (Folder != null)
        {
            // the Folder already exists, FileName name should be unique.
            return Uow.Files.GetAll()
                .Any(
                    x =>
                        x.FolderId == Folder.Id &&
                        x.fileName.Trim().ToLower() == fileName.Trim().ToLower()) ? Json(false, JsonRequestBehavior.AllowGet) : Json(false, JsonRequestBehavior.AllowGet);
        }
        // Folder name is new, in this case we can add new Folder and basked name
        return Json(true, JsonRequestBehavior.AllowGet);
    }

2- Create Custome remote attribute class

protected override ValidationResult IsValid(object value, ValidationContext validationContext)
    {
        // When using remote attribute, we specify the controller, action and the error message. The aim of the following is to retrieve the controller, action and error message
        //using reflection.

        // first get the controller
        Type controller =
            Assembly.GetExecutingAssembly()
                .GetTypes()
                .FirstOrDefault(
                    type =>
                        type.Name.ToLower() ==
                        string.Format("{0}Controller", this.RouteData["controller"].ToString()).ToLower());
        if (controller != null)
        {
            // Get the method in the controller with
            MethodInfo action =
                controller.GetMethods()
                    .FirstOrDefault(method => method.Name.ToLower() == this.RouteData["action"].ToString().ToLower());
            if (action != null)
            {
                // create instance of the controller
                object instance = Activator.CreateInstance(controller);

                //invoke the action method of the controller, and pass the value which is the parameter of the action
                object response = action.Invoke(instance, new object[] {value});

                // because the remote validation action returns JsonResult
                var returnType = response as JsonResult;
                if (returnType != null)
                {
                    object jsonData = returnType.Data;

                    //because the jsonDate is bool
                    if (jsonData is bool)
                    {
                        // return success or the error message
                        return (bool) jsonData ? ValidationResult.Success : new ValidationResult(this.ErrorMessage);
                    }
                }
            }
        }
        return new ValidationResult(ErrorMessage);
    }

3- My viewModel class

 public class FileInViewModel
    {

        public string FolderName { get; set; }

        [RemoteValidation("IsFileValid","Home",ErrorMessage="Please select different file name")]
        public string FileName { get; set; }

        // .....
    }
  • What am i missing to make it work? If also possible to have different error message for each error?
  • How can i ignore the validation for data already present when the edit page is loaded?
marc_s
  • 732,580
  • 175
  • 1,330
  • 1,459
Maro
  • 2,579
  • 9
  • 42
  • 79
  • Its a bit unclear why your creating a custom `RemoteAttribute` - all this is handles out of the box by the in-built attribute (by using the `AdditionalFiields` property to pass back the values of the other properties (which would include the ID of the model so you can check if its new or existing). And if you want to return different error messages, then its just `return Json("your error message", JsonRequestBehavior.AllowGet);` and that error will be displayed in the `@ValidationMessageFor()` placeholder –  Sep 07 '16 at 22:45
  • Because according to my tests, the built-in attribute will work only if javascript is enabled. – Maro Sep 08 '16 at 23:48
  • Yes of course (a `RemoteAttribute` is a client side validation attribute that works by using ajax to submit values to a controller via ajax - and all client side validation required javascipt/jquery to work in any case). So your attribute is not a _custom remote validation_. And a validation attribute should not be calling a database. But if your disabling javascript, then your code makes no sense since you returning a `JsonResult`. Are you wanting to have an attribute that allows you to do client side validation, but still gives you server side validation in case javascript is disabled? –  Sep 08 '16 at 23:56
  • I changed it to return ActionResult, and i'm trying to find a solution that work on both (javascript enabled or disabled) – Maro Sep 09 '16 at 00:27
  • Then use the standard `RemoteAttribute` that calls a server method (to work with javascript enabled). But that method in turn calls a private function in your controller that returns the result. Then you can also call that private function in the POST method (and if not valid, add a `ModelStateError` and return the view to display the error. –  Sep 09 '16 at 00:30
  • What you are saying is that i have to post the form then call the private function? if i would do the validation in the post why do i bother to do a remote validation?. or am i missing something – Maro Sep 09 '16 at 00:43
  • Because if you want client side validation (if javascript is enabled), then you need a `RemoteAttribute` (that's what it's for). But if you also want server side validation if javascript is disabled, then you need a fallback. –  Sep 09 '16 at 00:47
  • thanks Stephen, please post your comment as an answer and i will accept it. – Maro Sep 09 '16 at 10:01
  • No time today. Also suggest you look at [this answer](http://stackoverflow.com/questions/39325307/multifield-required-validation-is-not-working-in-client-side-in-mvc-5/39382081#39382081) for a validation attribute that handle your 2nd point. In your case you would apply `[RequiredWith("FolderName")` to the `FileName` property so that if the user adds a file name, an error message will be displayed if the `FolderName` is empty –  Sep 09 '16 at 10:16

1 Answers1

1

See the code below:

[Remote("CheckExist", "securitylevels", AdditionalFields = "Id", ErrorMessage = "the number is Zero!")]
public int Number { get; set; }
Jithin Scaria
  • 1,271
  • 1
  • 15
  • 26
donya
  • 11
  • 2