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?
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...
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.
Related
I am trying to use Ninject in ASP.NET MVC project. Here is my plan to use entity framework for my project-
//Web.config
<connectionStrings>
<add name="MyTestDbEntities" connectionString="...." />
</connectionStrings>
//Base controller
public abstract class BaseController : Controller
{
protected readonly MyTestDbEntities Db;
public BaseController() { }
public BaseController(MyTestDbEntities context)
{
this.Db = context;
}
}
public class HomeController : BaseController
{
public ActionResult Index()
{
Db.Students.Add(new Student() { StudentName="test"});
Db.SaveChanges();
return View();
}
}
I would like to use Ninject as follows-
kernel.Bind<MyTestDbEntities>().To<BaseController>().InRequestScope();
But it says-
The type 'NinjectTest.BaseController' cannot be used as type parameter
'TImplementation' in the generic type or method
'IBindingToSyntax<MyTestDbEntities>.To<TImplementation>()'.
There is no implicit reference conversion from 'NinjectTest.BaseController'
to 'NinjectTest.Models.MyTestDbEntities'.
Would you please suggest me how can I configure Ninject to work in the project?
what typically occurs is you bind an interface to a concrete Type that implements it, i.e.:
kernel.Bind<IMyService>().To<MyServiceImpl>();
you do not need to create a binding to be able to inject the service into every consumer (i.e., BaseController). you can use the binding anywhere by asking for it in the constructor (contructor injection), or decorating a property with [Inject] (property injection, or setter injection)
in your example, you would need to create a binding for your DbContext:
kernel.Bind<MyTestDbEntities>().ToSelf().InRequestScope();
and then it will be injected into your Controller constructors, but all Controllers that derive from BaseController will need to have that contructor that asks for the DbContext as a parameter
public HomeController(MyTestDbEntities db) : base(db) { }
however, be aware that you are creating a dependency on a concrete implementation (the DbContext), which sort of defeats the purpose of Dependency Injection.
I'm just going through some intro tutorials for ASP.NET and I've got a decent idea of how to implement a simple CRUD admin app.
Are there any commonly used patterns to implement generic List/Create/Update/Delete actions? It seems pretty tedious to have to build scaffolding for every model, and then to maintain all of the add, edit and list views and controllers. It would be a lot more efficient and less error-prone to implement generic actions like:
/List/Model
/Edit/Model/id
/Update/Model/id
/Delete/Model/id
that would handle any model.
I've done something similar, I think, to what you're talking about in an admin application I built. Basically, the key is to use generics. In other words, you create a controller like:
public abstract class AdminController<TEntity> : Controller
where TEntity : IEntity, class, new()
{
protected readonly ApplicationDbContext context;
public virtual ActionResult Index()
{
var entities = context.Set<TEntity>()
return View(entities);
}
public virtual ActionResult Create()
{
var entity = new TEntity();
return View(entity);
}
[HttpPost]
public virtual ActionResult Create(TEntity entity)
{
if (ModelState.IsValid)
{
context.Set<TEntity>().Add(entity);
context.SaveChanges();
return RedirectToAction("Index");
}
return View(entity);
}
...
}
In other words, you just build an entire reusable controller structure, with the key parts being that you're using the generic TEntity instead of a concrete class. Notice that TEntity is defined as IEntity, class, new(). This does a few things. First, class allows you to treat it as a concrete type and new() means that the type will be something that can be instantiated, rather than something like an abstract class. IEntity is just a placeholder for whatever you may be using in your application to ensure all the types have some common denominator. At the very least for a CRUD-style application, you'll need this to gain access to an Id or similar property for things like your edit and delete actions. Saying that TEntity implements IEntity lets you utilize any properties on IEntity. If you use a concrete type here instead of an interface, you can leave off the class part, e.g. where TEntity : Entity, new().
Then, in order to use this, you just define a new controller that inherits from AdminController<> and specify the type you're working with:
public class WidgetController : AdminController<Widget>
{
public WidgetController(ApplicationDbContext context)
{
this.context = context;
}
}
That could be potentially all you need for your individual controllers. Also, worth noting here is that I've set this up to employ dependency injection for your context. You could always change your constructor to something like:
public WidgetController()
{
this.context = new ApplicationDbContext();
}
But, I recommend you do look into using dependency injection, in general. Also, I'm using the context directly here for ease of explanation, but usually you'd be employing services, repositories, etc. here instead.
Finally, if you find you need to customize certain parts of a CRUD action, but not necessarily the whole thing, you can always add methods as extension points. For example, let's say you needed to populate a select list for one particular entity, you might do something like:
public abstract class AdminController<TEntity> : Controller
where TEntity : IEntity, class, new()
{
...
public virtual ActionResult Create()
{
var entity = new TEntity();
BeforeReturnView();
return View(entity);
}
...
protected virtual void BeforeReturnView()
{
}
...
And then:
public class WidgetController : AdminController<Widget>
{
...
protected override void BeforeReturnView()
{
ViewBag.MySelectList = new List<SelectListItem>
{
...
};
}
}
In other words, you have a hook in your base action method that you override to just change that particular bit of functionality instead of having to override the whole action itself.
You can also take this farther to include things like view models, where you might expand your generic class definition to something like:
public abstract class AdminController<TEntity, TEntityViewModel, TEntityCreateViewModel, TEntityUpdateViewModel>
where TEntity : IEntity, class, new()
where TEntityViewModel : class, new()
...
And then:
public class WidgetController : AdminController<Widget, WidgetViewModel, WidgetCreateViewModel, WidgetUpdateViewModel>
{
...
}
It all depends on what your application needs.
I need to setup a policy in base controller that applies to all controller instance, like below:
public class BaseController : Controller
{
private IPolicy Policy;
public BaseController()
{
this.Policy= new Policy(HttpContext);
}
}
Within the Policy class, I need to do something like:
this.httpContextBase.User.
Questions: (Update)
What is the better way to design the BaseController in terms of using HttpContext and Unit test.
What is the correct way to unit test HttpContext?
Absolutely no way. You are using the HttpContext inside the constructor of a controller when this context is still not initialized. Not only that this code cannot be tested but when you run the application it will also crash with NRE. You should never use any HttpContext related stuff in a constructor of a controller.
One possibility is to refactor your code and perform this inside the Initialize method:
public class BaseController : Controller
{
private IPolicy Policy;
protected override void Initialize(RequestContext requestContext)
{
base.Initialize(requestContext);
this.Policy = new Policy(HttpContext);
}
}
This being said, that's not the approach I would recommend. I would recommend you using dependency injection instead of service location which is considered by many as an anti-pattern.
So:
public abstract class BaseController : Controller
{
protected IPolicy Policy { get; private set; }
protected BaseController(IPolicy policy)
{
Policy = policy;
}
}
Now, all that's left is to configure your favourite Dependency Injection framework to inject the correct instance into the constructor. For example with Ninject.Mvc3 this is achieved with a single line of code:
kernel.Bind<IPolicy>().To<Policy>();
Now you can feel more than free to mock this IPolicy in your unit test without even caring about any HttpContext.
For example let's suppose that you have the following controller that you want to unit test:
public class FooController : BaseController
{
public FooController(IPolicy policy): base(policy)
{ }
[Authorize]
public ActionResult Index()
{
Policy.DoSomething();
return View();
}
}
Now, all that you need to do is pick up your favorite mock framework (Rhino Mocks in my case) and do the mocking:
[TestMethod]
public void Index_Action_Should_DoSomething_With_The_Policy()
{
// arrange
var policyStub = MockRepository.GenerateStub<IPolicy>();
var sut = new FooController(policyStub);
// act
var actual = sut.Index();
// assert
Assert.IsInstanceOfType(actual, typeof(ViewResult));
policyStub.AssertWasCalled(x => x.DoSomething());
}
The essence of my question is how to compose these objects (see below) in a sensible way with MVC3 and Ninject (though I am not sure DI should be playing a role in the solution). I can't disclose the real details of my project but here is an approximation which illustrates the issue/question. Answers in either VB or C# are appreciated!
I have several different products with widely varying properties yet all of them need to be represented in a catalog. Each product class has a corresponding table in my database. A catalog entry has a handful of properties specific to being a catalog entry and consequently have their own table. I have defined an interface for the catalog entries with the intent that calling the DescriptionText property will give me very different results based on the underlying concrete type.
Public Class Clothing
Property Identity as Int64
Property AvailableSizes As List(Of String)
Property AvailableColor As List(Of String)
End Class
Public Class Fasteners
Property Identity as Int64
Property AvailableSizes As List(Of String)
Property AvailableFinishes As List(Of String)
Property IsMetric As Boolean
End Class
Public Interface ICatalogEntry
Property ProductId as Int64
Property PublishedOn As DateTime
Property DescriptionText As String
End Interface
Given that the DescriptionText is a presentation layer concern I don't want to implement the ICatalogEntry interface in my product classes. Instead I want to delegate that to some kind of formatter.
Public Interface ICatalogEntryFormatter
Property DescriptionText As String
End Interface
Public Class ClothingCatalogEntryFormatter
Implements ICatalogEntryFormatter
Property DescriptionText As String
End Class
Public Class FastenerCatalogEntryFormatter
Implements ICatalogEntryFormatter
Property DescriptionText As String
End Class
In a controller somewhere there will be code like this:
Dim entries As List(Of ICatalogEntry)
= catalogService.CurrentCatalog(DateTime.Now)
In a view somewhere there will be code like this:
<ul>
#For Each entry As ICatalogEntry In Model.Catalog
#<li>#entry.DescriptionText</li>
Next
</ul>
So the question is what do the constructors look like? How to set it up so the appropriate objects are instantiated in the right places. Seems like generics or maybe DI can help with this but I seem to be having a mental block. The only idea I've come up with is to add a ProductType property to ICatalogEntry and then implement a factory like this:
Public Class CatalogEntryFactory
Public Function Create(catEntry as ICatalogEntry) As ICatalogEntry
Select Case catEntry.ProductType
Case "Clothing"
Dim clothingProduct = clothingService.Get(catEntry.ProductId)
Dim clothingEntry = New ClothingCatalogEntry(clothingProduct)
Return result
Case "Fastener"
Dim fastenerProduct = fastenerService.Get(catEntry.ProductId)
Dim fastenerEntry = New FastenerCatalogEntry(fastenerProduct)
fastenerEntry.Formatter = New FastenerCatalogEntryFormatter
Return fastenerEntry
...
End Function
End Class
Public ClothingCatalogEntry
Public Sub New (product As ClothingProduct)
Me.Formatter = New ClothingCatalogEntryFormatter(product)
End Sub
Property DescriptionText As String
Get
Return Me.Formatter.DescriptionText
End Get
End Property
End Class
...FastenerCatalogEntry is omitted but you get the idea...
Public Class CatalogService
Public Function CurrentCatalog(currentDate as DateTime)
Dim theCatalog As List(Of ICatalogEntry)
= Me.repository.GetCatalog(currentDate)
Dim theResult As New List(Of ICatalogEntry)
For Each entry As ICataLogEntry In theCatalog
theResult.Add(factory.Create(entry))
Next
Return theResult
End Function
End Class
IMHO, I am not really getting any smells off this code other than having to change the factory for every new product class that comes along. Yet, my gut says that this is the old way of doing things and nowadays DI and/or generics can do this better. Suggestions on how to handle this are much appreciated (as are suggestions on a better title...)
I like to just use the default constructor on models for the view and populate them via Automapper.
I would have a view model like this:
public interface IHasDescription
{
public string DescriptionText { get; set; }
}
public class ViewModelType : IHasDescription
{
[DisplayName("This will be rendered in the view")]
public string SomeText { get; set; }
public string DescriptionText { get; set; }
}
And I have a model from the DAL like this:
public class DALModelType
{
public string SomeText { get; set; }
}
So you have something like this in your controller:
var dalModel = someRepository.GetAll();
var viewModel = Mapper.Map<DALModelType, ViewModelType>(dalModel);
And you have the Automapper setup code in some file. This way you only have the conversion code in one place instead of in multiple methods/controllers. You have a custom resolver which uses dependency injection (instead of () => new CustomResolver()) and this will house your logic for getting the display text.
Mapper.CreateMap<IHasDescription, ViewModelType>()
.ForMember(dest => dest.DescriptionText,
opt => opt.ResolveUsing<CustomResolver>().ConstructedBy(() => new CustomResolver()));
Not sure if this works with your workflow but it should be able to get you what you want.
So making a few small changes I got this to work using the Ninject Factory extension.
Biggest change is that my entities have enough info to display either type (clothes or fasteners in my contrived example) if the item is actually clothes then the fastener specific properties will be null and vice versa.
Public Interface IDescribable
ReadOnly Property DescriptionText As String
End Interface
Public Enum ProductType
CLOTHING
FASTENER
End Enum
Public Interface ICatalogEntry
Inherits IDescribable
ReadOnly Property ProductId As Int64
ReadOnly Property PublishedOn As DateTime
ReadOnly Property ProductType As ProductType
End Interface
Public Class CatalogEntryEntity
Public Property ProductId As Long
Public Property ProductType As ProductType
Public Property PublishedOn As Date
Public Property DescriptionText As String
Public Property Color As String
Public Property Finish As String
Public Property IsMetric As Boolean
End Class
Then with this in place I can define my catalog service as follows:
Public Class CatalogService
Private ReadOnly _factory As ICatalogEntryFactory
Private ReadOnly _repository As CatalogRepository
Public Sub New(entryFactory As ICatalogEntryFactory, repository As CatalogRepository)
Me._factory = entryFactory
Me._repository = repository
End Sub
Public Function CurrentCatalog(currentDate As DateTime) As List(Of ICatalogEntry)
Dim items = Me._repository.GetCatalog()
Return (From item In items Select _factory.Create(item.ProductType.ToString(), item)).ToList()
End Function
End Class
Public Interface ICatalogEntryFactory
Function Create(bindingName As String, entity As CatalogEntryEntity) As ICatalogEntry
End Interface
Ninject will provide the factory (which is awesome!) assuming I setup the bindings like this:
theKernel.Bind(Of ICatalogEntry)().To(Of ClothingCatalogEntry)().Named("CLOTHING")
theKernel.Bind(Of ICatalogEntry)().To(Of FastenerCatalogEntry)().Named("FASTENER")
theKernel.Bind(Of ICatalogEntryFactory)().ToFactory(Function() New UseFirstParameterAsNameInstanceProvider())
I've omitted the FastenerCatalogEntry for brevity; the ClothingCatalogEntry is like this:
Public Class ClothingCatalogEntry
Public Sub New(ByVal entity As CatalogEntryEntity)
...
It was this post that helped me the most to figure this out. I used UseFirstParameterAsNameInstanceProvider exactly as shown there.
EDIT
The particular part that I am confused about is the error.
5) Injection of dependency ModelStateDictionary into parameter dictionary of constructor of type ModelStateDictionary
ModelStateDictionary has a constructor that accepts a ModelStateDictionary object. Is this why / where the error is occurring? If so, how do I resolve it as ModelStateDictionary is not a n object that I can directly modify.
Original
I've been trying to get dependency injection setup to work on for my controllers on in an asp.net mvc app. But I end up with a cyclic dependency on the System.Web.Mvc.ModelStateDictionary. I've done some searching ... here and here and others and I've tried some of the suggestions like creating a property (maybe I just don't know where to place them) instead of passing it through the constructor. However it seems to me that ninject is having a problem with the System.Web.Mvc.ModelStateDictionary class or definition. I get the following error ...
Activation path:
5) Injection of dependency ModelStateDictionary into parameter dictionary of constructor of type ModelStateDictionary
4) Injection of dependency ModelStateDictionary into parameter modelState of constructor of type ModelStateWrapper
3) Injection of dependency IValidationDictionary into parameter validationDictionary of constructor of type ProjectService
2) Injection of dependency IProjectService into parameter prjService of constructor of type ProjectController
1) Request for ProjectController
My classes are pretty much defined as follows. I have obviously removed some of the extraneous stuff ...
public class ProjectController : Controller
{
private IProjectService _prjService;
private IMembershipService _membershipService;
public ProjectController(IProjectService prjService,IMembershipService membershipService )
{
_membershipService = membershipService;
_prjService = prjService;
}
}
public class ProjectService : ServiceBase, IProjectService
{
public ProjectService(IValidationDictionary validationDictionary) : base(validationDictionary) { }
}
public class ServiceBase
{
private readonly IValidationDictionary _validationDictionary;
public IValidationDictionary ValidationDictionary { get { return _validationDictionary; } }
public ServiceBase(IValidationDictionary validationDictionary)
{
_validationDictionary = validationDictionary;
}
}
public interface IProjectService
{
// interface has other properties
IValidationDictionary ValidationDictionary { get; }
}
public class ModelStateWrapper : IValidationDictionary
{
private ModelStateDictionary _modelState;
public ModelStateWrapper(ModelStateDictionary modelState)
{
_modelState = modelState;
}
public ModelStateWrapper()
{
}
public void AddError(string key, string errorMessage)
{
_modelState.AddModelError(key, errorMessage);
}
public bool IsValid
{
get { return _modelState.IsValid; }
}
}
The definition of ModelStateDictionary is as follows ... at least as far as I think it pertains to this problem.
[Serializable]
public class ModelStateDictionary : IDictionary<string, ModelState>, ICollection<KeyValuePair<string, ModelState>>, IEnumerable<KeyValuePair<string, ModelState>>, IEnumerable
{
public ModelStateDictionary();
public ModelStateDictionary(ModelStateDictionary dictionary);
}
The bindings I've set up for ninject are as follows ...
kernel.Bind<IMembershipService>().To<AuthMembershipService>();
kernel.Bind<IProjectService>().To<ProjectService>();
kernel.Bind<IValidationDictionary>().To<ModelStateWrapper>();
Please let me know if I can provide any more information ... I initially tried to use structuremap but couldn't make the DI work ... I seem to have at least got ninject set up and working for the most part.
Thanks,
Ninject chooses the constructor with the most parameters it knows how to create by default. In this case the second constructor is choosen. This would result in a stackoverflow since it would have to create a ModelStateWrapper to inject into the ModelStateWrapper and andother to inject into the second one, ......
Unless there is a really good reason for the second construcotr you should simply delete it. Otherwise you have to give here enough information that we can understand why there is this second constructor.