I was willing to use the INC<T> version of the notify property change mecanism, which is much more concise than the Property + Field + RaisePropertyChanged version.
BUT, let say I have this ViewModel:
public abstract class PageViewModel : MvxViewModel
{
/// <summary>
/// The is loading
/// </summary>
public readonly INC<bool> IsLoading = new NC<bool>();
/// <summary>
/// The subtitle
/// </summary>
public readonly INC<string> Subtitle = new NC<string>();
/// <summary>
/// The title
/// </summary>
public readonly INC<string> Title = new NC<string>();
Now, let say I am in my android Activity, and I want to subscribe to these properties :
public partial class MainView : IFragmentHost
{
private void Subscribe(PageViewModel viewModel)
{
viewModel.Title.Changed += (xx) => Whatever;
}
On a second though, it would be nice to WeakSubscribe to them so:
viewModel.Title.WeakSubscri...
Mmmmh weird, I have no autocompletion on that.
Let's see the MvxWeakSubscriptionExtensionMethods:
public static class MvxWeakSubscriptionExtensionMethods
{
public static MvxNotifyPropertyChangedEventSubscription WeakSubscribe(this INotifyPropertyChanged source, EventHandler<PropertyChangedEventArgs> eventHandler)
{
return new MvxNotifyPropertyChangedEventSubscription(source, eventHandler);
}
public static MvxValueEventSubscription<T> WeakSubscribe<T>(this EventInfo eventInfo, object source, EventHandler<MvxValueEventArgs<T>> eventHandler)
{
return new MvxValueEventSubscription<T>(source, eventInfo, eventHandler);
}
And now the INC<T>
public interface INC<T> : INotifyChange<T>, INotifyChange
So, is there a way to weak subscribe to a INC<T> property ?
The plugin itself makes bindings using weak references using:
IDisposable _subscription = NotifyChangeEventInfo.WeakSubscribe(_notifyChange, NotifyChangeOnChanged);
where NotifyChangeOnChanged has signature:
protected abstract void NotifyChangeOnChanged(object sender, EventArgs eventArgs);
from https://github.com/MvvmCross/MvvmCross/blob/3.2/Plugins/Cirrious/FieldBinding/Cirrious.MvvmCross.Plugins.FieldBinding/MvxNotifyChangeFieldSourceBinding.cs#L38
Related
I have two controllers both are derivated from a base controller. The code inside them is exactly the same. The only difference is in constructors. Below is my code:
[RoutePrefix("api/v2")]
public class CategoryController : BaseController
{
private IGetTroubleTicketService getTroubleTicketService;
private ICategoryService categoryService;
/// <summary>
/// Constructor for initialization
/// </summary>
public CategoryController()
{
getTroubleTicketService = MethodFactory.Create<IGetTroubleTicketService>();
getTroubleTicketService.SetProvider(new ServiceProvider(Global.Container));
categoryService = MethodFactory.Create<ICategoryService>();
categoryService.SetProvider(new ServiceProvider(Global.Container));
}
/// <summary>
/// Retrieve all Categories
/// </summary>
/// <returns>Categories(Id, Label)</returns>
[HttpGet]
[Route("categoryRef")]
public HttpResponseMessage Categories()
{
try
{
// Validate User Id and Application Id
var user = ValidateUserAndApplication(getTroubleTicketService);
var userLanaguage = Convert.ToInt32(user.Language, CultureInfo.InvariantCulture);
var categories = categoryService.CategoriesData(userLanaguage);
LoggingRequest("categoryRef",null);
response = Request.CreateResponse(HttpStatusCode.OK, categories);
}
catch (Exception exception)
{
//CheckError
CheckError(exception);
}
return response;
}
}
The second one is
[RoutePrefix("api/v2")]
public class ProblemCategoryController : BaseController
{
private IGetTroubleTicketService getTroubleTicketService;
private ICategoryService categoryService;
/// <summary>
/// Constructor for initialization
/// </summary>
public ProblemCategoryController()
{
getTroubleTicketService = MethodFactory.Create<IGetTroubleTicketService>();
getTroubleTicketService.SetProvider(new ServiceProvider(Global.Container));
categoryService = MethodFactory.Create<ICategoryService>();
categoryService.SetProvider(new ServiceProvider(Global.Container));
}
/// <summary>
/// Retrieve all Natures of problem
/// </summary>
/// <returns>Categories(Id, Label)</returns>
[HttpGet]
[Route("problemCategoryRef")]
public HttpResponseMessage ProblemCategories()
{
try
{
// Validate User Id and Application Id
var user = ValidateUserAndApplication(getTroubleTicketService);
var userLanaguage = Convert.ToInt32(user.Language, CultureInfo.InvariantCulture);
var categories = categoryService.CategoriesData(userLanaguage);
LoggingRequest("problemCategoryRef", null);
response = Request.CreateResponse(HttpStatusCode.OK, categories);
}
catch (Exception exception)
{
//CheckError
CheckError(exception);
}
return response;
}
Now as you can see the internal code is exactly the same which I want to avoid creating a Helper class. How can I make this common class for it so as to remove code duplicacy? It's possible without rewrite all the context code to get User and Id app?
I tried this
public class NatureOfProblemHelper : BaseController
{
private IGetTroubleTicketService getTroubleTicketService;
private ICategoryService categoryService;
private string resourceName;
/// <summary>
/// Initializes a new instance of the <see cref="NatureOfProblemHelper"/> class.
/// Constructor for initialization.
/// <param name="resource">Resource requested by user.</param>
/// </summary>
public NatureOfProblemHelper(string resource)
{
getTroubleTicketService = MethodFactory.Create<IGetTroubleTicketService>();
getTroubleTicketService.SetProvider(new ServiceProvider(Global.Container));
categoryService = MethodFactory.Create<ICategoryService>();
categoryService.SetProvider(new ServiceProvider(Global.Container));
resourceName = resource;
}
/// <summary>
/// Retrieve all Natures of problem.
/// </summary>
/// <returns>Categories(Id, Label).</returns>
public HttpResponseMessage GetNaturesOfProblem()
{
// Validate User Id and Application Id
var user = ValidateUserAndApplication(getTroubleTicketService);
var userLanaguage = Convert.ToInt32(user.Language, CultureInfo.InvariantCulture);
var categories = categoryService.CategoriesData(userLanaguage);
LoggingRequest(resourceName, null);
return Request.CreateResponse(HttpStatusCode.OK, categories);
}
And then into each controller
[HttpGet]
[Route("problemCategoryRef")]
public HttpResponseMessage ProblemCategories()
{
try
{
response = natureOfProblem.NaturesOfProblem();
}
catch (Exception exception)
{
//CheckError
CheckError(exception);
}
return response;
}
This build, but I can't get the context that comes from this variable
// Validate User Id and Application Id
var user = ValidateUserAndApplication(getTroubleTicketService);
Why if I put the same lines of code directly in my controller works but if I put in my Helper it doesn't work??
Using asp.net 5 I'd like my controller to be injected with a Func<T>instead of T
For example:
public HomeController(Func<Interfaces.IUnitOfWork> uow)
Instead of
public HomeController(Interfaces.IUnitOfWork uow)
Is it possible with the built-in DI or am I forced to move to an external DI?
Func<T> does not get registered or resolved by default but there is nothing stopping you from registering it yourself.
e.g.
services.AddSingleton(provider =>
new Func<IUnitOfWork>(() => provider.GetService<IUnitOfWork>()));
Note that you will also need to register IUnitOfWork itself in the usual way.
You can register a Func<T> or a delegate with a ServiceCollection. I recommend a delegate because it allows you to distinguish between different methods with identical signatures.
Here's an example.
public interface IThingINeed {}
public class ThingINeed : IThingINeed { }
public delegate IThingINeed ThingINeedFactory();
public class DelegateRegistrationTests
{
[Test]
public void RegisterDelegateFromDependency()
{
var serviceCollection = new ServiceCollection();
serviceCollection.AddTransient<IThingINeed, ThingINeed>();
serviceCollection.AddTransient<ThingINeedFactory>(
provider => provider.GetService<IThingINeed>);
var serviceProvider = serviceCollection.BuildServiceProvider();
var factoryMethod = serviceProvider.GetService<ThingINeedFactory>();
var output = factoryMethod();
Assert.IsInstanceOf<ThingINeed>(output);
}
}
This almost looks like a service locator because the function we're resolving is actually IServiceCollection.GetService<ThingINeedFactory>(). But that's hidden in the composition root. A class that injects this delegate depends on the delegate, not on the implementation.
You can use the same approach if the method you want to return belongs to a class that the container must resolve.
public interface IThingINeed
{
string SayHello();
}
public class ThingINeed : IThingINeed
{
private readonly string _greeting;
public ThingINeed(string greeting)
{
_greeting = greeting;
}
public string SayHello() => _greeting;
}
public class ThingINeedFactory
{
public IThingINeed Create(string input) => new ThingINeed(input);
}
public delegate IThingINeed ThingINeedFactoryMethod(string input);
public class DelegateRegistrationTests
{
[Test]
public void RegisterDelegateFromDependency()
{
var serviceCollection = new ServiceCollection();
serviceCollection.AddSingleton<IThingINeed, ThingINeed>();
serviceCollection.AddSingleton<ThingINeedFactory>();
serviceCollection.AddSingleton<ThingINeedFactoryMethod>(provider =>
provider.GetService<ThingINeedFactory>().Create);
var serviceProvider = serviceCollection.BuildServiceProvider();
var factoryMethod = serviceProvider.GetService<ThingINeedFactoryMethod>();
var created = factoryMethod("abc");
var greeting = created.SayHello();
Assert.AreEqual("abc", greeting);
}
}
Here's an extension method to (maybe) make it a little bit easier:
public static class ServiceCollectionExtensions
{
public static IServiceCollection RegisterDelegate<TSource, TDelegate>(
this IServiceCollection serviceCollection,
Func<TSource, TDelegate> getDelegateFromSource)
where TDelegate : class
{
return serviceCollection.AddSingleton(provider =>
getDelegateFromSource(provider.GetService<TSource>()));
}
}
serviceCollection
.RegisterDelegate<ThingINeedFactory, ThingINeedFactoryMethod>(
factory => factory.Create);
As far as I'm aware deferring dependencies like this isn't possible using the current default IoC container within ASP.NET Core. I've not been able to get it working anyway!
To defer the initialisation of dependencies like this you'll need to implement an existing, more feature rich IoC container.
While there is no built in Func building support in the default dependency injection for .net core we can build an extension method to add in all the missing funcs. We just need to make sure we call it at the end of registration.
public static class ServiceCollectionExtensions
{
private static MethodInfo GetServiceMethod;
static ServiceCollectionExtensions()
{
Func<IServiceProvider, object> getServiceMethod = ServiceProviderServiceExtensions.GetService<object>;
GetServiceMethod = getServiceMethod.Method.GetGenericMethodDefinition();
}
/// <summary>
/// Registers all Funcs in constructors to the ServiceCollection - important to call after all registrations
/// </summary>
/// <param name="collection"></param>
/// <returns></returns>
public static IServiceCollection AddFactories(this IServiceCollection collection)
{
// Get a list of all Funcs used in constructors of regigstered types
var funcTypes = new HashSet<Type>(collection.Where(x => x.ImplementationType != null)
.Select(x => x.ImplementationType)
.SelectMany(x => x.GetConstructors(BindingFlags.Public | BindingFlags.Instance))
.SelectMany(x => x.GetParameters())
.Select(x => x.ParameterType)
.Where(x => x.IsGenericType && x.GetGenericTypeDefinition() == typeof(Func<>)));
// Get a list of already registered Func<> and remove them from the hashset
var registeredFuncs = collection.Select(x => x.ServiceType)
.Where(x => x.IsGenericType && x.GetGenericTypeDefinition() == typeof(Func<>));
funcTypes.ExceptWith(registeredFuncs);
// Each func build the factory for it
foreach (var funcType in funcTypes)
{
var type = funcType.GetGenericArguments().First();
collection.AddTransient(funcType, FuncBuilder(type));
}
return collection;
}
/// <summary>
/// This build expression tree for a func that is equivalent to
/// Func<IServiceProvider, Func<TType>> factory = serviceProvider => new Func<TType>(serviceProvider.GetService<TType>);
/// </summary>
/// <param name="type"></param>
/// <returns></returns>
private static Func<IServiceProvider, object> FuncBuilder(Type type)
{
var serviceProvider = Expression.Parameter(typeof(IServiceProvider), "serviceProvider");
var method = GetServiceMethod.MakeGenericMethod(type);
var call = Expression.Call(method, serviceProvider);
var returnType = typeof(Func<>).MakeGenericType(type);
var returnFunc = Expression.Lambda(returnType, call);
var func = Expression.Lambda(typeof(Func<,>).MakeGenericType(typeof(IServiceProvider), returnType), returnFunc, serviceProvider);
var factory = func.Compile() as Func<IServiceProvider, object>;
return factory;
}
}
In AddFactories we get a list of all the concreate types that are registered then check their constructors for any Func<>. From that list remove any Func that has been registered before. Using some expressiontrees we build the needed Funcs.
The code is also over in codereview, minus the check for already registered funcs.
I wrote a little extension method that registres the service and the factory (Func<T>):
public static class IServiceCollectionExtension
{
public static IServiceCollection AddFactory<TService, TServiceImplementation>(this IServiceCollection serviceCollection)
where TService : class
where TServiceImplementation : class, TService
{
return serviceCollection
.AddTransient<TService, TServiceImplementation>();
.AddSingleton<Func<TService>>(sp => sp.GetRequiredService<TService>);
}
}
Usage:
serviceCollection
.AddFactory<IMyInterface, MyImplementation>()
There are a few options available to you, the first is you can switch over to use the incredible Lamar (with it's ASP.NET Core integration).
For the most part, switching to Lamar is a few lines of code, and you'll be able to resolve Func<> and Lazy<> all day long.
I've been using it at scale for a while on a large microservices based platform and we're completely happy with it *.
If you don't want to move over to Lamar, you can use this for resolving Lazy<> (sorry, I've tried and tried, and I can't get it to work with Func<>:
// Add to your Service Collection.
services.AddTransient(typeof(Lazy<>), typeof(LazyServiceFactory<>));
class LazyServiceFactory<T> : Lazy<T>
{
public LazyServiceFactory(IServiceProvider serviceProvider)
: base(() => serviceProvider.GetRequiredService<T>())
{
}
}
And just for completeness, here's a test too.
// And some tests...
[TestMethod]
[DataTestMethod]
[DataRow(ServiceLifetime.Transient)]
[DataRow(ServiceLifetime.Scoped)]
[DataRow(ServiceLifetime.Singleton)]
public void Resolve_GivenLazyilyRegisteredService_CanResolve(ServiceLifetime serviceLifetime)
{
// Arrange
IServiceProvider serviceProvider = CreateServiceProvider(serviceLifetime);
using IServiceScope scope = serviceProvider.CreateScope();
// Act
Func<Lazy<ClassHello>> result = () => scope.ServiceProvider.GetRequiredService<Lazy<ClassHello>>();
// Assert
result
.Should()
.NotThrow()
.And
.Subject()
.Value
.Should()
.NotBeNull();
}
static IServiceProvider CreateServiceProvider(ServiceLifetime serviceLifetime)
{
IServiceCollection services = new ServiceCollection();
services.Add(new ServiceDescriptor(typeof(Lazy<>), typeof(LazyServiceFactory<>), serviceLifetime));
services.Add(new ServiceDescriptor(typeof(ClassHello), typeof(ClassHello), serviceLifetime));
return services.BuildServiceProvider(true);
}
I've not put this through it's paces as I use Lamar pretty much exclusivly now, but this has come in handy for smaller/ disposable projects.
* My only minor issue is that it doesn't support IAsyncDisposable yet.
I have solution below
public static IServiceCollection WithFunc<TService>(this IServiceCollection serviceCollection) where TService : class {
var serviceType = typeof(TService);
var serviceDescriptor = serviceCollection.LastOrDefault(x => x.ServiceType == serviceType);
Debug.Assert(serviceDescriptor != null);
serviceCollection.Add(ServiceDescriptor.Describe(typeof(Func<TService>),
scope => new Func<TService>(scope.GetRequiredService<TService>),
serviceDescriptor.Lifetime));
return serviceCollection;
}
usage
[Fact]
void with_func() {
var services = new ServiceCollection()
.AddTransient<IFoo, Foo>().WithFunc<IFoo>()
.BuildServiceProvider();
var fooFunc = services.GetRequiredService<Func<IFoo>>();
Assert.NotNull(fooFunc);
}
more detail in gist https://gist.github.com/leoninew/d2f174fe1422e453c60fb78e69342310
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);
}
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
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.