ASP.NET MVC 4 属性-为发布重命名

ASP.NET MVC 4 property-renaming for posting

给出了以下约定。每个 Action 都有一个 BaseRequest 类型的参数,其数据取决于 ActionViewModel 始终是 BaseResponse.

类型

我想做的是,如果 View 包含一个表单,POST-Action 需要某种 BaseRequest。 从 ViewModel 开始,我如何实现正确的模型绑定是 BaseResponse

我已经尝试在 XYZResponse 中添加 XYZRequest 的 属性 这样我就可以像

那样绑定
@Html.ChecBoxFor(m => m.RequestObject.SomeBooleanProperty)

但这会生成 name RequestObject.SomeBooleanProperty,它不会正确绑定到接受 XYZRequest.

的 POST-Action

这种约定是否完全错误或者我遗漏了什么?

更新#1

我还尝试创建一个 XYZRequest 类型的新 temporary 对象并像

那样绑定到它
@Html.CheckBoxFor(m = tmpReq.SomeBooleanProperty)

这将呈现 nametmp.SomeBooleanProperty 也无法绑定。

更新 #2 - 附加信息

设置了以下结构。

如果继承自BaseResponseGetOverviewResponse返回给View并提供一个名为[=48=的属性 ] 类型 GetOverviewRequest 绑定失败

@Html.TextBoxFor(m => m.TheProperty.SomeBooleanValue)

将尝试绑定到 GetOverviewRequest 对象中的 TheProperty-属性,该对象不存在。

如果 GetOverviewRequest 有一个名为 TheProperty 的 属性 来绑定,这可能会起作用。但如果命名不同,绑定也会失败。

我只想要

<input name="SomeBooleanValue">
<input name="SomeComplexType.SomeStringValue">

而不是

<input name="TheProperty.SomeBooleanValue">
<input name="TheProperty.SomeComplexType.SomeStringValue">

更新 #3 - 添加了示例项目

Sample project via dropbox.com

更新 #4 - 解释,为什么@StephenMuecke 的解决方案不起作用

如评论中所述,其他问题的解决方案需要知道 GetOverviewResponse-object 中 属性 的名称。 属性 被命名为 TheProperty,因此我必须添加 [Bind(Prefix = "TheProperty)] 才能启用正确的绑定。我真的不喜欢魔术弦。 "TheProperty" 是一个神奇的字符串。如果将 TheProperty 的名称更改为 RenamedProperty,整个绑定将失败。

所以。我现在正在寻找一种动态设置前缀的方法。

[Bind(Prefix = GetOverviewResponse.NameOf(m => m.TheProperty))]

真的很棒。也许某种自定义属性?由于 BindAttribute 是密封的,因此没有机会创建一个继承自此的。

有什么想法吗?

MVC 中的绑定适用于名称/值字典。所以如果你有:

public class BaseRequest
{
    public string prop1 {get; set;}
    public string prop2 {get; set;}
    public string prop3 {get; set;}
}

cshtml:

@Html.TextBoxFor(x => x.prop1)

那么控制器接受的对象无关紧要:

public ActionResult MyAction(NotBaseRequest request)
{   
    //do something
}

接收到的新对象:

public class NotBaseRequest
{
    public string prop1 {get; set;}
}

MVC 可以毫无问题地绑定它。

所以如果你想绑定一个子对象,那么你必须在控制器接受的对象中有基础对象:

public class BaseRequest
{
    public NotBaseRequest NotBaseRequest {get; set;}
}

cshtml

@Html.TextBoxFor(x => x.NotBaseRequest.prop1)
//<input type="text" name="NotBaseReqest.prop1" value /> 

MVC 将使用名称属性将值发送到控制器。

控制器

public ActionResult MyAction(OtherRequest request)
{
    //do something
}

你拿进来的对象,只要里面有NotBaseRequest,随便叫什么都行。

新对象:

public class OtherRequest
{
    public NotBaseRequest NotBaseRequest {get; set;}
}

html 对象的名称属性将创建子对象并为其赋值。

如评论所述,我创建了一些新结构来实现我的需要。

我创建了一个新的 class BaseRequestWrapperResponse<TRequest> 来将 Request 对象封装在 Response

    public abstract class BaseRequestWrapperResponse<TRequest> : BaseResponse where TRequest : IRequestFromResponse

这个class目前有一个属性:

    public TRequest Request { get; set; }

接下来我创建了一个界面:

    public interface IRequestFromResponse

我的 Requset-对象将从中继承 -> 将用于绑定。

在我的自定义模型绑定器中覆盖 protected override object CreateModel 我检查 if (modelType.GetInterfaces().Contains(typeof(IRequestFromResponse))) 看看我的 Request 是否需要特殊处理。如果是这样,我会动态创建 BindAttribute 并在 normal 活页夹完成剩下的工作之前进行设置:

                var bindAttribute = new BindAttribute {Prefix = GetPropertyName<BaseRequestWrapperResponse<IRequestFromResponse>, IRequestFromResponse>(r => r.Request)};
            TypeDescriptor.AddAttributes(modelType, bindAttribute);

其中定义了 GetPropertyName:

        private static string GetPropertyName<TSource, TProperty>(Expression<Func<TSource, TProperty>> propertyLambda)
    {
        var member = (MemberExpression)propertyLambda.Body;
        return member.Member.Name;
    }

另请参阅: