Отмеченный ответ не выполнен на 100%, так как он игнорирует любой IContractResolver, который может быть зарегистрирован, например CamelCasePropertyNamesContractResolver и т. д.
Также возврат false для can convert может предотвратить другие случаи пользователя, поэтому я изменил его на return objectType.GetCustomAttributes(true).OfType
Вот обновленная версия: https://dotnetfiddle.net/F8C8U8
Я также удалил необходимость установить JsonProperty
на свойство, как показано в ссылке.
Если по какой-либо причине ссылка выше умирает или взрывается, я также включаю следующий код:
public class JsonPathConverter : JsonConverter
{
///
public override object ReadJson(
JsonReader reader,
Type objectType,
object existingValue,
JsonSerializer serializer)
{
JObject jo = JObject.Load(reader);
object targetObj = Activator.CreateInstance(objectType);
foreach (PropertyInfo prop in objectType.GetProperties().Where(p => p.CanRead && p.CanWrite))
{
JsonPropertyAttribute att = prop.GetCustomAttributes(true)
.OfType()
.FirstOrDefault();
string jsonPath = att != null ? att.PropertyName : prop.Name;
if (serializer.ContractResolver is DefaultContractResolver)
{
var resolver = (DefaultContractResolver)serializer.ContractResolver;
jsonPath = resolver.GetResolvedPropertyName(jsonPath);
}
if (!Regex.IsMatch(jsonPath, @"^[a-zA-Z0-9_.-]+$"))
{
throw new InvalidOperationException($"JProperties of JsonPathConverter can have only letters, numbers, underscores, hiffens and dots but name was ${jsonPath}."); // Array operations not permitted
}
JToken token = jo.SelectToken(jsonPath);
if (token != null && token.Type != JTokenType.Null)
{
object value = token.ToObject(prop.PropertyType, serializer);
prop.SetValue(targetObj, value, null);
}
}
return targetObj;
}
///
public override bool CanConvert(Type objectType)
{
// CanConvert is not called when [JsonConverter] attribute is used
return objectType.GetCustomAttributes(true).OfType().Any();
}
///
public override void WriteJson(JsonWriter writer, object value, JsonSerializer serializer)
{
var properties = value.GetType().GetRuntimeProperties().Where(p => p.CanRead && p.CanWrite);
JObject main = new JObject();
foreach (PropertyInfo prop in properties)
{
JsonPropertyAttribute att = prop.GetCustomAttributes(true)
.OfType()
.FirstOrDefault();
string jsonPath = att != null ? att.PropertyName : prop.Name;
if (serializer.ContractResolver is DefaultContractResolver)
{
var resolver = (DefaultContractResolver)serializer.ContractResolver;
jsonPath = resolver.GetResolvedPropertyName(jsonPath);
}
var nesting = jsonPath.Split('.');
JObject lastLevel = main;
for (int i = 0; i < nesting.Length; i++)
{
if (i == nesting.Length - 1)
{
lastLevel[nesting[i]] = new JValue(prop.GetValue(value));
}
else
{
if (lastLevel[nesting[i]] == null)
{
lastLevel[nesting[i]] = new JObject();
}
lastLevel = (JObject)lastLevel[nesting[i]];
}
}
}
serializer.Serialize(writer, main);
}
}
Если Вы только хотите удалить запаздывающие наклонные черты с, ПОЛУЧАЮТ запросы, используют ниже:
RewriteCond %{REQUEST_METHOD} =GET
RewriteRule ^(.*)/$ /$1 [L,R=301]
изменить правило перезаписи на:
RewriteRule ^(.+[^/])/$ http://%{HTTP_HOST}/$1 [R=301,L]
на английском языке: сопоставить начало строки, одно или несколько значений, НЕ косую черту, косую черту, конец.
^(.+[^/])/$
Т.е. передний символ не должен быть косой чертой.