Fetching data within an ASP.NET MVC ViewModel class?

前端 未结 6 1231
清歌不尽
清歌不尽 2021-01-30 18:36

For those that create ViewModels (for use by typed views) in ASP.NET MVC, do you prefer to fetch the data from a service/repository from within the ViewModel, or the controller

6条回答
  •  情深已故
    2021-01-30 19:21

    I wouldn't be fetching data from the database in your ViewModel. The ViewModel exists to promote separation of concerns (between your View and your Model). Tangling up persistance logic in there kind of defeats the purpose.

    Luckily, the ASP.NET MVC framework gives us more integration points, specifically the ModelBinder.

    I've got an implementation of a generic ModelBinder pulling information from the service layer at:-

    http://www.iaingalloway.com/going-further-a-generic-servicelayer-modelbinder

    It doesn't use a ViewModel, but that's easily fixed. It's by no means the only implementation. For a real-world project, you're probably better off with a less generic, more customised solution.

    If you're diligent, your GET methods don't even need to know that the service layer exists.

    The solution probably looks something like:-

    Controller action method:-

    public ActionResult Details(MyTypeIndexViewModel model)
    {
      if( ModelState.IsValid )
      {
        return View(model);
      }
      else
      {
        // Handle the case where the ModelState is invalid
        // usually because they've requested MyType/Details/x
        // and there's no matching MyType in the repository
        // e.g. return RedirectToAction("Index")
      }
    }
    

    ModelBinder:-

    public object BindModel
    (
      ControllerContext controllerContext,
      BindingContext bindingContext
    )
    {
      // Get the Primary Key from the requestValueProvider.
      // e.g. bindingContext.ValueProvider["id"]
      int id = ...;
    
      // Get an instance of your service layer via your
      // favourite dependancy injection framework.
      // Or grab the controller's copy e.g.
      // (controllerContext.Controller as MyController).Service
      IMyTypeService service = ...;
    
      MyType myType = service.GetMyTypeById(id)
    
      if (myType == null)
      {
        // handle the case where the PK has no matching MyType in the repository
        // e.g. bindingContext.ModelState.AddModelError(...)
      }
    
    
      MyTypeIndexViewModel model = new MyTypeIndexViewModel(myType);
    
      // If you've got more repository calls to make
      // (e.g. populating extra fields on the model)
      // you can do that here.
    
      return model;
    }
    

    ViewModel:-

    public class MyTypeIndexViewModel
    {
      public MyTypeIndexViewModel(MyType source)
      {
        // Bind all the properties of the ViewModel in here, or better
        // inherit from e.g. MyTypeViewModel, bind all the properties
        // shared between views in there and chain up base(source)
      }
    }
    

    Build your service layer, and register your ModelBinder as normal.

提交回复
热议问题