views:

45

answers:

1

I am sort of new to MVC so pardon my ignorance. I am using IoC ( StructureMap ) and I have a need to pass in an instance of what I consider to be a set of Controls to each view, so I have created ViewModels in order to accomodate this. The view model is populated with an instance of the Controls and the View is then rendered. When a user performs a POST, the Controls are not being passed back to the Action.

Snip from the Controller

Private _WebControls As Products.Services.IControlsRepository
Private _customerRepo As Profiles.Services.ICustomerRepository

Sub New()
    Me.New(ObjectFactory.GetInstance(Of Products.Services.IControlsRepository),
           ObjectFactory.GetInstance(Of Profiles.Services.ICustomerRepository))
End Sub

Sub New(ByVal webRepo As Products.Services.IControlsRepository, 
        ByVal custRepo As Profiles.Services.ICustomerRepository)
    _WebControls = webRepo
    _customerRepo = custRepo
End Sub

<HttpGet()>
Function SendPassword() As ActionResult
    Dim vm As New SendPasswordViewModel
    vm.Controls = _WebControls
    Return View(vm)
End Function
<HttpPost()>
Function SendPassword(ByVal model As SendPasswordViewModel) As ActionResult
    If ModelState.IsValid Then
        If _customerRepo.SendPassword(model.EmailAddress, model.Controls.WebControls.MacsDivision) = True Then
            model.SendPasswordResponseMessage = "Email successfully sent.  Please check your email for your password."
        Else
            model.SendPasswordResponseMessage = "No account was found with the email that you provided."
        End If
    End If
    Return View("SendPassword", model)
End Function
A: 

As I understand it your controller uses constructor injection and depends on IControlsRepository and ICustomerRepository. As a new controller instance is created on each request this means that your controller will always have access to the private fields where you stored those repositories (_WebControls and _customerRepo). As a consequence to this you don't need to have the Controls property of SendPasswordViewModel. In your POST action you could directly use it:

<HttpPost()>
Function SendPassword(ByVal model As SendPasswordViewModel) As ActionResult
    ' Directly use _WebControls here instead of relying on model.Controls
    ...
End Function

So remove the Controls property of the SendPasswordViewModel class as the view doesn't need a repository. It's the controller that works with the repository.

Darin Dimitrov
Thanks for the quick Reply. I did figure that part out about utilizing the private _WebControls object, which works. I do however still need to pass it to the ViewModel as some of the values within the _WebControls dictate what Partial view is rendered. I guess I was looking more for an answer as to whether or not the Controls should have been passed through on the post since they were present during the Get.
If you are passing a repository to your view it means that you are doing MVC all wrong. When you invoke a controller action the model binder will automatically populate the object that is passed in parameter based on the Request values. Having a repository in a view model will never be populated as never passed in the request. As a conclusion don't expect from the model binder to instantiate you such an interface in the view model on the POST action. Furthermore you don't need it as you already have it as a controller field.
Darin Dimitrov
As an addition you are saying that this repository dictates which partial is rendered. If this is the case you could use simple boolean or string properties to your view model that will indicate this and have the controller use the repository and populate them.
Darin Dimitrov
The WebControls is really just a simple class with properties that are used as parameters in almost every other repository call as well as properties that are used to determine partial views much like the following:<% Html.RenderPartial(String.Format("masthead{0}", Model.Controls.WebControls.SiteId), Model.Controls.WebControls)%>