2017-02-19 15 views
9

wchodzi w ASP.NET 1.1 CORE projektu Mam następujący model:Tworzenie niestandardowego modelu Binder dla niestandardowego typu

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

OrderExpression to klasa, która ma następującą metodę:

Boolean TryParse(String value, out OrderExpression expression) 

Sposób powoduje wystąpienie OrderExpression z String i mogą być stosowane:

OrderExpression expression; 

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

H ow czy mogę utworzyć niestandardowy segregator modelu dla właściwości typu OrderExpression?

+0

Czy próbujesz powiązać właściwości OrderExpression lub próbujesz powiązać OrderExpression do danych wejściowych do kontrolera/action, który byłby ciągiem wejściowym, a następnie mapowałby do obiektu OrderExpression? –

+0

@AshleyLee Próbuję powiązać OrderExpression do danych wejściowych akcji kontrolera ... Czy to pomaga? –

+0

@MiguelMoura, zastanawiam się, czy miałeś okazję wypróbować proponowane rozwiązanie? –

Odpowiedz

5

Zakładam, że w twoim żądaniu danych znajduje się właściwość orderBy, którą chcesz powiązać z OrderExpression przy użyciu OrderExpression.TryParse.

Załóżmy klasa OrderExpression wygląda następująco, gdzie dostarczyły bardzo prostą realizację metodę 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; 
    } 
} 

Następnie można utworzyć model spoiwo, które w zasadzie dostaje surową wartość ciągu i wywołuje 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; 
    } 
} 

Potrzebny będzie również nowego dostawcę modelu spoiwa, która zwraca nowy wiążący tylko dla typu 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()); 
}); 

Dzięki temu na miejscu można powiązać parametry OrderExpression akcji kontrolera. Coś jak w poniższym przykładzie:

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

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

Jednak jest coś, co należy zrobić, aby być w stanie wysłać JSON i powiązać go z złożonym modelu podobnego GetProductsModel który zawiera OrderExpression wewnętrznie. Mówię o scenariuszu tak:

[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'}) 
}); 

W tym scenariuszu ASP.Net Rdzeń będzie po prostu użyć Newtonsoft.Json jako InputFormatter i konwertowania odebranego JSON do instancji modelu GetProductsModel, nie próbując użyć nowy OrderExpressionBinderProvider dla własności wewnętrznej.

szczęście, można również powiedzieć Newtonsoft.Json jak sformatować właściwości OrderExpression typu tworząc swój 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(); 
    } 
} 

który powinien być zarejestrowany w swojej klasie Uruchomienie:

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

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

teraz ty w końcu będzie w stanie obsłużyć oba scenariusze :)