创建自定义模型绑定为一个自定义类型

问题描述:

在ASP.NET 1.1 CORE项目,我有以下型号:创建自定义模型绑定为一个自定义类型

public class GetProductsModel { 
    public OrderExpression OrderBy { get; set; } 
} 

OrderExpression是具有以下方法的类:

Boolean TryParse(String value, out OrderExpression expression) 

该方法从一个String创建OrderExpression实例,可用于:

OrderExpression expression; 

Boolean parsed = OrderExpression.TryParse(value, out expression); 

ħ我可以创建一个自定义模型绑定器到OrderExpression类型的属性吗?

+0

您是否尝试绑定OrderExpression的属性,或者您是否尝试将OrderExpression绑定到控制器的输入/ action,这将是一个字符串输入,然后映射到一个OrderExpression对象? –

+0

@AshleyLee我正在尝试将OrderExpression绑定到控制器操作的输入...这有帮助吗? –

+0

@MiguelMoura,只是想知道你是否有机会尝试我提出的解决方案? –

我假设您的请求数据中有一个属性orderBy,您想使用OrderExpression.TryParse绑定到OrderExpression

让我们假设你的OrderExpression类是什么样子如下,其中我提供了一个非常简单的实现你的TryParse方法:

public class OrderExpression 
{ 
    public string RawValue { get; set; } 
    public static bool TryParse(string value, out OrderExpression expr) 
    { 
     expr = new OrderExpression { RawValue = value }; 
     return true; 
    } 
} 

然后,你可以创建一个模型粘合剂,它基本上得到原始字符串值,并调用OrderExpression.TryParse

public class OrderExpressionBinder : IModelBinder 
{ 
    public Task BindModelAsync(ModelBindingContext bindingContext) 
    {    
     var values = bindingContext.ValueProvider.GetValue(bindingContext.ModelName); 
     if (values.Length == 0) return Task.CompletedTask; 

     // Attempt to parse 
     var stringValue = values.FirstValue; 
     OrderExpression expression; 
     if (OrderExpression.TryParse(stringValue, out expression)) 
     { 
      bindingContext.ModelState.SetModelValue(bindingContext.ModelName, expression, stringValue); 
      bindingContext.Result = ModelBindingResult.Success(expression); 
     } 

     return Task.CompletedTask; 
    } 
} 

您还需要一个新的模型绑定提供商,它返回新粘结剂只为OrderExpression类型:

public class OrderExpressionBinderProvider : IModelBinderProvider 
{ 
    public IModelBinder GetBinder(ModelBinderProviderContext context) 
    { 
     return context.Metadata.ModelType == typeof(OrderExpression) ? new OrderExpressionBinder() : null; 
    } 
} 

// It should be registered in your Startup class, adding it to the ModelBinderProviders collection: 
services.AddMvc(opts => { 
    opts.ModelBinderProviders.Insert(0, new OrderExpressionBinderProvider()); 
}); 

有了这个功能,您将能够绑定OrderExpression控制器操作的参数。像下面的例子:

[HttpPost] 
public IActionResult Products([FromBody]OrderExpression orderBy) 
{ 
    return Ok(); 
} 

$.ajax({ 
    method: 'POST', 
    dataType: 'json', 
    url: '/home/products', 
    data: {orderby: 'my orderby expression'} 
}); 

但是有别的东西,需要做的事情让你能够发送一个JSON并将其绑定到像GetProductsModel一个复杂的模型,它内部包含一个OrderExpression。我讲的一个场景是这样的:

[HttpPost] 
public IActionResult Products([FromBody]GetProductsModel model) 
{ 
    return Ok(); 
} 

public class GetProductsModel 
{ 
    public OrderExpression OrderBy { get; set; } 
} 

$.ajax({ 
    method: 'POST', 
    dataType: 'json', 
    contentType: 'application/json; charset=utf-8', 
    url: '/home/products', 
    data: JSON.stringify({orderby: 'my orderby expression'}) 
}); 

在这种情况下ASP.Net核心将只使用Newtonsoft.Json作为InputFormatter和接收到的JSON转换成GetProductsModel模型的实例,但不尝试使用新的内部财产OrderExpressionBinderProvider

幸运的是,你还可以告诉Newtonsoft.Json如何通过创建JsonConverter格式化OrderExpression类型的属性:

public class OrderExpressionJsonConverter : JsonConverter 
{ 
    public override bool CanConvert(Type objectType) 
    { 
     return objectType == typeof(OrderExpression); 
    } 

    public override object ReadJson(JsonReader reader, Type objectType, object existingValue, JsonSerializer serializer) 
    { 
     var stringValue = reader.Value?.ToString(); 
     OrderExpression expression; 
     if (OrderExpression.TryParse(stringValue, out expression)) 
     { 
      return expression; 
     } 
     return null; 
    } 

    public override void WriteJson(JsonWriter writer, object value, JsonSerializer serializer) 
    { 
     throw new NotImplementedException(); 
    } 
} 

应在您的启动类注册:

services.AddMvc(opts => { 
    opts.ModelBinderProviders.Insert(0, new OrderExpressionBinderProvider()); 

}).AddJsonOptions(opts => { 
    opts.SerializerSettings.Converters.Add(new OrderExpressionJsonConverter()); 
}); 

现在你将最终能够处理这两种情况:)