IoC Castle Windsor in MVC routing problem - asp.net-mvc

I've set up castle windsor in my mvc app. everything works great except it also catches routes that are of type link or image. The problem is that right before exiting from the controller and generating the view "GetControllerInstance" is executed with 'null' type. This happends anytime there a link on a page like:
<link rel="stylesheet" type="text/css" href="non-existing.css"/>
Or a link to an image that does not exist. Why is this happening?
My windows class:
public class WindsorControllerFactory : DefaultControllerFactory
{
#region Constants and Fields
/// <summary>
/// The container.
/// </summary>
private readonly WindsorContainer container;
#endregion
// The constructor:
// 1. Sets up a new IoC container
// 2. Registers all components specified in web.config
// 3. Registers all controller types as components
#region Constructors and Destructors
/// <summary>
/// Initializes a new instance of the <see cref="WindsorControllerFactory"/> class.
/// </summary>
public WindsorControllerFactory()
{
// Instantiate a container, taking configuration from web.config
this.container = InversionOfControl.Container;
// Also register all the controller types as transient
IEnumerable<Type> controllerTypes = from t in Assembly.GetExecutingAssembly().GetTypes()
where typeof(IController).IsAssignableFrom(t)
select t;
foreach (Type t in controllerTypes)
{
this.container.AddComponentLifeStyle(t.FullName, t, LifestyleType.Transient);
}
}
#endregion
#region Methods
/// <summary>
/// The get controller instance.
/// </summary>
/// <param name="requestContext">
/// The request context.
/// </param>
/// <param name="controllerType">
/// The controller type.
/// </param>
/// <returns>
/// Resolved controller instance.
/// </returns>
protected override IController GetControllerInstance(RequestContext requestContext, Type controllerType)
{
if (controllerType == null)
{
controllerType = typeof(HomeController);
}
return (IController)this.container.Resolve(controllerType);
}
#endregion
}

This is only natural. The non-existing image or css cannot find the controller but you are defaulting it to the HomeController while this controller cannot handle static content.
I do not think you need an override here. Let the default controller handle what it does and resource will get a 404 error if it cannot be found instead you forcing it to be served by that controller.
As I said, it is only natural for the type to be null if it cannot be found.
Change it to this:
if (controllerType == null)
{
return base.GetControllerInstance(requestContext, controllerType);
}

I found that I had to return null when the controllerType was null. Handing it on to the base class resulted in an exception. Below is the working code that I am using.
public class DependencyControllerFactory : DefaultControllerFactory, IDisposable
{
protected readonly WindsorContainer _container;
public DependencyControllerFactory()
{
_container = new WindsorContainer();
_container.Kernel.Resolver.AddSubResolver(new CollectionResolver(_container.Kernel));
_container.Install(FromAssembly.This());
}
protected override IController GetControllerInstance(RequestContext requestContext, Type controllerType)
{
if (controllerType == null)
{
return null;
}
else
{
return (IController)_container.Resolve(controllerType);
}
}
public override void ReleaseController(IController controller)
{
_container.Release(controller);
}
public void Dispose()
{
_container.Dispose();
}
}

Related

Circular Reference + IoC

