2017-02-19 2 views
9

В качестве 1.1 проекта ASP.NET CORE У меня есть следующие модели:Создание пользовательской модели Binder для пользовательского типа

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

OrderExpression класс, который имеет следующий метод:

Boolean TryParse(String value, out OrderExpression expression) 

метод создает экземпляр OrderExpression из String и могут быть использованы:

OrderExpression expression; 

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

Н ow я могу создать настраиваемое связующее устройство для свойств типа OrderExpression?

+0

Вы пытаетесь связать свойства OrderExpression или пытаетесь привязать OrderExpression к вводу контроллера/action, который будет строковым вводом, а затем отобразит объект OrderExpression? –

+0

@AshleyLee Я пытаюсь привязать OrderExpression к вводу действия контроллера ... Помогает ли это? –

+0

@MiguelMoura, просто интересно, есть ли у вас шанс попробовать мое предложенное решение? –

ответ

5

Я предполагаю, что в ваших запросах есть свойство orderBy, которое вы хотите связать в OrderExpression, используя OrderExpression.TryParse.

Давайте предположим, что ваш 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, как форматировать свойства OrderExpression типа путем создания JsonConverter:

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()); 
}); 

Теперь вам наконец, смогут обрабатывать оба сценария :)

Смежные вопросы