MVC模型绑定 - 表单帖子以数字开头

时间:2013-09-12 12:31:15

标签: c# asp.net-mvc asp.net-mvc-4 sagepay

我正在尝试为SagePay通知创建一个模型。我知道MVC模型绑定器将根据POST名称自动绑定我的所有属性。

SagePay系统传递以下表单名称:

Status
VendorTxCode
VPSTxId
VPSSignature
StatusDetail
AVSCV2
AddressResult
PostCodeResult
CV2Result
GiftAid
3DSecureStatus
CAVV
AddressStatus
PayerStatus
CardType
Last4Digits
DeclineCode
ExpiryDate
FraudResponse
BankAuthCode

我创建了以下类。

public class NotificationModel
{
    public string Status { get; set; }
    public string VendorTxCode { get; set; }
    public string VPSTxId { get; set; }
    public string VPSSignature { get; set; }
    public string StatusDetail { get; set; }
    public string AVSCV2 { get; set; }
    public string AddressResult { get; set; }
    public string PostCodeResult { get; set; }
    public string CV2Result { get; set; }
    public string GiftAid { get; set; }
    // When binding the model will MVC ignore the underscore?
    public string _3DSecureStatus { get; set; }
    public string CAVV { get; set; }
    public string AddressStatus { get; set; }
    public string PayerStatus { get; set; }
    public string CardType { get; set; }
    public string Last4Digits { get; set; }
    public string DeclineCode { get; set; }
    public string ExpiryDate { get; set; }
    public string FraudResponse { get; set; }
    public string BankAuthCode { get; set; }
}

不幸的是,c#属性名称不能以数字开头。如何让模型绑定器自动将3DSecureStatus帖子名称绑定到属性?

2 个答案:

答案 0 :(得分:2)

您可以使用自定义模型绑定器执行此操作:

public class NotificationModelBinder : DefaultModelBinder
{
    public override object BindModel(ControllerContext controllerContext,
        ModelBindingContext bindingContext)
    {
        var model = this.CreateModel(controllerContext,
            bindingContext, bindingContext.ModelType);
        bindingContext.ModelMetadata.Model = model;

        var formValue = bindingContext.ValueProvider
            .GetValue(this.FormField).AttemptedValue;

        var target = model.GetType().GetProperty(this.FieldToBindTo);
        target.SetValue(model, formValue);

        // Let the default model binder take care of the rest
        return base.BindModel(controllerContext, bindingContext);
    }

    private readonly string FieldToBindTo = "_3DSecureStatus";
    private readonly string FormField = "3DSecureStatus";
}

我没有添加错误处理,因为这个场景只处理1个字符串是微不足道的。除了字符串的实际值不是你期望的东西之外,唯一的另一个错误(在这种情况下是例外情况)你可以获得的是如果你的模型上找不到目标属性,但显然这是一个也很简单。

编辑:实际上,如果在表单上找不到该字段,您也可以获得formValue的例外,但是再次,因为这是第三方支付系统,我倾向于说那不会不会改变。

你会这样使用它:

[HttpPost]
public ActionResult Index([ModelBinder(typeof(NotificationModelBinder))]NotificationModel model)
{
    // do stuff
}

答案 1 :(得分:0)

如果您希望使用Web API控制器执行此操作,以下模型绑定器将有所帮助(实现System.Web.Http.ModelBinding.IModelBinder

public class SagePayTransactionNotificationModelBinder : IModelBinder
{
    public bool BindModel(HttpActionContext actionContext, ModelBindingContext bindingContext)
    {
        var model = actionContext.Request.Content.ReadAsStringAsync()
                        .ContinueWith(t =>
                            {
                                var formCollection = HttpUtility.ParseQueryString(t.Result);

                                return new SagePayTransactionNotification
                                {
                                    VPSProtocol = formCollection["VPSProtocol"],
                                    TxType = formCollection["TxType"],
                                    VendorTxCode = formCollection["VendorTxCode"],
                                    VPSTxId = formCollection["VPSTxId"],
                                    Status = formCollection["Status"],
                                    StatusDetail = formCollection["StatusDetail"],
                                    TxAuthNo = formCollection["TxAuthNo"],
                                    AVSCV2 = formCollection["AVSCV2"],
                                    AddressResult = formCollection["AddressResult"],
                                    PostcodeResult = formCollection["PostcodeResult"],
                                    CV2Result = formCollection["CV2Result"],
                                    GiftAid = formCollection["GiftAid"],
                                    ThreeDSecureStatus = formCollection["3DSecureStatus"],
                                    CAVV = formCollection["CAVV"],
                                    CardType = formCollection["CardType"],
                                    Last4Digits = formCollection["Last4Digits"],
                                    VPSSignature = formCollection["VPSSignature"]
                                };
                            })
                        .Result;

        bindingContext.Model = model;

        return true;
    }
}

可以像这样应用于您的Controller方法:

[ActionName("Notifications")]
public string Post([ModelBinder(typeof(SagePayTransactionNotificationModelBinder))] SagePayTransactionNotification notification)
{
    ...
}

我知道这并不是问题中严格要求的问题,但当我遇到与OP完全相同的问题并且认为它可能对后来的其他人有用时,这就是我最终的结果。