0

我开始遇到一个奇怪的问题。

我有一个 ASP.NET 项目,其中有一个接受 POST 参数的 API。由于我使用接口,因此我使用自定义反序列化器来读取 POST 对象。它工作正常,直到最后几天。但是,有一天我开始收到 500 - 内部服务器错误,说“无法创建接口的实例......通过 CreateModel”。当时,我正在使用 PostMan 应用程序。由于代码几乎没有变化,我认为可能是 PostMan 应用程序损坏了。

我不确定,所以我在 Fiddler 上尝试了相同的查询,它运行良好。现在,3-4 天后,Fiddler 也停止工作,出现同样的错误。

深入研究后,我发现“BindModel”以某种方式开始执行可能在 ActionFilterAttribute 之前。我只是不确定这怎么可能。有什么办法可以克服这种情况吗?我发布的 http 调用只是没有进入 JsonFilter 的 OnActionExecuting 方法

错误信息:

[MissingMethodException:无法创建接口的实例。]
System.RuntimeTypeHandle.CreateInstance(...)
System.RuntimeType.CreateInstanceSlow(...)
System.Activator.CreateInstance(...)
System.Activator.CreateInstance(.. .)
System.Web.Mvc.DefaultModelBinder.CreateModel(...)

[MissingMethodException:无法创建接口的实例。对象类型'MyCommonObj.IMyInterface'。]
System.Web.Mvc.DefaultModelBinder.CreateModel(...)
System.Web.Mvc.DefaultModelBinder.BindComplexModel(...)
System.Web.Mvc.DefaultModelBinder.BindModel(... )

代码片段:

public class JsonFilter : ActionFilterAttribute {
    public string Parameter { get; set; }
    public Type JsonDataType { get; set; }

    public override void OnActionExecuting(ActionExecutingContext filterContext) {
        if (filterContext.HttpContext.Request.ContentType.Contains("application/json")) {
            string inputContent;
            filterContext.HttpContext.Request.InputStream.Position = 0;
            using (var sr = new StreamReader(filterContext.HttpContext.Request.InputStream)) {
                inputContent = sr.ReadToEnd();
            };

            var jsonSerializerSettings = new JsonSerializerSettings() {
                TypeNameHandling = TypeNameHandling.All
            };

            if (JsonDataType == typeof(MyClass)) {
                var result = JsonConvert.DeserializeObject<MyClass>(inputContent, jsonSerializerSettings);
                filterContext.ActionParameters[Parameter] = result;
            }
            else {
                throw new NotImplementedException();
            }
        }
    }
}

[HttpPost]
[JsonFilter(Parameter = "config", JsonDataType = typeof(MyClass))]
public ActionResult ExecuteApi(MyClass config) {
    var result = DoSomething(config);
    return Json(result);
}

public interface IMyInterface {
    string GetValue();
}

public class MyDerivedClass : IMyInterface {
    public string Value { get; set; }

    public MyDerivedClass(string v) {
        Value = v;
    }

    public string GetValue() { return Value; }
}

public class Query {
    [JsonProperty(TypeNameHandling = TypeNameHandling.All)] 
    public IMyInterface type { get; set; }

    public Query () {}
}

public class MyClass {
    List<Query> myList { get; set; }

    public MyClass () {}
}
4

1 回答 1

1

动作过滤器总是在模型绑定器之后运行。如果您需要在模型绑定器之前运行过滤器,则应使用IAuthorizationFilter.

[AttributeUsage(AttributeTargets.Method | AttributeTargets.Class, AllowMultiple = false)]
public class JsonFilter : Attribute, IAuthorizationFilter
{
    public string Parameter { get; set; }
    public Type JsonDataType { get; set; }

    public void OnAuthorization(AuthorizationContext filterContext)
    {
        if (filterContext.HttpContext.Request.ContentType.Contains("application/json"))
        {
            string inputContent;
            filterContext.HttpContext.Request.InputStream.Position = 0;
            using (var sr = new StreamReader(filterContext.HttpContext.Request.InputStream))
            {
                inputContent = sr.ReadToEnd();
            };

            var jsonSerializerSettings = new JsonSerializerSettings()
            {
                TypeNameHandling = TypeNameHandling.All
            };

            if (JsonDataType == typeof(MyClass))
            {
                var result = JsonConvert.DeserializeObject<MyClass>(inputContent, jsonSerializerSettings);
                filterContext.ActionParameters[Parameter] = result;
            }
            else
            {
                throw new NotImplementedException();
            }
        }
    }
}
于 2016-04-20T09:07:08.310 回答