How to include a specific column (user ID) in the audit - audit.net

I'm having doubts about how to implement user code in the audit table. The audit.net includes the name of the user connected to the database (example: sa) but I would also like to include the user ID of my system. I ran some tests reading the code and I didn't succeed. Can you show me where I'm wrong, please?
//public partial class coletasEntities : DbContext (orignal)
public partial class coletasEntities : AuditDbContext (changed)
{
...
}
//my main form_load
private void frmPrincipal_Load(object sender, EventArgs e)
{
Audit.Core.Configuration.Setup()
.UseEntityFramework(x => x
.AuditTypeNameMapper(typeName => "_Audit" + typeName)
.AuditEntityAction<IAudit>((ev, ent, auditEntity) =>
{
auditEntity.AuditUser = Global.id_usuario; //my user ID
}));
....
}
//interface create do add my custom property
public interface IAudit
{
int AuditUser { get; set; }
}
If I just change the inheritance class from DbContext to Auditdbcontext the automatic generation for each audited table occurs but the custom field I want (obviously) is not included.
With the code modified as above is not created anything, nothing happens.
I'm using Entity Framework 6.

Related

Implement Authentication using ASP Identity With 2 Tables

Instead of the default 5 tables, I would like to use just UserLoginsTable and UserTable. Because I just have one 'User' type (Admin) and there's no point of having the other tables.
I'm using ASP MVC 5 framework and Entity Framework 6 (Code First approach).
How can I achieve this in my application?
when you run add-migration "ApplicationDbContext", its give you the code of migration file which contains all the queries, what you need here is write the code to delete other 4 tables like:
enable-migrations
add-migration "drop tables" //selected specific context
write down the below code inside the migration code class
DropTable("dbo.AspNetUserClaims");
DropTable("dbo.AspNetUserLogins");
DropTable("dbo.AspNetUserRoles");
DropTable("dbo.AspNetRoles");
finally run the below command
update-database
You create your own User inheriting IdentityUser like this:
public class User : IdentityUser
{
}
Then you ignore the other classes in your DbContext, including the original IdentityUser, including your Users DbSet:
public class MyDbContext : IdentityDbContext
{
public DbSet<User> Users { get; set; }
protected override void OnModelCreating(DbModelBuilder modelBuilder)
{
// avoid some base class sets...
modelBuilder.Ignore<IdentityUser>();
modelBuilder.Ignore<IdentityUserRole>();
modelBuilder.Ignore<IdentityRole>();
modelBuilder.Ignore<IdentityUserClaim>();
// keep identity's original configurations for AspNetUsers and AspNetUserLogins
EntityTypeConfiguration<User> configuration = modelBuilder.Entity<User>().ToTable("AspNetUsers");
configuration.HasMany<IdentityUserLogin>(u => u.Logins).WithRequired().HasForeignKey(ul => ul.UserId);
IndexAttribute indexAttribute = new IndexAttribute("UserNameIndex")
{
IsUnique = true
};
configuration.Property((Expression<Func<User, string>>)(u => u.UserName)).IsRequired().HasMaxLength(0x100).HasColumnAnnotation("Index", new IndexAnnotation(indexAttribute));
configuration.Property((Expression<Func<User, string>>)(u => u.Email)).HasMaxLength(0x100);
modelBuilder.Entity<IdentityUserLogin>().HasKey(l => new { LoginProvider = l.LoginProvider, ProviderKey = l.ProviderKey, UserId = l.UserId }).ToTable("AspNetUserLogins");
}
}
The reason why I ignored the original IdentityUser and created my own User is because of this exception:
The navigation property 'Roles' is not a declared property on type
'IdentityUser'. Verify that it has not been explicitly excluded from
the model and that it is a valid navigation property.
I tried using modelBuilder.Entity<IdentityUser>().Ignore(u => u.Roles); but it didn't solve, though if someone knows how to solve this, we could keep things simpler, I would appreciate any suggestions.

what is wrong with my code first migration?

This is my migration and seeding code:
internal sealed class Configuration : DbMigrationsConfiguration<AuthDb>
{
public Configuration()
{
AutomaticMigrationsEnabled = false;
ContextKey = "Service.DAL.AuthDb";
}
}
public class CreateOrRunMigrations: CreateDatabaseIfNotExists<AuthDb>
{
public override void InitializeDatabase(AuthDb context)
{
base.InitializeDatabase(context);
var migrator = new DbMigrator(new Migrations.Configuration());
migrator.Update();
}
protected override void Seed(AuthDb context)
{
base.Seed(context);
// add Default product and company
}
}
The context is constructed this way
public class AuthDb : DbContext
{
public AuthDb() : base("name=xxx")
{
Database.SetInitializer(new CreateOrRunMigrations());
Configuration.LazyLoadingEnabled = false;
Configuration.ProxyCreationEnabled = false;
Configuration.AutoDetectChangesEnabled = true;
}
}
What I want is:
When the database is created first time, the seeding data is added.
When I make a change in the model, the migration code will apply the changes to the database automatically.
When I make a change (e.g. Company), and use update_database to add a migration in the console, the migration file was created. But when the code is run, I got an error complaining that my model and database doesn't match any more.
Of course it doesn't match as I just made a change and I was hoping that the migration will apply the change. However, it didn't. What I did wrong?
Your initializer derives from CreateDatabaseIfNotExists so it's only going to run when the database does not exist. Try making it derive from MigrateDatabaseToLatestVersion:
public class CreateOrRunMigrations: MigrateDatabaseToLatestVersion<AuthDb>
{
// no need for InitializeDatabase override since that's what this initializer does...
protected override void Seed(AuthDb context)
{
base.Seed(context);
// add Default product and company
}
}

