【问题标题】:JSON API action parameter for unknown object未知对象的 JSON API 操作参数
【发布时间】:2013-03-25 15:31:44
【问题描述】:

我正在创建一个通用 JSON API 来处理任何对象,每个对象所需的额外编码最少。这是所有其他控制器(EmployeeController、ProductController 等)继承的 BaseController:

public partial class BaseController<T> : Controller where T : ModelBase<T>, new()
{
    [RestHttpVerbFilter]
    public ActionResult Index (long? Id, string Property, long? PropertyId, T Model, string Format, string HttpVerb)
    {            
        switch (HttpVerb)
        {
            case "GET":
                return Json(Get(Id.Value, Property, PropertyId), JsonRequestBehavior.AllowGet);
            case "POST":
                return Json(Post(Id, Property, PropertyId, Model));
            case "PUT":
                return Json(Put(Id.Value, Property, PropertyId, Model));
            case "DELETE":
                return Json(Delete(Id, Property, PropertyId));
        }
        return Json(new { error = "Unknown HTTP verb" });
    }        

    internal object Post (long? Id, string Property, long? PropertyId, T Model)
    {
        if (!Id.HasValue && string.IsNullOrEmpty(Property) && !PropertyId.HasValue && Repository.Add(Model))
        {
            return Get(Model.ID);
        }            
        return new { error = "Unable to save new " + typeof(T).Name };
    }

    internal object Put (long? Id, string Property, long? PropertyId, T Model)
    {
        if (Id.HasValue)
        {
            Model.ID = Id.Value;
            if (string.IsNullOrEmpty(Property) && !PropertyId.HasValue && Repository.Update(Model))
            {
                return Get(Id.Value);
            }
        }
        return new { error = "Unable to update " + typeof(T).Name };
    }

我删除了一些不相关的代码(获取、删除)。现在,我已经设置好了,因此您可以向http://example.com/API/Venue/43/Events 之类的东西发出GET 请求,这将返回ID 为43 指定的地点的所有事件。您还可以将POST 发送到@987654325 @创建一个新的场地。我希望能够POSThttp://example.com/API/Venue/43/Events 为该场地创建一个新活动。

Index 操作的参数中,现在Model 对象在发布时会选择场地。当我 POST 将 Event 对象添加到操作时,Model 参数仍然会拾取它。我尝试将T Model 替换为以下内容,导致以下问题:

  • object Model,然后根据 POSTed 到的 URL 进行投射。这给出了System.InvalidCastException
  • dynamic Model,然后使用 (T)Model 进行投射。这也给出了System.InvalidCastException
  • dynamic Model,然后使用 Model as T 进行投射。 Model 则为 null,表示转换失败
  • IModelBase Model,一个接口,因为modelbinder试图实例化它而不起作用

我原以为dynamic 会起作用,但我似乎无法避免InvalidCastException。顺便说一句,上面的代码适用于控制器的对象(POSTing a Venue to http://example.com/API/Venue)。

【问题讨论】:

    标签: c# asp.net-mvc json api reflection


    【解决方案1】:

    这可能有点含糊,但希望我的解决方案能帮助那些不幸落入此地的人。首先,我从 Index 操作中删除了 Model 参数。然后我创建了以下帮助类:

    internal static class Deserializer
    {
        internal static Dictionary<string, string> Deserialize (System.Web.HttpRequestBase Request)
        {
            Request.InputStream.Position = 0;
            string Json = new StreamReader(Request.InputStream).ReadToEnd();
            return new JavaScriptSerializer().Deserialize<Dictionary<string, string>>(Json);
        }
    }
    

    然后我发现,在内部 Post 方法中,POSTed 的 URL 是什么,然后使用以下帮助程序类来构造正确的对象:

    internal static class ModelBuilder
    {
        internal static object Build (Dictionary<string, string> Model, Type ModelType)
        {
            var Instance = Activator.CreateInstance(ModelType);
            foreach (var Property in ModelType.GetProperties(BindingFlags.Public | BindingFlags.Instance | BindingFlags.DeclaredOnly))
            {
                var PropertyType = Property.PropertyType;
                if (Model.ContainsKey(Property.Name))
                {
                    Property.SetValue(Instance, Convert.ChangeType(Model[Property.Name], PropertyType), null);
                }
            }
            return Instance;
        }
    }
    

    这需要重构以处理奇怪的情况,但到目前为止我还没有遇到任何问题。

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2023-03-05
      • 1970-01-01
      • 2021-11-27
      • 1970-01-01
      • 2020-03-15
      相关资源
      最近更新 更多