Audit trail: Web application - database

I am working on an audit trail project where we have been told to following.
Track all the tables (200+) in our db with shadow tables just as Hibernate Envers does. It follows that we have create snapshot for a each transactions involving CUD.
In the past, I implemented audit solutions for finite sets of important data for each of my clients. For the current work, my questions are:
Does it make sense to audit every single table in the database?
How much of value would it be track the data like Envers does? Any application would want to have deltas for specific data points. Querying huge sets of data to figure out deltas seem to be unrealistic.
An Envers like solution requires tying up CUD actions with a transaction effectively ruling out triggers. This is because triggers run in their own transactions and hence the data in shadow tables can get out of sync in case of transaction rollbacks from the application. Anything I am missing here?
Does anybody suggest using NoSQL DBs for audit trail?

Fully implemented and can be improved more. I hope this may help someone :
public partial class Entity:DbContext
{
public enum AuditActions {I,U,D}
public override int SaveChanges( )
{
ChangeTracker.DetectChanges();
ObjectContext ctx = ((IObjectContextAdapter)this).ObjectContext;
// string UserName = WindowsIdentity.GetCurrent().Name;
IPrincipal principal = Thread.CurrentPrincipal;
IIdentity identity = principal == null ? null : principal.Identity;
string name = identity == null ? "" : identity.Name;
//Thread.CurrentPrincipal = new GenericPrincipal(new GenericIdentity((userName), roles);
List<ObjectStateEntry> objectStateEntryList =
ctx.ObjectStateManager.GetObjectStateEntries(EntityState.Added
| EntityState.Modified
| EntityState.Deleted)
.ToList();
List<DBAudit> AuditList = new List<DBAudit>();
string Audittable = string.Empty;
foreach (ObjectStateEntry entry in objectStateEntryList)
{
Audittable = entry.EntitySet.ToString();
if (!entry.IsRelationship && Audittable!="Audit table name")
{
//sIsAuditTble =entry.EntitySet="DBAudit"? true:false;
switch (entry.State)
{
case EntityState.Added:
AuditList= LogDetails(entry, name, AuditActions.I);
break;
case EntityState.Deleted:
AuditList= LogDetails(entry, name, AuditActions.D);
break;
case EntityState.Modified:
AuditList= LogDetails(entry, name, AuditActions.U);
break;
}
}
}
using (var context = new ProjectTrackerEntities())
{
for (int i = 0; i < AuditList.Count; i++)
{
context.DBAudits.Add(AuditList[i]);
context.SaveChanges();
}
}
return base.SaveChanges();
}
public List<DBAudit> LogDetails(ObjectStateEntry entry, string UserName, AuditActions action)
{
List<DBAudit> dbAuditList = new List<DBAudit>();
if (action == AuditActions.I)
{
var keyValues = new Dictionary<string, object>();
var currentValues = entry.CurrentValues;
// entry.Entity key = new EntityKey();
DBAudit audit = new DBAudit();
audit.AuditId = Guid.NewGuid().ToString();
audit.RevisionStamp = DateTime.Now;
audit.TableName = entry.EntitySet.Name;
audit.UserName = UserName;
audit.OldData = "";
audit.Actions = action.ToString();
for (int i = 0; i < currentValues.FieldCount; i++)
{
audit.ChangedColumns = audit.ChangedColumns + currentValues.GetName(i);
audit.NewData = audit.NewData + currentValues.GetValue(i);
audit.ChangedColumns = audit.ChangedColumns + ", ";
audit.NewData = audit.NewData + ", ";
}
dbAuditList.Add(audit);
//LogSave(audit);
}
else if (action == AuditActions.D)
{
var keyValues = new Dictionary<string, object>();
var DeletedValues = entry.OriginalValues;
// entry.Entity key = new EntityKey();
DBAudit audit = new DBAudit();
audit.AuditId = Guid.NewGuid().ToString();
audit.RevisionStamp = DateTime.Now;
audit.TableName = entry.EntitySet.Name;
audit.UserName = UserName;
audit.NewData = "";
audit.Actions = action.ToString();
for (int i = 0; i < DeletedValues.FieldCount; i++)
{
audit.ChangedColumns = audit.ChangedColumns + DeletedValues.GetName(i);
audit.OldData = audit.OldData + DeletedValues.GetValue(i);
audit.ChangedColumns = audit.ChangedColumns + ", ";
audit.OldData = audit.OldData + ", ";
}
dbAuditList.Add(audit);
}
else
{
foreach (string propertyName in entry.GetModifiedProperties())
{
DBAudit audit = new DBAudit();
DbDataRecord original = entry.OriginalValues;
string oldValue = original.GetValue(original.GetOrdinal(propertyName)).ToString();
CurrentValueRecord current = entry.CurrentValues;
string newValue = current.GetValue(current.GetOrdinal(propertyName)).ToString();
audit.AuditId = Guid.NewGuid().ToString();
audit.RevisionStamp = DateTime.Now;
audit.TableName = entry.EntitySet.Name;
audit.UserName = UserName;
audit.ChangedColumns = propertyName;
audit.OldData = oldValue;
audit.NewData = newValue;
audit.Actions = action.ToString();
dbAuditList.Add(audit);
//LogSave(audit);
}
}
return dbAuditList;
}
}

