ASP.NET MVC Model/ViewModel Validation

2020-07-13 09:26发布

问题:

I have model classes in Linq-to-Sql with partial classes marked with data annotation attributes and a reference to xVal.

When I bind a view directly to a model everything works great, both the JS generated by xVal and server side double check.

Many of my views don't take input to one specific model, so I am setting up view model classes. Instead of exposing an entire model instance I expose properties into the model that I allow/need to be set by the view.

// foo model 
public class Foo {
    public string FooField { ... }
    public Bar Bar { ... }
}

// bar model, where bar is a parent relationship of foo in the db
public class Bar {
    public string BarField { ... }
}

// view model stuff
public class FooViewModel {
    private Foo foo;

    public FooViewModel() {
        foo = new Foo() { Bar = new Bar() };
    }

    public Foo Model {
        get { return foo; }
        set { foo = value; }
    }

    public string BarField { 
        get { return foo.Bar.BarField; }
        set { foo.Bar.BarField = value; }
    }

    public string ExtraViewModelField {
        get; set; 
    }
}

This approach populates the view model class correctly and the repository can populate the record correctly.

It doesn't pull through the validation at all though. I have looked at the client code emitted and the validation array is empty for xval. Additionally, the server side check for IsValid is always true.

Can I have the data annotations pull though the properties of view model for validation like this, or should I be doing this another way?

回答1:

If you use partials, and pass in the subtype, you still need to qualify. See as follows:

<%@ Control Language="C#" 
                   Inherits="System.Web.Mvc.ViewUserControl<MvcWeb.Models.OrderDetail>" %>

<% using (Html.BeginForm()) { %>

    <fieldset>
        <legend>Fields</legend>
            <%= Html.Hidden("OrderId", Model.OrderId) %>
            <%= Html.Hidden("ProductId", Model.ProductId)%>
        <p>
            <label for="Quantity">Quantity:</label>
            <%= Html.TextBox("OrderDetails.Quantity", Model.Quantity)%>
            <%= Html.ValidationMessage("OrderDetails.Quantity", "*") %>
        </p>
        <p>
            <input type="submit" value="Save" />
        </p>
    </fieldset>

<% } %>

Notice that the type is OrderDetails, but I'm still prefixing that to deal with validation messages.



回答2:

Can you post your xval helper code, and some of your Html.Helpers?

It takes the entity and the prefix, so I don't see why the structure within your view model should make any difference. Something like:

<%= Html.ClientSideValidation<Foo>("Foo") %>
<%= Html.ClientSideValidation<Bar>("Foo.Bar") %>

James



回答3:

If i read this correctly you are putting the DataAnnotations on the linq to sql class then populating your viewmodel properties with the ones from you linq to sql class.

To get this to work with xval you would need to put the DataAnnotations on the view model properties. As far as i can tell from xvals code it dosen't look beyond the public properties for any validation information (someone please correct me if im wrong here).

If you wanted to make the validation transparent between your model and viewmodel you could go down the route of using postsharp to bind the attributes but this could be a lot of work for little gain if you program is small.