C# 如何使用Json格式化程序将抽象类传递给Asp.NETWebAPI?
基本上,我正在尝试使我的WebApi更通用: 型号:C# 如何使用Json格式化程序将抽象类传递给Asp.NETWebAPI?,c#,json,asp.net-web-api,C#,Json,Asp.net Web Api,基本上,我正在尝试使我的WebApi更通用: 型号: public abstract class A {} public class B : A { } 客户: using (var client = new HttpClient()) { client.BaseAddress = new Uri("http://localhost:49611/"); var aList = List<A> { new B() }; var response = awa
public abstract class A {}
public class B : A { }
客户:
using (var client = new HttpClient())
{
client.BaseAddress = new Uri("http://localhost:49611/");
var aList = List<A> { new B() };
var response = await client.PostAsJsonAsync("api/a", aList);
}
然而,这对我不起作用
但是,作为测试,如果我直接使用JsonConverter,我确实看到TypeNameHandling.Auto
工作正常:
var aList = List<A> { new B() };
var settings = new JsonSerializerSettings { TypeNameHandling = TypeNameHandling.Auto };
var str = JsonConvert.SerializeObject(aList, Formatting.Indented, settings);
var obj = JsonConvert.DeserializeObject<List<A>>(str, settings);
这是我的网站配置:
public static class WebApiConfig
{
public static void Register(HttpConfiguration config)
{
// Web API configuration and services
// Configure Web API to use only bearer token authentication.
config.SuppressDefaultHostAuthentication();
config.Filters.Add(new HostAuthenticationFilter(OAuthDefaults.AuthenticationType));
// Web API routes
config.MapHttpAttributeRoutes();
config.Routes.MapHttpRoute(
name: "DefaultApi",
routeTemplate: "api/{controller}/{id}",
defaults: new { id = RouteParameter.Optional }
);
config.formatters.clear();
config.Formatters.Add(new CustomJsonFormatter() { SerializerSettings = new JsonSerializerSettings() { TypeNameHandling = TypeNameHandling.Auto } });
}
}
有人有线索吗
更新和解决方案:
好吧,经过一番挣扎,我自己找到了答案。问题出在使用clien.PostAsJsonAsync
的客户端请求中。我必须使用另一个带有格式化程序参数的函数PostAsync
来添加typenameholling.Auto
,如下所示
var formatter = new JsonMediaTypeFormatter() { SerializerSettings = new JsonSerializerSettings() { TypeNameHandling = TypeNameHandling.Auto } };
var response = await client.PostAsync("api/a", aList, formatter);
在WebApiConfig.cs
中,使用此函数和typenameholling.Auto
,可以正确地反序列化和序列化派生类
public class CustomJsonFormatter : JsonMediaTypeFormatter
{
public override Task WriteToStreamAsync(Type type, object value, Stream writeStream, HttpContent content, TransportContext transportContext)
{
try
{
Encoding effectiveEncoding = SelectCharacterEncoding(content == null ? null : content.Headers);
if (!UseDataContractJsonSerializer)
{
using (JsonTextWriter jsonTextWriter = new JsonTextWriter(new StreamWriter(writeStream, effectiveEncoding)) { CloseOutput = false })
{
if (Indent)
{
jsonTextWriter.Formatting = Newtonsoft.Json.Formatting.Indented;
}
JsonSerializer jsonSerializer = JsonSerializer.Create(this.SerializerSettings);
jsonSerializer.Serialize(jsonTextWriter, value, type); //NOTE: passing in 'type' here
jsonTextWriter.Flush();
}
}
else
{
return base.WriteToStreamAsync(type, value, writeStream, content, transportContext);
}
return TaskHelpers.Completed();
}
catch (Exception e)
{
return TaskHelpers.FromError(e);
}
}
}
internal class TaskHelpers
{
private static readonly Task _defaultCompleted = FromResult<AsyncVoid>(default(AsyncVoid));
/// <summary>
/// Used as the T in a "conversion" of a Task into a Task{T}
/// </summary>
private struct AsyncVoid
{
}
internal static Task<TResult> FromResult<TResult>(TResult result)
{
TaskCompletionSource<TResult> tcs = new TaskCompletionSource<TResult>();
tcs.SetResult(result);
return tcs.Task;
}
/// <summary>
/// Returns an error task. The task is Completed, IsCanceled = False, IsFaulted = True
/// </summary>
internal static Task FromError(Exception exception)
{
return FromError<AsyncVoid>(exception);
}
/// <summary>
/// Returns an error task of the given type. The task is Completed, IsCanceled = False, IsFaulted = True
/// </summary>
/// <typeparam name="TResult"></typeparam>
internal static Task<TResult> FromError<TResult>(Exception exception)
{
TaskCompletionSource<TResult> tcs = new TaskCompletionSource<TResult>();
tcs.SetException(exception);
return tcs.Task;
}
/// <summary>
/// Returns a completed task that has no result.
/// </summary>
internal static Task Completed()
{
return _defaultCompleted;
}
}
public static class WebApiConfig
{
public static void Register(HttpConfiguration config)
{
// Web API configuration and services
// Configure Web API to use only bearer token authentication.
config.SuppressDefaultHostAuthentication();
config.Filters.Add(new HostAuthenticationFilter(OAuthDefaults.AuthenticationType));
// Web API routes
config.MapHttpAttributeRoutes();
config.Routes.MapHttpRoute(
name: "DefaultApi",
routeTemplate: "api/{controller}/{id}",
defaults: new { id = RouteParameter.Optional }
);
config.formatters.clear();
config.Formatters.Add(new CustomJsonFormatter() { SerializerSettings = new JsonSerializerSettings() { TypeNameHandling = TypeNameHandling.Auto } });
}
}
var formatter = new JsonMediaTypeFormatter() { SerializerSettings = new JsonSerializerSettings() { TypeNameHandling = TypeNameHandling.Auto } };
var response = await client.PostAsync("api/a", aList, formatter);