In the startup.cs, I want to define an extended ServiceProvider: It basically wraps the default IServiceProvider implementation.
public IServiceProvider ConfigureServices(IServiceCollection services)
{
[...]
var servicesProvider = services.BuildExtendedServiceProvider();
return servicesProvider;
}
Here is the core extended service provider implementation
/// <summary>
/// Extends the native asp.net service provider
/// </summary>
public class ExtendedServicesProvider : IServiceProvider
{
private readonly IServiceProvider _serviceProvider;
/// <summary>
/// Creates a new instance of <see cref="ExtendedServicesProvider"/> provider based on the native mvc <see cref="IServiceProvider"/>
/// </summary>
/// <param name="serviceProvider"></param>
public ExtendedServicesProvider(IServiceProvider serviceProvider)
{
_serviceProvider = serviceProvider;
}
/// <inheritDoc />
public object GetService(Type serviceType)
{
var resolvedService = _serviceProvider.GetService(serviceType);
[...]
return resolvedService;
}
}
At startup, I can see that GetService is called for each service with "singleton" life time (great!!)
However, it is not called anymore after that, and the default ServiceProvider is called instead...
By the way, if I request the resolution of IServiceProvider, this is the native one that I get.
I would like my serviceProvider to replace completely the native one and to be called EVERY TIME.
Did I miss something??
Ok, I just checked the source code (I should have checked before posting the question sorry).
https://github.com/aspnet/DependencyInjection/blob/master/src/Microsoft.Extensions.DependencyInjection/ServiceProvider.cs
The build method adds by itself the IServiceProvider type with the native instance.
As there seem to have no way to modify it properly (without reflection on "_table" field I mean :-). It seems to me that the approach is clearly not good.
I think I'll try other dependency injection engines such as Autofac, but I really wanted to keep the native engine that seemed to me really light weight.
Related
I started creating a PoC following SO this post but I wasn't able to get a very basic sample to work.
What I did:
I created an ASP.NET MVC project using empty template and MVC references.
I added Bootstrapper, CustomControllerFactory and CustomViewEngine classes and also the corresponding lines in Application_Start.
I created an ASP.NET MVC project using MVC template.
I added the Export and PartCreationPolicy decorators on HomeController.
I published the module project to a folder inside /Modules directory -in WebHost root path.
What didn't work:
The method CompositionContainer.GetExportedValue throws an exception saying that it couldn't load one or more required types and that there is more information on LoaderExceptions property. That property is an array with 77 instances of what appears to be the same exception:
Could not load file or assembly Antlr3.Runtime, Version=3.4.1.9004, Culture=neutral, PublicKeyToken=eb42632606e9261f or one of its dependencies.
In FusionLog property I can see that the problem is related to the assembly version (see here).
I found a workaround for "solving" this by copying the dependentAssembly declarations from the module's web.config to the WebHost configuration file. However I'd like to avoid this as the WebHost should not be modified based on the module's needs.
Even after the workaround, it didn't work. While rendering the view, it threw this exception:
CS0234: The type or namespace name 'Optimization' does not exist in the namespace 'System.Web' (are you missing an assembly reference?)
For your help is share a full test project using MEF. visit this github link.
You need something like--
public class AzRDependencyResolver : System.Web.Http.Dependencies.IDependencyResolver, System.Web.Mvc.IDependencyResolver
{
private readonly CompositionContainer _container;
public AzRDependencyResolver(CompositionContainer container)
{
_container = container;
}
public IDependencyScope BeginScope()
{
return this;
}
/// <summary>
/// Called to request a service implementation.
///
/// Here we call upon MEF to instantiate implementations of dependencies.
/// </summary>
/// <param name="serviceType">Type of service requested.</param>
/// <returns>Service implementation or null.</returns>
public object GetService(Type serviceType)
{
if (serviceType == null)
throw new ArgumentNullException("serviceType");
var name = AttributedModelServices.GetContractName(serviceType);
var export = _container.GetExportedValueOrDefault<object>(name);
return export;
}
/// <summary>
/// Called to request service implementations.
///
/// Here we call upon MEF to instantiate implementations of dependencies.
/// </summary>
/// <param name="serviceType">Type of service requested.</param>
/// <returns>Service implementations.</returns>
public IEnumerable<object> GetServices(Type serviceType)
{
if (serviceType == null)
throw new ArgumentNullException("serviceType");
var exports = _container.GetExportedValues<object>(AttributedModelServices.GetContractName(serviceType));
return exports;
}
public void Dispose()
{
}
}
I want to preserve the DI abstraction layer Kephas provides, but in my particular case I need to register a service which is imported from a third-party library. Given this, I cannot annotate the service with the [AppServiceContract] attribute required for service registration. Is there a way to achieve this?
Yes there is. Here are the steps to follow:
Define a class implementing IConventionsRegistrar.
Use the conventions builder to register the desired services.
Sample code:
public class MyConventionsRegistrar : IConventionsRegistrar
{
/// <summary>
/// Registers the conventions.
/// </summary>
/// <param name="builder">The registration builder.</param>
/// <param name="candidateTypes">The candidate types which can take part in the composition.</param>
/// <param name="registrationContext">Context for the registration.</param>
public void RegisterConventions(
IConventionsBuilder builder,
IEnumerable<TypeInfo> candidateTypes,
ICompositionRegistrationContext registrationContext)
{
//... here you can use the conventions builder to register your services using the fluent API. The candidate types are provided if you need the identified application types. A couple of examples are provided below:
// shared/singleton service exported as IMyService with MyService implementation.
builder.ForType(typeof(MyServiceImpl))
.Export(b => b.AsContractType(typeof(IMyService)))
.Shared();
// instance-based multiple services exported as IMultiImplService
builder.ForTypesDerivedFrom(typeof(IMultiImplService))
.Export(b => b.AsContractType(typeof(IMultiImplService)));
}
There is a second way of registering services, however by the means of service descriptors instead of a fluent API. For this case, follow the steps:
Define a class implementing IAppServiceInfoProvider.
Return the descriptors of the desired services.
Sample code with the same registrations as above:
public class MyAppServiceInfoProvider : IAppServiceInfoProvider
{
/// <summary>
/// Gets an enumeration of application service information objects.
/// </summary>
/// <param name="candidateTypes">The candidate types which can take part in the composition.</param>
/// <param name="registrationContext">Context for the registration.</param>
/// <returns>
/// An enumeration of application service information objects and their associated contract type.
/// </returns>
public IEnumerable<(TypeInfo contractType, IAppServiceInfo appServiceInfo)> GetAppServiceInfos(IEnumerable<TypeInfo> candidateTypes, ICompositionRegistrationContext registrationContext)
{
yield return (typeof(IMyService).GetTypeInfo(),
new AppServiceInfo(typeof(IMyService),
typeof(MyServiceImpl),
AppServiceLifetime.Shared));
yield return (typeof(IMultiImplService).GetTypeInfo(),
new AppServiceInfo(typeof(IMultiImplService),
AppServiceLifetime.Instance,
allowMultiple: true));
}
Both cases are autodiscovered and, at the proper time, the registration methods are called. However, in the second case, the advantage is that the registrations are available as service metadata for querying at a later time.
How can I split the properties, functionality and classes out of the default ASP.Net Mvc / Identity 2.0? I am battling with a few things:
by default, it wants to use OWIN's context to wire up some kind of dependency injection, and control the Managers
it puts the ApplicationDbContext at the application level, where my architecture requires it be available at "lower" levels.
It requires that I declare any properties in the same class as the functionality that acts on those properties (which doesn't fit in with my architecture)
The ApplcationUser model has dependencies on Asp.Net, which I would like to break if I am to move the POCO to a non-MVC layer of the solution
Application architecture:
I have a solution that has several tiers :
Api - defines interfaces for services
Domain - stores POCO models representing a business domain
Business - stores logic for interacting with domain objects, and consumes services
Service - implementation of services, including Entity Framework, and the structure maps for the domain objects
Application - in this case, an MVC application.
My business layer only knows about service interfaces, not implementation, and I am using dependency injection to wire everything up.
I have some interfaces defining read/write/unit of work operations for a data service, and an implementation of these that inherit from DbContext (in my Service layer). Instead of having a series of DbSet<MyPoco> MyPocos {get;set;}, I am wiring it up by passing a series of type configurations that define relationships, then accessing my types through Set<Type>(). All that works great.
This stack has been in place for an existing application, and works well. I know it will transition to an MVC application, and am only having issues with the "out of the box" ASP.Net Identity-2.
My solution to this was to: Abstract all the things
I got around this by abstracting most of the functionality of identity into its own project which allowed for easier unit testing and reuse of the abstraction in other projects.
I got the idea after reading this article
Persistence-Ignorant ASP.NET Identity with Patterns
I then fine tuned the idea to suit my needs. I basically just swapped out everything I needed from asp.net.identity for my custom interfaces which more or less mirrored the functionality provided by the framework but with the advantage of easier abstractions and not implementations.
IIdentityUser
/// <summary>
/// Minimal interface for a user with an id of type <seealso cref="System.String"/>
/// </summary>
public interface IIdentityUser : IIdentityUser<string> { }
/// <summary>
/// Minimal interface for a user
/// </summary>
public interface IIdentityUser<TKey>
where TKey : System.IEquatable<TKey> {
TKey Id { get; set; }
string UserName { get; set; }
string Email { get; set; }
//...other code removed for brevity
}
IIdentityManager
/// <summary>
/// Exposes user related api which will automatically save changes to the UserStore
/// </summary>
public interface IIdentityManager : IIdentityManager<IIdentityUser> { }
/// <summary>
/// Exposes user related api which will automatically save changes to the UserStore
/// </summary>
public interface IIdentityManager<TUser> : IIdentityManager<TUser, string>
where TUser : class, IIdentityUser<string> { }
/// <summary>
/// Exposes user related api which will automatically save changes to the UserStore
/// </summary>
public interface IIdentityManager<TUser, TKey> : IDisposable
where TUser : class, IIdentityUser<TKey>
where TKey : System.IEquatable<TKey> {
//...other code removed for brevity
}
IIdentityResult
/// <summary>
/// Represents the minimal result of an identity operation
/// </summary>
public interface IIdentityResult : System.Collections.Generic.IEnumerable<string> {
bool Succeeded { get; }
}
In my default implementation of the identity manager, which also lives in its own project, I simply wrapped the ApplicationManager and then mapped results and functionality between my types and the asp.net.identity types.
public class DefaultUserManager : IIdentityManager {
private ApplicationUserManager innerManager;
public DefaultUserManager() {
this.innerManager = ApplicationUserManager.Instance;
}
//..other code removed for brevity
public async Task<IIdentityResult> ConfirmEmailAsync(string userId, string token) {
var result = await innerManager.ConfirmEmailAsync(userId, token);
return result.AsIIdentityResult();
}
//...other code removed for brevity
}
The application layer is only aware of the abstractions and the implementation is configured at startup. I don't have any using Microsoft.AspNet.Identity at the higher level as they are all using the local abstractions.
the tiers can look like this :
Api - defines interfaces for services (including Identity abstraction interfaces)
Domain - stores POCO models representing a business domain
Business - stores logic for interacting with domain objects, and consumes services
Service - implementation of services, including Entity Framework, and the structure maps for the domain objects
Identity - implementation of Microsoft.AspNet.Identity specific services, including Microsoft.AspNet.Identity.EntityFramework; and OWIN configuration
Application - in this case, an MVC application.
In MVC Application layer the AccountController thus only needed
using MyNamespace.Identity.Abstractions
public partial class AccountController : Controller {
private readonly IIdentityManager userManager;
public AccountController(IIdentityManager userManager) {
this.userManager = userManager;
}
//...other code removed for brevity
[HttpPost]
[AllowAnonymous]
[ValidateAntiForgeryToken]
public async Task<ActionResult> Signin(LoginViewModel model, string returnUrl) {
if (ModelState.IsValid) {
// authenticate user
var user = await userManager.FindAsync(model.UserName, model.Password);
if (user != null) {
//...code removed for brevity
} else {
// login failed
setFailedLoginIncrementalDelay();
ModelState.AddModelError("", "Invalid user name or password provided.");
}
}
//TODO: Audit failed login
// If we got this far, something failed, redisplay form
return View(model);
}
}
This assumes you are using some DI framework. It is only in the configuring of the IoC that any mention is made of the layer that implements identity completely abstracting it away from those that have need of using identity.
//NOTE: This is custom code.
protected override void ConfigureDependencies(IContainerBuilder builder) {
if (!builder.HasHandler(typeof(IIdentityManager))) {
builder.PerRequest<IIdentityManager, DefaultUserManager>();
}
}
How Do I convert the following Ninject DI to Unity? I'm having trouble understanding the correct syntax.
/// <summary>
/// Load your modules or register your services here!
/// </summary>
/// <param name="kernel">The kernel.</param>
private static void RegisterServices(IKernel kernel)
{
Database.SetInitializer(new MigrateDatabaseToLatestVersion<DefaultMembershipRebootDatabase, BrockAllen.MembershipReboot.Ef.Migrations.Configuration>());
var config = MembershipRebootConfig.Create();
kernel.Bind<MembershipRebootConfiguration>().ToConstant(config);
kernel.Bind<UserAccountService>().ToSelf();
kernel.Bind<AuthenticationService>().To<SamAuthenticationService>();
kernel.Bind<IUserAccountQuery>().To<DefaultUserAccountRepository>().InRequestScope();
kernel.Bind<IUserAccountRepository>().To<DefaultUserAccountRepository>().InRequestScope();
}
Registering a single instance is done using the RegisterInstance method.
Registering types as 'self' is done using the RegisterType<T>() method.
Registering types with a request lifestyle is done using the HierarchicalLifetimeManager.
I'm currently working on a project whereby I will be developing views that will be pre-compiled and will be part of an external MVC 3.0 web solution I do not have any control over.
Part of my requirements is that I will need to access an underlying database in order to get some data. I would like to use Ninject (I've been informed that's what the external solution uses) to inject the database instance into my controllers as necessary.
I understand that you add the bindings in such a place as the Global.asax however I do not have access to this as that is part of the external solution out of my control.
Is there anyway I can create this dependency injection in my project that contains the pre-compiled views etc and ensure it is resolved when the external project loads our controller?
If this is too vague let me know and I'll try and offer more information.
EDIT:
Initially upon taken on Darin's suggestion I got the exception below:
System.InvalidOperationException crossed a native/managed boundary
Message=Sequence contains no elements
Source=System.Core
StackTrace:
at System.Linq.Enumerable.Single[TSource](IEnumerable`1 source)
at Ninject.Web.Mvc.NinjectMvcHttpApplicationPlugin.Start() in c:\Projects\Ninject\ninject.web.mvc\mvc3\src\Ninject.Web.Mvc\NinjectMvcHttpApplicationPlugin.cs:line 53
at Ninject.Web.Common.Bootstrapper.<Initialize>b__0(INinjectHttpApplicationPlugin c) in c:\Projects\Ninject\Ninject.Web.Common\src\Ninject.Web.Common\Bootstrapper.cs:line 52
at Ninject.Infrastructure.Language.ExtensionsForIEnumerableOfT.Map[T](IEnumerable`1 series, Action`1 action) in c:\Projects\Ninject\ninject\src\Ninject\Infrastructure\Language\ExtensionsForIEnumerableOfT.cs:line 32
at Ninject.Web.Common.Bootstrapper.Initialize(Func`1 createKernelCallback) in c:\Projects\Ninject\Ninject.Web.Common\src\Ninject.Web.Common\Bootstrapper.cs:line 52
at MyApp.App_Start.NinjectWebCommon.Start() in C:\App\NinjectWebCommon.cs:line 28
InnerException:
However upon thinking about it, the bootstrapper should already be initialised in our external MVC application (assuming they are using this method I guess). So I don't need to do all the initialisation all I need to do is register my dependencies with the current Kernal.
Something like:
public static class NinjectWebCommon
{
private static readonly Bootstrapper bootstrapper = new Bootstrapper();
/// <summary>
/// Starts the application
/// </summary>
public static void Start()
{
RegisterServices(bootstrapper.Kernel);
}
/// <summary>
/// Load your modules or register your services here!
/// </summary>
/// <param name="kernel">The kernel.</param>
private static void RegisterServices(IKernel kernel)
{
kernel.Bind<IDataContext>().To<ApiDataContext>();
}
}
When doing this I now get the items injected. However I'm not 100% this is the correct solution but it seems to work?
I understand that you add the bindings in such a place as the Global.asax
Not necessarily. Have you recently installed the Ninject.MVC3 NuGet in a new MVC application? If you haven't I invite you to do so now. Simply create a new ASP.NET MVC 3 project using the Internet Application template in Visual Studio and install this NuGet. Ready?
After doing that you will notice that the NuGet package created in App_Start folder to your project. It didn't touch at any Global.asax. Now let's inspect the contents of the NinjectWebCommon.cs file added to this folder:
[assembly: WebActivator.PreApplicationStartMethod(typeof(MvcApplication1.App_Start.NinjectWebCommon), "Start")]
[assembly: WebActivator.ApplicationShutdownMethodAttribute(typeof(MvcApplication1.App_Start.NinjectWebCommon), "Stop")]
namespace MvcApplication1.App_Start
{
using System;
using System.Web;
using Microsoft.Web.Infrastructure.DynamicModuleHelper;
using Ninject;
using Ninject.Web.Common;
public static class NinjectWebCommon
{
private static readonly Bootstrapper bootstrapper = new Bootstrapper();
/// <summary>
/// Starts the application
/// </summary>
public static void Start()
{
DynamicModuleUtility.RegisterModule(typeof(OnePerRequestHttpModule));
DynamicModuleUtility.RegisterModule(typeof(NinjectHttpModule));
bootstrapper.Initialize(CreateKernel);
}
/// <summary>
/// Stops the application.
/// </summary>
public static void Stop()
{
bootstrapper.ShutDown();
}
/// <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)
{
}
}
}
Notice the WebActivator's PreApplicationStartMethod and ApplicationShutdownMethodAttribute assembly attributes that allow you to plug code that executes when an ASP.NET application respectively starts and shuts down.
Alright, now simply put this code in your library and configure your kernel in the RegisterServices method.