I want to use NopCommerce libraries for a console project (for migrate data transfer).
I create a console project and add the base libraries (Nop.Core, Nop.Data, Nop.Service, Nop.Web.Freamework) to it, I also copy the App_Data folder.
I also use Class Startup.cs to run the project
namespace Nop.Console
{
class Program
{
static void Main(string[] args)
{
using var host = Host.CreateDefaultBuilder(args)
.UseServiceProviderFactory(new AutofacServiceProviderFactory())
.ConfigureWebHostDefaults(webBuilder => webBuilder
.ConfigureAppConfiguration(config =>
{
config
.AddJsonFile(NopConfigurationDefaults.AppSettingsFilePath, true, true)
.AddEnvironmentVariables();
})
.UseStartup<Startup>())
.Build();
var engine = EngineContext.Create();
var cs = engine.Resolve<ICategoryService>();
System.Console.WriteLine("Hello World!");
}
}
}
But engine.Resolve(); return null;
Any idea?
I'm not 100% sure if this is the best solution, but at least works for me for NopCommerce 4.40.4. The code in my Console application is following:
/// <summary>
/// EngineContextInitializer
/// </summary>
public static class EngineContextInitializer
{
/// <summary>
/// Runs this instance.
/// </summary>
public static async Task<IHost> RunAsync()
{
string[] args = Array.Empty<string>();
var host = Host.CreateDefaultBuilder(args)
.UseServiceProviderFactory(new AutofacServiceProviderFactory())
.ConfigureWebHostDefaults(webBuilder => webBuilder
.ConfigureAppConfiguration(config =>
{
config
.AddJsonFile(NopConfigurationDefaults.AppSettingsFilePath, true, true)
.AddEnvironmentVariables();
})
.UseStartup<Startup>())
.Build();
//start the program, a task will be completed when the host starts
await host.StartAsync();
return host;
}
}
The usage of EngineContextInitializer is following:
private async Task GetProductById(int id)
{
using var host = await EngineContextInitializer.RunAsync();
IEngine engine = EngineContext.Current;
var productService = engine.Resolve<IProductService>();
var product = await productService.GetProductByIdAsync(id);
await host.StopAsync();
}
So what does make the difference between your and mine code?
I'm running the code:
await host.StartAsync();
Most importantly I'm disposing IHost after I got the product from IProductService.
On the line is the difference:
var host = Host.CreateDefaultBuilder(args)
And 1 more thing, you don't need to call EngineContext.Create(), because if you check the class and Current getter you will see the following code:
/// <summary>
/// Gets the singleton Nop engine used to access Nop services.
/// </summary>
public static IEngine Current
{
get
{
if (Singleton<IEngine>.Instance == null)
{
Create();
}
return Singleton<IEngine>.Instance;
}
}
Please don't forget to dispose IHost as it implements IDisposable to avoid memory leaks.
Disclaimer: I'm not part of NopCommerce dev team, usage is at your own risk. Please follow official NopCommerce documentation or response on the topic on their website (documentation, forum or GitHub).
Related
I'm going around in circles with this. Is there any way to use the Castle Windsor dependency injection adapter (https://github.com/volosoft/castle-windsor-ms-adapter) with Azure Function apps?
The code example on the adaptor github page is for ASP.NET Core but I would have imagined that there'd be a way to specify the service provider used for a function app, too?
There have been no official documents on this but there is a feature request made by DavidJFowler
Please find the sample code from the above feature request.
The IJobActivatorEx implementation:
public class CastleWindsorJobActivator : IJobActivatorEx
{
private readonly WindsorContainer container;
public CastleWindsorJobActivator(WindsorContainer container) => this.container = container;
public T CreateInstance<T>(IFunctionInstanceEx functionInstance)
{
var disposer = functionInstance.InstanceServices.GetRequiredService<ScopeDisposable>();
disposer.Scope = container.BeginScope();
return container.Resolve<T>();
}
// Ensures a created Castle.Windsor scope is disposed at the end of the request
public sealed class ScopeDisposable : IDisposable
{
public IDisposable Scope { get; set; }
public void Dispose() => this.Scope?.Dispose();
}
public T CreateInstance<T>()
{
var disposer = container.Resolve<ScopeDisposable>();
disposer.Scope = container.BeginScope();
return container.Resolve<T>();
}
}
Startup class:
[assembly: FunctionsStartup(typeof(FunctionApp2.Startup))]
namespace FunctionApp2
{
public class Startup: FunctionsStartup
{
public override void Configure(IFunctionsHostBuilder builder)
{
var container = new WindsorContainer();
container.Register(Component.For<IScoped1>().ImplementedBy<Scoped1>().LifestyleScoped())
.Register(Component.For<IScoped2>().ImplementedBy<Scoped2>().LifestyleScoped())
.Register(Component.For<ISingleton1>().ImplementedBy<Singleton1>())
.Register(Component.For<ISingleton2>().ImplementedBy<Singleton2>());
// register function classes in container
var functions = Assembly.GetExecutingAssembly().GetTypes().Where(t =>
t.GetMethods().Any(m => m.GetCustomAttributes(typeof(FunctionNameAttribute), false).Any()));
foreach (var function in functions)
{
container.Register(Component.For(function).LifestyleScoped());
}
builder.Services.AddScoped<CastleWindsorJobActivator.ScopeDisposable>()
.AddSingleton<IJobActivator>(new CastleWindsorJobActivator(container));
container.AddServices(builder.Services);
}
}
}
Example function:
public class Function1
{
public Function1(IScoped1 scoped1, IScoped2 scoped2, ISingleton1 singleton1, ISingleton2 singleton2)
{
}
[FunctionName("Function1")]
public async Task<IActionResult> Run(
[HttpTrigger(AuthorizationLevel.Function, "get", "post", Route = null)] HttpRequest req,
ILogger log)
{
log.LogInformation("C# HTTP trigger function processed a request.");
string name = req.Query["name"];
string requestBody = await new StreamReader(req.Body).ReadToEndAsync();
dynamic data = JsonConvert.DeserializeObject(requestBody);
name = name ?? data?.name;
return name != null
? (ActionResult)new OkObjectResult($"Hello, {name}")
: new BadRequestObjectResult("Please pass a name on the query string or in the request body");
}
}
For now, this feature isn't officially released but you can follow other dependency injection patterns. You can raise a feature request from Microsoft QnA or from Azure Portal.
I'm developing a .NET core 3.1 Console application (web-api).
I use a Serilog service (it is basically using the Microsoft.Extensions.Logging).
The Serilog is injected and can be used in the FW Controllers methods.
Now - I need something a little bit different - Whenever the system is starting up (after being down) I need to make an http post request - you can see it when executing the ConnectionInitiator.Initiate(), in the startup method. In that same scope (method\class) - I need to use the logger, in order to log some data. Now - If the request would be through the controller - the logger, would be available (by the DI).
To make a long story short - I need somehow to inject the Ilogger to the class or to make it available in some other way. I've tried use the logger in the startUp, but this seems to be impossible (since .net core 3.0 - if I understand correctly)
See my code:
Program.cs:
public class Program
{
public static void Main(string[] args)
{
var loggerConfig = new ConfigurationBuilder()
.AddJsonFile("appsettings.json")
.Build();
//Reading the appconfig.json
Log.Logger = new LoggerConfiguration().ReadFrom.Configuration(loggerConfig).CreateLogger();
try
{
Log.Information("System Started up");
CreateWebHostBuilder(args).Build().Run();
}
catch (Exception ex)
{
Log.Fatal(ex, "THE APPLICATION FAILED TO START UP");
}
finally
{
Log.CloseAndFlush();
}
}
public static IWebHostBuilder CreateWebHostBuilder(string[] args)
{
return WebHost.CreateDefaultBuilder(args).ConfigureLogging((context, logging) =>
{
logging.ClearProviders();
}).UseSerilog().UseStartup<Startup>();
}
public static IHostBuilder CreateHostBuilder(string[] args) =>
Host.CreateDefaultBuilder(args)
.ConfigureWebHostDefaults(webBuilder =>
{
webBuilder.UseStartup<Startup>();
});
}
StartUp.cs
public class Startup
{
public Startup(IConfiguration configuration/*, Microsoft.Extensions.Logging.ILogger logger*/)
{
Configuration = configuration;
ConnectionInitiator.Initiate(configuration/*, logger*/);
}
public IConfiguration Configuration { get; }
// This method gets called by the runtime. Use this method to add services to the container.
public void ConfigureServices(IServiceCollection services)
{
services.AddCors();
services.AddControllers();
services.AddLogging(loggingBuilder => loggingBuilder.AddSerilog(dispose: true));
}
// This method gets called by the runtime. Use this method to configure the HTTP request pipeline.
public void Configure(IApplicationBuilder app, IWebHostEnvironment env)
{
app.UseCors(builder => builder.AllowAnyHeader().AllowAnyMethod().SetIsOriginAllowed((host) => true).AllowCredentials());
if (env.IsDevelopment())
{
app.UseDeveloperExceptionPage();
}
app.UseRouting();
app.UseAuthentication();
app.UseEndpoints(endpoints =>
{
endpoints.MapControllers();
});
}
}
ConnectionInitiator.cs:
using Microsoft.Extensions.Configuration;
using Microsoft.Extensions.Logging;
using System.Threading.Tasks;
namespace AAA.BL
{
public static class ConnectionInitiator
{
private static readonly object threadlock = new object();
private static MyConfig myConfig;
private static ILogger ilogger;
/*
public ConnectionInitiator(ILogger _logger)
{
ilogger = _logger;
}
*/
public static void/*async Task*/ Initiate(IConfiguration configuration/*, ILogger ilogger*/)
{
HttpRequester httpRequester = new HttpRequester();
if (myConfig == null)
{
myConfig = new myConfig(configuration);
}
IssueOTPResponse response = /*await*/ httpRequester.PostSomething(myConfig, ilogger).Result; //Double check thread safe singleton implementation
if (response.ststuacode != 200)
{
ilogger.logcritical($"critical error when initiate connection (connectioninitiator): {response.statusdescription}");
}
}
}
}
It seems like the answer is much simpler that I expected - By using the Serilog and was added as a service in the Configure method - It can be reached globally (in every place of the namepsace) by using the static class Log and its static method Logger, for example:
Log.Logger.Information("XXXXX");
I'm currently working on a POC project and I'm trying to figure out how I can share a service dependency between different endpoints to control application state and handle all service requests (lets call it ControlService) - specifically when one of those endpoints is a KestrelCommunicationListener / HttpSysCommunicationListener and combined with a FabricTransportServiceRemotingListener (or any other type of custom listener)
Autofac looked promising but the examples don't show how to get a HTTP listener working when the container is built in startup rather than the main entry point - would I need to pass the container to MyFabricService so it can be passed into and added to by the startup registrations?
I've seen references to using container.Update() or adding registrations on the fly using container.BeginLifetimeScope() but they are all using a container built in main and then I'm not sure how I would add the APIs created by the HTTP listener to the original container.
I'm possibly not explaining it that well so in summary I'm looking to have something like the below service that can receive communications via n. different endpoints - process the message and then send messages out via n. clients (aka other service endpoints)
Happy to clarify if anything is unclear - perhaps even using another creative diagram :)
Updated:
From Program.Main()
ServiceRuntime.RegisterServiceAsync("ManagementServiceType",
context => new ManagementService(context)).GetAwaiter().GetResult();
Here is my fabric service
public ManagementService(StatefulServiceContext context)
: base(context)
{
//this does not work but is pretty much what I'm after
_managementService = ServiceProviderFactory.ServiceProvider.GetService(typeof(IManagementService)) as IManagementService;
}
protected override IEnumerable<ServiceReplicaListener> CreateServiceReplicaListeners() =>
new ServiceReplicaListener[]
{
//create external http listener
ServiceReplicaListenerFactory.CreateExternalListener(typeof(Startup), StateManager, (serviceContext, message) => ServiceEventSource.Current.ServiceMessage(serviceContext, message), "ServiceEndpoint"),
//create remoting listener with injected dependency
ServiceReplicaListenerFactory.CreateServiceReplicaListenerFor(() => new RemotingListenerService(_managementService), "ManagmentServiceRemotingEndpoint", "ManagementServiceListener")
};
ServiceReplicaListener
public static ServiceReplicaListener CreateExternalListener(Type startupType, IReliableStateManager stateManager, Action<StatefulServiceContext, string> loggingCallback, string endpointname)
{
return new ServiceReplicaListener(serviceContext =>
{
return new KestrelCommunicationListener(serviceContext, endpointname, (url, listener) =>
{
loggingCallback(serviceContext, $"Starting Kestrel on {url}");
return new WebHostBuilder().UseKestrel()
.ConfigureServices((hostingContext, services) =>
{
services.AddSingleton(serviceContext);
services.AddSingleton(stateManager);
services.AddApplicationInsightsTelemetry(hostingContext.Configuration);
services.AddSingleton<ITelemetryInitializer>((serviceProvider) => new FabricTelemetryInitializer(serviceContext));
})
.ConfigureAppConfiguration((hostingContext, config) =>
{
config.AddServiceFabricConfiguration(serviceContext);
})
.ConfigureLogging((hostingContext, logging) =>
{
logging.AddConfiguration(hostingContext.Configuration.GetSection("Logging"));
logging.AddDebug();
})
.UseContentRoot(Directory.GetCurrentDirectory())
.UseServiceFabricIntegration(listener, ServiceFabricIntegrationOptions.None)
.UseStartup(startupType)
.UseUrls(url)
.Build();
});
});
}
Startup
public class Startup
{
private const string apiTitle = "Management Service API";
private const string apiVersion = "v1";
private readonly IConfiguration configuration;
public Startup(IConfiguration configuration)
{
this.configuration = configuration;
}
public void ConfigureServices(IServiceCollection services)
{
var modules = new List<ICompositionModule>
{
new Composition.CompositionModule(),
new BusinessCompositionModule()
};
foreach (var module in modules)
{
module.AddServices(services, configuration);
}
services.AddSwashbuckle(configuration, apiTitle, apiVersion, "ManagementService.xml");
}
public void Configure(IApplicationBuilder app, IHostingEnvironment env, ILoggerFactory loggerFactory)
{
loggerFactory.AddApplicationInsights(app.ApplicationServices);
// app.UseAuthentication();
// app.UseSecurityContext();
if (env.IsDevelopment())
{
app.UseDeveloperExceptionPage();
// app.UseBrowserLink();
}
else
{
app.UseExceptionHandler("/Home/Error");
}
app.UseStaticFiles();
app.UseCors("CorsPolicy");
app.UseMvc();
app.UseSwagger(apiTitle, apiVersion);
//app.UseMvc(routes =>
//{
// routes.MapRoute(
// name: "default",
// template: "{controller=Home}/{action=Index}/{id?}");
//});
}
}
All the service dependencies are added in the CompositionModules using Microsoft.Extensions.DependencyInjection (not autofac) in startup.cs
This works great and creates my HTTP listener - I now just need a way of getting access to my services that were added to the container during startup of my http listener / webhost.
You can use Autofac.Integration.ServiceFabriŅ, an Autofac extension to support Service Fabric. You need to create a container in Program.cs
var builder = new ContainerBuilder();
builder.RegisterServiceFabricSupport();
builder.RegisterType<SomeService>().As<IManagementService>();
builder.RegisterStatelessService<ManagementService>("ManagementServiceType");
using (builder.Build())
{
// Prevents this host process from terminating so services keep running.
Thread.Sleep(Timeout.Infinite);
}
Then you can inject it to the constructor of your fabric service. You can find more information on this topic on https://alexmg.com/posts/introducing-the-autofac-integration-for-service-fabric
#Tim
Sorry for a late response. Currently I am working on library package that we use in our company for internal projects. This library simplifies configuration of Reliable Services. I think our recent enhancements can do what you need to do (hope I get the use case correctly).
All the information about the library can be found on project page on GitHub and NuGet package can be found here (please note that it is a pre-release version but we are planning to turn into complete release soon).
In case you have any questions or need more information feel free to contact me.
UPDATE
I have create a sample application. Please feel free to try it.
Here is a code example.
public interface IManagementService
{
string GetImportantValue();
}
public interface IMessageProvider
{
string GetMessage();
}
public class MessageProvider : IMessageProvider
{
public string GetMessage()
{
return "Value";
}
}
public class ManagementService : IManagementService
{
private readonly IMessageProvider provider;
public ManagementService(
IMessageProvider provider)
{
this.provider = provider;
}
public string GetImportantValue()
{
// Same instances should have the same hash
return this.provider.GetMessage() + $"Hash: {this.GetHashCode()}";
}
}
public interface IRemotingImplementation : IService
{
Task<string> RemotingGetImportantValue();
}
public class RemotingImplementation : IRemotingImplementation
{
private readonly IManagementService managementService;
public RemotingImplementation(
IManagementService managementService)
{
this.managementService = managementService;
}
public Task<string> RemotingGetImportantValue()
{
return Task.FromResult(this.managementService.GetImportantValue());
}
}
public class WebApiImplementationController : ControllerBase
{
private readonly IManagementService managementService;
public WebApiImplementationController(
IManagementService managementService)
{
this.managementService = managementService;
}
[HttpGet]
public Task<string> WebApiGetImportantValue()
{
return Task.FromResult(this.managementService.GetImportantValue());
}
}
public class WebApiStartup
{
private readonly IConfiguration configuration;
public WebApiStartup(
IConfiguration configuration)
{
this.configuration = configuration;
}
public void ConfigureServices(
IServiceCollection services)
{
services.AddMvc();
}
public void Configure(
IApplicationBuilder app,
IHostingEnvironment env,
ILoggerFactory loggerFactory)
{
app.UseMvcWithDefaultRoute();
}
}
internal static class Program
{
/// <summary>
/// This is the entry point of the service host process.
/// </summary>
private static void Main()
{
var host = new HostBuilder()
.ConfigureServices(
services =>
{
services.AddTransient<IMessageProvider, MessageProvider>();
services.AddSingleton<IManagementService, ManagementService>();
})
.ConfigureStatefulService(
serviceBuilder =>
{
serviceBuilder
.UseServiceType("StatefulServiceType")
.DefineAspNetCoreListener(
listenerBuilder =>
{
listenerBuilder
.UseEndpointName("ServiceEndpoint")
.UseKestrel()
.UseUniqueServiceUrlIntegration()
.ConfigureWebHost(
webHostBuilder =>
{
webHostBuilder.UseStartup<WebApiStartup>();
});
})
.DefineRemotingListener(
listenerBuilder =>
{
listenerBuilder
.UseEndpointName("ServiceEndpoint2")
.UseImplementation<RemotingImplementation>();
});
})
.Build()
.Run();
}
}
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 am developing a Web Api and I decided to use custom DependencyResolver. I refer this [Dependency Injection for Web API Controllers] article. Everything is working well so far in the terms of dependency injection into controllers. Code snippet of my configuration from my Owin startup class
private void RegisterIoC(HttpConfiguration config)
{
_unityContainer = new UnityContainer();
_unityContainer.RegisterType<IAccountService, AccountService>();
.........
.........
config.DependencyResolver = new UnityResolver(_unityContainer);
}
But at the time when Api starts for the very first time some ResolutionFailedException thrown (but catched) inside the UnityResolver's GetService method. Here is the exception message
"Exception occurred while: while resolving.
Exception is: InvalidOperationException -
The current type, System.Web.Http.Hosting.IHostBufferPolicySelector,
**is an interface and cannot be constructed. Are you missing a type mapping?**"
Above same exception thrown following types
System.Web.Http.Hosting.IHostBufferPolicySelector
System.Web.Http.Tracing.ITraceWriter
System.Web.Http.Metadata.ModelMetadataProvider
System.Web.Http.Tracing.ITraceManager
System.Web.Http.Dispatcher.IHttpControllerSelector
System.Web.Http.Dispatcher.IAssembliesResolver
System.Web.Http.Dispatcher.IHttpControllerTypeResolver
System.Web.Http.Controllers.IHttpActionSelector
System.Web.Http.Controllers.IActionValueBinder
System.Web.Http.Validation.IBodyModelValidator
System.Net.Http.Formatting.IContentNegotiator
I know that these ResolutionFailedException are thrown because I did not provide mappings in my unity configuration for above types.
Now here is my question :-, If I implement custom unity DependencyResolver I need to define mappings of above types and if need to define what will be their corresponding default implementation types OR is there some alternative way to implement DependencyResolver. I am really concerned even though application is running fine now, failing to resolve above type can cause serious issue later. Please help.
One final Addition:-
For following types, same ResolutionFailedException thrown when I make request for any action into the my web api
System.Web.Http.Dispatcher.IHttpControllerActivator
System.Web.Http.Validation.IModelValidatorCache
System.Web.Http.Controllers.IHttpActionInvoker
I was running in to the same issue using Unity with WebApi and OWIN/Katana.
The solution for me was to use the UnityDependencyResolver defined in the Unity.WebApi Nuget package instead of my own custom implementation (like #Omar Alani above)
Install-Package Unity.WebAPI
Note that the package will try and add a file named UnityConfig.cs in App_Start (the filename I used myself).
In that UnityConfig.cs file the package will add code to register the container against the GlobalConfiguration.Configuration.DependencyResolver which is not what we want with OWIN.
So instead of using:
GlobalConfiguration.Configuration.DependencyResolver = new UnityDependencyResolver(container);
Change to use:
config.DependencyResolver = new UnityDependencyResolver(container);
For completeness:
My UnityConfig.cs
public static class UnityConfig
{
public static void Register(HttpConfiguration config)
{
var container = new UnityContainer();
// Your mappings here
config.DependencyResolver = new UnityDependencyResolver(container);
}
}
My Startup.cs
[assembly: OwinStartup(typeof(UnityTest.BusinessLayer.Api.ApiStartup))]
namespace UnityTest.BusinessLayer.Api
{
public partial class ApiStartup
{
public void Configuration(IAppBuilder app)
{
app.UseCors(Microsoft.Owin.Cors.CorsOptions.AllowAll);
HttpConfiguration httpConfig = new HttpConfiguration();
UnityConfig.Register(httpConfig);
ConfigureAuth(app); //In App_Start ->Startup.Auth
WebApiConfig.Register(httpConfig);
app.UseWebApi(httpConfig);
}
}
}
In case any of the above solutions still don't work for people, here's how I solved it.
After spending a day chasing down this error, it turned out to be some sort of VS caching issue. Out of desperation, I deleted all .suo files and force-get-latest, which seems to have resolved the issue.
This has been asked a long time ago, but I encountered a solution that wasn't mentioned here so maybe someone is still interested.
In my case, these exceptions were already caught internally by Unity (or whatever), but my Exception Settings in Visual Studio made them still show up. I just had to uncheck the "Break when this exception type is shown" check box and the application went on functioning normally.
The implementation of Unity.WebAPI is not very different from the one mentioned in the question. I liked the version referred to by the OP as it ignores only ResultionFailedException and lets the rest propagate up the stack. Unity.WebAPI suppresses all exceptions. What I'd do is ignore errors that we know are safe to do so and log (or rethrow) others.
public object GetService(Type serviceType)
{
try
{
return container.Resolve(serviceType);
}
catch(ResolutionFailedException ex)
{
if (!(typeof(System.Web.Http.Tracing.ITraceWriter).IsAssignableFrom(serviceType))
|| typeof(System.Web.Http.Metadata.ModelMetadataProvider).IsAssignableFrom(serviceType)
//...
))
{
// log error
}
}
return null;
}
Normally, you don't need to with Unity.
I use this implementation for IDependencyResolver with unity, and I don't have to register or map other than my interfaces/services.
public class UnityDependencyInjectionResolver : Disposable, IDependencyResolver
{
protected IUnityContainer Container;
public UnityDependencyInjectionResolver(IUnityContainer container)
{
if (container == null)
{
throw new ArgumentNullException("container");
}
Container = container;
}
public object GetService(Type serviceType)
{
try
{
return Container.Resolve(serviceType);
}
catch (ResolutionFailedException)
{
return null;
}
}
public T GetService<T>()
{
try
{
var serviceType = typeof(T);
return (T)Container.Resolve(serviceType);
}
catch (ResolutionFailedException)
{
return default(T);
}
}
public T GetService<T>(string name)
{
try
{
var serviceType = typeof (T);
return (T) Container.Resolve(serviceType, name);
}
catch (ResolutionFailedException)
{
return default(T);
}
}
public IEnumerable<object> GetServices(Type serviceType)
{
try
{
return Container.ResolveAll(serviceType);
}
catch (ResolutionFailedException)
{
return new List<object>();
}
}
public IDependencyScope BeginScope()
{
var child = Container.CreateChildContainer();
return new UnityDependencyInjectionResolver(child);
}
protected override void DisposeManagedResources()
{
if (Container == null)
{
return;
}
Container.Dispose();
Container = null;
}
}
where Disposable is just a base class implements IDispoable.
Hope that helps.
As this seems to still get disputed, here's my version of the code...
/// <summary>
/// Specifies the Unity configuration for the main container.
/// </summary>
public class UnityConfig
{
private static Lazy<IUnityContainer> container = new Lazy<IUnityContainer>(() =>
{
var container = new UnityContainer();
RegisterTypes(container);
return container;
});
/// <summary>
/// Gets the configured Unity container.
/// </summary>
public static IUnityContainer GetConfiguredContainer()
{
return container.Value;
}
public static void RegisterTypes(IUnityContainer container)
{
// Keeping this separate allows easier unit testing
// Your type mappings here
}
}
and
[assembly: OwinStartup(typeof(UnityTest.BusinessLayer.Api.ApiStartup))]
namespace UnityTest.BusinessLayer.Api
{
public static HttpConfiguration Config { get; private set; }
public partial class ApiStartup
{
public void Configuration(IAppBuilder app)
{
// IoC
var container = UnityConfig.GetConfiguredContainer();
var resolver = new UnityHierarchicalDependencyResolver(container); // Gets us scoped resolution
app.UseDependencyResolverScope(resolver); // And for the OWIN
app.UseCors(Microsoft.Owin.Cors.CorsOptions.AllowAll);
// NB Must be before WebApiConfig.Register
ConfigureAuth(app); //In App_Start ->Startup.Auth
// See http://stackoverflow.com/questions/33402654/web-api-with-owin-throws-objectdisposedexception-for-httpmessageinvoker
// and http://aspnetwebstack.codeplex.com/workitem/2091
#if SELFHOST
// WebAPI configuration
Config = new HttpConfiguration
{
DependencyResolver = resolver
};
WebApiConfig.Register(Config);
app.UseWebApi(Config);
#else
GlobalConfiguration.Configuration.DependencyResolver = resolver;
// http://stackoverflow.com/questions/19907226/asp-net-webapi-2-attribute-routing-not-working
// Needs to be before RouteConfig.RegisterRoutes(RouteTable.Routes);
GlobalConfiguration.Configure(WebApiConfig.Register);
Config = GlobalConfiguration.Configuration;
#endif
// Now do MVC configuration if appropriate
}
}
}
Finally bits are the extensions to use the scoped container in the Owin middleware as well as straight WebAPI
public static class AppBuilderExtensions
{
public static IAppBuilder UseDependencyResolverScope(this IAppBuilder app, IDependencyResolver resolver)
{
return app.Use<DependencyResolverScopeMiddleware>(resolver);
}
}
/// <summary>
/// Wraps middleware in a <see cref="IDependencyResolver"/> scope.
/// </summary>
public class DependencyResolverScopeMiddleware : OwinMiddleware
{
private readonly IDependencyResolver resolver;
public DependencyResolverScopeMiddleware(OwinMiddleware next, IDependencyResolver resolver) : base(next)
{
this.resolver = resolver;
}
public override async Task Invoke(IOwinContext context)
{
using (var scope = resolver.BeginScope())
{
context.SetDependencyScope(scope);
await Next.Invoke(context);
}
}
}
The rationale for this is the original MVC Work Item where we see
kichalla wrote Oct 27, 2014 at 4:34 PM
Yes...right...UseWebApi extension should be used only with
self-hosting scenarios...since we are all on the same page, I am
closing this issue as by-design...please let us know if you have any
more questions...
Thanks, Kiran
and
kichalla wrote Oct 29, 2014 at 5:28 PM
#thebothead: Thanks for finding this out!...right, this sample
shouldn't have been using Microsoft.AspNet.WebApi.Owin in IIS as it
was never intended to be used in that host...we will investigate the
issue further to see why this exception happens...but meanwhile you
could follow the approach mentioned in the sample that I provided
earlier...
Thanks, Kiran
From my own experience if you don't use this form of the code, it will work in debug etc but will not scale and start behaving strangely.
I has deleted dependencyResolver and this problem was solved
public static class UnityConfig
{
public static void Register(HttpConfiguration config)
{
var container = new UnityContainer();
// Your mappings here
config.DependencyResolver = null;
}
}