-1

Sometimes you need to pass some extra data to the view. For example news groups in the adding news page, should be retrieved from database.

I know that creating instance of Db-context in view is not a good practice for doing that. instead we can add some properties to the view model and pass these data to the view or using View-Bag and type-cast it, but in these cases you may need to do write some code in HttpGet and HttpPost the same when you need to return the same view in Get and Post methods.

Whats the best practice for doing such operations? is there another way write it once?

  • use a view model (https://stackoverflow.com/questions/14423056/why-do-we-use-viewmodels) – Fran Aug 02 '17 at 15:18
  • Thanks for answers, As I told, I know how to pass these extra data in View-Model, what a View-Model is, how and why we should use this View-Model for separation between business logic and UI logic. – farrokh charoghchi Aug 03 '17 at 06:05
  • I was wondering if there is another way that match these cases better. Any other ideas to keep View-Model simple? – farrokh charoghchi Aug 03 '17 at 06:12

3 Answers3

1

As I understand it, you seem to have a handle on what you need to do, but don't like the code duplication between get and post actions. For that, simply factor out the common code into a protected or private method on the controller that both actions can call. For example, let's say you needed a select list of Foo items:

public class MyViewModel
{
    ...
    public IEnumerable<SelectListItem> FooOptions { get; set; }
}

Then:

public class MyController : Controller
{
    ...

    private void PopulateFooOptions(MyViewModel model)
    {
        var foos = db.Foos.ToList();
        model.FooOptions = foos.Select(f => new SelectListItem { Value = f.Id.ToString(), f.Name });
    }

    public ActionResult Create()
    {
        var model = new MyViewModel();
        PopulateFooOptions(model);
        return View(model);
    }

    [HttpPost]
    public ActionResult Create(MyViewModel model)
    {
        if (ModelState.IsValid)
        {
            // do stuff
        }

        PopulateFooOptions(model);
        return View(model);
    }
}
Chris Pratt
  • 232,153
  • 36
  • 385
  • 444
0

To write a component just once and reuse it in different views, package the component into its own action, with its own ViewModel and Partial View.

If it does not make sense that this action can be called from externally on its own, attribute it as [ChildActionOnly]. Database access should happen in this child action, data should be passed to the View using the ViewModel.

Render the HTML generated by this action when needed using @Html.Action("{actionName}", "{controllerName}").

For example:

NewsController contains child action:

[ChildActionOnly]
public PartialViewResult ShowNewsGroups(long userId) {

    var data = // ... read from DB using userId parameter
    var vm = new ShowNewsGroupsViewModel {
           GroupInfos = data
    };

    return PartialView("_ShowNewsGroups", vm);
}

Partial View _ShowNewsGroups.cshtml renders the news groups:

@model ShowNewsGroupsViewModel 
@for(var i = 0; i < Model.GroupInfos.Count(); i++) {
    @Html.DisplayFor(m => m.GroupInfos[i])
}

Main View calls child action and passes required parameter:

@Html.Action("ShowNewsGroups", "News", new { userId = Model.UserId }))
Georg Patscheider
  • 9,357
  • 1
  • 26
  • 36
0

For this specifc reason we use the ViewModel concept its nothing but just a model with needing property

for example let say you have a model called test now you want to pass some additional property like boolean of isValid and a datetime Created so

your view =model will be

public class YourViewMode
{
public test mainModel{get;set;}
public bool isValid {get;set;}
public datetime Created {get;set;}
}

now just initialize this model to your view this is how basically viewmodel works

RAHUL S R
  • 1,569
  • 1
  • 11
  • 20