I am using the audit.net and audit.entityframework for audit logging changes made in a asp.net MVC 5 application using entityframework code first principle.
On a user webform multiple roles can be assigned to a user.
Using the following short loop in the action of the controller:
foreach (var role in roles)
{
base.UserManager.AddToRole(user.Id, role.Name);
}
I get a log of approx 700 lines in sqlprofiler.
However if I enable the audit.net logger in my Startup.cs:
Audit.EntityFramework.Configuration.Setup()
.ForAnyContext(x => x.IncludeEntityObjects(true)
.ForEntity<User>(config => config
.Ignore(u => u.PasswordHash))
.AuditEventType("{context}:{database}"))
.UseOptIn().IncludeAny(t.Name.ToLower().IndexOf("user") >= 0);
The result is more than 10.000 sql profiler records created for the same action, assigning 51 roles to a single user. Also the 51 event records by audit.net have each a datafield with rougly 2 million characters asccording to the ms-sql len function.
Can anybody explain the reason for this massive sql activity caused by enabling logging on the userroles table and how to avoid it.
Related
I'm having an issue at the moment where, we have a database which was already created, so used ef scaffold to create a model of it - the schema the model was created against is called "xxxx-dev".
Now, this has been fine, but in preparation to go live, I created a new DB server and provisioned the database to be called "xxxx-live". Switched the connection string, and attempted a query against it, and got an error.
It seems that scaffolding has hard-coded the schema name into every table in the OnModelCreating call, for example:
modelBuilder.Entity<xxxx>(entity =>
{
...
entity.ToTable("xxxx", "xxxx-dev");
...
});
This is a bit of an issue as going forward, we might have multi-tenant sites based on the same database, and obviously the query overriding the connection string every query isn't a great experience.
Is there anyway to configure the schema name, either in the Scaffold, or at runtime? I've done a bit of searching around and can't seem to see a solution.
Thanks,
Situation
We have one ASP.NET MVC 5 application running along with SQL Server. We have one master database which contains a table Tenants where all of our tenants are registrated with a connection string property to their own personal database.
For authentication we are using the Microsoft Owin library.
Autofac
We have setup autofac like this:
var builder = new ContainerBuilder();
// Register the controllers
builder.RegisterControllers(typeof(Project.Web.ProjectApplication).Assembly);
// ### Register all persistence objects
// Project main database registration ( Peta Poco instance using connectionstring as parameter )
builder.RegisterType<ProjectDatabase>()
.As<ProjectDatabase>()
.WithParameter(new NamedParameter("connectionString", GlobalSettings.ProjectTenantConnectionString))
.InstancePerLifetimeScope();
// Project tenant specific database registration
// ...
// Unit of work
builder.RegisterType<PetaPocoUnitOfWork>()
.As<IDatabaseUnitOfWork>()
.InstancePerRequest();
// ### Register all services
builder.RegisterAssemblyTypes(Assembly.Load("Project.Core"))
.Where(t => t.Name.EndsWith("Service"))
.AsImplementedInterfaces()
.InstancePerLifetimeScope();
// ### Register all repositories
builder.RegisterType<RepositoryFactory>()
.As<IRepositoryFactory>()
.InstancePerLifetimeScope();
builder.RegisterAssemblyTypes(Assembly.Load("Project.Core"))
.Where(t => t.Name.EndsWith("Repository"))
.AsImplementedInterfaces()
.InstancePerLifetimeScope();
// Register Logging
builder.RegisterType<Logger>().As<ILogger>().InstancePerLifetimeScope();
// Register Automapper
builder.RegisterAssemblyTypes(Assembly.Load("Project.Core")).As<Profile>();
builder.RegisterAssemblyTypes(Assembly.Load("Project.Web")).As<Profile>();
builder.Register(context => new MapperConfiguration(cfg =>
{
foreach (var profile in context.Resolve<IEnumerable<Profile>>())
{
cfg.AddProfile(profile);
}
})).AsSelf().SingleInstance();
builder.Register(c => c.Resolve<MapperConfiguration>().CreateMapper(c.Resolve))
.As<AutoMapper.IMapper>()
.InstancePerLifetimeScope();
// Register Owin
builder.Register(ctx => HttpContext.Current.GetOwinContext()).As<IOwinContext>();
builder.Register(
c => new IdentityUserStore(c.Resolve<IUserService>()))
.AsImplementedInterfaces().InstancePerRequest();
builder.Register(
ctx => ctx.Resolve<IOwinContext>().Authentication)
.As<IAuthenticationManager>().InstancePerRequest();
builder.RegisterType<IdentityUserManager>().AsSelf().Inst‌​ancePerRequest();
// Build container
var container = builder.Build();
// Tenant container
var tenantIdentifier = new RequestSubdomainStrategy();
var mtc = new MultitenantContainer(tenantIdentifier, container);
// Set autofac as dependency resolver
DependencyResolver.SetResolver(new AutofacDependencyResolver(mtc));
More details
Using this setup we have an instance setup in Autofac to our master Tenant database.
This is then injected into our PetaPocoUnitOfWork for committing the transaction.
This works, and I can get the tenant information.
But now we need the following to work and we don't have a clue where to start.
How do we setup autofac to register tenants peta poco database instances to inject into the PetaPocoUnitOfWork and how will the app now how to resolve this? Because we need to have access to 2 databases ( the master and the personal tenants database ), first for getting the tenants connection string and then for doing crud operations on the tenants database.
What about our PetaPocoUnitOfWork, which contains the database to work with, should we register this also per tenant and pass the database using the resolving method of autofac and set this on a instance per request?
You can actually have a shard manager [More similar to that of the Microsoft Azure Shard Manager] that takes the connectionstring name and the tenant context. From these information, it can resolve the connection and then pass it on to the Context.
This will be resolved on a per-tenant basis and then the application works with the tenant based connection, i.e. this is injected in each of the services so that the identity established [logged in user identity] could be used to set the right connection object in the EF / Data Tier. This way, it facilitates loose coupled design and also easy to test and mockup.
You can find sample code and little documentation of how such an implementation would look like from my github repository
IMHO, the rationale behind this approach that I suggest would be the fact that the partitions per tenant would be stored in a database [typically your master database] and that would need to be fetched and used even if you are able to some-how inject these via Autofac. I did not reproduce the code here as it takes a bit long explanation to get the code and explanations here, which is being taken care in github.
HTH
We are using forms authentication on our ASP.NET website but are wanting to upgrade to the new Identity Provider. Currently we are using the database first approach and are ultimately wanting to just extend our current User table (not aspnet_users) to use the new identity format. We are using StructureMap to inject our context into our business logic classes. For instance our User service currently has this as its constructor:
private readonly SiteModelContainer _context;
public UserService(SiteModelContainer context)
{
this._context = context;
}
And in our IoC registry we have this:
var ecsbuilder = new EntityConnectionStringBuilder();
ecsbuilder.Provider = "System.Data.SqlClient";
ecsbuilder.ProviderConnectionString = #"data source=***;initial catalog=***;persist security info=True;User ID=***;Password=***;multipleactiveresultsets=True;App=EntityFramework";
ecsbuilder.Metadata = #"res://*/Data.***.csdl|res://*/Data.***.ssdl|res://*/Data.***.msl";
string connectionString = ecsbuilder.ToString();
For<SiteModelContainer>().Use<SiteModelContainer>().Ctor<string>("connectionString").Is(connectionString);
For<IUserService>().Use<UserService>();
...all the rest of our services
We are also using database first with EDMX and entity framework. Previously we just used ASP.NET authentication as it came out the box and had a separate user table to store profile information, but would like to have everything working off one users class instead.
1)Is it possible to extend our userservice to handle everything related to using Identity? So that Identity uses the same context that we inject into our classes? If so, I am unable to find any articles about it?
2) Are we able to extend our User object if it is created in the EDMX file?
Thanks
I have migrated 2 fairly large projects from MembershipProvider into Asp.Net Identity and both of the times I ended up rewriting most parts of the user-management and everything that touched user. A fairly chunky rewrites.
What you ask for is possible, but hard and very time consuming. You may start from this question - the OP have got his db-first project running with identity. And we had a discussion in comments with some links that might help you.
Hi does anybody know if its possible to truncate a staging table via a web service in AX 2012? There is the delete method, however this is a bit slow for a large number of records.
For anyone who is struggling with this. I created a new method (class and operation) in my web service and exposed this, to delete all records from a table. The following code was used:
[SysEntryPointAttribute(true)]
public void truncateTable()
{
TableNameHere tableNameHere;
;
ttsBegin;
delete_from tableNameHere;
ttsCommit;
}
As I don't have any details about your web service (is that customization of some standard service or you've created custom service?), I'd like to suggest following: create Custom web service with one method which will delete required records.
I have two tables
Users (Userid, Name, PhoneNumber)
Applications (ApplicationsId,UserId, ApplicationName, ActiveDate)
Every user will have more than 1 application.
In Nhibernate using lazy loading I can get the users data along with all the applications for every user. So, I used to do something like user.applications[i].Applicationname to get all the applications.
But, Now how do i retrieve all the applications along with the users data using oracle commands. I know how to get one application using joins. But, how do i retrieve multiple applications and store it in a IList. Any help is greatly appreciated. Thank you.
First you should download the Oracle Data Provider for .NET in
http://www.oracle.com/technology/tech/windows/odpnet/index.html
after you make sure that you can open a connection to your oracle database then
define mapping file of your entities in Nhibernate and map table columns of your oracle table to .NET object. after that you can use the following code snippet to get the list of your entity from database
// create the query...
IQuery query = session.CreateQuery( "from Post p where p.Blog.Author = :author" );
// set the parameters...
query.SetString("author", (String) instance);
// fetch the results...
IList results = query.List();
You should define the (Post) entity and (Blog) entity to your mapping file and as you can see (Post) has relation to (Blog) entity which is defined in the mapping file too.