NServiceBus Version 5 Asp.NET MVC - asp.net-mvc

We have an ASP.NET MVC 4 website using NServiceBus to send messages to various services. Because our dev environments don't have these services installed, we stub the ServiceBus instance for local development. We use an Autofac Module registered in our Application_Start to set this all up and configure our Bus instance for injection into controllers.
My NSB 3.3 configuration:
public class ServiceModule : Module
{
protected override void Load(ContainerBuilder builder)
{
builder.Register<IBus>((c, p) =>
{
var useServiceBus = bool.Parse(ConfigurationManager.AppSettings["UseServiceBus"]);
if (useServiceBus)
{
return NServiceBus.Configure.With()
.Log4Net()
.DefaultBuilder()
.XmlSerializer()
.MsmqTransport().IsTransactional(false).PurgeOnStartup(false)
.MsmqSubscriptionStorage()
.UnicastBus().ImpersonateSender(false)
.CreateBus()
.Start(() => NServiceBus.Configure.Instance.ForInstallationOn<NServiceBus.Installation.Environments.Windows>().Install());
}
else
return c.Resolve<TestServiceBus>();
}).SingleInstance();
}
}
My attempted NSB 5.0.3 configuration:
public class ServiceModule : Module
{
protected override void Load(ContainerBuilder builder)
{
builder.Register<IBus>((c, p) =>
{
var useServiceBus = bool.Parse(ConfigurationManager.AppSettings["UseServiceBus"]);
if (useServiceBus)
{
var configuration = new BusConfiguration();
configuration.UsePersistence<RavenDBPersistence>();
configuration.RegisterComponents(r =>
{
r.ConfigureComponent<EnvironmentMessageMutator>(() => new EnvironmentMessageMutator(new DetectsEnvironment().GetEnvironment()), DependencyLifecycle.InstancePerCall);
});
return Bus.Create(configuration);
}
else
return c.Resolve<TestServiceBus>();
}).SingleInstance();
}
}
Bus.Create is failing with an ObjectDisposedException, "Cannot access a disposed object" on CommonObjectBuilder. I can't find any documentation on the correct way to set this up in NSB 5, or how to configure the regular NServiceBus injection to allow us to do the stubbing described above.
(This should be tagged NServiceBus 5, but I don't have the reputation)

Okay, it turns out this is NSB 5's way of telling you you have the ServiceControl monitoring plugins installed in your endpoint, but don't have the appropriate queues on the machine.
Solution is to install ServiceControl.

Related

Add EvenLogging to an IHost container

I’m creating a console app and have recently started adding custom services to the IHost container so I can simply pass the IHost to any number of factory classes and have everything thing I need to configure them. But I’ve gotten stuck when it comes to adding Windows Event Logging as a service, could use some help getting past this.
My Main static method in Program calls CreateHostBuilder and returns an IHostBuilder as shown below.
public static IHostBuilder CreateHostBuilder(string[] args)
{
IConfigurationBuilder configurationBuilder = new ConfigurationBuilder();
configurationBuilder.AddJsonFile("appsettings.json");
IConfiguration configuration = configurationBuilder.Build();
var hostBuilder = Host.CreateDefaultBuilder(args)
.ConfigureLogging((hostContext, logging) =>
{
logging.ClearProviders();
logging.SetMinimumLevel(LogLevel.Information);
logging.AddEventLog(eventViewerSettings =>
{
eventViewerSettings.SourceName = "MeCore2";
eventViewerSettings.LogName = "Application";
eventViewerSettings.MachineName = ".";
});
})
.ConfigureServices(services => services.AddDbContext<MeCore2Context>())
// Add custom service for performing DNS queries
.ConfigureServices(services => services.AddTransient<IDnsQueryService>(DnsQueryFactory.Create))
// Add custom service for Managing Runtime Environment Settings
.ConfigureServices(services => services.AddTransient<IEnvironmentSettings>(EnvironmentSettingsFactory.Create))
// Add custom service for Managing String Extractions
.ConfigureServices(services => services.AddTransient<IExtractStringsService>(ExtraxtStringsFactory.Create))
// Add custom service for IP GeoLocation
.ConfigureServices(services => services.AddTransient<IIpGeolocationService>(IpGeolocationFactory.Create));
return hostBuilder;
}
My factory classes are implemented like this.
public static class DnsQueryFactory
{
public static DnsQueryService Create(IServiceProvider serviceProvider)
{
bool exceptionDisplayOnly = serviceProvider.GetRequiredService<IEnvironmentSettings>().WriteErrorsToEventLogs;
IHost host = serviceProvider.GetRequiredService<IHost>();
return new DnsQueryService(exceptionDisplayOnly, host);
}
}
And my concrete service constructors are implemented like this.
public DnsQueryService(bool exceptionDisplayOnly, IHost host)
{
this.exceptionDisplayOnly = exceptionDisplayOnly;
this.logger = host.Services.GetRequiredService<ILogger>();
this.environmentSettings = host.Services.GetRequiredService<IEnvironmentSettings>();
}
When I ran the app after setting up in this manner, I was unable to pull an ILogger from the host container, I could though, pull an ILoggerFactory then I needed to take some additional steps before I had a fully functional ILogger.
I would like to be able to pull the ILogger from the Host container with it fully configured and ready to use for exception handling, warnings, and basic information logging. But I'm stumped here as I can't seem to get the right syntax for using the ILoggingBuilder or ILoggerFactory into the Host container.
I started down the path of creating a static class EventLoggingServices that would accept an IServiceProvider finish out the configuration steps and return an ILogger, but this too has got me stumped. I'm close but not where I need to be and can't find a blog that covers this approach, either that or I'm going at this the wrong way, to begin with. Appreciate the help and thanks in advance.
I believe I've answered my own question with the following code, it is writing to the event logs. I implemented a factory method to encapsulate the ILogger as follows.
public static class EventLoggingFactory
{
public static ILogger<IEventLogging> Create(IServiceProvider serviceProvider)
{
return new EventLogging().EventLogger;
}
}
public class EventLogging : IEventLogging
{
#region *-- Private Members --*
private ILogger<IEventLogging> _logger = null;
#endregion
public ILogger<IEventLogging> EventLogger { get { return this._logger; } }
public EventLogging()
{
EventLogSettings settings = new EventLogSettings();
settings.LogName = "Application";
settings.SourceName = "MeCore2";
settings.MachineName = ".";
ILoggerFactory loggerFactory = new LoggerFactory();
loggerFactory.AddProvider(new EventLogLoggerProvider(settings));
this._logger = loggerFactory.CreateLogger<IEventLogging>();
}
}
public interface IEventLogging
{
ILogger<IEventLogging> EventLogger { get; }
}
And in my HostBuilder the following:
.ConfigureServices(services => services.AddTransient(EventLoggingFactory.Create))
What I haven't considered and I'm still wrapping my head around are service LifeTimes. Using this approach the Ilogger is Transient, but is that the best way to implement it?
The final code block on this post has been a sufficient solution for my needs. With a little more effort I've been able to expand the features used to capture log data for viewing in Windows Event Viewer.

Registering Dependency with in NServiceBus with Autofac after upgrade

I am having a problem working out how to register dependencies in my NServiceBus endpoint. I am using NServiceBus 7.2 and Autofac 5.0 and NServiceBus.Autofac 7.0.0 and can't find any examples that use these versions. I am using Asp.Net Core 3.
My Program.cs code looks like this
public class Program
{
public static void Main(string[] args)
{
CreateHostBuilder(args).Build().Run();
}
public static IHostBuilder CreateHostBuilder(string[] args) =>
Host.CreateDefaultBuilder(args)
.UseServiceProviderFactory(new AutofacServiceProviderFactory())
.ConfigureWebHostDefaults(webBuilder =>
{
webBuilder.UseStartup<Startup>();
});
}
My ConfigureServices method looks like this
public void ConfigureServices(IServiceCollection services)
{
services.InstallServicesInAssembly(Configuration);
services.AddAutoMapper(typeof(Startup));
services.AddMediatR(typeof(Startup).Assembly);
}
This runs all the installers I have but this runs BEFORE the ConfigureContainer method called by the Framework. AutoFac automatically adds all the services that have been added in COnfigureServices. I have a separate class for each installer. My ConfigureContainer method is currently empty since the Automapper and MediatR services are added anyway because the services are added in ConfigureServices. This resolves both IMediatR and IMapper when they are injected into the controllers of the Api. But they are not available in the NServiceBus Message Handlers. This is because I can't see how to register the endpoint configuration or share the Autofac container after it is created. See the NServiceBus installer code comment below.
//here we register stuff directly with autofac
public void ConfigureContainer(ContainerBuilder builder)
{
// Register your own things directly with Autofac, like:
//builder.AddAutoMapper(typeof(Startup).Assembly);
// builder.AddMediatR(typeof(Startup).Assembly);
}
I want to be able to make use of AutoMapper and MediatR in my NServiceBus Message Handlers and so want these dependencies injected into the constructors of the handlers.
And My NServiceBusInstaller is as follows
public class NServiceBusInstaller : IInstaller
{
public async void InstallServices(IServiceCollection services, IConfiguration configuration)
{
var rabbitMQSettings = new RabbitMQSettings();
configuration.Bind(nameof(rabbitMQSettings), rabbitMQSettings);
services.AddSingleton(rabbitMQSettings);
var endpointConfiguration = new EndpointConfiguration(rabbitMQSettings.SilvaDirectory);
endpointConfiguration.EnableInstallers();
//Here I want to configure the endpoint to use the dependencies in the AutoFac container
//How to get reference to this container??
/*
endpointConfiguration.UseContainer<AutofacBuilder>(
customizations: customizations => {
customizations.ExistingLifetimeScope(container);
});
*/
var transport = endpointConfiguration.UseTransport<RabbitMQTransport>();
transport.UseConventionalRoutingTopology();
transport.ConnectionString(rabbitMQSettings.ConnectionString);
transport.TimeToWaitBeforeTriggeringCircuitBreaker(TimeSpan.FromMinutes(1));
//services.AddNServiceBus(endpointConfiguration);
await Endpoint.Start(endpointConfiguration).ConfigureAwait(false);
}
}
ANd finally one of my message handlers looks like this. Currently I am getting an Exception because NServiceBus cannot resolve the IMapper and IMediator..
public class CreateDirectoryEntryHandler : IHandleMessages<CreateDirectoryEntry>
{
private readonly IMapper _mapper;
private readonly IMediator _mediator;
public CreateDirectoryEntryHandler(IMapper mapper, IMediator mediator)
{
_mapper = mapper;
_mediator = mediator;
}
public async Task Handle(CreateDirectoryEntry message, IMessageHandlerContext context)
{
var command = _mapper.Map<CreateNewCustomerCommand>(message);
CommandResponse response = await _mediator.Send(command);
if(response.Success)
{
await context.Reply(new DirectoryEntryCreated() { Email = message.Email }).ConfigureAwait(false);
}
else
{
await context.Reply(new DirectoryEntryRejected() { Email = message.Email, Error = response.Error }).ConfigureAwait(false);
}
}
}
I am probably missing something obvious. My mental block is because the ConfigureContainer method is called after the Configure services method by the framework so I don't have the container reference to pass in to the NServiceBus installer. What am I missing? Any help would be greatly appreciated.
Thanks
you might want to look at this sample https://docs.particular.net/samples/dependency-injection/aspnetcore/. It shows how to use Asp.Net Core 3 with NServiceBus and Autofac.
In your sample code, you use endpointConfiguration.UseContainer<AutofacBuilder>() API that assumes it's NServiceBus that controls the lifecycle of the DI container. This obviously isn't the case.
The sample uses NServiceBus.Extensions.Hosting and Autofac.Extensions.DependencyInjection packages. First, makes sure that NServiceBus can work with DI container that is managed externally by via Microsoft.Extensions.Hosting and the second is Autofac adapter for Microsoft DI abstractions.

How do you bind the dependencies of the service dll's at that layer in .NET Core

I would like to make a contained libraries/services in the new .NET Core world. Basically I have several SASS products:
ServiceProduct1: has a repository layer that the UI/Composistion root layer doesn't need to know about.
ServiceProduct2: has a repository layer that the UI/Composistion root layer doesn't need to know about. Has an Email service in it as well.
These two service products are used in multiple applications, but the consuming application has to know to bind the interfaces hidden in the repository. Also the Email service uses Dependency Injection and it has to be
bound in the consuming application, even though it is used by a service.
Prior to .NET Core I would have used Recursion to search the dlls for things to bind:
public static IKernel LoadAssemblies(IKernel kernel)
{
var type = typeof(INinjectDependency);
var dependencies = AppDomain.CurrentDomain.GetAssemblies()
.SelectMany(x => x.GetMatchingTypesInAssembly(y => type.IsAssignableFrom(y) && y.IsClass));
var assemblies = dependencies.Select(Assembly.GetAssembly).Distinct();
kernel.Load(assemblies);
return kernel;
}
Then in the consumed services you would do all your binding.
I am not using Ninject any longer but the concept is the same. Now unless you swap to publish the dll's on build, you cannot use this approach anymore. I do not want to publish my dll's.
Is there another way to handle this?
A lot of the documentation floating around points specifically to the implementation of ASP.NET Core, so I can see why this is confusing. The answer is rather simple. If your services are full executables, i.e.; when compiled they generate an *.exe then you need to wire-up you services at startup - somewhere near the main entry point. If your service is simply a *.dll, then you must have a host application (executable) that wires up the dependencies for you - and then hands you the service collection, such that you can construct an IServiceProvider.
Here is a great article on Dependency Injection with .NET Core. Here is the example of how you would achieve this:
public class Host
{
public static void Main()
{
IServiceCollection serviceCollection = new ServiceCollection();
ConfigureServices(serviceCollection);
var application = new Application(serviceCollection);
// Run
// ...
}
static void ConfigureServices(
IServiceCollection serviceCollection)
{
ILoggerFactory loggerFactory = new Logging.LoggerFactory();
serviceCollection.AddInstance<ILoggerFactory>(loggerFactory);
}
}
There are some standard naming conventions here, notice the ConfigureServices. Then the Application object is defined as such:
public class Application
{
public IServiceProvider Services { get; set; }
public ILogger Logger { get; set; }
public Application(IServiceCollection serviceCollection)
{
ConfigureServices(serviceCollection);
// The service-provider is not built until all services are configured.
Services = serviceCollection.BuildServiceProvider();
Logger =
Services.GetRequiredService<ILoggerFactory>()
.CreateLogger<Application>();
Logger.LogInformation("Application created successfully.");
}
public void MakePayment(PaymentDetails paymentDetails)
{
Logger.LogInformation(
$"Begin making a payment { paymentDetails }");
IPaymentService paymentService =
Services.GetRequiredService<IPaymentService>();
// ...
}
void ConfigureServices(IServiceCollection serviceCollection)
{
serviceCollection.AddSingleton<IPaymentService, PaymentService>();
}
}
We can now imagine that the interface and corresponding implementation of the payment service looks something like this:
public class PaymentService: IPaymentService
{
public ILogger Logger { get; }
public PaymentService(ILoggerFactory loggerFactory)
{
Logger = loggerFactory?.CreateLogger<PaymentService>();
if (Logger == null)
{
throw new ArgumentNullException(nameof(loggerFactory));
}
Logger.LogInformation("PaymentService created");
}
}
Note
This does not have to be an ASP.NET Core application.

Cannot get a working Unity Session Lifetime Manager, ASP.NET MVC5

I've read and Googled everything on this, but can't seem to get it to work. I created a custom LifetimeManager for Unity in my MVC5 application based on these posts:
MVC3 Unity Framework and Per Session Lifetime Manager
This may be the issue I am experiencing
Here is my SessionLifetimeManager
public class SessionLifetimeManager : LifetimeManager
{
private string key = Guid.NewGuid().ToString();
public override object GetValue()
{
return HttpContext.Current.Session[key];
}
public override void RemoveValue()
{
HttpContext.Current.Session.Remove(key);
}
public override void SetValue(object newValue)
{
HttpContext.Current.Session[key] = newValue;
}
}
I only have a few types I'm playing with, here is the relevant registrations in UnityConfig.cs:
container.RegisterType<IEpiSession, EpiSession>(new SessionLifetimeManager(),
new InjectionConstructor(config.AppServerURI, config.PathToSysConfig));
container.RegisterType<IReportRepository, EpicorReportRepository>(new TransientLifetimeManager());
DependencyResolver.SetResolver(new UnityDependencyResolver(container));
Note that the EpicorReportRepository has a dependency on IEpiSession via constructor injection.
public class EpicorReportRepository : IReportRepository
{
private IEpiSession session;
// DI constructor
public EpicorReportRepository(IEpiSession session) {
this.session = session;
}
// ...
}
My Problem: After the first user / session connects to the application, every new user / session after that seems to still be using the EpiSession object and credentials that the first user had create/injected for him. This seems to be a common pattern used on the interwebs, so I'm wondering what I am missing.
How did you test that IEpiSession is the same in different Sessions?
Try to open you application from different browsers. If you open several tabs in the same browser then the same session is used.
I checked your code and it works for me.
There is the only one difference in SetResolver():
DependencyResolver.SetResolver(
type => container.Resolve(type),
types => container.ResolveAll(types));
The full registration code is the following:
public class MvcApplication : System.Web.HttpApplication
{
protected void Application_Start()
{
...
var container = new UnityContainer();
container.RegisterType<IEpiSession, EpiSession>(
new SessionLifetimeManager(),
new InjectionConstructor("config.AppServerURI", "config.PathToSysConfig"));
container.RegisterType<IReportRepository, EpicorReportRepository>(new TransientLifetimeManager());
DependencyResolver.SetResolver(
type => container.Resolve(type),
types => container.ResolveAll(types));
}
}

How can I get started with ASP.NET (5) Core and Castle Windsor for Dependency Injection?

Background:
I've used Castle Windsor with Installers and Facilities according to the Castle Windsor tutorial with earlier versions of MVC (pre-6) and WebAPI.
ASP.NET (5) Core has included some Dependency Injection support but I still haven't figured out exactly how to wire it up, and the few samples I have found look a lot different than how I've used it before (with the installers/facilities). Most examples predate ASP.NET (5) cores recent release and some seem to have outdated information.
It seems to have changed quite radically from the previous versions composition root setup, and not even Microsoft.Framework.DependencyInjection.ServiceProvider can resolve all of the dependencies when I set it as the Castle Windsor DI fallback. I'm still digging into the details but there isn't much up to date information.
My attempt to use Castle Windsor for DI
I've found an adapter like this: Github Castle.Windsor DI container.
Startup.cs
private static IWindsorContainer container;
public void Configure(IApplicationBuilder app, IHostingEnvironment env, ILoggerFactory loggerfactory)
{
container = new WindsorContainer();
app.UseServices(services =>
{
// ADDED app.ApplicationServices FOR FALLBACK DI
container.Populate(services, app.ApplicationServices);
container.BeginScope();
return container.Resolve<IServiceProvider>();
});
// ... default stuff
WindsorRegistration.cs
I added a few lines to add a Castle Windsor ILazyComponentLoader fallback.
using Castle.MicroKernel.Lifestyle;
using Castle.MicroKernel.Registration;
using Castle.MicroKernel.Resolvers.SpecializedResolvers;
using Castle.Windsor;
using Microsoft.Framework.DependencyInjection;
using System;
using System.Collections.Generic;
using System.Reflection;
namespace Notes.Infrastructure
{
/// <summary>
/// An adapted current autofac code to work with Castle.Windsor container.
/// https://github.com/aspnet/Home/issues/263
/// </summary>
public static class WindsorRegistration
{
public static void Populate(
this IWindsorContainer container,
IEnumerable<IServiceDescriptor> descriptors,
IServiceProvider fallbackProvider // ADDED FOR FALLBACK DI
)
{
// ADDED FOR FALLBACK DI
// http://davidzych.com/2014/08/27/building-the-castle-windsor-dependency-injection-populator-for-asp-net-vnext/
// Trying to add a fallback if Castle Windsor doesn't find the .NET stuff
var fallbackComponentLoader = new FallbackLazyComponentLoader(fallbackProvider);
container.Register(Component.For<ILazyComponentLoader>().Instance(fallbackComponentLoader));
// Rest as usual from the Github link
container.Register(Component.For<IWindsorContainer>().Instance(container));
container.Register(Component.For<IServiceProvider>().ImplementedBy<WindsorServiceProvider>());
container.Register(Component.For<IServiceScopeFactory>().ImplementedBy<WindsorServiceScopeFactory>());
container.Kernel.Resolver.AddSubResolver(new CollectionResolver(container.Kernel));
Register(container, descriptors);
}
private static void Register(
IWindsorContainer container,
IEnumerable<IServiceDescriptor> descriptors)
{
foreach (var descriptor in descriptors)
{
if (descriptor.ImplementationType != null)
{
// Test if the an open generic type is being registered
var serviceTypeInfo = descriptor.ServiceType.GetTypeInfo();
if (serviceTypeInfo.IsGenericTypeDefinition)
{
container.Register(Component.For(descriptor.ServiceType)
.ImplementedBy(descriptor.ImplementationType)
.ConfigureLifecycle(descriptor.Lifecycle)
.OnlyNewServices());
}
else
{
container.Register(Component.For(descriptor.ServiceType)
.ImplementedBy(descriptor.ImplementationType)
.ConfigureLifecycle(descriptor.Lifecycle)
.OnlyNewServices());
}
}
else if (descriptor.ImplementationFactory != null)
{
var service1 = descriptor;
container.Register(Component.For(descriptor.ServiceType)
.UsingFactoryMethod<object>(c =>
{
var builderProvider = container.Resolve<IServiceProvider>();
return
service1.ImplementationFactory(builderProvider);
})
.ConfigureLifecycle(descriptor.Lifecycle)
.OnlyNewServices());
}
else
{
container.Register(Component.For(descriptor.ServiceType)
.Instance(descriptor.ImplementationInstance)
.ConfigureLifecycle(descriptor.Lifecycle)
.OnlyNewServices());
}
}
}
private static ComponentRegistration<object> ConfigureLifecycle(
this ComponentRegistration<object> registrationBuilder,
LifecycleKind lifecycleKind)
{
switch (lifecycleKind)
{
case LifecycleKind.Singleton:
registrationBuilder.LifestyleSingleton();
break;
case LifecycleKind.Scoped:
registrationBuilder.LifestyleScoped();
break;
case LifecycleKind.Transient:
registrationBuilder.LifestyleTransient();
break;
}
return registrationBuilder;
}
private class WindsorServiceProvider : IServiceProvider
{
private readonly IWindsorContainer _container;
public WindsorServiceProvider(IWindsorContainer container)
{
_container = container;
}
public object GetService(Type serviceType)
{
return _container.Resolve(serviceType);
}
}
private class WindsorServiceScopeFactory : IServiceScopeFactory
{
private readonly IWindsorContainer _container;
public WindsorServiceScopeFactory(IWindsorContainer container)
{
_container = container;
}
public IServiceScope CreateScope()
{
return new WindsorServiceScope(_container);
}
}
private class WindsorServiceScope : IServiceScope
{
private readonly IServiceProvider _serviceProvider;
private readonly IDisposable _scope;
public WindsorServiceScope(IWindsorContainer container)
{
_scope = container.BeginScope();
_serviceProvider = container.Resolve<IServiceProvider>();
}
public IServiceProvider ServiceProvider
{
get { return _serviceProvider; }
}
public void Dispose()
{
_scope.Dispose();
}
}
}
}
First hiccup and resolution attempt
From that example I was getting:
An exception of type 'Castle.MicroKernel.ComponentNotFoundException' occurred in Castle.Windsor.dll but was not handled in user code
Additional information: No component for supporting the service Microsoft.Framework.Runtime.IAssemblyLoaderEngine was found
It wasn't available looking in the debugger at the Castle Fallback - Microsoft.Framework.DependencyInjection.ServiceProvider (table of services).
From http://davidzych.com/tag/castle-windsor/ I have tried to add a Fallback since Windsor couldn't resolve all of the ASP.NET dependencies.
FallbackLazyComponentLoader.cs
/// <summary>
/// https://github.com/davezych/DependencyInjection/blob/windsor/src/Microsoft.Framework.DependencyInjection.Windsor/FallbackLazyComponentLoader.cs
/// </summary>
public class FallbackLazyComponentLoader : ILazyComponentLoader
{
private IServiceProvider _fallbackProvider;
public FallbackLazyComponentLoader(IServiceProvider provider)
{
_fallbackProvider = provider;
}
public IRegistration Load(string name, Type service, IDictionary arguments)
{
var serviceFromFallback = _fallbackProvider.GetService(service);
if (serviceFromFallback != null)
{
return Component.For(service).Instance(serviceFromFallback);
}
return null;
}
}
It was seemingly necessary (to inject all the .NET dependencies)
I could comment out startup.cs app.UseBrowserLink(); to get rid of the IAssemblyLoaderEngine exception.
if (string.Equals(env.EnvironmentName, "Development", StringComparison.OrdinalIgnoreCase))
{
//app.UseBrowserLink(); //
Now I run into an exception:
An exception of type 'System.Reflection.TargetInvocationException' occurred in mscorlib.dll but was not handled in user code
Trying to get the service: {Name = "IUrlHelper" FullName = "Microsoft.AspNet.Mvc.IUrlHelper"}
public IRegistration Load(string name, Type service, IDictionary arguments)
{
var serviceFromFallback = _fallbackProvider.GetService(service);
How to move forward?
What is wrong with this attempt to wire up Castle Windsor DI into ASP.NET (5) Core?
For now I don't think you can use Castle Windsor Container as the DI container because Windsor doesn't support the new DNVM. But AutoFac does and they follow the same rule.
In the Startup.cs there is a ConfigureServices method whose return type is void. You can change the return type to ISerivceProvider and return a concrete IServiceProvider, the system will use the new IServiceProvider as the default DI container. Below is the AutoFac example.
public IServiceProvider ConfigureServices(IServiceCollection services)
{
services.Configure<AppSettings>(Configuration.GetSubKey("AppSettings"));
services.AddMvc();
var builder = new ContainerBuilder();
AutofacRegistration.Populate(builder, services);
var container = builder.Build();
return container.Resolve<IServiceProvider>();
}
The other DI adapters also implemented the similar interfaces. You can try yourself, but note AutoFac is in beta5 now so you need to make some adjustment to make your application run.
Hope this helps
There is a lot going on in your question, and to be honest I don't understand all of it.
However, there is a working Castle Windsor composition root in MvcSiteMapProvider that you are welcome reverse-engineer. Follow these steps to get a working composition root demo project for Windsor:
Create a new MVC 5 project.
Install MvcSiteMapProvider.MVC5.DI.Windsor.
Analyze the following files for the basic structure:
/App_Start/DIConfig.cs
/App_Start/CompositionRoot.cs
/DI/InjectableControllerFactory.cs
/DI/Windsor/WindsorDependencyInjectionContainer.cs
/DI/Windsor/Installers/MvcInstaller.cs
/DI/Windsor/Installers/MvcSiteMapProviderInstaller.cs
Once you have this working configuration, you can then refactor it and add to it to suit your application's needs.
As I recall, there weren't any changes required to make the MVC 4 DI configuration work with MVC 5. So, the problem you are running into is most likely one of the following:
You are using a 3rd party DI component that is not compatible with MVC 5.
You are using DependencyResolver, and your configuration doesn't include the necessary code to resolve the dependencies of MVC 5.
You are using advanced features of Castle Windsor that we are not using, and have them misconfigured in some way.
ControllerFactory vs DependencyResolver
Do note that according to Dependency Injection in .NET by Mark Seemann (which I highly recommend), it is ill-advised to use IDependencyResolver with Castle Windsor because it guarantees resource leaks. In fact, this is probably the most compelling argument that he makes for his reasoning for declaring service locator as anti-pattern.
The recommended approach is to use IControllerFactory as the integration point into MVC, which implements a ReleaseController method to solve this issue.
So looking at your code, literally all of it can be replaced by Castle.Windsor.MsDependencyInjection library.
Add Castle.Windsor.MsDependencyInjection to your project then use like so:
public IServiceProvider ConfigureServices(IServiceCollection services)
{
services.AddMvc();
// Normal component registration can go here...
return WindsorRegistrationHelper.CreateServiceProvider(yourWindsorContainer, services);
}

Resources