One option for a NoSQL database is RavenDB, using its "versioning bundle".
Though at this point it's probably too early, I recently listened to an interesting episode of Herding code where they talk with Eric Sink on about Veracity. As I understand, Veracity is part distributed version control system, and part NoSQL database. It is designed to be the backend to anything from a source control system to a wiki. It's been in development for a couple years, but is still effectively in pre-beta stages (as of Nov 2010).

Related

Not able to update the data in more than one table in Asp .net MVC5

Here I am able to add the data in more than one table. Let i have 3 tables User, Franchise and Fee.
I am not able to update the data in more than one table,it throwing the exception:
A referential integrity constraint violation occurred: The property value(s) of 'User.Id' on one end of a relationship do not match the property value(s) of 'Franchise.UserId' on the other end.
Code:
public MessageResult SaveAndUpdateFranchisee(UserViewModel model)
{
var result = new MessageResult();
try
{
User userData = new User();
Franchise franchiseData = new Franchise();
var ExistUser = db.Users.Where(a => a.Id == model.Id).FirstOrDefault();
//Update record
if (model.Id > 0)
{
Fee feeData = new Fee
{
FranchiseeFee = model.FranchiseeFee,
PaymentTermsFranchiseFee = model.PaymentTermsFranchiseFee,
EquipmentCost = model.EquipmentCost,
PaymentTermsEquipmentCost = model.PaymentTermsEquipmentCost,
OtherFee = model.OtherFee,
PaymentTermsOtherFee = model.PaymentTermsOtherFee,
ConsumableStock = model.ConsumableStock,
PaymentTermsConsumableStock = model.PaymentTermsConsumableStock,
FrozenFoodStock = model.FrozenFoodStock,
PaymentTermsFrozenFoodStock = model.PaymentTermsFrozenFoodStock,
TotalAmountDue = model.TotalAmountDue,
TotalAmountPaid = model.TotalAmountPaid,
BalanceAmount = model.BalanceAmount,
LoyaltyFeePercentage = model.LoyaltyFeePercentage,
FixedMonthlyFee = model.FixedMonthlyFee,
Note = model.Note,
UserId = model.CurrentUserId,
LOIDocUrl = model.LOIDocUrl,
ModifiedDate = DateTime.Now
};
ExistUser.Email = model.Email;
//var pwd = SecutiryServices.EncodePasswordToBase64(model.Password);
//userData.Password = pwd;
ExistUser.Password = model.Password;
ExistUser.FirstName = model.FirstName;
ExistUser.MiddleName = model.MiddleName;
ExistUser.LastName = model.LastName;
ExistUser.FullName = model.FullName;
ExistUser.MobileNo = model.MobileNo;
ExistUser.ModifyDate = DateTime.Now;
franchiseData.Name = model.FullName;
franchiseData.MobileNo = model.MobileNo;
franchiseData.AlternateNo = model.AlternetNo;
franchiseData.CompanyPhoneNo = model.PhoneNo;
franchiseData.Address = model.Address;
franchiseData.City = model.City;
franchiseData.State = model.State;
franchiseData.PinCode = model.PinCode;
franchiseData.CompanyName = model.CompanyName;
franchiseData.CompanyAddress = model.CompanyAddress;
franchiseData.CompanyCity = model.CompanyCity;
franchiseData.CompanyState = model.CompanyState;
franchiseData.CompanyAddress = model.CompanyAddress;
franchiseData.CompanyPinCode = model.CompanyPinCode;
franchiseData.ModifiedDate = DateTime.Now;
userData.Franchises.Add(franchiseData);
foreach (var item in userData.Franchises)
{
item.Fees.Add(feeData);
}
db.Users.Attach(userData);
db.Entry(userData).State = System.Data.Entity.EntityState.Modified;
//db.Users.Add(userData);
db.SaveChanges();
result.Message = "Your franchise has been updated successfully..";
result.Status = true;
}
//For Insert recored..
else
{
Fee feeData = new Fee
{
FranchiseeFee = model.FranchiseeFee,
PaymentTermsFranchiseFee = model.PaymentTermsFranchiseFee,
EquipmentCost = model.EquipmentCost,
PaymentTermsEquipmentCost = model.PaymentTermsEquipmentCost,
OtherFee = model.OtherFee,
PaymentTermsOtherFee = model.PaymentTermsOtherFee,
ConsumableStock = model.ConsumableStock,
PaymentTermsConsumableStock = model.PaymentTermsConsumableStock,
FrozenFoodStock = model.FrozenFoodStock,
PaymentTermsFrozenFoodStock = model.PaymentTermsFrozenFoodStock,
TotalAmountDue = model.TotalAmountDue,
TotalAmountPaid = model.TotalAmountPaid,
BalanceAmount = model.BalanceAmount,
LoyaltyFeePercentage = model.LoyaltyFeePercentage,
FixedMonthlyFee = model.FixedMonthlyFee,
Note = model.Note,
UserId = model.CurrentUserId,
LOIDocUrl = model.LOIDocUrl,
CreatedDate = DateTime.Now
};
userData.Email = model.Email;
//var pwd = SecutiryServices.EncodePasswordToBase64(model.Password);
//userData.Password = pwd;
userData.Password = model.Password;
userData.FirstName = model.FirstName;
userData.FullName = model.FirstName + " " + model.LastName;
userData.LastName = model.LastName;
userData.MobileNo = model.MobileNo;
userData.IsActive = true;
userData.IsDelete = false;
userData.CreatedDate = DateTime.Now;
userData.UserTypeId = 2;
franchiseData.CompanyId = model.CurrentUserId;
franchiseData.Name = userData.FullName;
franchiseData.MobileNo = model.MobileNo;
franchiseData.AlternateNo = model.AlternetNo;
franchiseData.Address = model.Address;
franchiseData.City = model.City;
franchiseData.State = model.State;
franchiseData.PinCode = model.PinCode;
franchiseData.CompanyName = model.CompanyName;
franchiseData.CompanyPhoneNo = model.PhoneNo;
franchiseData.CompanyAddress = model.CompanyAddress;
franchiseData.CompanyCity = model.CompanyCity;
franchiseData.CompanyState = model.CompanyState;
franchiseData.CompanyAddress = model.CompanyAddress;
franchiseData.CompanyPinCode = model.CompanyPinCode;
franchiseData.CreatedDate = DateTime.Now;
franchiseData.IsActive = true;
userData.Franchises.Add(franchiseData);
foreach (var item in userData.Franchises)
{
item.Fees.Add(feeData);
}
db.Users.Add(userData);
db.SaveChanges();
//db.AddUserRole(userData.Id, 4);
result.Message = "Your franchisee has been created successfully..";
result.Status = true;
}
return result;
}
catch (Exception ex)
{
result.Message = "We are unable to process your request at this time. Please try again later.";
result.Status = false;
return result;
}
}
The error message is straightforward - your code is creating a new Franchise object but it never sets the franchiseData.UserId property.
Add this to your franchiseData population code before you call db.SaveChanges():
franchiseData.UserId = model.CurrentUserId;
BTW, you should add code verify that the current user has permission to set foreign-key reference properties (like UserId) directly from values read from submitted forms because otherwise any user could enter Id values belonging to other users and gain access to information they shouldn't have access to - or otherwise alter with your database.

