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());
}));
Related
I have developed an azure function in .net core and configured automapper in startup.cs by builder.Services.AddAutoMapper(Assembly.GetAssembly(this.GetType()));
I am trying to create a map between domain class (table in EF core) and a DTO. The domain class has a property RowVersion . I want this property to be ignored while mapping dto to domain.
For this I created a Profile Class and created my custom map but this is not working.
I tried DoNotValidate , but it doesn't seem to work
Startup.cs
builder.Services.AddAutoMapper(Assembly.GetAssembly(this.GetType()));
public class MapperProfile :Profile
{
public MapperProfile()
{
CreateMap<MyDto, MyDomain>().ForMember(i => i.RowVersion, opt => opt.Ignore());
}
}
Service.cs
_mapper.Map<myDomain>(myDtoInstance)
getting the below error
Unmapped members were found. Review the types and members below.
Add a custom mapping expression, ignore, add a custom resolver, or modify the source/destination type
For no matching constructor, add a no-arg ctor, add optional arguments, or map all of the constructor parameters
Unmapped properties:
[5/28/2019 7:00:40 AM] RowVersion
ForMember is used for referencing the destination objects, in your case, MyDto.
Use ForSourceMember instead:
public MapperProfile()
{
CreateMap<MyDto, MyDomain>().ForSourceMember(i => i.RowVersion, opt => opt.Ignore());
}
In the configuration I have to specify the paths to .js and .ts files defining entities:
MikroORM.init({
...
entitiesDirs: ["build/entities"],
entitiesDirsTs: ["src/entities"],
});
So, when I will go to release or distribute the application. Will I need distribute the typescript code too? or will I need distribute only the cache generated? or will I need distribute both? or... none?
As of MikroORM v2.2
Now you can work with default metadata provider, it will require entity source files only if you do not provide entity or type options in your decorators (you can use entity callback to use reference to entity class instead of using string name in type, handle for refactoring via IDE like webstorm).
Original answer:
You should ship the typescript code too, and let the cache regenerate on the server - cache would be rebuilt anyway as it checks absolute path to cached entity for invalidation.
You could implement your own cache adapter or metadata provider to get around this, if you don't want to ship the typescript code.
This is how you could implement custom metadata provider that simply throws error when the type option is missing:
import { MetadataProvider, Utils } from 'mikro-orm';
import { EntityMetadata } from 'mikro-orm/dist/decorators';
export class SimpleMetadataProvider extends MetadataProvider {
async loadEntityMetadata(meta: EntityMetadata, name: string): Promise<void> {
// init types and column names
Object.values(meta.properties).forEach(prop => {
if (prop.entity) {
prop.type = Utils.className(prop.entity());
} else if (!prop.type) {
throw new Error(`type is missing for ${meta.name}.${prop.name}`)
}
});
}
}
Then provide this class when initializing:
const orm = await MikroORM.init({
// ...
metadataProvider: SimpleMetadataProvider,
});
The value of type should be JS types, like string/number/Date... You can observe your cached metadata to be sure what values should be there.
Also keep in mind that without TS metadata provider, you will need to specify entity type in #ManyToOne decorator too (either via entity callback, or as a string via type).
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 :)
I'm new to ASP.NET vNext and I don't find how to configure Google OAuth.
I have uncomment the line in Startup.cs:
app.UseGoogleAuthentication();
But where am I supposed to configure it? I tried to replicate the pattern:
services.Configure<MicrosoftAccountAuthenticationOptions>(options =>
{
options.ClientId = Configuration["Authentication:MicrosoftAccount:ClientId"];
options.ClientSecret = Configuration["Authentication:MicrosoftAccount:ClientSecret"];
});
But
services.Configure<GoogleOAuth2AuthenticationOptions>
Isn't recognized even if the dependency is present in project.json:
"Microsoft.AspNet.Authentication.Google": "1.0.0-beta5",
What am I missing?
There is a sample at https://github.com/aspnet/Security/blob/dev/samples/SocialSample/Startup.cs.
I haven't tried it, but it looks like you configure it using app.UseGoogleAuthentication():
app.UseGoogleAuthentication(options =>
{
options.ClientId = "560027070069-37ldt4kfuohhu3m495hk2j4pjp92d382.apps.googleusercontent.com";
options.ClientSecret = "n2Q-GEw9RQjzcRbU3qhfTj8f";
options.Events = new OAuthEvents()
{
OnRemoteError = ctx =>
{
ctx.Response.Redirect("/error?ErrorMessage=" + UrlEncoder.Default.Encode(ctx.Error.Message));
ctx.HandleResponse();
return Task.FromResult(0);
}
};
});
If you're using the configuration store like this
Configuration["Authentication:MicrosoftAccount:ClientId"];
then what you're also missing (if that's what you mean by 'configure Google OAuth') is the part where you store the values in the SecretManager as described in the ASP.NET docs (they use facebook but you can just put whatever keys you want in there). It's a command line tool and it avoids you storing the keys in the code like that. In Google's case you'd probably want to change it to:
Configuration["Authentication:Google:ClientID"];
Configuration["Authentication:Google:ClientSecret"];
but it can be whatever you want.
I am looking for a good solution to on-the-fly connection of databases within Symfony utilizing Doctrine for entity management.
The scenario I have is that all inbound users to our service will be visiting *.website.com addresses, like client1.website.com.
We would like to use one Doctrine entity for the Client table to then look up their database credentials based on the URL of their account on the fly.
So far I have found the following topics here on stackoverflow that discuss dynamically changing the database credentials--but no clear workable solutions.
I'd like to propose collaborating to put together a working solution, and I'll put together a blog/tutorial post for other folks looking to modify database connection parameters within Symfony.
Here are some related posts:
Dynamic database connection symfony2
Symfony2, Dynamic DB Connection/Early override of Doctrine Service
Thanks!
If $em is existing entity manager and you want to reuse it's configuration, you can use this:
$conn = array(
'driver' => 'pdo_mysql',
'user' => 'root',
'password' => '',
'dbname' => 'foo'
);
$new = \Doctrine\ORM\EntityManager::create(
$conn,
$em->getConfiguration(),
$em->getEventManager()
);
I needed to do something similar - runtime discovery of an available database server. I did it by overriding the doctrine.dbal.connection_factory.class parameter and substituting my own derivation of the Doctrine bundle's ConnectionFactory class
My services.yml provides the parameter, pointing at my custom class
parameters:
doctrine.dbal.connection_factory.class: Path\To\Class\CustomConnectionFactory
Then fill in your discovery logic in Path\To\Class\CustomConnectionFactory.php
<?php
namespace Path\To\Class;
use Doctrine\Bundle\DoctrineBundle\ConnectionFactory;
use Doctrine\Common\EventManager;
use Doctrine\DBAL\Configuration;
class CustomConnectionFactory extends ConnectionFactory
{
public function createConnection(array $params, Configuration $config = null, EventManager $eventManager = null, array $mappingTypes = array())
{
// Discover and override $params array here.
// A real-world example might obtain them from zookeeper,
// consul or etcd for example. You'll probably want to cache
// anything you obtain from such a service too.
$params['driver'] = 'pdo_mysql';
$params['host'] = '10.1.2.3';
$params['port'] = 3306;
$params['dbname'] = 'foo';
$params['user'] = 'myuser';
$params['password'] = 'mypass';
//continue with regular connection creation using new params
return parent::createConnection($params, $config, $eventManager,$mappingTypes);
}
}
Note also that Symfony 3.2 features the ability to use environment variables in container configurations, and to use their values on-demand (rather than fixing them when the container is compiled). See the blog announcement for more details.