AspNet WebApi多态参数通过Json $类型约定而非反序列化

时间:2018-02-01 21:30:56

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

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

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

  

/ API /简单/ AspNetJsonDeserializing实例= {%20 “$类型”:%20 “SimpleWebApi.Controllers.ConcreteTestInstance,%20SimpleWebApi” %20 “主机名”:%20 “google.com” %20} <? / p>

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

但是,我收到以下异常:

  

无法创建界面实例。

相反,如果我使用我的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>

2 个答案:

答案 0 :(得分:0)

快速更新。

我改变了一些事情,这些事情提供了一些新的结果。

首先,我已将AspNetJsonDeserializing属性切换为HttpPost

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

显然现在,如果强迫我通过PostMan调用它。

所有这些现在都删除了异常,但实例为null。在ConcreteTestInstance构造函数上没有命中断点(我添加了另一个零参数构造函数来两种方式验证它。)

以下是所有变化。

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

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

答案 1 :(得分:0)

另一个更新。

我现在已经使用HttpPost处理了代码。问题是json格式:FACEPALM:

在PostMan中,我使用的格式是

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

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

此外,我测试过,ITestInstance参数的[FromBody]属性无关紧要。

所以问题仍然是我如何以HttpGet 启用此功能。

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