DropCreateDataBaseAlways is not working when working with multiple db schemas with Entity Framework 6 Code First

After watching the "Enhancements to Code First Migrations: Using HasDefaultSchema and ContextKey for Multiple Model Support" section of Julie Lerman's PluralSite video, "Entity Framework 6: Ninija Edition-What's New in EF 6" (https://app.pluralsight.com/library/courses/entity-framework-6-ninja-edition-whats-new/table-of-contents), it seems there is a way to run multiple schemas under a single database in Entity Framwork 6 using Code First Migrations...
However, based on the video you still need to these package manager commands for each project that houses a separate context:
1. enable-migrations
2. add-migration [MIGRATION NAME]
3. update-database
This is fine and good if you actually care about maintaining migrations going forward, which is not a concern of mine.
What I'd like to do is have each of my Context's initializers set to DropCreateDatabaseAlways, and when I start up my client app (in this case, an MVC site), code first will create the database for the first context used, create the tables in with the correct schema for that context, and then create the tables for the rest of the contexts with the correct schema.
I don't mind if the whole database is dropped and recreated every time I hit F5.
What is happening now is the last context that is accessed in the client app is the only context tables that are created in the database... any contexts being accessed before the last get their tables blown away.
I am currently using two contexts, a Billing context and a Shipping context.
Here is my code:
My client app is an MVC website, and its HomeController's Index method looks like this:
public ActionResult Index()
{
List<Shipping.Customer>
List<Billing.Customer> billingCustomers;
using (var shippingContext = new Shipping.ShippingContext())
{
shippingCustomers = shippingContext.Customers.ToList();
}
using (var billingContext = new Billing.BillingContext())
{
billingCustomers = billingContext.Customers.ToList();
}
}
Here is my DbMigrationsConfigurationClass and ShippingContext class for the Shipping Context:
internal sealed class Configuration : DbMigrationsConfiguration<ShippingContext>
{
public Configuration()
{
AutomaticMigrationsEnabled = false;
}
protected override void Seed(ShippingContext context)
{
}
}
public class ShippingContext : DbContext
{
public ShippingContext() : base("MultipleModelDb")
{
}
static ShippingContext()
{
Database.SetInitializer(new ShippingContextInitializer());
}
protected override void OnModelCreating(DbModelBuilder modelBuilder)
{
modelBuilder.HasDefaultSchema("Shipping");
base.OnModelCreating(modelBuilder);
}
public DbSet<Customer> Customers { get; set; }
class ShippingContextInitializer : DropCreateDatabaseAlways<ShippingContext>
{
}
}
Likewise, here is the DbMigrationConfiguration class for the Billing Context and the BillingContext class:
internal sealed class Configuration : DbMigrationsConfiguration<BillingContext>
{
public Configuration()
{
AutomaticMigrationsEnabled = false;
}
protected override void Seed(BillingContext context)
{
}
}
public class BillingContext : DbContext
{
public BillingContext() : base("MultipleModelDb")
{
}
static BillingContext()
{
Database.SetInitializer(new BillingContextInitializer());
}
protected override void OnModelCreating(DbModelBuilder modelBuilder)
{
modelBuilder.HasDefaultSchema("Billing");
base.OnModelCreating(modelBuilder);
}
public DbSet<Customer> Customers { get; set; }
class BillingContextInitializer : DropCreateDatabaseAlways<BillingContext>
{
}
}
based on the order that the contexts are being called in the controller's action method, whichever context is accessed last is the only context that is created... the other context is wiped out.
I feel like what I'm trying to do is very simple, yet code first migrations, as well as trying to "shoehorn" Entity Framework to represent multiple contexts as separate schemas in the same physical database seems a bit "hacky"...
I'm not that versed with migrations to begin with, so what I'm trying to do might not make any sense at all.
Any feedback would be helpful.
Thanks,
Mike

Strange Guid.NewGuid() behaviour

