I am creating a generic JSON API to handle any object with as little additional coding per object required. Here is the BaseController from which all other controllers (EmployeeController, ProductController, etc.) inherit:
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 };
}
I've removed some irrelevant code (Get, Delete). Right now, I have it set up so you can make GET
requests to something like http://example.com/API/Venue/43/Events
, which will return all the events at the Venue specified by the Id of 43. You are also able to POST
to http://example.com/API/Venue
to create a new Venue. I would like to be able to POST
to http://example.com/API/Venue/43/Events
to create a new Event for that Venue.
In the parameters for the Index
action, right now the Model
object picks up the Venue when it is posted. When I POST
an Event object to the action, the Model
parameter still picks it up. I have tried replacing T Model
with the following, resulting in the following issues:
object Model
, then casting it based on what URL it was POST
ed to. This gives a System.InvalidCastException
dynamic Model
, then casting it with (T)Model
. This also gives a System.InvalidCastException
dynamic Model
, then casting it with Model as T
. Model
is then null
, meaning the cast failed IModelBase Model
, an interface, which doesn't work because the modelbinder tries to instantiate it I would have thought that a dynamic
would have worked, but I can't seem to avoid the InvalidCastException
. The above code works, BTW, for the controller's object ( POST
ing a Venue to http://example.com/API/Venue
).
This might have been a little vague, but hopefully my solution will help anybody who happens to unfortunately end up here. Firstly, I removed the Model
parameter from the Index action. I then created the following helper class:
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);
}
}
I then discovered, in the internal Post method, what URL was being POST
ed to, then used the following helper class to construct the proper object:
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;
}
}
This needs to be refactored to deal with weird cases, but I have not run into any problems so far.
The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.