Assigns me no mail after user creation - Does Logic Apps make a mistake?

This is the case, for example, if a user now creates a page. So the next day I need Azure Logic apps to send an email after 1 day.
The problem is: right now, it is by no means sending any email to me if I sign up yesterday. But it sends me an email that now it has gone through with succe.
I would like to know what goes wrong since it by no means email me as I set up yesterday.
My Logic app (From Azure) - Images
However, be aware that the code can be made short but I just need to find out if Logic apps are making mistakes or if thus my code previously works without problems.
[Route("/api/cronjob")]
[HttpGet]
public async Task<IActionResult> NewSletterUserEmail()
{
await Newsletter();
return Ok("Godkendt!");
}
public async Task<IActionResult> Newsletter()
{
var m = new Settings.ArdklarMail();
var dtt = DateTime.Now;
var days = _dbContext.OfferUser.Max(i => i.Days);
var MaxDays = DateTime.Now.AddDays(-days);
var userlist = _dbContext.Users.Where(i => i.Opretdate >= MaxDays && i.TilmeldtNyhedsbrev == true).ToList();
if (userlist != null)
{
foreach (var item in userlist)
{
string mail = item.Brugernavn;
string fullname = item.Navn;
var memberData = _dbContext.MemberShipValue.FirstOrDefault(r => r.UserId == item.UserId);
if (memberData == null)
{
//alm bruger
var result = _dbContext.OfferUser.Where(x => x.Value == 1).ToList();
if (result != null)
{
foreach (var itemValue in result)
{
int itemValueDays = itemValue.Days;//hvis den ingen antal har så giver den 0.
var daysValue = DateTime.Now.AddDays(-itemValueDays);
if (item.Opretdate.Date == daysValue)
{
var title = itemValue.Title;
var viewModel = new EmailModel
{
getUrl = m.RemoveLinkUrl(),
Title = title,
FullName = fullname,
Text = itemValue.Text.ToHtmlString()
};
var resultMail = await _viewRenderService.RenderToStringAsync("~/Views/Templates/OfferToUsers.cshtml", viewModel);//return Null here
MailMessageControl mailA = new MailMessageControl();
mailA.SetCredentials(m.azureName(), m.password());
mailA.SetSender(m.mailFrom());
mailA.AddAddressSee(item.Brugernavn);
mailA.SetSubject(title);
mailA.SetBody(resultMail);
mailA.SendEmail();
await Task.Delay(2200);
}
}
}
}
else
{
var result = _dbContext.OfferUser.Where(x => x.Value == 2).ToList();
if (result != null)
{
foreach (var itemValue in result)
{
int itemValueDays = itemValue.Days;//hvis den ingen antal har så giver den 0.
var daysValue = DateTime.Now.AddDays(-itemValueDays);
if (item.Opretdate.Date == daysValue)
{
var title = itemValue.Title;
var viewModel = new EmailModel
{
getUrl = m.RemoveLinkUrl(),
Title = title,
FullName = fullname,
Text = itemValue.Text.ToHtmlString()
};
var resultMail = await _viewRenderService.RenderToStringAsync("~/Views/Templates/OfferToUsers.cshtml", viewModel);//return Null here
MailMessageControl mailA = new MailMessageControl();
mailA.SetCredentials(m.azureName(), m.password());
mailA.SetSender(m.mailFrom());
mailA.AddAddressSee(item.Brugernavn);
mailA.SetSubject(title);
mailA.SetBody(resultMail);
mailA.SendEmail();
await Task.Delay(2200);
}
}
}
}
}
}
//Det er til dem fra nyhedsbrevet som få tilsendt nyhedsbrev omkring div ting.
var newsletterlist = _dbContext.NewsletterList.Where(i => i.Tilmeldtdato >= MaxDays).ToList();
if (newsletterlist != null)
{
foreach (var item in newsletterlist)
{
string mail = item.Email;
string fullname = item.Email;
//til de nyhedsbrevet område
var result = _dbContext.OfferUser.Where(x => x.Value == 3).ToList();
if (result != null)
{
foreach (var itemValue in result)
{
int itemValueDays = itemValue.Days;
var daysValue = DateTime.Now.AddDays(-itemValueDays);
if (item.Tilmeldtdato.Date == daysValue)
{
var title = itemValue.Title;
var viewModel = new EmailModel
{
getUrl = m.RemoveLinkUrl(),
Title = title,
FullName = fullname,
Text = itemValue.Text.ToHtmlString()
};
var resultMail = await _viewRenderService.RenderToStringAsync("~/Views/Templates/OfferToUsers.cshtml", viewModel);
MailMessageControl mailA = new MailMessageControl();
mailA.SetCredentials(m.azureName(), m.password());
mailA.SetSender(m.mailFrom());
mailA.AddAddressSee(mail);
mailA.SetSubject(title);
mailA.SetBody(resultMail);
mailA.SendEmail();
await Task.Delay(3500);
}
}
}
}
}
return Ok("Godkendt!");
}
No, I don't see mistake in Azure Logic Apps. Since the Logic App uses a recurrence trigger, it triggers the Logic App at the defined interval of time.
As there was send email action both side on the parallel branch, it will somehow send you an email by no means.

