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、Delete) を削除しました。GET現在、43 の Id で指定された Venue ですべてのイベントを返すようなリクエストを行うことができるようにセットアップしました。また、新しい Venue を作成することhttp://example.com/API/Venue/43/Eventsもできます。その会場の新しいイベントを作成できるようにしたいと考えています。POSThttp://example.com/API/VenuePOSThttp://example.com/API/Venue/43/Events

Indexアクションのパラメーターでは、現在、Modelオブジェクトは投稿されたときに会場を取得します。アクションにPOSTEvent オブジェクトを渡すと、Modelパラメーターは引き続きそれを取得します。以下に置き換えてみましT Modelたが、次の問題が発生しました。

  • object ModelPOST、次に、編集先のURL に基づいてキャストします。これにより、System.InvalidCastException
  • dynamic Model、次にそれをキャストし(T)Modelます。これはまた、System.InvalidCastException
  • dynamic Model、次にそれをキャストしModel as Tます。Modelその場合はnull、キャストが失敗したことを意味します
  • IModelBase Model、モデルバインダーがインスタンス化しようとするため機能しないインターフェース

dynamic私は aがうまくいったと思っていたでしょうが、 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 に答える