Creating MVC3 ValueProviderFactories That Require Type Information?

坚强是说给别人听的谎言 提交于 2020-01-23 12:05:37

问题


I'm attempting to write a Protobuf ValueProviderFactory for ASP MVC3. I've managed to work out how to add the factories, but now I've stumbled on a more pressing problem. Here is where the current serialization takes place in JsonValueProviderFactory.cs

    JavaScriptSerializer serializer = new JavaScriptSerializer();
    object jsonData = serializer.DeserializeObject(bodyText);
    return jsonData;

So the deserialization is accomplished without any type information? What sort of object does DeserializeObject return? A Dynamic? How does it know the type of data? I was hoping to slot protobuf-net in here but it obviously needs a type to do its magic!

I haven't looked through all the MVC3 source, but I'm guessing the mapping to types occurs at the final stage, and there is no way to know of the types in the ValueProviderFactories?

Will I have to give up and do the conversion in the actions?


回答1:


There are a few questions here.

For how JavaScriptSerializer works you should read the documentation. The class tries to infer the type for basic types (int, bool, date, etc) and returns Dictionary<string, object> for more complex cases. In addition if the JSON blob contains a special property called "__type" then the deserializer will try to create an object of that type.

Now for how this works in MVC. The process of mapping values from a request to an object instance used in your controller is called model binding. This is split into two components: ModelBinder and ValueProviders. The model binder knows the target type (e.g. Product), tries to create an instance of it, and then populate its properties with values from the request. It does so by asking the ValueProviders. For example, to set the Name property on the Product instance it asks the value providers for the value of "Name". The value providers get queried in sequence and return a match (from query string, post data, JSON request body, etc).

There's lots of resources about this on the web, but in short value providers shouldn't really be concerned with types.




回答2:


Here is a quick stab at a solution using a ModelBinder, as suggested by marcind. It's untested, but it's a start. In this case FromProtobuf<T> is a simple byte[] to object extension method.

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>();
        }
    }
}

This could be setup as follows:

ModelBinders.Binders.Add(typeof(MyClass), new ProtobufModelBinder<MyClass>());


来源:https://stackoverflow.com/questions/6902885/creating-mvc3-valueproviderfactories-that-require-type-information

易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!