【问题标题】:ASP.NET Web API Model BindingASP.NET Web API 模型绑定
【发布时间】:2012-08-09 02:22:00
【问题描述】:

我在 ASP .NET MVC 4 RC 中使用 Web API,并且我有一个方法可以接收具有可为空的 DateTime 属性的复杂对象。我希望从查询字符串中读取输入的值,所以我有这样的东西:

public class MyCriteria
{
    public int? ID { get; set; }
    public DateTime? Date { get; set; }
}

[HttpGet]
public IEnumerable<MyResult> Search([FromUri]MyCriteria criteria)
{
    // Do stuff here.
}

如果我在查询字符串中传递标准日期格式,例如 2012 年 1 月 15 日:

http://mysite/Search?ID=1&Date=01/15/2012

但是,我想为 DateTime 指定一个自定义格式(可能是 MMddyyyy)...例如:

http://mysite/Search?ID=1&Date=01152012

编辑:

我尝试应用自定义模型绑定器,但我没有任何运气将其仅应用于 DateTime 对象。我试过的 ModelBinderProvider 看起来像这样:

public class DateTimeModelBinderProvider : ModelBinderProvider
{
    public override IModelBinder GetBinder(HttpActionContext actionContext, ModelBindingContext bindingContext)
    {
        if (bindingContext.ModelType == typeof(DateTime) || bindingContext.ModelType == typeof(DateTime?))
        {
            return new DateTimeModelBinder();
        }
        return null;
    }
}

// In the Global.asax
GlobalConfiguration.Configuration.Services.Add(typeof(ModelBinderProvider), new DateTimeModelBinderProvider());

创建了新的模型绑定器提供程序,但GetBinder 仅被调用一次(对于复杂模型参数,而不是模型中的每个属性)。这是有道理的,但我想找到一种方法,让它将我的DateTimeModelBinder 用于 DateTime 属性,同时对非 DateTime 属性使用默认绑定。有没有办法覆盖默认的ModelBinder 并指定每个属性的绑定方式?

谢谢!!!

【问题讨论】:

  • stackoverflow.com/questions/528545/… - 同样的问题,可能对您有所帮助。
  • 这篇文章适用于 MVC 网页中的控制器操作,但我无法找到 Web API 的等价物。我已经尝试为 Web API 注册一个自定义模型绑定器,我认为如果我的方法采用单独的参数,它会起作用。但是,我希望它接受一个复杂的对象作为输入,我还没有找到一种方法来覆盖 DateTime 属性的绑定,同时使用其他的默认绑定。
  • 正如您已经正确提到的,您可以通过自定义活页夹解决它吗?你到底有什么问题?
  • 我会使用专用视图模型而不是域模型将信息发送到视图并再次进行模型绑定。然后我将 MyCriteriaViewModel.Date 设置为类型字符串,并在我将其映射到控制器或映射层中的域模型 (MyCriteria.Date) 时处理转换。
  • @alexanderb 我已经更新了我的问题以提供更多详细信息...我还没有弄清楚如何仅为某些类型的属性注册模型绑定器。

标签: asp.net-mvc asp.net-web-api


【解决方案1】:

考虑将视图模型的 Date 属性设置为类型 string

然后编写一个实用函数来处理视图模型类型和域模型类型之间的映射:

public static MyCriteria MapMyCriteriaViewModelToDomain(MyCriteriaViewModel model){

    var date = Convert.ToDateTime(model.Date.Substring(0,2) + "/" model.Date.Substring(2,2) + "/" model.Date.Substring(4,2));

    return new MyCriteria
    {
        ID = model.ID,
        Date = date
    };

}

或者使用像AutoMapper这样的工具,像这样:

在 Global.asax 中

//if passed as MMDDYYYY:
Mapper.CreateMap<MyCriteriaViewModel, MyCriteria>().
    .ForMember(
          dest => dest.Date, 
          opt => opt.MapFrom(src => Convert.ToDateTime(src.Date.Substring(0,2) + "/" src.Date.Substring(2,2) + "/" src.Date.Substring(4,2)))
);

在控制器中:

public ActionResult MyAction(MyCriteriaViewModel model)
{
    var myCriteria = Mapper.Map<MyCriteriaViewModel, MyCriteria>(model);

    //  etc.
}

从这个例子看来,AutoMapper 似乎没有提供任何附加价值。当您使用通常比本示例具有更多属性的对象配置多个或多个映射时,它的价值就出现了。 CreateMap 将自动映射具有相同名称和类型的属性,因此它节省了大量的输入,而且更干燥。

【讨论】:

  • 我使用过 AutoMapper,我喜欢它提供的功能,但我仍然希望在执行操作之前应用此映射。这样看起来更干净,恕我直言。我还需要定义 API 控制器实现的接口。该接口将用于为 API 动态创建客户端。我希望接口在定义期望时更加明确,而不是接受字符串。
猜你喜欢
  • 2012-08-28
  • 1970-01-01
  • 2016-08-16
  • 2012-09-27
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多