Can StructureMap load modules/assemblies on demand? - assemblies

Are there facilities in StructureMap that will allow me to load services from other modules (assemblies) on demand like it's done in Unity?

Like This?
Assembly ass = Assembly.GetCallingAssembly();
Container.Configure(x => x.Scan(scan =>
{
scan.Assembly(ass);
scan.LookForRegistries();
}));

Related

Scoped service in DBContext with DBContextFactory can't resolve from root provider

I want to register a scoped ICurrentUserService and then use it in the DbContext to set the CreatedBy property on every entity. I want it scoped because it uses the current HttpContext to get the user id from the claims and the HttpContext is scoped by definition.
services.AddTransient<ICurrentUserService, CurrentUserService>();
However when I try to use this with the DbContextFactory like this:
services.AddDbContextFactory<MyDbContext>(options =>
options.UseSqlServer(config.ConnectionStrings.MSSQLConnection, x =>
{
x.MigrationsHistoryTable("...");
x.MigrationsAssembly("...");
}));
services.AddScoped<IMyDbContext>(provider => provider.GetRequiredService<IDbContextFactory<MyDbContext>>().CreateDbContext());
services.AddScoped<MyDbContext>(provider => provider.GetRequiredService<IDbContextFactory<MyDbContext>>().CreateDbContext());
I get the error
Cannot resolve scoped service 'SomeNamespace.ICurrentUserService' from root provider.
I can change it to Transient but that seems wrong and will probably be an issue later on for testing when I want to mock this and every class gets a new instance.
I'm actually not sure why Scoped does not work here. The DbContextFactory is registered Singleton but the Context is resolved as Scoped too.
Try it with ServiceLifetime.Scoped
services.AddDbContextFactory<ApplicationDbContext>(contextOptions =>
... YOUR OPTIONS
), ServiceLifetime.Scoped);

ILoggingBuilder does not have AddEventSourceLogger with 0 parameters. How to initialize this logging

'ILoggingBuilder' does not contain a definition for 'AddEventSourceLogger' and no accessible extension method 'AddEventSourceLogger' accepting a first argument of type 'ILoggingBuilder' could be found
Microsoft.AspNetCore.WebHost.CreateDefaultBuilder(args)
.ConfigureLogging(logging =>
{
// Requires `using Microsoft.Extensions.Logging;`
// logging.AddConfiguration(hostingContext.Configuration.GetSection("Logging"));
logging.AddConsole();
logging.AddDebug();
logging.AddEventSourceLogger();
})
.UseApplicationInsights()
.UseStartup<StartupConsole>()
.UseDefaultServiceProvider(options => options.ValidateScopes = false);
I am currently using .net-core 2.1 and have nuget for using Microsoft.Extensions.Logging installed.
Make sure you have installed the Microsoft.Extensions.Logging.EventSource NuGet package.
Reference: Logging in .NET Core and ASP.NET Core

Is it possible to configure everything within context?

I am trying to configure Audit.net and define my custom logic for saving logs.
Is there a way to configure included entities within context?
I tried this
`
public ResidentMasterContext(DbContextOptions options) : base(options)
{
AuditDataProvider = new DynamicDataProvider();
Mode = AuditOptionMode.OptIn;
IncludeEntityObjects = true;
EntitySettings = new Dictionary<Type, EfEntitySettings>
{
{typeof(Apartment), new EfEntitySettings()}
};
}
`
but OnScopeSaving is not firing. And when I change mode to OptOut it takes all entities
I guess you are referring to the Audit.NET EntityFramework extension.
if you use OptIn you need to mark the included entities with [AuditInclude] attribute, or use the Include methods of the fluent API. You can check the documentation here.
An example using the fluent API for the EF configuration, to include only the entities User and UserDetail:
Audit.EntityFramework.Configuration.Setup()
.ForContext<ResidentMasterContext>(config => config
.IncludeEntityObjects())
.UseOptIn()
.Include<User>()
.Include<UserDetail>();
An example of the output configuration:
Audit.Core.Configuration.Setup()
.UseDynamicProvider(_ => _.OnInsertAndReplace(auditEvent =>
{
Console.WriteLine(auditEvent.ToJson());
}));

Q: How to extend the routing config in Rebus