I have this situation:
Web Project - calling a Business class using Unity 3 IoC. The Web Project doesn't see Business Project. It just references Contracts Project.
namespace Biblioteca.Web.Controllers
{
public class HomeController : Controller
{
public ActionResult Index()
{
return View();
var Autor = Inject.Resolve<IAutorBO>();
}
}
}
Business Project - Here I use the Unity 3 IoC to point to AutorDO class which is in the Data Project (see below). The Business Project doesn't see Data Project.
namespace Biblioteca.Data
{
public sealed partial class AutorBO : IAutorBO
{
#region Atributos
private IAutorDO AutorDO = Inject.Resolve<IAutorDO>();
#endregion
#region Métodos Interface
public IQueryable<DTOAutor> GetAll()
{
return AutorDO.GetAll();
}
public DTOAutor GetById(int id)
{
return AutorDO.GetById(id);
}
void IAutorBO.Insert(DTOAutor dto)
{
AutorDO.Insert(dto);
}
void IAutorBO.Delete(DTOAutor dto)
{
AutorDO.Delete(dto);
}
void IAutorBO.Update(DTOAutor dto)
{
AutorDO.Update(dto);
}
//IQueryable<DTOAutor> IAutorBO.SearchFor(Expression<Func<Autor, bool>> predicate)
//{
// return AutorDO.SearchFor(predicate);
//}
IQueryable<DTOAutor> IAutorBO.GetAll()
{
return AutorDO.GetAll();
}
DTOAutor IAutorBO.GetById(int id)
{
return AutorDO.GetById(id);
}
#endregion
#region Outros Métodos
#endregion
}
}
Data Access Project - Here is my Data Project.
namespace Biblioteca.Data
{
public sealed partial class AutorDO : IAutorDO
{
#region Atributos
Repository<Autor> repository = new Repository<Autor>();
#endregion
#region Implementações Interface
/// <summary>
/// Implementação do método de interface Insert
/// </summary>
/// <param name="dto"></param>
void IAutorDO.Insert(Transport.DTOAutor dto)
{
Autor entity = AssemblerAutor.ToEntity(dto);
repository.Insert(entity);
}
/// <summary>
/// Implementação do método de interface Delete
/// </summary>
/// <param name="dto"></param>
void IAutorDO.Delete(Transport.DTOAutor dto)
{
Autor entity = AssemblerAutor.ToEntity(dto);
repository.Delete(entity);
}
/// <summary>
/// Implementação do método de interface Update
/// </summary>
/// <param name="dto"></param>
void IAutorDO.Update(Transport.DTOAutor dto)
{
Autor entity = AssemblerAutor.ToEntity(dto);
repository.Update(entity);
}
/// <summary>
/// Implementação do método de interface SearchFor
/// </summary>
/// <param name="dto"></param>
/// <returns></returns>
//IQueryable<Transport.DTOAutor> IAutorDO.SearchFor(Expression<Func<Autor, bool>> predicate)
//{
// IQueryable<Autor> list = repository.SearchFor(predicate);
// IQueryable<Transport.DTOAutor> dtoList = (IQueryable<Transport.DTOAutor>)AssemblerAutor.ToDTOs(list);
// return dtoList;
//}
/// <summary>
/// Implementação do método de interface GetAll
/// </summary>
/// <returns></returns>
IQueryable<Transport.DTOAutor> IAutorDO.GetAll()
{
IQueryable<Autor> list = repository.GetAll();
IQueryable<Transport.DTOAutor> dtoList = (IQueryable<Transport.DTOAutor>)AssemblerAutor.ToDTOs(list);
return dtoList;
}
/// <summary>
/// Implementação do método de interface GetById
/// </summary>
/// <param name="id"></param>
/// <returns></returns>
Transport.DTOAutor IAutorDO.GetById(int id)
{
Autor entity = new Autor();
Transport.DTOAutor dto = new Transport.DTOAutor();
using (var ctx = new BibliotecaContext())
{
entity = repository.GetById(id);
dto = AssemblerAutor.ToDTO(entity);
}
return dto;
}
#endregion
}
}
Both Business and Data Projects references the Contracts Project which has all Unity 3 IoC Interfaces, used for implementing IoC. Below are the interfaces used to implement IoC:
namespace Biblioteca.Contracts
{
public interface IAutorBO
{
#region Métodos CRUD
void Insert(DTOAutor dto);
void Delete(DTOAutor dto);
void Update(DTOAutor dto);
//IQueryable<DTOAutor> SearchFor(Expression<Func<Autor, bool>> predicate);
IQueryable<DTOAutor> GetAll();
DTOAutor GetById(int id);
#endregion
}
}
namespace Biblioteca.Contracts
{
public interface IAutorDO
{
#region Métodos CRUD
void Insert(DTOAutor dto);
void Delete(DTOAutor dto);
void Update(DTOAutor dto);
//IQueryable<DTOAutor> SearchFor(Expression<Func<Autor, bool>> predicate);
IQueryable<DTOAutor> GetAll();
DTOAutor GetById(int id);
#endregion
}
}
To complement, I use a generic repository, as below:
namespace Biblioteca.Data
{
/// <summary>
/// Interface para classe genérica para métodos CRUD
/// </summary>
/// <typeparam name="T"></typeparam>
public interface IRepository<T>
{
void Insert(T entity);
void Delete(T entity);
void Update(T entity);
IQueryable<T> SearchFor(Expression<Func<T, bool>> predicate);
IQueryable<T> GetAll();
T GetById(int id);
}
}
namespace Biblioteca.Data
{
/// <summary>
/// Classe genérica para métodos CRUD da camada Data
/// </summary>
/// <typeparam name="T"></typeparam>
public class Repository<T> : IRepository<T> where T : class
{
#region Attributes
protected DbSet<T> dbset;
protected DbContext ctx;
#endregion
#region Constructor
public Repository()
{ }
public Repository(DbContext ctx)
{
this.ctx = ctx;
dbset = ctx.Set<T>();
}
#endregion
#region IRepository<T> Members
public void Insert(T entity)
{
if (dbset.Contains(entity))
{
Update(entity);
}
else
{
dbset.Add(entity);
}
}
public void Delete(T entity)
{
dbset.Remove(entity);
}
public void Update(T entity)
{
using (ctx)
{
ctx.Set<T>().Attach(entity);
ctx.SaveChanges();
}
}
public IQueryable<T> SearchFor(Expression<Func<T, bool>> predicate)
{
return dbset.Where(predicate);
}
public IQueryable<T> GetAll()
{
return dbset;
}
public T GetById(int id)
{
return dbset.Find(id);
}
#endregion
}
}
Notice that I have a commented method in all classes. This Method can not be implemented cause it will cause a circular dependency.
I have the Data Project referencing Contract Project. But I can not use the method "SearchFor" cause it needs the Entity Autor which is in Data Project.
Notice that both Business and Data needs to see Entity classes, cause I have the same method signature.
I need some way to permit use the IoC the way it is, where Web not references Business and Business not references Data, and be able to create other methods where I can pass Entity as parameter.
Any suggestion ? I have already tried to create a third project and points to it but I can't make it works. Is it possible to use Reflection ? If possible, how ?
I will appreciate any suggestion.
If you have a circular dependency, it is a clue you should modify your architecture.
If you need to "have the Data Project referencing Contract Project", then Contract cannot reference Data to get the Entity. You say "Business and Data needs to see Entity classes", so why not keep your entity Autor in an Entities project.
Data
-> references Contract
-> references Entities
Contract
-> references Entities
Or as an alternative, define your entities in the Contract project instead of Data.

