views:

158

answers:

2

I've this controller

public class AdminController : Controller
{
 private IAdministratorService _administratorService;

 public AdminController(IAdministratorService administratorService)
 {
  _administratorService = administratorService;
 }
}

And I've this:

 private ModelStateDictionary _modelState;

 public AdministratorService(IRepository repository, ModelStateDictionary modelState)
 {
  _repository = repository;
  _modelState = modelState;
 }

I've configured Dependency Injection for the Controllers so it would load properly except for sending the ModelState from the Container. How do you do it?

A: 

You should really avoid such circular references. Your service class should not depend on the controller or anything in the System.Web.Mvc assembly whatsoever. It is the role of the controller or some action filter or model binder to manipulate the ModelState according to events happening in the service layer.

Darin Dimitrov
I'm in fact using a ModelStateWrapper that inherits from a IErrorDictionary. The service uses IErrorDictionary and so it is not bound to System.Web.Mvc. I've written this for the sake of simplicity
CodingTales
A: 

Here is one way to handle this problem...

Controller...

Public Class AdminController
  Inherits System.Web.Mvc.Controller

  Private _adminService as IAdminService

  Public Sub New(adminService as IAdminService)

    _adminService = adminService

    'Initialize the services that use validation...
    _adminService.Initialize(New ModelStateWrapper(Me.ModelState))

  End Sub

  ...

End Class

Service...

Public Class AdminService
  Implements IAdminService

  Private _repository As IAdminRepository
  Private _dictionary as IValidationDictionary

  Public Sub New(repository as IAdminRepository)

    _repository = repository

  End Sub

  Public Sub Initialize(dictionary As IValidationDictionary) Implements IAdminService.Initialize

    _dictionary = dictionary

  End Sub

  ...

End Class

Wrapper Interface...

Public Interface IValidationDictionary

  ReadOnly Property IsValid() As Boolean
  Sub AddError(Key as String, errorMessage as String)

End Interface

Wrapper implementation...

Public Class ModelStateWrapper
  Implements IValidationDictionary

  Private _modelState as ModelStateDictionary

  Public ReadOnly Property IsValid() As Boolean Implements IValidationDictionary.IsValid
    Get
      Return _modelState.IsValid
    End Get
  End Property

  Public Sub New(modelState as ModelStateDictionary)

    _modelState = modelState

  End Sub

  Public Sub AddError(key as string, errorMessage as string) Implements IValidationDictionary.AddError

    _modelState.AddModelError(key, errorMessage)

End Class

The use of the ModelStateWrapper allows the service classes to be loosely coupled with MVC. Although, we do have a tight coupling between the AdminController and the ModelStateWrapper because of the New statement, but I don't really care because the model state is MVC specific anyway. By doing this, you would not need to register ModelStateWrapper or ModelState with StructureMap.

In your unit tests, you could call the Initialize method on the service after creating the controller to pass in your testing model state and check the validation errors.

I know you had said you were using a ModelStateWrapper, but just wanted to add a more complete example that might help others...

Dragn1821
Even I came out with this way to solve the problem! However, you get the point... even though it's not exactly the solution
CodingTales