I have a rebus config project which is shared for many web api projects
So basically, it looks like
Web api 1 ==> Shared Rebus Config
Web api 2 ==> Shared Rebus Config
Web api 3 ==> Shared Rebus Config
My question is, if I have some messages & handlers in Web api 3 project, how can I configure the routing for them?
My current config:
var autofacContainerAdapter = new AutofacContainerAdapter(container);
return Configure
.With(autofacContainerAdapter)
.Serialization(s => s.UseNewtonsoftJson())
.Routing(r =>
{
r.TypeBased()
.MapAssemblyOf<ProjectA.MessageA>(EnvironmentVariables.ServiceBusQueueName)
.MapAssemblyOf<ProjectB.MessageB>(EnvironmentVariables.ServiceBusQueueName);
})
.Sagas(s =>
{
s.StoreInSqlServer(EnvironmentVariables.ConnectionString, "Saga", "SagaIndex");
})
.Options(o =>
{
o.LogPipeline();
o.EnableDataBus().StoreInBlobStorage(EnvironmentVariables.AzureStorageConnectionString, EnvironmentVariables.BlobStorageContainerName);
o.EnableSagaAuditing().StoreInSqlServer(EnvironmentVariables.ConnectionString, "Snapshots");
})
.Logging(l =>
{
l.Use(new SentryLogFactory());
})
.Transport(t =>
{
t.UseAzureServiceBus(EnvironmentVariables.AzureServiceBusConnectionString, EnvironmentVariables.ServiceBusQueueName).AutomaticallyRenewPeekLock();
})
.Start();
Well... as you have probably already found out, it is not possible to make additional calls to the .Routing(r => r.TypeBased()....) part. Therefore, I can see two fairly easy ways forward:
1: Simply pass additional parameters to your shared configuration method from the outside, e.g. something like this:
var additionalEndpointMappings = new Dictionary<Assembly, string>
{
{ typeof(Whatever).Assembly, "another-queue" }
};
var bus = CreateBus("my-queue", additionalEndpointMappings);
which of course then needs to be handled appropriately in the .Routing(...) configuration callback.
2: Pull out all the common configurations into a new extension method. I almost always use this method myself, because I have found it to be easy to maintain.
First you create a new RebusConfigurer extension method in a shared lib somewhere:
// shared lib
public static class CustomRebusConfigEx
{
public static RebusConfigurer AsServer(this RebusConfigurer configurer, string inputQueueName)
{
return configurer
.Logging(...)
.Transport(...))
.Sagas(...)
.Serialization(...)
.Options(...);
}
}
and then you can call this by going
Configure.With(...)
.AsServer("my-queue")
.Start();
in your endpoints.
3: A combination of (1) and (2) which enables this:
Configure.With(...)
.AsServer("my-queue")
.StandardRouting(r => r.MapAssemblyOf<MessageType>("somewhere-else"))
.Start();
which can end up avoiding repetitive code, still preserving a great deal of flexibility, and actually looking pretty neat :)

Doctrine2 Multiple DBs without Symfony2?

I know that using the Doctrinebundle in Symfony2 it is possible to instantiate multiple DB connections under Doctrine...
$connectionFactory = $this->container->get('doctrine.dbal.connection_factory');
$connection = $connectionFactory->createConnection(array(
'driver' => 'pdo_mysql',
'user' => 'foo_user',
'password' => 'foo_pass',
'host' => 'foo_host',
'dbname' => 'foo_db',
));
I'm curious if this is the case if you are using PURELY Doctrine though?, I've set up Doctrine via Composer like so...
{
"config": {
"vendor-dir": "lib/"
},
"require": {
"doctrine/orm": "2.3.4",
"doctrine/dbal": "2.3.4"
}
}
And have been looking for my ConnectionFactory class but am not seeing it anywhere? Am I required to use Symfony2 to do this?
Should I just download ConnectionFactory.php from the DoctrineBundle and include it in my DBAL folder?? idk?
A bundle is only in the context of symfony needed, it wraps the orm into symfony infrastructure (services, etc.). For pure use of the orm you should read the ORM: Installation and Configuration. As you see you must create an entity manager by yourself with EntityManager::create($dbParams, $config), so simply create different entity managers for your different databases.
For DBAL use you should read DBAL: Configuration and see, a connection can simply obtained trough DriverManager::getConnection($connectionParams, $config); But if you are sure the ConnectionFactory has no dependency to symfony stuff and you really need it, you can try copy it to your code and construct a new factory to obtain a DBAL connection.
$connectionFactory = new ConnectionFactory(array());
$connection = $connectionFactory->createConnection(array(
'driver' => 'pdo_mysql',
'user' => 'foo_user',
'password' => 'foo_pass',
'host' => 'foo_host',
'dbname' => 'foo_db',
));
But take care, this is a DBAL connection, i.e. it's a abstraction layer which sits on top of PDO and only for pure SQL queries. If you need a entity manager you have to initialize it as mentioned in the docs above, or maybe you find another entity manager factory class, which you can "copy".

Resources