Programatically retrieve data using iterator in oracle ADF Mobile

I want to read programatically data using iterator in ADF mobile. My code is :
try {
ValueExpression vex = AdfmfJavaUtilities.getValueExpression("#{bindings.WeatherDescriptionIterator}", Object.class);
AmxIteratorBinding iter = (AmxIteratorBinding)vex.getValue(AdfmfJavaUtilities.getAdfELContext());
GenericType row = null;
BasicIterator bIter = iter.getIterator();
iter.getIterator().first();
ArrayList employees = new ArrayList();
for(int i = 0; i < iter.getIterator().getTotalRowCount(); i++) {
row = (GenericType)iter.getCurrentRow();
String phone = "";
String email = "";
if(row.getAttribute("Description") != null)
phone = row.getAttribute("Description").toString();
if(row.getAttribute("WeatherID") != null)
email = row.getAttribute("WeatherID").toString();
setTempValue(phone + " " + email);
iter.getIterator().next();
}
}
catch(Exception e1) {
AdfException ex = new AdfException(""+e1.getLocalizedMessage(), AdfException.ERROR );
throw ex;
}
I get error :-> cant not find property bindings
the expression should be :
ValueExpression vex = AdfmfJavaUtilities.getValueExpression("#bindings.WeatherDescriptionIterator.iteratorBinding}", Object.class);