I have searched the site for an answer to this question, but I cannot seem to figure this one out.
I have use the NewGuid() method many times and it has worked greate. But now for some reason it creates an empty Guid.
Here is my code:
// Class of the Guid Object
public class CardUserAccount
{
// User ID of the user's profile
public Guid UserId { get; set; }
}
//Page object where method is called
Public partial class CreateSale : System.Web.UI.UserControl
{
// Create the UserProfile object
public CardUserAccount profile = new CardUserAccount();
protected void ContinueButton_Click(object sender, EventArgs e)
{
Guid _userId = Guid.NewGuid();
profile.UserId = _userId;
}
protected void SubmitButton_Click(object sender, EventArgs e)
{
// Method to add object to database
SubmitProfile(profile);
}
I then call a simple linq to entities method to add the object to the entity object.
I have double checked it and I am not overwriting it anywhere.
However could it be a problem that I am creating the profile object outside of the page_load method. I thought this would not affect the object during postback.
I would appreciate the help
Is this actual code? Because you declare and initialize the variable, then do nothing with it.
If you intend to overwrite a field value, you should not declare that field inside this method.

Order of fields in Dynamic Data?

Does anybody know if it is possible to choose the order of the fields in Dynamic Data (of course, without customizing the templates of each table) ?
Thanks !
In .NET 4.0, using the 4.0 release of the Dynamic Data dll, you can set data annotations like so:
[Display(Name = " Mission Statement", Order = 30)]
public object MissionStatement { get; set; }
[Display(Name = "Last Mod", Order = 40)]
public object DateModified { get; private set; }
As per this thread - you can use the ColumnOrderAttribute in the dynamic data futures dll. You can grab the futures from codeplex.
You can do this by modifying the order of the public properties in your LINQ to SQL file.
For example, I went into Northwind.designer.cs which was my auto-generated LINQ to SQL file and moved the public property named Products above the public property CategoryName in the public partial class Category. Then I recompiled and the default template displayed the columns in my new order.
Of course, this means your editing auto-generated code and if you regenerate it, your changes are lost, so this technique is not without peril.
You have to create a custom page in DynamicData folder.
Here are the steps:
Create a folder that is the same name as your table name that you want to customize the ordering of columns under "DynamicData\CustomPages" folder
Create a custom page under "DynamicData\CustomPages\[folder with table name]" folder.
I just copy the existing "List.aspx" file from "DynamicData\PageTemplates" into the folder above.
Open the aspx file and modify GridView control to "AutoGenerateColumns='false'"
Inside columns section of GridView, add "DynamicControl" controls with the "DataField" attribute value to the name of your column in the order you want.
Here is a screencast from ScottHa:
http://www.asp.net/learn/3.5-SP1/video-293.aspx
GridView have ColumnsGenerator property, use it by implementing GenerateFields method of IAutoFieldGenerator interface in which you can set fields orders based on your custom rules (attributes, meta info, ...)
protected override void OnInit(EventArgs e)
{
...
this.gvItemsList.ColumnsGenerator = new EntityFieldsGenerator(CurrentDataSource.CurrentTableMetadata);
...
}
public class EntityFieldsGenerator : IAutoFieldGenerator {
...
public ICollection GenerateFields(Control control)
{
// based on entity meta info
var fields = from item in this.entityMetadata.Columns
where this.IncludeColumn(item.Value)
orderby item.Value.Order
select new DynamicField
{
DataField = item.Value.Column.Name,
HeaderText = item.Value.DisplayName,
DataFormatString = item.Value.DataFormatString,
UIHint = GetColumnUIHint(item.Value)
};
return fields.ToList();
} }
To avoid using the Dynamic Data futures dll, you can roll your own ColumnOrder attribute as follows:
[AttributeUsage(AttributeTargets.Property)]
public class ColumnOrderAttribute : Attribute
{
public int Order { get; private set; }
public ColumnOrderAttribute() { Order = int.MaxValue; }
public ColumnOrderAttribute(int order) { Order = order; }
public static ColumnOrderAttribute Default = new ColumnOrderAttribute();
}
and then in your class that implements IAutoFieldGenerator, you have
public static class ExtensionMethods
{
public static int GetOrder (this MetaColumn column)
{
var orderAttribute = column.Attributes.OfType<ColumnOrderAttribute>().DefaultIfEmpty(ColumnOrderAttribute.Default).Single();
return orderAttribute.Order;
}
}
public ICollection GenerateFields(Control control)
{
var fields = new List<DynamicField>();
var columns = _table.Columns.OrderBy(column => column.GetOrder());
foreach (var column in columns)
{
if (!column.Scaffold) { continue; }
fields.Add(new DynamicField {DataField = column.Name});
}
}
and finally your usage would look like
[MetadataType(typeof(CustomerMetadata))]
public partial class Customer {}
public class CustomerMetadata
{
[ColumnOrder(1)]
public object FirstName {get;set;}
[ColumnOrder(2)]
public object LastName {get;set;}
}
I'm answering an old question because it seems to me that the possible solution changed in newer versions of the framework.
It seems that the Display(Order) works now directly as asked (Visual Web Developer 2010 on .NET 4.0) without any particular workaround.
Example:
[Display(Order = 50)]
An important thing it's to check the correct object name to map the foreignkey:
in one project a field OperatoreID translated in the entity class as:
public object Operatore { get; set; }
being Operatore the source table of the foreignkey; for a second reference on the same table it will get something like 1 and so on.

Resources