我无法让依赖注入为下面的Newtonsoft JsonConverter在.NET Core3.1中工作。
我只想在属性级别使用它,而不是在全局级别使用它。因此,只有当指定的属性来自某个类(Es)时,才应该执行它。
JsonConverter
public class HelloWorldCustomConverter : JsonConverter<string>
{
private readonly IMyService _myService;
public HelloWorldCustomConverter(IMyService myService)
{
_myService = myService;
}
public override bool CanRead => false;
public override string ReadJson(JsonReader reader, Type objectType, string existingValue, bool hasExistingValue, JsonSerializer serializer)
{
throw new NotImplementedException();
}
public override void WriteJson(JsonWriter writer, string value, JsonSerializer serializer)
{
// append a value using the injected service
writer.WriteValue($"{value}-{myService.GetValue()}");
}
}
用法:
public class MyClass
{
public string Title { get; set; }
[JsonConverter(typeof(HelloWorldCustomConverter))]
public string Details { get; set; }
}
它是.NET Core3.1和Newtonsoft.json版本13.0.1。
我很感谢你的帮助,谢谢。
编辑1
我从StackOverflow那里查了很多答案,但到目前为止没有一个对我有用。他们中的大多数人已经过时了,或者缺少了一些东西来让它发挥作用。我已经查过的几个对我没有用的:
编辑2
我试过作为重复引用的帖子,但在我的情况下不起作用。
我试着旋转我的头和各种各样的其他选择,但没有运气。
詹姆斯(日期:2108年)提出的建议之一没有奏效。
参考文献:https://github.com/JamesNK/Newtonsoft.Json/issues/1910
你可以尝试这样的方法
public class JsonOptions : IConfigureOptions<MvcJsonOptions>
{
IHttpContextAccessor _accessor;
public JsonOptions(IHttpContextAccessor accessor)
{
_accessor = accessor;
}
public virtual void Configure(MvcJsonOptions options)
{
options.SerializerSettings.Converters.Add(new MyCustomConverter(_accessor));
}
}
在你的启动中注册
services.AddSingleton<IConfigureOptions<MvcJsonOptions>, JsonOptions>()
(不记得默认情况下是否注册了IHttpContextAccessor,因此您可能也需要注册)
然后,在读/写Then方法中,使用_accessor.HttpContext访问请求的上下文
发布于 2022-02-22 18:05:08
下面是它对我的作用:
使用ContractResolver。(我在我的案例中使用转换器)。
自定义ContractResolver.根据需要更改逻辑.
using HelloWorld.Attributes;
using HelloWorld.Helpers;
using Microsoft.AspNetCore.Http;
using Microsoft.Extensions.DependencyInjection;
using Newtonsoft.Json;
using Newtonsoft.Json.Serialization;
using System;
using System.Reflection;
namespace HelloWorld.Serializers
{
public class MyCustomContractResolver : CamelCasePropertyNamesContractResolver
{
private readonly IServiceProvider _serviceProvider;
public MyCustomContractResolver(IServiceProvider serviceProvider)
{
_serviceProvider = serviceProvider;
}
protected override JsonProperty CreateProperty(MemberInfo member, MemberSerialization memberSerialization)
{
var property = base.CreateProperty(member, memberSerialization);
// this condition is specific to my case, just to showcase how I'm accessing value from HTTP Context
if (Attribute.IsDefined(member, typeof(MyCustomAttribute),true))
{
if (property.PropertyType == typeof(string))
{
PropertyInfo propertyInfo = member as PropertyInfo;
// access required services here
var contextAccessor = _serviceProvider.GetRequiredService<IHttpContextAccessor>();
var customHelper = _serviceProvider.GetRequiredService<ICustomHelper>();
var attribute = (MyCustomAttribute)member.GetCustomAttribute(typeof(MyCustomAttributeAttribute));
property.ValueProvider = new StringValueProvider(propertyInfo, customHelper, contextAccessor, attribute);
}
}
return property;
}
public class StringValueProvider : IValueProvider
{
private PropertyInfo _targetProperty;
private readonly ICustomHelper _customHelper;
private readonly IHttpContextAccessor _httpContextAccessor;
private readonly MyCustomAttribute _attribute;
public StringValueProvider(
PropertyInfo targetProperty,
ICustomHelper customHelper,
IHttpContextAccessor httpContextAccessor,
MyCustomAttribute attribute)
{
_targetProperty = targetProperty;
_customHelper = customHelper;
_httpContextAccessor = httpContextAccessor;
_attribute = attribute;
}
// SetValue gets called by Json.Net during deserialization.
// The value parameter has the original value read from the JSON;
// target is the object on which to set the value.
public void SetValue(object target, object value)
{
_targetProperty.SetValue(target, value);
}
// GetValue is called by Json.Net during serialization.
// The target parameter has the object from which to read the value;
// the return value is what gets written to the JSON
public object GetValue(object target)
{
object value = _targetProperty.GetValue(target);
var userId = _httpContextAccessor.HttpContext.Request.Headers["UserId"].ToString();
return value == null ? value : _customHelper.SetGreetingsTextForUser(value.ToString(),userId, _attribute.UserRole);
}
}
}
}
MvcNewtonsoftJsonOptionsWrapper与serviceProvider注入
using HelloWorld.Serializers;
using Microsoft.AspNetCore.Mvc;
using Microsoft.Extensions.Options;
using System;
namespace HelloWorld.Extensions
{
public class MvcNewtonsoftJsonOptionsWrapper : IConfigureOptions<MvcNewtonsoftJsonOptions>
{
IServiceProvider ServiceProvider;
public MvcNewtonsoftJsonOptionsWrapper(IServiceProvider serviceProvider)
{
this.ServiceProvider = serviceProvider;
}
public void Configure(MvcNewtonsoftJsonOptions options)
{
options.SerializerSettings.ContractResolver = new MyCustomContractResolver(ServiceProvider);
}
}
}
ServiceCollection扩展来注册ContractResolver:
public static class ServiceCollectionExtensions
{
public static IServiceCollection MyCustomContractResolver(this IServiceCollection services)
{
services.TryAddSingleton<IHttpContextAccessor, HttpContextAccessor>();
services.AddTransient<IConfigureOptions<MvcNewtonsoftJsonOptions>, MvcNewtonsoftJsonOptionsWrapper>();
return services;
}
}
在Startup.cs文件中,在DI中注册ContractResolver:
public void ConfigureServices(IServiceCollection services)
{
...
services.AddAppendSasTokenContractResolver();
...
}
就这样。如果这对你有用,请告诉我!
发布于 2022-02-22 16:43:06
从托马斯的博客文章中的评论判断,您已经尝试过他的方法。不管你是否成功地让它发挥作用,当我试图实现Thomas的hack时,我会发布我遇到的问题的解决方案--也许这会对其他人有所帮助。
在我的设置中,定制的JsonConverter
实际上不是由MVC框架直接实例化的,而是通过Newtonsoft的JToken.ToObject()
间接地进行实例化,后者创建了一个带有默认JsonSerializerSettings
的JsonSerializer
。在ToObject()
的调用链中,使用这些默认设置实例化了我的自定义JsonConverter
。
为了使的hack工作,我需要将IConfigureOptions<MvcNewtonsoftJsonOptions>.Configure()'
的实现更改为:
public void Configure(MvcNewtonsoftJsonOptions options)
{
JsonConvert.DefaultSettings = () =>
{
var settings = new JsonSerializerSettings();
settings.Converters.Add(new ServiceProviderDummyConverter(_httpContextAccessor, _serviceProvider));
return settings;
};
}
发布于 2021-10-12 16:36:50
IMHO --你想要达到的目标有很大的问题。序列化控制器方法的结果不应该包含任何逻辑。
更重要的是,您的api应该允许内容协商,其中Accept: application/json
为您提供一个json字符串,而Accept: application/xml
为您提供一个xml。
相反,您应该利用依赖注入,将MyService
注入到其他服务中,并在那里调用myResult.whatever = myService.GetValue()
。
https://stackoverflow.com/questions/69520303
复制相似问题