【问题标题】:AspNet WebApi Polymorphic Parameter via Json $type convention not deserializing通过 Json $type 约定的 AspNet WebApi 多态参数未反序列化
【发布时间】:2018-02-01 21:30:56
【问题描述】:

所以问题来了,我实际上是在 Sitecore 中这样做的,但我非常沮丧,我推出了一个新的样板 WebApi 项目,只是为了找到我的问题。

我的断言是,鉴于以下请求,

/api/Simple/AspNetJsonDeserializing?instance={%20"$type":%20"SimpleWebApi.Controllers.ConcreteTestInstance,%20SimpleWebApi",%20"hostName":%20"google.com"%20}

我应该在我的AspNetJsonDeserializing 操作方法中为ITestInstance 实例获取ConcreteTestInstance 的非空参数值。

但是,我收到以下异常:

无法创建接口的实例。

相反,如果我使用我的 NewtonsoftJsonDeserializing 操作方法,并传递一个 jsonString 并使用 Newtonsoft JsonConvert 显式反序列化它,它将很好地反序列化。

我做错了什么?

这是所有代码

Json

{  
    "$type": "SimpleWebApi.Controllers.ConcreteTestInstance, SimpleWebApi", 
    "hostName": "google.com"  
}

控制器/动作

[JsonInterfaceBindingAndNonDefaultConstructors]
public class SimpleController : ApiController
{
    [System.Web.Http.HttpGet]
    public JsonResult<string> NewtonsoftJsonDeserializing(string jsonString) // [FromUri] ITestInstance instance) //   
    {

        JsonSerializerSettings jsonSerializerSettingForTypeHandling = new JsonSerializerSettings { TypeNameHandling = TypeNameHandling.All, ConstructorHandling = ConstructorHandling.AllowNonPublicDefaultConstructor };
        ITestInstance instance = JsonConvert.DeserializeObject<ITestInstance>(jsonString, jsonSerializerSettingForTypeHandling);
        return Json("OK");
    }

    [System.Web.Http.HttpGet]
    public JsonResult<string> AspNetJsonDeserializing([FromUri] ITestInstance instance)
    {
        return Json($"Uri:{((ConcreteTestInstance)instance)._instanceUri}");
    }
}

用于修改 SerializerSettings 的属性

[AttributeUsage(AttributeTargets.Class)]
public class JsonInterfaceBindingAndNonDefaultConstructors : Attribute, IControllerConfiguration
{
    public void Initialize(HttpControllerSettings controllerSettings, HttpControllerDescriptor controllerDescriptor)
    {
        IEnumerable<JsonMediaTypeFormatter> jsonFormatters = controllerSettings.Formatters.OfType<JsonMediaTypeFormatter>();
        foreach (var jsonFormatter in jsonFormatters)
        {
            jsonFormatter.SerializerSettings.ContractResolver = new DefaultContractResolver();  //new JsonContractResolver(new JsonMediaTypeFormatter() {});
            jsonFormatter.SerializerSettings.TypeNameHandling = TypeNameHandling.All;
            jsonFormatter.SerializerSettings.ConstructorHandling = ConstructorHandling.AllowNonPublicDefaultConstructor;
        }
    }
}

界面

public interface ITestInstance
{
}

具体子类

public class ConcreteTestInstance : ITestInstance
{
    private const string SCHEME = "http://";
    private const int PORT = 80;
    private const string API_PATH = "/";
    private const string QUERYSTRING = "";


    public readonly Uri _instanceUri;

    public ConcreteTestInstance(string hostName)
    {
        _instanceUri = new UriBuilder(SCHEME, hostName, PORT, API_PATH, QUERYSTRING).Uri;
    }
}

异常:无法创建接口实例。