ASP.NET MVC4 Unity - Resolve dependencies on another project

I have this configuration in my project MVC4 Unity and a generic configucion for drivers.
Bootstrapper.cs
namespace MyProyect.Web
{
public static class Bootstrapper
{
public static void Initialise()
{
var container = BuildUnityContainer();
ServiceLocator.SetLocatorProvider(() => new UnityServiceLocator(container));
DependencyResolver.SetResolver(new UnityDependencyResolver(container));
GlobalConfiguration.Configuration.DependencyResolver = new Unity.WebApi.UnityDependencyResolver(container);
}
private static IUnityContainer BuildUnityContainer()
{
var container = new UnityContainer();
container.RegisterType<MyProyect.Model.DataAccessContract.ICountryDao, MyProyect.DataAccess.CountryDao>();
container.RegisterType<MyProyect.Model.DataAccessContract.IContactDao, MyProyect.DataAccess.ContactDao>();
return container;
}
}
}
Global.asax:
protected void Application_Start()
{
...
Bootstrapper.Initialise();
...
}
GenericModelBinder.cs:
namespace MyProyect.Web.ModelBinder
{
public class GenericModelBinder : DefaultModelBinder//, IValueProvider
{
protected override object CreateModel(ControllerContext controllerContext, ModelBindingContext bindingContext, Type modelType)
{
var resolver = (Unity.Mvc4.UnityDependencyResolver)DependencyResolver.Current;
if (modelType == null)
{
return base.CreateModel(controllerContext, bindingContext, null);
}
return resolver.GetService(modelType);
}
}
}
Now that I need is to resolve a dependency in another project within the solution. My question is how I can do to that recognize the settings Unity in another project?. I currently I have this class but the current configuration does not bring in the MVC project.
namespace MyProyect.Model.ListData
{
public abstract class ListDataGenericResolver
{
protected T ResolverType<T>()
{
IUnityContainer container = new UnityContainer();
UnityServiceLocator locator = new UnityServiceLocator(container);
ServiceLocator.SetLocatorProvider(() => locator);
//return unity.Resolve<T>();
return (T)container.Resolve(typeof(T));
}
}
}
this is a example how to use ListDataGenericResolver:
namespace MyProyect.Model.ListData.Types
{
public class CountryListData : ListDataGenericResolver, IGetListData
{
private readonly ICountryDao countryDao;
private string defaultValue;
public CountryListData(object defaultValue)
{
// Resolver
this.countryDao = this.ResolverType<ICountryDao>();
this.defaultValue = defaultValue == null ? string.Empty : defaultValue.ToString();
}
public IList<SelectData> GetData()
{
var data = this.countryDao.GetAllCountry(new Entity.Parameters.CountryGetAllParameters());
return data.Select(d => new SelectData
{
Value = d.CountryId.ToString(),
Text = d.Description,
Selected = this.defaultValue == d.CountryId.ToString()
}).ToList();
}
}
}
Thank you.
Here is how I do this.
In Application_Start, I create the unity container. I have a custom library that I use for all of my MVC projects that I import through NuGet, so I make the call to its configure method, then call the other project's Configure() methods. You could simply omit the custom library and add that code in here as well. All of that keeps my Application_Start nice and clean.
protected void Application_Start()
{
// Standard MVC setup
// <removed>
// Application configuration
var container = new UnityContainer();
new CompanyName.Mvc.UnityBootstrap().Configure(container);
new AppName.ProjectName1.UnityBootstrap().Configure(container);
new AppName.ProjectName2.UnityBootstrap().Configure(container);
// <removed>
}
This is the code for the custom MVC library's UnityBootstrap class
namespace CompanyName.Mvc
{
/// <summary>
/// Bootstraps <see cref="CompanyName.Mvc"/> into a Unity container.
/// </summary>
public class UnityBootstrap : IUnityBootstrap
{
/// <inheritdoc />
public IUnityContainer Configure(IUnityContainer container)
{
// Convenience registration for authentication
container.RegisterType<IPrincipal>(new InjectionFactory(c => HttpContext.Current.User));
// Integrate MVC with Unity
container.RegisterFilterProvider();
DependencyResolver.SetResolver(new UnityDependencyResolver(container));
return container;
}
}
}
Then, in the other projects, I have a UnityBootstrap there, that was called from Application_Start:
ProjectName1:
namespace AppName.ProjectName1
{
public class UnityBootstrap : IUnityBootstrap
{
public IUnityContainer Configure(IUnityContainer container)
{
return container.RegisterType<IDocumentRoutingConfiguration, DocumentRoutingConfiguration>();
}
}
}
ProjectName2: - and you can see in here, that this one depends on some other projects in another library and it is calling their Configure() methods to get them set up too...
namespace AppName.ProjectName2
{
public class UnityBootstrap : IUnityBootstrap
{
public IUnityContainer Configure(IUnityContainer container)
{
new CompanyName.Security.UnityBootstrap().Configure(container);
new CompanyName.Data.UnityBootstrap().Configure(container);
container.RegisterSecureServices<AuthorizationRulesEngine>(typeof(UnityBootstrap).Assembly);
return container
.RegisterType<IAuthorizationRulesEngine, AuthorizationRulesEngine>()
.RegisterType<IDateTimeFactory, DateTimeFactory>()
.RegisterType<IDirectoryInfoFactory, DirectoryInfoFactory>()
.RegisterType<IDirectoryWrapper, DirectoryWrapper>()
.RegisterType<IEmailService, EmailService>()
.RegisterType<IEntryPointService, EntryPointService>();
}
}
}
Here is the IUnityBootstrap interface that is used throughout the code above (for your reference)
/// <summary>
/// Defines a standard interface for bootstrapping an assembly into a Unity container.
/// </summary>
public interface IUnityBootstrap
{
/// <summary>
/// Registers all of the assembly's classes to their public interfaces and performs any other necessary configuration.
/// </summary>
/// <param name="container">The Unity container instance to configure.</param>
/// <returns>The same IUnityContainer object that this method was called on.</returns>
IUnityContainer Configure(IUnityContainer container);
}
I hope this helps you out.

