ASP.NET MVC 3 Проверка ComplexModel.EntityCollection.Property1 только для первых X элементов в коллекции с помощью пользовательского атрибута ValidationAttribute - PullRequest
2 голосов
/ 23 апреля 2011

Моя модель описана ниже.Я бы хотел только подмножество полей ссылки для первых 2 элементов в коллекции Application.References.Я хотел бы, чтобы это происходило как на стороне клиента, так и на стороне сервера.У меня есть рабочий метод, который я опишу ниже, но я чувствую, что клиентская сторона довольно хитрая, поэтому я задаюсь вопросом, может ли быть лучший способ справиться с этим.Я хотел бы быть универсальным, если это возможно, потому что у меня есть несколько других коллекций в объекте Application для проверки подмножества.

EF Model

public class Application
{
    //...EF framework code...
    public EntityCollection<Reference> References
    {
        //get, set
    }
}

public partial class Reference : EntityObject
{
    public global::System.String FullName
    {
        //get, set
    }

    public global::System.String Relationship
    {
        //get, set
    }

    public global::System.String PhoneNumber
    {
        //get, set
    }

    public global::int? RelationshipLength //radio button
    {
        //get, set
    }

    public global::int? ReferenceType //radio button
    {
        //get, set
    }
}

ReferenceMetaData.cs

[MetadataType(typeof(ReferenceMetadata))]
public partial class Reference
{
}

public class ReferenceMetadata
{
    [DisplayFormat(NullDisplayText = "N/A")]
    [DisplayName("Full Name")]
    public string FullName { get; set; }

    [DisplayFormat(NullDisplayText = "N/A")]
    [DisplayName("Reference Type")]
    public string ReferenceType { get; set; }

    [DisplayFormat(NullDisplayText = "N/A")]
    [DisplayName("How long have you known this person?")]
    public string RelationshipLength { get; set; }

    [DisplayFormat(NullDisplayText = "N/A")]
    [DisplayName("Relationship")]
    public string Relationship { get; set; }

    [DisplayFormat(NullDisplayText = "N/A")]
    [DisplayName("Phone")]
    public string Phone { get; set; }
    //...more properites
}

В настоящее время я использую расширения RuleException и RulesViolationException Стивена Сандерсона из Pro ASP.NET MVC 2 Framework для ручной проверки на стороне сервера следующим образом:

public static class ApplicationBusinessLogic
{
    public static void RunServerValidation(Application app)
    {
        var errors = new RulesException<Application>();

        for (int i = 0; i < 3; i ++)
        {
            if (string.IsNullOrEmpty(app.References.ElementAt(i).FullName))
                errors.ErrorFor(x => x.References.ElementAt(i).FullName, "The Full Name for a first and second reference are required.");
            if (app.References.ElementAt(i).ReferenceType == null)
                errors.ErrorFor(x => x.References.ElementAt(i).ReferenceType, "The Reference Type for a first and second reference are required.");
            if (app.References.ElementAt(i).RelationshipLength == null)
                errors.ErrorFor(x => x.References.ElementAt(i).RelationshipLength, "The Relationship Length for a first and second reference are required.");
            if (string.IsNullOrEmpty(app.References.ElementAt(i).Relationship))
                errors.ErrorFor(x => x.References.ElementAt(i).Relationship, "The Relationship for a first and second reference are required.");
            if (string.IsNullOrEmpty(app.References.ElementAt(i).Phone))
                errors.ErrorFor(x => x.References.ElementAt(i).Relationship, "The Phone Number for a first and second reference are required.");
        }

        if (errors.Errors.Any())
            throw errors;
    }

}

Я просто вызываю этот метод RunServerValidation из контроллера, отлавливаю исключения и затем копирую их в ModelState.Это работает нормально, но я не уверен, как справиться с этим на стороне клиента.Если бы я использовал метаданные [Обязательный], все 3 элемента в коллекции будут иметь эти обязательные поля.Я просто хочу 2 из 3.

Клуджый способ, которым я подключил проверку клиента, заключается в указании атрибутов data-val и data-val-required в представлении при рендеринге входных данных, например, так:

@for (int i = 0; i < 3; i++)
{
    ViewData.TemplateInfo.HtmlFieldPrefix = "Application.References[" + i + "]";    
    <h3>Reference @i</h3>
    @Html.ValidationMessageFor(model => model.Application.References.ElementAt(i).FullName)
    <div class="editor-label">
        @Html.LabelFor(model => model.Application.References.ElementAt(i).FullName)
    </div>                
    <div class="editor-field">   
        @Html.TextBoxFor(model => model.Application.References.ElementAt(i).FullName, new { maxlength = "100", data_val="true", data_val_required="The Full Name for a first and second reference are required." })
    </div>
    @* and so on for other properties... *@
}

Это работает, но это не может быть идеальным.Я думал, может быть, я мог бы сделать общий атрибут ValidationAttribute, но я бы подумал, что это будет сложно.Я думал [RequiredFieldsForFirstXCollectionItems(FirstXItems=2, Fields= new [] {"FullName", "ReferenceType" /* etc */})] о члене Application.References, но я не уверен, как это сделать в общем виде.Я на правильном пути с этой мыслью, хотя?Тогда я мог бы реализовать клиентскую и серверную стороны таким образом, но это был бы довольно сложный код, я думаю.

Обновление 26.04.2011:

Я думаю, что этовероятно, мне лучше добавить проверку на стороне клиента с помощью плагина jquery.Validation в функции $ (document) .ready, а не помещать атрибуты data-val и data-val-required html5 во входные теги.Тогда, по крайней мере, у меня есть централизованное место для проверки моего клиента.Вот что я сделал:

@*End of Razor View file*@
<script type="text/javascript>
     function addValidationRules() {
        //references
        for (var i = 0; i < 2; i++) {

            $("#Application_References_" + i + "__FullName").rules("add", {
                required: true,
                messages: {
                    required: "The Full Name for a first and second reference are required."
                }
            });
            //etc. for other properties
        }//end for-loop
    }//end addValidationRules()
    $(document).ready(function () {
        addValidationRules();
        //more js code...
    });
</script>

Конечно, когда я использую файлы ресурсов для сообщений об ошибках, это может немного усложниться, если я решу переместить javascript в файл .js.Я думаю, что если я сохраню функцию в представлении, я смогу читать файл ресурсов по мере необходимости.

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...