Linq entityref assignment in one to many relation

i have some problem with my linq database with a one to many relation. Here are classes:
private EntityRef<Account> _account;
[Association(Storage = "_account", ThisKey = "IDMovement", OtherKey = "IDAccount", IsForeignKey = true)]
public Account Account
{
get { return this._account.Entity; }
set
{
Account previousValue = this._account.Entity;
if (((previousValue != value) || (this._account.HasLoadedOrAssignedValue == false)))
{
NotifyPropertyChanging("Account");
if ((previousValue != null))
{
this._account.Entity = null;
previousValue.Movements.Remove(this);
}
this._account.Entity = value;
if ((value != null))
{
value.Movements.Add(this);
}
NotifyPropertyChanged("Account");
}
}
}
and on the other side:
private EntitySet<Movement> _movements;
[Association(Storage = "_movements", OtherKey = "IDMovement", ThisKey = "IDAccount")]
public EntitySet<Movement> Movements
{
get { return this._movements; }
set { this._movements.Assign(value); }
}
private void OnMovementAdded(Movement movement)
{
NotifyPropertyChanging("Movement");
movement.Account = this;
NotifyPropertyChanged("Movement");
}
private void OnMovementRemoved(Movement movement)
{
NotifyPropertyChanging("Movement");
movement.Account = null;
NotifyPropertyChanged("Movement");
}
my problem is that when i have to insert new movements in the database i don't know how to assign the "EntityRef _account" variable with a value that i already have in the database.
For example: i have to insert a movement for the account "general", this account is already in my database of course...how can i say to my movement that the account "general" that it has in "movement.Account" it's exactly the same included in my database?
I tried something like that but It doesn't work because it's like i have created a new account:
Movement movement = new Movement();
movement.Category = (from f in context.Categories
where f.Name == this.Categories.ElementAt(this.ChoosenCategory).Name
select f).FirstOrDefault();
movement.Account = (from f in context.Accounts
where f.Name == ChoosenAccount.Name
select f).FirstOrDefault();
context.Movements.InsertOnSubmit(movement);
context.SubmitChanges();
You need to call Load() method for EntityRef such as if (!order.CustomersReference.IsLoaded)
order.CustomersReference.Load();

