1

我正在创建一个通用 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 };
    }

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

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

  • object Model,然后根据它被POST编辑到的 URL 进行转换。这给出了一个System.InvalidCastException
  • dynamic Model,然后用(T)Model. 这也给出了一个System.InvalidCastException
  • dynamic Model,然后用Model as T. Modelis then null,意味着演员阵容失败
  • IModelBase Model, 一个接口,它不起作用,因为模型绑定器试图实例化它

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

4

1 回答 1

2

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

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 方法中发现了正在POST编辑的 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;
    }
}

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

于 2013-03-26T13:54:42.960 回答