mvc 4 mef import/export confusion

I'm having a difficult time wrapping my head around Mef and how imports and exports work. My project structure is as follows.
Projects:
MefMVPApp (Main MVC 4 app)
MefMVCFramework.Common(Interfaces shared between the projects)
MefMVCDemo.Plugins.OrderStatus (pluggable area.)
MefMVCDemo.Plugins.Data (Repository for OrderStatus)
OrderStatus.Models(domain models shared between the projects)
The goal of the main Mvc App will be to host plug-able areas via mef.
The OrderStatus Area has a controller called OrderStatusController and is decorated with the Export Attribute and a ImportingConstructor.
[Export(typeof(IController))]
[ExportMetadata("controllerName", "OrderStatus")]
[PartCreationPolicy(CreationPolicy.NonShared)]
public class OrderStatusController : Controller
{
private readonly IRepository<OrderStatusApp.OrderStatusResponse>_repository ;
[ImportingConstructor]
public OrderStatusController(IRepository<OrderStatusApp.OrderStatusResponse> oRepository)
{
_repository = oRepository;
}
public ActionResult Index()
{
var model = _repository.GetAll();
return View();
}
}
IRepository is a class in the MefMVCFramework.Common assembly and will be used for generic CRUD operations.
public interface IRepository<T> where T : class
{
IEnumerable<T> GetAll();
T GetById(int id);
void Add(T entity);
int SaveOrUpdate(T entity);
bool Delete(T entity);
bool Delete(int id);
}
The MefMVCDemo.Plugins.Data assembly contains a Class called OrderManagementRepository that inherents for the generic repository and is marked with an Export Attribute.
[Export(typeof(IRepository<OrderStatusApp.OrderStatusResponse>))]
[PartCreationPolicy(CreationPolicy.NonShared)]
public class OrderManagementRepository : IRepository<OrderStatusApp.OrderStatusResponse>
{
private readonly JsonServiceClient _client;
public OrderManagementRepository()
{
_client = new JsonServiceClient("http://localhost:52266");
}
public IEnumerable<OrderStatusApp.OrderStatusResponse> GetAll()
{
throw new NotImplementedException("Can not get all");
}
public OrderStatusApp.OrderStatusResponse GetById(int id)
{
throw new NotImplementedException();
}
public void Add(OrderStatusApp.OrderStatusResponse entity)
{
throw new NotImplementedException();
}
public int SaveOrUpdate(OrderStatusApp.OrderStatusResponse entity)
{
throw new NotImplementedException();
}
public bool Delete(OrderStatusApp.OrderStatusResponse entity)
{
throw new NotImplementedException();
}
public bool Delete(int id)
{
throw new NotImplementedException();
}
}
Using Mefx tool I am able to see my parts and there are no rejection.
mefx /dir:C:\
Source.PreBranch.Keep\Prototypes\Projects\MefDemoApp\mefMVC4App\bin /parts
MefMVCDemo.Plugins.Data.OrderManagementRepository
mefMVCDemo.Plugins.OrderStatus.Controllers.OrderStatusController
MefMVCDemo.Plugins.OrderStatus.Verbs.OrderStatusVerb
I can see my import.
mefx /dir:C:\
Source.PreBranch.Keep\Prototypes\Projects\MefDemoApp\mefMVC4App\bin /imports
MefMVCFramework.Common.IRepository(OrderStatus.Models.OrderStatusApp+OrderStatus
Response)
MefMVCFramework.Common.IRepository(OrderStatus.Models.OrderStatusApp+OrderStatus
Response)
Now when browse my main mvc site with the /orderstatus uri I get the following error:
No parameterless constructor defined for this object.
Adding a default constructor to the OrderStatusController that takes no overloads doesn't seem to work.
I guess the question is what am I doing wrong? Why does my interface in the constructor all way end up being null and why is there an mvc error about the "No parameterless constructor defined for this object".
The default controller factory in MVC tries to create the controller using a parameterless constructor. If you want to change this behavior, then you need to create your own custom controller factory.
Here is an example of a ControllerFactory using imports/exports on controllers
I'm using MEF for importing some parts to my app but my controllers are not imported/exported, so I created the following controller factory
public class ControllerFactory : IControllerFactory
{
private readonly CompositionContainer _container;
private IControllerFactory _innerFactory;
/// <summary>
/// Constructor used to create the factory
/// </summary>
/// <param name="container">MEF Container that will be used for importing</param>
public ControllerFactory(CompositionContainer container)
{
_container = container;
_innerFactory = new DefaultControllerFactory();
}
/// <summary>
/// Method used for create the controller based on the provided name. It calls the
/// constructor of the controller passing the MEF container
/// </summary>
/// <param name="requestContext">Context of the request</param>
/// <param name="controllerName">Name of the controller provided in the route</param>
/// <returns>The controller instance</returns>
public IController CreateController(System.Web.Routing.RequestContext requestContext, string controllerName)
{
Type controllerType = FindControllerByName(controllerName);
var args = new object[] { this._container };
var controller = (IController)Activator.CreateInstance(controllerType, args);
return controller;
}
/// <summary>
/// This methods looks into the current Assembly for the Controller type
/// </summary>
/// <param name="name">The controller name provided in the route</param>
/// <returns>The controller type</returns>
private static Type FindControllerByName(string name){
var a = Assembly.GetAssembly(typeof(ControllerFactory));
var types = a.GetTypes();
Type type = types.Where(t => t.Name == String.Format("{0}Controller", name)).FirstOrDefault();
return type;
}
public System.Web.SessionState.SessionStateBehavior GetControllerSessionBehavior(System.Web.Routing.RequestContext requestContext, string controllerName)
{
return System.Web.SessionState.SessionStateBehavior.Default;
}
public void ReleaseController(IController controller)
{
var disposableController = controller as IDisposable;
if (disposableController != null)
{
disposableController.Dispose();
}
}
}
Thank you pollirrata for pointing me in the right direction.
I had to change a few things to get this to work.
1.) I added an interface called INameMetadata to my MefMVCFramework.Common project.
public interface INameMetadata
{
string Name { get; }
}
2.) Modified My ExportMetadata Tag on my controller export to be Name, OrderStatus.
[Export(typeof(IController))]
[ExportMetadata("Name", "OrderStatus")]
[PartCreationPolicy(CreationPolicy.NonShared)]
public class OrderStatusController : Controller
{
private IRepository<OrderStatusApp.OrderStatusResponse> _repository;
[ImportingConstructor]
public OrderStatusController(IRepository<OrderStatusApp.OrderStatusResponse> oRepository)
{
_repository = oRepository;
}
public ActionResult Index()
{
var model = _repository.GetById(47985);
return View(model);
}
}
3.) Created the MefControllerFactory (based off what pollirrata posted but modified to look for the Metadata)
public class MefControllerFactory : IControllerFactory
{
private string _pluginPath;
private readonly DirectoryCatalog _catalog;
private readonly CompositionContainer _container;
private DefaultControllerFactory _defaultControllerFactory;
public MefControllerFactory(string pluginPath)
{
_pluginPath = pluginPath;
_catalog = new DirectoryCatalog(pluginPath);
_container = new CompositionContainer(_catalog);
_defaultControllerFactory = new DefaultControllerFactory();
}
public MefControllerFactory(CompositionContainer compositionContainer)
{
_container = compositionContainer;
_defaultControllerFactory = new DefaultControllerFactory();
}
#region IControllerFactory Members
public IController CreateController(System.Web.Routing.RequestContext requestContext, string controllerName)
{
//IController controller = null;
var controller = _container.GetExports<IController,INameMetadata>()
.Where(e=>e.Metadata.Name.Equals(controllerName))
.Select(e=>e.Value).FirstOrDefault();
if (controller == null)
{
throw new HttpException(404, "Not found");
}
return controller;
}
public void ReleaseController(IController controller)
{
var disposable = controller as IDisposable;
if (disposable != null)
{
disposable.Dispose();
}
}
#endregion
public SessionStateBehavior GetControllerSessionBehavior(System.Web.Routing.RequestContext requestContext, string controllerName)
{
return SessionStateBehavior.Default;
}
}
4.) I created a Class called MefConfig in Main MVC app and moved it to the App_Start Dir.
public static class MefConfig
{
public static void RegisterMef()
{
//var builder = new RegistrationBuilder();
//builder.ForTypesDerivedFrom<IRepository<OrderStatusApp.OrderStatusResponse>>().Export<IRepository<IRepository<OrderStatusApp.OrderStatusResponse>>>();
var directoryCatalog = new DirectoryCatalog(HostingEnvironment.MapPath("~/bin"), "*.dll");
var container = new CompositionContainer(directoryCatalog, true);
ControllerBuilder.Current.SetControllerFactory(new MefControllerFactory(container));
//Working
//ControllerBuilder.Current.SetControllerFactory(new MefControllerFactory(HostingEnvironment.MapPath("~/bin")));
// Install MEF dependency resolver for MVC
var resolver = new MefDependencyResolver(container);
DependencyResolver.SetResolver(resolver);
// Install MEF dependency resolver for Web API
GlobalConfiguration.Configuration.DependencyResolver = resolver;
var d = container.GetExportedValues<IRepository<OrderStatusApp.OrderStatusResponse>>();
//Mefx.
try
{
//var ci = new CompositionInfo(aggregateCatalog, container);
var ci = new CompositionInfo(directoryCatalog, container);
var partDef = ci.GetPartDefinitionInfo(typeof(IRepository<OrderStatusApp.OrderStatusResponse>));
//var possibleCauses = partDef.FindPossibleRootCauses();
var stringWriter = new StringWriter();
CompositionInfoTextFormatter.Write(ci, stringWriter);
var compStatString = stringWriter.ToString();
}
catch
{
}
MvcApplication.ActionVerbs = container.GetExports<IActionVerb, IActionVerbMetadata>();
}
}
5.) Load the Mefconfig from the global.asax.
protected void Application_Start()
{
AreaRegistration.RegisterAllAreas();
//Register Mef
MefConfig.RegisterMef();
WebApiConfig.Register(GlobalConfiguration.Configuration);
FilterConfig.RegisterGlobalFilters(GlobalFilters.Filters);
RouteConfig.RegisterRoutes(RouteTable.Routes);
BundleConfig.RegisterBundles(BundleTable.Bundles);
}