<Error>
<Message>An error has occurred.</Message>
<ExceptionMessage>Cannot create an instance of an interface.</ExceptionMessage>
<ExceptionType>System.MissingMethodException</ExceptionType>
<StackTrace>
at System.RuntimeTypeHandle.CreateInstance(RuntimeType type, Boolean publicOnly, Boolean noCheck, Boolean& canBeCached, RuntimeMethodHandleInternal& ctor, Boolean& bNeedSecurityCheck) at System.RuntimeType.CreateInstanceSlow(Boolean publicOnly, Boolean skipCheckThis, Boolean fillCache, StackCrawlMark& stackMark) at System.RuntimeType.CreateInstanceDefaultCtor(Boolean publicOnly, Boolean skipCheckThis, Boolean fillCache, StackCrawlMark& stackMark) at System.Activator.CreateInstance(Type type, Boolean nonPublic) at System.Activator.CreateInstance(Type type) at System.Web.Http.ModelBinding.Binders.MutableObjectModelBinder.CreateModel(HttpActionContext actionContext, ModelBindingContext bindingContext) at System.Web.Http.ModelBinding.Binders.MutableObjectModelBinder.EnsureModel(HttpActionContext actionContext, ModelBindingContext bindingContext) at System.Web.Http.ModelBinding.Binders.MutableObjectModelBinder.BindModel(HttpActionContext actionContext, ModelBindingContext bindingContext) at System.Web.Http.Controllers.HttpActionContextExtensions.Bind(HttpActionContext actionContext, ModelBindingContext bindingContext, IEnumerable`1 binders) at System.Web.Http.ModelBinding.Binders.CompositeModelBinder.BindModel(HttpActionContext actionContext, ModelBindingContext bindingContext) at System.Web.Http.ModelBinding.ModelBinderParameterBinding.ExecuteBindingAsync(ModelMetadataProvider metadataProvider, HttpActionContext actionContext, CancellationToken cancellationToken) at System.Web.Http.Controllers.HttpActionBinding.<ExecuteBindingAsyncCore>d__0.MoveNext() --- End of stack trace from previous location where exception was thrown --- at System.Runtime.CompilerServices.TaskAwaiter.ThrowForNonSuccess(Task task) at System.Runtime.CompilerServices.TaskAwaiter.HandleNonSuccessAndDebuggerNotification(Task task) at System.Web.Http.Controllers.ActionFilterResult.<ExecuteAsync>d__2.MoveNext() --- End of stack trace from previous location where exception was thrown --- at System.Runtime.CompilerServices.TaskAwaiter.ThrowForNonSuccess(Task task) at System.Runtime.CompilerServices.TaskAwaiter.HandleNonSuccessAndDebuggerNotification(Task task) at System.Web.Http.Controllers.AuthenticationFilterResult.<ExecuteAsync>d__0.MoveNext() --- End of stack trace from previous location where exception was thrown --- at System.Runtime.CompilerServices.TaskAwaiter.ThrowForNonSuccess(Task task) at System.Runtime.CompilerServices.TaskAwaiter.HandleNonSuccessAndDebuggerNotification(Task task) at System.Web.Http.Dispatcher.HttpControllerDispatcher.<SendAsync>d__1.MoveNext()
</StackTrace>
</Error>

【问题讨论】:

    标签: json asp.net-web-api json.net


    【解决方案1】:

    只是一个快速更新。

    我改变了一些东西,带来了一些新的结果。

    首先我将AspNetJsonDeserializing 属性切换为HttpPost

    我也将AspNetJsonDeserializing参数ITestInstance instance属性切换为[FromBody]

    现在显然,这迫使我通过 PostMan 调用它。

    现在所有这些都删除了异常,但实例为空。在 ConcreteTestInstance 构造函数上没有遇到断点(我添加了另一个零参数构造函数以双向验证它)。

    以下是所有变化。

    [System.Web.Http.HttpPost]
    public JsonResult<string> AspNetJsonDeserializing([FromBody] ITestInstance instance)
    {
        ConcreteTestInstance myConcreteTestInstance = ((ConcreteTestInstance) instance);
        return Json($"Uri:{myConcreteTestInstance._instanceUri}");
    }
    

    这么短的故事,我还在寻找,为什么instance 为空

    【讨论】:

      【解决方案2】:

      另一个更新。

      我的代码现在可以与 HttpPost 一起使用。问题是 json 格式:FACEPALM:

      在 PostMan 中我使用的格式是

      {instance: {  
          "$type": "SimpleWebApi.Controllers.ConcreteTestInstance, SimpleWebApi", 
          "hostName": "google.com"  
      }}
      

      当我删除实例变量时,它纠正了问题。

      另外,我测试过,ITestInstance 参数上的[FromBody] 属性是不相关的。

      所以问题仍然存在,如何将这个功能作为 HttpGet 启用

      目前,当我将属性从 HttpPost 切换到 HttpGet 时,我开始收到第一篇文章中提到的异常。

      【讨论】:

        猜你喜欢
        • 1970-01-01
        • 1970-01-01
        • 2016-08-31
        • 1970-01-01
        • 1970-01-01
        • 2016-04-25
        • 2017-10-31
        • 1970-01-01
        • 2019-12-13
        相关资源
        最近更新 更多