Derive Model from Another Model
In my ASP.Net MVC 3 project, I'd like to have a base class model object that has certain properties that I will then use in all of the other models in my application (or at least most of them). That way, the views that use these derived models will also have the base class model properties.
The base class model properties could be set in, say a base class controller, and then somehow I need to populate the derived models with that same data. Any suggestions on how to best get 'er done?
Or should I be looking into creating my own DefaultModelBinder somehow? I'm a little confused as to my op开发者_StackOverflow社区tions here. As if you couldn't tell. :)
Sample Code
Base Model
public class ElkModel
{
public bool IsAdministrator { get; set; }
}
Derived Model
public class UserModel : ElkModel
{
[HiddenInput]
public int User_ID { get; set; }
// Other properties specific to this model
}
So in the base controller
private BaseModel baseModel;
protected override void OnActionExecuting(ActionExecutingContext filterContext)
{
baseModel = new baseModel();
baseModel.MyProperty = "test";
base.OnActionExecuting(filterContext);
}
And in the derived controller action method
public ActionResult Index()
{
// Derives from the base model in the base controller
UserModel model = new UserModel();
// model.IsAdministrator where IsAdministrator is a property of the base Model not UserModel
return View(model);
}
If you need this 'common data' across all views, I would not throw inheritance in the mix. I would go for an extension method.
Something along the lines of:
public static CommonData GetCommonData(this HtmlHelper htmlhelper)
{
// do your magic here
}
In your View you could then simply call:
@Html.GetCommonData()...
That way you keep your models cleaner.
Inheritance might be a valid approach, if this Common Data really 'fits' well with your Model classes.
It would help if you provided some examples ;-)
** EDIT **
I would keep your 'BaseModel' as a property in the Controller and populate it on OnActionExecuting as you suggest.
But I would use ExtensionMethods on the Controller and Html helper to access the the data. If you use inheritance you will needlessly complicate things.
Let me know if you need samples of the extension methods.
This approach is DRY. You are not duplicating code.
** EDIT 2 **
Here is how your extension method should look like: (off the top of my head, so it might not compile)
public static class ExtensionHelpers
{
public static BaseModel GetCommonData(this HtmlHelper htmlhelper)
{
YourController HtmlHelper = htmlhelper.ViewContext.Controller as YourController;
if (controller != null)
{
return HtmlHelper.BaseModel;
}
return null;
}
Make sure the Controller derives from the Controller class where you add the BaseModel property. I called it 'YourController' above.
Then you should be good to go ;-)
Edit 3
Just a reminder that the namespace needs to be known if you want to use extension methods in a View. The best way to achieve this is to include the namespace in the Web.Config in your Views folder.
<system.web.webPages.razor>
<host factoryType="System.Web.Mvc.MvcWebRazorHostFactory, System.Web.Mvc, Version=3.0.0.0, Culture=neutral, PublicKeyToken=31BF3856AD364E35" />
<pages pageBaseType="System.Web.Mvc.WebViewPage">
<namespaces>
<add namespace="System.Web.Mvc" />
<add namespace="System.Web.Mvc.Ajax" />
<add namespace="System.Web.Mvc.Html" />
<add namespace="System.Web.Routing" />
<add namespace="Yournamespace" /> <- LOOK HERE
</namespaces>
</pages>
</system.web.webPages.razor>
Depends a little on if you're talking about the incoming model or the outgoing model (i.e. the viewmodel served up or the model param being posted by a form).
In the former case, it's pretty easy to do it as you suggested; via a base controller that populates the model w/ the common info before or after the action executes (overriding OnActionExecuting or OnActionExecuted). You can also use an ActionFilter which may be more flexible in that it doesn't require you to follow one inheritance chain for all your controllers. I tend to recommend the latter approach for that very reason.
On the form post side, you may need to create your own Model Binder, but only if you have some reason you want to have a single action take in more than one type of the model, and frankly that could get hairy. In that case you'd have to have the actual type name be put into a hidden form elemetn or something so that your model binder can ascertain which model to instantiate. I'd recommend against this approach unless you have a compelling reason for it.
精彩评论