Ninject : Constructor parameter

I am using Ninject together with ASP.NET MVC 4. I am using repositories and want to do constructor injection to pass in the repository to one of the controllers.
This is my Repository interface:
public interface IRepository<T> where T : TableServiceEntity
{
void Add(T item);
void Delete(T item);
void Update(T item);
IEnumerable<T> Find(params Specification<T>[] specifications);
IEnumerable<T> RetrieveAll();
void SaveChanges();
}
The AzureTableStorageRepository below is an implementation of IRepository<T>:
public class AzureTableRepository<T> : IRepository<T> where T : TableServiceEntity
{
private readonly string _tableName;
private readonly TableServiceContext _dataContext;
private CloudStorageAccount _storageAccount;
private CloudTableClient _tableClient;
public AzureTableRepository(string tableName)
{
// Create an instance of a Windows Azure Storage account
_storageAccount = CloudStorageAccount.Parse(ConfigurationManager.ConnectionStrings["StorageConnectionString"].ConnectionString);
_tableClient = _storageAccount.CreateCloudTableClient();
_tableClient.CreateTableIfNotExist(tableName);
_dataContext = _tableClient.GetDataServiceContext();
_tableName = tableName;
}
Note the tableName parameter needed because I was using a generic table repository to persist data to Azure.
And finally I have the following controller.
public class CategoriesController : ApiController
{
static IRepository<Category> _repository;
public CategoriesController(IRepository<Category> repository)
{
if (repository == null)
{
throw new ArgumentNullException("repository");
}
_repository = repository;
}
Now I want to inject a repository into the controller. So I have created a module that contains the bindings:
/// <summary>
/// Ninject module to handle dependency injection of repositories
/// </summary>
public class RepositoryNinjectModule : NinjectModule
{
public override void Load()
{
Bind<IRepository<Category>>().To<AzureTableRepository<Category>>();
}
}
The loading of the module is done in the NinjectWebCommon.cs
/// <summary>
/// Creates the kernel that will manage your application.
/// </summary>
/// <returns>The created kernel.</returns>
private static IKernel CreateKernel()
{
var kernel = new StandardKernel();
kernel.Bind<Func<IKernel>>().ToMethod(ctx => () => new Bootstrapper().Kernel);
kernel.Bind<IHttpModule>().To<HttpApplicationInitializationHttpModule>();
RegisterServices(kernel);
return kernel;
}
/// <summary>
/// Load your modules or register your services here!
/// </summary>
/// <param name="kernel">The kernel.</param>
private static void RegisterServices(IKernel kernel)
{
// Load the module that contains the binding
kernel.Load(new RepositoryNinjectModule());
// Set resolver needed to use Ninject with MVC4 Web API
GlobalConfiguration.Configuration.DependencyResolver = new NinjectResolver(kernel);
}
The DependencyResolver was created because Ninject's DependencyResolver implements System.Web.Mvc.IDependencyResolver and this cannot be assigned to GlobalConfiguration.Configuration of the WebApi Application.
So with all this in place, the Ninject part is actually injecting the right type in the Controller but Ninject cannot inject the tableName parameter in the constructor of AzureTableRepository.
How would I be able to do this in this case? I have consulted a lot of articles and the ninject documentation to see how I could use parameters, but I cannot seem to get it working.
Any help would be appreciated.
I'd use the WithConstructorArgument() method like...
Bind<IRepository<Category>>().To<AzureTableRepository<Category>>()
.WithConstructorArgument("tableName", "categories");
The rest of the repository design is probably another question. IMHO It seems like a big no no to create a table or do any heavy lifting in a ctor.
Meanwhile I have been playing around with Providers to try and do the trick and it seems to work.
I don't know if this is good idea or if it is overkill but here is what I have done:
I have created a generic provider class:
public abstract class NinjectProvider<T> : IProvider
{
public virtual Type Type { get; set; }
protected abstract T CreateInstance(IContext context);
public object Create(IContext context)
{
throw new NotImplementedException();
}
object IProvider.Create(IContext context)
{
throw new NotImplementedException();
}
Type IProvider.Type
{
get { throw new NotImplementedException(); }
}
}
And then I implemented that one in the AzureTableRepositoryProvider. (T to support having the same repository for multiple entity types.)
public class AzureTableRepositoryProvider<T> : Provider<AzureTableRepository<T>> where T : TableServiceEntity
{
protected override AzureTableRepository<T> CreateInstance(IContext context)
{
string tableName = "";
if (typeof(T).Name == typeof(Category).Name)
{
// TODO Get the table names from a resource
tableName = "categories";
}
// Here other types will be addedd as needed
AzureTableRepository<T> azureTableRepository = new AzureTableRepository<T>(tableName);
return azureTableRepository;
}
}
By using this provider I can pass in the right table name for the repository to work with. But for me, two questions remain:
Is this good practice or could we do things much simpler?
In the NinjectProvider class I have two notImplementedException cases. How could I resolve these? I used sample code from the following link but that does not work as the Provider is abstract and the code does not have a body for the create method... enter link description here

Creating WindsorViewPageActivator

I was playing with new Asp net mvc 3 RC2. I have created a WindsorViewPageActivator class as follows
public class WindsorViewPageActivator : IViewPageActivator
{
object IViewPageActivator.Create(ControllerContext controllerContext, Type type)
{
return DependencyResolver.Current.GetService(type);
}
}
and then a WindsorDependencyResolver class
public class WindsorDependencyResolver : IDependencyResolver
{
private readonly IWindsorContainer container;
public WindsorDependencyResolver(IWindsorContainer container)
{
this.container = container;
}
#region IDependencyResolver Members
public object GetService(Type serviceType)
{
return Resolve(serviceType);
}
public IEnumerable<object> GetServices(Type serviceType)
{
return container.ResolveAll(serviceType).Cast<object>();
}
public IEnumerable<TService> GetAllInstances<TService>()
{
return container.ResolveAll<TService>();
}
public TService GetInstance<TService>()
{
return (TService)Resolve(typeof(TService));
}
#endregion
private object Resolve(Type serviceType)
{
try
{
return container.Resolve( serviceType);
}
catch (Exception ex)
{
return null;
}
}
}
}
Now I am doing in Global.asax something like this
container.Register(Component.For<IControllerActivator>().ImplementedBy<WindsorControllerActivator>());
container.Register(Component.For<IViewPageActivator>().ImplementedBy<WindsorViewPageActivator>());
container.Register(Component.For<IControllerFactory>().ImplementedBy<DefaultControllerFactory>());
DependencyResolver.SetResolver (new WindsorDependencyResolver(container));
'
Now I am getting the following error
The view found at '~/Views/Account/LogOn.cshtml' was not created.
Do I need to register each view page in windsor container If yes then how can I register each view. I am using Razor view engine.
Thanks
Yes, in order to resolve stuff you need to register it. Have a look at the documentation to familiarise yourself with the API.
I have tried this myself, and unfortunately I can't seem to get it to work properly. I do the following in my solution:
public class WindsorViewPageActivator : IViewPageActivator
{
private readonly IKernel _kernel;
/// <summary>
/// Initializes a new instance of the <see cref="WindsorViewPageActivator"/> class.
/// </summary>
/// <param name="kernel">The kernel.</param>
public WindsorViewPageActivator([NotNull] IKernel kernel)
{
if (kernel == null) throw new ArgumentNullException("kernel");
_kernel = kernel;
}
public object Create(ControllerContext controllerContext, Type type)
{
if (!_kernel.HasComponent(type))
{
if (IsSupportedView(type))
{
_kernel.Register(Component.For(type).LifestylePerWebRequest());
}
else
{
return Activator.CreateInstance(type);
}
}
var viewPageInstance = _kernel.Resolve(type);
return viewPageInstance;
}
/// <summary>
/// Determines whether the specified type is of a supported view type.
/// </summary>
/// <param name="viewType">Type of the service.</param>
/// <returns>
/// <c>true</c> if the specified type is of a supported view type; otherwise, <c>false</c>.
/// </returns>
private static bool IsSupportedView(Type viewType)
{
return viewType.IsAssignableTo<WebViewPage>()
|| viewType.IsAssignableTo<ViewPage>()
|| viewType.IsAssignableTo<ViewMasterPage>()
|| viewType.IsAssignableTo<ViewUserControl>()
;
}
}
This works as long as you don't change anything in your markup. If you do, you'll get a registration error, as the view now will generate a new type, that doesn't exist in the container (but it has the same name!).
What I thought of doing, was to aggressively release the view component as soon as it's resolved, but I can't get rid of it in the container for some reason. Not even an explicit call to _kernel.ReleaseComponent(viewPageInstance) would do it (but that's of course just releasing the instance, not the type).
What we really need to do, is make Windsor inject properties into existing instances. That is, use Activator.CreateInstance(type) and then tell Windsor to inject the properties into the instance. But Windsor doesn't support injecting properties into existing instances, so we need to hack something together, that will do that for us.
I've seen this one http://www.jeremyskinner.co.uk/2008/11/08/dependency-injection-with-aspnet-mvc-action-filters/ (at the bottom), but that wouldn't perform very well.
My solution was simply to manually set my properties in the viewpage activator (you have a base viewpage type), but maybe there's some better solution?
EDIT
I managed to get it working after all!
My solution is to simply create a custom component activator and mimic what's being done in the MVC framework, like so:
public class ViewPageComponentActivator : DefaultComponentActivator
{
public ViewPageComponentActivator(ComponentModel model, IKernel kernel, ComponentInstanceDelegate onCreation, ComponentInstanceDelegate onDestruction)
: base(model, kernel, onCreation, onDestruction)
{
}
protected override object CreateInstance(CreationContext context, ConstructorCandidate constructor, object[] arguments)
{
// Do like the MVC framework.
var instance = Activator.CreateInstance(context.RequestedType);
return instance;
}
}
The component activator simply always return a new instance of the view. Because the component is registered as being transient, CreateInstanceis always called. There might be some tweaking possibilities here.
The viewpage activator is now much simpler. Note that the type of service is different whenever you change the view, so we must register the type based on it's unique name (I haven't tweaked this yet, but there might be a nicer way to name the component).
/// <summary>
/// An activator using Castle Kernel for activating views.
/// </summary>
public class WindsorViewPageActivator : IViewPageActivator
{
private readonly IKernel _kernel;
/// <summary>
/// Initializes a new instance of the <see cref="WindsorViewPageActivator"/> class.
/// </summary>
/// <param name="kernel">The kernel.</param>
public WindsorViewPageActivator([NotNull] IKernel kernel)
{
if (kernel == null) throw new ArgumentNullException("kernel");
_kernel = kernel;
}
public object Create(ControllerContext controllerContext, Type type)
{
if (!_kernel.HasComponent(type.FullName))
{
_kernel.Register(Component.For(type).Named(type.FullName).Activator<ViewPageComponentActivator>().LifestyleTransient());
}
return _kernel.Resolve(type.FullName, type);
}
}
I hope this might be of use to someone in similar situations.

Resources