我正在尝试为ASP MVC3编写一个Protobuf ValueProviderFactory。我已经设法解决how to add the factories,但现在我偶然发现了一个更紧迫的问题。
以下是JsonValueProviderFactory.cs
JavaScriptSerializer serializer = new JavaScriptSerializer();
object jsonData = serializer.DeserializeObject(bodyText);
return jsonData;
所以反序列化是在没有任何类型信息的情况下完成的吗? DeserializeObject
返回什么样的对象?一个动态?它是如何知道数据类型的?我希望在这里插入protobuf-net,但它显然需要一种类型才能发挥其魔力!
我没有查看所有的MVC3源代码,但我猜测到类型的映射是在最后阶段发生的,而且没有办法知道ValueProviderFactories中的类型?
我是否必须放弃并在行动中进行转换?
答案 0 :(得分:2)
这里有几个问题。
有关JavaScriptSerializer
的工作原理,请阅读documentation。该类尝试推断基本类型的类型(int,bool,date等),并为更复杂的情况返回Dictionary<string, object>
。此外,如果JSON blob包含一个名为“__type”的特殊属性,则反序列化器将尝试创建该类型的对象。
现在了解它如何在MVC中运行。将值从请求映射到控制器中使用的对象实例的过程称为模型绑定。它分为两个组件:ModelBinder和ValueProviders。模型绑定器知道目标类型(例如Product),尝试创建它的实例,然后使用请求中的值填充其属性。它通过询问ValueProviders来实现。例如,要在Product实例上设置Name属性,它会向值提供程序询问“Name”的值。值提供程序按顺序查询并返回匹配项(从查询字符串,发布数据,JSON请求体等)。
网上有很多关于此的资源,但简而言之,价值提供者不应该真正关注类型。
答案 1 :(得分:1)
正如marcind所建议的,这是使用ModelBinder的快速解决方案。这是未经测试的,但这是一个开始。在这种情况下,FromProtobuf<T>
是一个简单的byte[]
对象扩展方法。
public class ProtobufModelBinder<T> : IModelBinder
{
public object BindModel(ControllerContext controllerContext, ModelBindingContext bindingContext)
{
if (!controllerContext.HttpContext.Request.ContentType.StartsWith("application/x-protobuf", StringComparison.OrdinalIgnoreCase))
return null;
using (MemoryStream ms = new MemoryStream())
{
controllerContext.HttpContext.Request.InputStream.CopyTo(ms);
return ms.ToArray().FromProtobuf<T>();
}
}
}
这可以设置如下:
ModelBinders.Binders.Add(typeof(MyClass), new ProtobufModelBinder<MyClass>());