4

我正在尝试为 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; }
}

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

4

2 回答 2

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,但同样,由于这是第 3 方支付系统,我倾向于说这也不会改变。

你会这样使用它:

[HttpPost]
public ActionResult Index([ModelBinder(typeof(NotificationModelBinder))]NotificationModel model)
{
    // do stuff
}
于 2013-09-30T18:29:43.737 回答
1

如果您希望使用 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 完全相同的问题并认为这可能对以后的其他人有用时,我最终会遇到这种情况。

于 2013-10-13T17:04:41.230 回答