Handling subtypes in ASP.NET MVC
I can't think of a "best" way of handling the following situation - basically, I have a bunch of stored objects that inherit from a base type and would like to be able to retrieve one from storage, find its subtype (perhaps via "if(x is y)") and then act accordingly - some using a shared im开发者_高级运维plementation, others with dedicated logic and views.
I guess [stripped down] this would look a little like:
/vehicle/details/1234
- Views
- Vehicle
- Details.aspx
abstract class Vehicle{
public int ID{ get; }
}
class Motorbike : Vehicle{
//whatever
}
class Car : Vehicle{
public int NoOfDoors{ get; }
}
class VehicleController : Controller{
VehicleRepository _vehicleRepository; //injected, etc
public ActionResult Details(int id){
var vehicle = _vehicleRepository.Get(id);
//we can now figure out what subtype the vehicle is
//and can respond accordingly
}
}
Now, if we weren't worried about future extension and maintenance and all that, we could go down the dark path and implement something like the following - which would function just fine, but would no doubt be[come] an absolute nightmare.
- Views
- Vehicle
- Details.aspx
- CarDetails.aspx
public ActionResult Details(int id){
var vehicle = _vehicleRepository.Get(id);
return (vehicle is Car) ? DetailsView((Car)vehicle) : DetailsView(vehicle);
}
private ActionResult DetailsView(Car car){
var crashTestResults = GetCrashTestResults(car);
var carData = new CarDetailsViewData(car, crashTestResults);
return View("CarDetails", carData);
}
private ActionResult DetailsView(Vehicle vehicle){
var vehicleData = new VehicleDetailsViewData(car, crashTestResults);
return View("Details", vehicleData);
}
Another mechanism would be to use subfolders at the view layer - which would keep the code reasonably clean, but doesn't work for my situation since I want a custom action method too...
- Views
- Vehicle
- Car
- Details.aspx
- Motorbike
- Details.aspx
public ActionResult Details(int id){
var vehicle = _vehicleRepository.Get(id);
return View(vehicle.GetType().Name + "\Details", vehicle);
}
Ideally, the solution would be a base controller and dedicated controllers with overrides where required - but since we have to pull the object from storage before we could determine that ideal controller, I can't figure out how to make that work...
My current ideas generally fall over the first hurdle of having the "VehicleController" know far too much about what those subtype overrides are so any ideas would be appreciated.
Cheers.
Two solutions I can see, depending which would lead to less duplication:
1) Have Vehicle include abstract methods GetViewName
and GetViewData
, which allows you to have multiple views but your controller doesn't need to know about them.
2) Have Vehicle include an abstract GetViewData
method which returns an object containing all of the ViewData for that class. The ViewData would then implement interfaces and your single view can condition out sections of HTML based on if (ViewData is IHasCrashTestData)
or something like that.
In most cases, I would suggest option 1 is more extensible.
I could be wrong, but it really looks to me like you're just trying to ask the question of how to render a view appropriate to the given subtype (e.g. Motorcycle or Boat or whatever).
The controller logic, aside from that different view stuff, doesn't look like it needs to be different' for each vehicle type. Are you actually trying to change the program flow based on the vehicle type, or is the controller mostly about handling the CRUD operations?
Assuming that you're just trying to change the rendered view, then have a look at MVC 2's DisplayFor and EditorFor functionaliity. That should allow you to pass down just the model type and then render an appropriate view (iirc, haven't played with it much).
If that doesn't work quite teh way you want, or if you don't want to use MVC 2 since it's just RC still, not RTM, then your next best bet is to override the ViewEngine (probably subclassing your current one) to change the logic of how views are looked up to cover either your folder-based scenario above or whatever scheme you want to apply.
Why you want to create new controller for all vehicle types. In Database N-M assocation will be simply and flexible.
VehicleTypes
->Id
->Name
VehicleTypeVariables
->Id
->Name
Vehicles
->Id
->VehicleTypeId
VehicleVariables
->Id
->VehicleId
->VehicleTypeVariableId
->Value
精彩评论