How to retrieve parentaccountid from account using queryexpression and silverlight

My query returns account.name, account.account and account.parentaccountid.
I'm using Silverlight and CRM2011.
Now I'm having trouble to find out how to extract value from parentaccountid attribute.
I have silverlightextensionmethods.cs file included in my VS project, and I'm using GetAttributeValue<Guid>("parentaccountid") to get the value from parentaccountid.
The value returned is empty.
Has anyone any ideas how to accomplish this?
I can get any other attribute value, but parentaccountid in account and parentcustomerid in contact are making my life very difficult.
Code:
FIRST I CREATE QUERYEXPRESSION:
string temp="name;accountid;parentaccountid";
string[] fields = temp.Split(';');
QueryExpression query = new QueryExpression()
{
EntityName = entity,
ColumnSet = new ColumnSet { Columns = new System.Collections.ObjectModel.ObservableCollection<string>(fields) },
Criteria = new FilterExpression
{
FilterOperator = LogicalOperator.And,
Conditions =
{
new ConditionExpression
{
AttributeName = parentidfield,
Operator = ConditionOperator.Equal,
Values = { id }
}
}
}
};
OrganizationRequest req = new OrganizationRequest();
req.RequestName = "RetrieveMultiple";
req["Query"] = query;
service.BeginExecute(req, new AsyncCallback(GetChildren_ExecuteCallBack), service);
NEXT I TY TO READ VALUES FORM RESPONSE
void GetChildren_ExecuteCallBack(IAsyncResult childresult)
{
List<TreeRecord> listc = new List<TreeRecord>();
try
{
OrganizationResponse childresponse = ((IOrganizationService)childresult.AsyncState).EndExecute(childresult);
EntityCollection childresults = (EntityCollection)childresponse["EntityCollection"];
if (childresults.Entities.Count > 0)
{
TreeConfig sitm = new TreeConfig();
string sdisplay = "";
string[] fields = "".Split(';');
string sid = "";
string pid = "";
foreach (Entity childentity in childresults.Entities)
{
foreach (TreeConfig sitem in Configs)
{
if (sitem.EntityName == childentity.LogicalName)
{
sitm = sitem;
}
}
TreeRecord childitem = new TreeRecord();
string sValue = "";
sdisplay = "name;accountid;parentaccountid";
fields = sdisplay.Split(';');
sid = "accountid";
pid = "parentaccountid";
int i = sdisplay.Split(';').Length;
for (int j = 0; j < i; j++)
{
try { sValue += childentity.GetAttributeValue<string>(fields[j]) + " "; }
catch (Exception ex)
{
//s = "sValue haku: " + ex.Message.ToString();
//this.ReportMessage(s.ToString());
}
}
childitem.Name = sValue;
childitem.EntityName = childentity.LogicalName;
childitem.Level = sitm.Level;
childitem.ParentEntityName = sitm.EntityName;
childitem.Color = sitm.Color;
childitem.RecordId = childentity.GetEntityId<Guid>(sid);
try { childitem.ParentId = childentity.GetAttributeValue<Guid>(pid); }
catch
{
//sb.AppendLine("guid: parentid tietoa ei löydy");
//this.ReportMessage(sb.ToString());
}
listc.Add(childitem);
}
}
}
Instead of
childentity.GetAttributeValue<Guid>(pid)
use
childentity.GetAttributeValue<EntityReference>(pid)

Resources