在ASP.NET CORE 1.1项目中,我有以下模型:
select id
,concat(',',concat_ws(',',A),',') as left_side_of_regexp
,concat(',(',concat_ws('|',B),'),') as right_side_of_regexp
,concat(',',concat_ws(',',A),',') regexp
concat(',(',concat_ws('|',B),'),') as are_common_elements
from mytable
;
OrderExpression是一个具有以下方法的类:
+----+---------------------+----------------------+---------------------+
| id | left_side_of_regexp | right_side_of_regexp | are_common_elements |
+----+---------------------+----------------------+---------------------+
| 1 | ,P908,S57,A65, | ,(P908|S57), | true |
| 2 | ,P908,S57,A65, | ,(P9|S5777), | false |
+----+---------------------+----------------------+---------------------+
该方法从//
// Some globals to store what the user selects.
//
VAR _COUNTY, _STATE, _CITY;
//
// This will append scripts to the body so that you dont need to load all the
// scripts in one go, this is the trick.
//
function addScript( src,callback) {
var s = document.createElement( 'script' );
s.setAttribute( 'src', src );
s.onload=callback;
document.body.appendChild( s );
}
//
// Get all the states based on country
// add the correct file to the dom
// ie: country/Canada.js
// these files would be better scoped geodata.country geodata.state.
//
// IMPORTANT CHANGE YOUR HTML SELECT HANDLER TO FIRE HERE.
// <select name="country" id="country" onchange="getStates();">
//
function getStates(){
_COUNRTY = document.getElementById('country'),
file = ["country/",_COUNTRY,".js"].join;
addScript(file, setStates);
};
//
//
// Called when the script loads
//
function setStates() {
//
// Here is where we would do
// geodata.states for now I'm using your declaration of state.
//
var stateList = states;
changeSelect('state', stateList, stateList);
// Not sure why you are doing this they need to select a state first?
setCities();
}
//
// Called when they select a state,
// I would replicate the state code and load all the cities per state.
// I would disable the city drop down until the states are loaded.
//
function setCities() {
_STATE = document.getElementById('state');
cityList = cities[_COUNTRY][_STATE];
changeSelect('city', cityList, cityList);
}
function changeSelect(fieldID, newOptions, newValues) {
selectField = document.getElementById(fieldID);
selectField.options.length = 0;
for (i=0; i<newOptions.length; i++) {
selectField.options[selectField.length]=newOption(newOptions[i],newValues[i]);
}
}
function addLoadEvent(func) {
var oldonload = window.onload;
if (typeof window.onload != 'function') {
window.onload = func;
} else {
window.onload = function() {
if (oldonload) {
oldonload();
}
func();
}
}
}
addLoadEvent(function() {
setStates();
});
创建public class GetProductsModel {
public OrderExpression OrderBy { get; set; }
}
实例,可以使用:
Boolean TryParse(String value, out OrderExpression expression)
如何为OrderExpression
类型的属性创建自定义模型绑定器?
答案 0 :(得分:6)
我假设您的请求数据中有一个属性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
的{{1}}这样的复杂模型。我在谈论这样的场景:
OrderExpression
在这种情况下,ASP.Net Core将使用Newtonsoft.Json作为InputFormatter,并将收到的json转换为[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'})
});
模型的实例,而不是尝试将新的GetProductsModel
用于内部属性。
幸运的是,您还可以通过创建JsonConverter告诉Newtonsoft.Json如何格式化OrderExpressionBinderProvider
类型的属性:
OrderExpression
哪些应该在您的Startup类中注册:
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();
}
}
现在你终于可以处理这两种情况:)