Home Products Downloads Purchase Support News Members Company
SITE FEED
Support Forum
The fastest and most effective to get answers to your questions quickly. Click Here for more info.
FAQs
Quick answers to common questions. Click Here for more info.
Troubleshooting
Known issues and basic troubleshooting techniques for problems or unexpected behaviors. Click Here for more info.
Knowledgebase
Technical tips, How-to articles, and other tutorials about ApexSQL Tools. Click Here for more info.
Online Documentation
All of our help files for download or convenient viewing online. Click Here for more info.
Videos
Watch product demos, training videos, or tutorials of our products' main features.  We frequently upload new videos so check often for updates. Click Here for more info.

ApexSQL Knowledgebase

Tips and How-to Articles for Apex SQL Tools


How to audit user names in ASP.Net application

This KB article discusses how to modify an ASP .Net application so that it can give ApexSQL Audit the information it needs to audit the ASP .Net application's user names/login information.

DESCRIPTION
ApexSQL Audit is a server-side application that gathers information directly from the server. When using ApexSQL Audit along with ASP.Net applications, it may not be able to log the user information you want. For most ASP.Net applications, users will have an application login separate from the login information that the application uses to connect to the SQL Server. Usually, Asp.net applications connect to a database as a single user, using either NT authentication or SQL Server authentication (e.g. “sa”).

If the ASP.Net application uses NT authentication and the NT users are granted login rights to the SQL server--then ApexSQL Audit will audit the user names correctly (NT authentication should also be used in the connection string within ASP.Net application). However, in the case where the ASP.Net application uses a single user login (for example, “sa”) or custom name mapping (that is, each ASP.Net user is mapped to the appropriate SQL server login inside the application), then by design, this is the only information that ApexSQL Audit will audit.

With just a few simple steps however, you can enable ApexSQL Audit to audit the user names in the ASP .Net application as well. The following steps discuss an easy and convenient way to let ApexSQL Audit know about the ASP.Net user and log it correctly.

SOLUTION
To define the application’s user name within the audit trigger, we recommend using SQL connection’s CONTEXT_INFO functionality. The following query will set the user name for current connection:

DECLARE @BinVar varbinary(128)
SET @BinVar = CAST(N'User Name' AS varbinary(128) )
SET CONTEXT_INFO @BinVar


This way, you can easily map your ASP.Net user to corresponding connections.
In the audit trigger, this user name can be obtained from its context by the following query:

SELECT CAST(CONTEXT_INFO() AS NVARCHAR(64) )

The typical function to execute queries or stored procedure calls in ASP.Net applications looks like below:

public static int ExecuteNonQuery(string connectionString, CommandType 
commandType, string commandText, params SqlParameter[]
commandParameters)
{
if( connectionString == null || connectionString.Length
== 0 ) throw new ArgumentNullException
( "connectionString" );

// Create & open a SqlConnection, and dispose it after we are done
using (SqlConnection connection = new SqlConnection(connectionString))
{
connection.Open();

// Call the overloaded method that takes a ready connection
instead of the connection string
return ExecuteNonQuery(connection, commandType, commandText,
commandParameters);
}
}


Instead of directly creating a SqlConnection, we recommend you to create a function that will set up the newly created connection. Note that in below example, the “username” parameter is the desired application user name we want ApexSQL Audit to log in the audit triggers:

public static SqlConnection NewSqlConnection(string connectionString, 
string username)
{
if( connectionString == null || connectionString.Length == 0 )
throw new ArgumentNullException( "connectionString" );
SqlConnection connection = new SqlConnection(connectionString);
connection.Open();
// Set username for the created connection in CONTEXT_INFO
SqlCommand command = connection.CreateCommand();
command.CommandText = string.Format("DECLARE @BinVar varbinary
(128)"
+
" SET @BinVar = CAST(N'{0}' AS varbinary(128) ) "+
"SET CONTEXT_INFO @BinVar ", username);
command.ExecuteNonQuery();
return connection;
}


Now we change the very first method using our helper function:

public static int ExecuteNonQuery(string connectionString, string username
, CommandType commandType, string commandText, params SqlParameter
[] commandParameters)
{
// Create & open a SqlConnection, and dispose it after we are done
using (SqlConnection connection = NewSqlConnection
(connectionString, username))
{
// Call the overloaded method that takes a ready connection instead
of the connection string
return ExecuteNonQuery(connection, commandType,
commandText, commandParameters);
}
}


Function NewSqlConnection should be called everywhere when you create a new connection. It will set up the user name and guarantee that the command will always be executed from the appropriate user.

You will now be able to get the user name in the trigger’s context as shown below:

    INSERT
    INTO {%AUDIT.PRINT DATABASENAME%}.{%AUDIT.PRINT TRANSACTIONSTABLENAME%}
    (
        TABLE_NAME,
        TABLE_SCHEMA,
        AUDIT_ACTION_ID,
        HOST_NAME,
        APP_NAME,
        MODIFIED_BY,
        MODIFIED_DATE,
        AFFECTED_ROWS,
        [DATABASE]
    )
    VALUES(
        '{%Audit.Print Replace(objTable.Name, "'", "''")%}',
'{%Audit.Print Replace(objTable.Owner, "
'", "''")%}',
        2,    --    ACTION ID For INSERT
        CASE
          WHEN LEN(HOST_NAME()) < 1 THEN ' '
          ELSE HOST_NAME()
        END,
        CASE
          WHEN LEN(APP_NAME()) < 1 THEN ' '
          ELSE APP_NAME()
        END,
        CAST(CONTEXT_INFO() AS NVARCHAR(64) ),
        GETDATE(),
        @ROWS_COUNT,
        '{%Audit.Print Audit.Database.Name%}'
    )


Using the above approach, you should always call most of functions with the user name.

Above approach may be inconvenient as you will have to change your interface in all functions. We suggest yet another approach to make changes only in the data access layer. To do this, you can create an additional helper class. You should be able to instantiate the Class, for example, the SqlHelper class is a connection provider:

internal sealed class SqlHelper
{
private string username = string.Empty;
public SqlHelper(string username)
{
this.username = username;
}
public SqlConnection NewSqlConnection(string
connectionString)
{
if( connectionString == null ||
connectionString.Length == 0 ) throw new
ArgumentNullException
( "connectionString" );
SqlConnection connection = new SqlConnection
(connectionString);
connection.Open();
// Set username for the created connection in
CONTEXT_INFO
SqlCommand command = connection.CreateCommand();
command.CommandText = string.Format
("DECLARE @BinVar varbinary(128)" +
" SET @BinVar = CAST(N'{0}' AS
varbinary(128) ) "
+
"SET CONTEXT_INFO @BinVar ", username);
command.ExecuteNonQuery();
return connection;
}
}


And this will not change the interface:

public int ExecuteNonQuery(string connectionString, CommandType 
commandType, string commandText, params SqlParameter[]
commandParameters)
{
// Create & open a SqlConnection, and dispose of it after we are
done
using (SqlConnection connection = NewSqlConnection
(connectionString))
{
// Call the overload that takes a connection in place of
the connection string
return ExecuteNonQuery(connection, commandType,
commandText, commandParameters);
}
}


Connection provider should be stored in the session variables or created for each usage with the username (which is usually stored in the session variables).

Now your ASP.Net users will be logged correctly by ApexSQL Audit.

AUTHOR
Denis Mack

LAST REVIEW DATE
10 August 2007

Labels:

...


Installing the Audit Tables on another Database

DESCRIPTION
This KB discusses how to store ApexSQL's Audit data on a separate database.

SOLUTION
To illustrate how, we call the database containing the Audit storage tables the “Audit Storage DB” while we call the database being audited the “Audited DB”. The first database's main purpose is reporting.

First, you need to make sure that the following Architecture structures are added/installed to the Audit Storage DB: DDL, Reporting (Standard and/or Aggregate), and Delete Architecture. For the Audited DB, at the very least, the DDL Architecture must be added. Triggers won’t be created without it. All these can be done via the Install Architecture dialog:



The Install Architecture dialog can be opened by choosing Install Auditing command from the Audit menu or by clicking the Auditing Toolbar, . You may also click from the Auditing Outlook Bar.

Installing Delete Architecture to the Audited DB is optional. Its main purpose is to automatically remove the Architecture and triggers, all of which can be done manually.

Next, the Trigger template of the Audited DB needs to be changed such that insertion statements point to the Audit Storage db. For example, [audit_db] in [audit_db].[dbo].[AUDIT_LOG_TRANSACTIONS] should be the Audit Storage database name. The template editor's Find/Replace feature can be used to do this.

Example
The default template contains insert statements like the one shown below:

    INSERT
    INTO {%Audit.Print DatabaseName%}.{%Audit.Print TransactionsTableName%}
    (
        TABLE_NAME,
        TABLE_SCHEMA,
        AUDIT_ACTION_ID,
        HOST_NAME,
        APP_NAME,
        MODIFIED_BY,
        MODIFIED_DATE,
        AFFECTED_ROWS,
        [DATABASE]
    )
    values(
        '{%Audit.Print Replace(objTable.Name, "'", "''")%}',
'{%Audit.Print Replace(objTable.Owner, "
'", "''")%}',
        2,    --    ACTION ID For INSERT
        CASE
          WHEN LEN(HOST_NAME()) < 1 THEN ' '
          ELSE HOST_NAME()
        END,
        CASE
          WHEN LEN(APP_NAME()) < 1 THEN ' '
          ELSE APP_NAME()
        END,
        SUSER_SNAME(),
        GETDATE(),
        @ROWS_COUNT,
        '{%Audit.Print Audit.Database.Name%}'
    )


The name of the Audit Storage DB is defined by the DatabaseName variable of the trigger template:
 StartTriggerNameInsert = "tr_i_AUDIT_"
StartTriggerNameUpdate = "tr_u_AUDIT_"
StartTriggerNameDelete = "tr_d_AUDIT_"

DatabaseName = "[" & Audit.Database.Name & "]"
TransactionsTableName = "dbo.AUDIT_LOG_TRANSACTIONS"
DataTableName = "dbo.AUDIT_LOG_DATA"


Change the value of this variable to define a custom name for the Audit Storage DB. For example,
DatabaseName = "MyStorageDatabase"

Make sure to give update rights to the audited tables' owners to allow for writing to the Audit Storage DB. The triggers are executed using the rights of the table owners.

Note: In SQL Server 2005, trigger executing rights can be defined for a user. For example:

' =============================================================
' =============================================================
' INSERT INSERT INSERT INSERT INSERT INSERT INSERT
' =============================================================
' =============================================================
caption = "Create Insert Trigger " & "[" & objTable.Owner & "].
[" & StartTriggerNameInsert & objTable.Name & "]" & _
" for Table " & TableFullName%}
IF OBJECT_ID('{%Audit.Print replace("[" & objTable.Owner & "].["
& StartTriggerNameInsert & objTable.Name & "]", "'",
"''") %}','TR') IS NOT NULL
BEGIN
DROP TRIGGER {%Audit.Print "[" & objTable.Owner & "].[" &
StartTriggerNameInsert & objTable.Name & "]" %}
PRINT '{% Audit.Print "Trigger Dropped: " & StartTriggerNameInsert
& Replace(objTable.Name,"'","''")%}'
END
GO
-- {%Audit.Print caption%}
Print '{%Audit.Print Replace(caption, "'", "''")%}'
go
CREATE TRIGGER {%Audit.Print "[" & objTable.Owner & "].[" &
StartTriggerNameInsert & objTable.Name & "]" %}
ON {%Audit.Print TableFullName%}
WITH EXECUTE AS '{%Audit.Print Auditor%}'
FOR INSERT
NOT FOR REPLICATION
As


Above code shows the beginning of the INSERT trigger template. It displays the user whose rights will be applied for trigger executing context. The Auditor is a string variable that stores the user name. It should be defined somewhere at the top of the triggers template (for example, near the DatabaseName) as follows:
Auditor = "db_auditor"


For viewing the reports, connect to the Audit Storage DB. For creating the triggers, connect to the Audited DB.

Important: The UnDo procedure is not available in this approach.

AUTHOR
Denis Mack

LAST REVIEW DATE
10 August 2007

Labels:

...


How to Delete Old Data in Audit tables

DESCRIPTION
ApexSQL Audit stores audit data in SQL Server tables. These tables can be installed in the same database being audited or in a different database on the same server. These tables can be queried via SQL or other data access tools. The tables included in the default architecture are: AUDIT_LOG_DATA and AUDIT_LOG_TRANSACTIONS. This article discusses how to delete data in these tables as they grow.

SOLUTION
1) From the Outlook Bar, click Manage Audit Data.



2) The Manage Data dialog is displayed.



The following delete options are available:

a) Option 1: I want to delete all data now.
This option truncates the data from your Audit tables when you click the Delete All button.

b) Option 2: I want to delete data now based on Data Deletion Criteria below.
This option allows you to specify a deletion criteria.



Deletion criteria can be any of the following:

-by Age (e.g. Delete data older than one month)
-by Log size (e.g. Delete 30 rows of data)
-Delete All Data (same as Option 1)

To perform deletion based on the criteria you set, click Run Task Now.

c) Option 3: I want to Create and Schedule a Job to Delete Data Later Based on Data Deletion Criteria Below
This option allows you to create a scheduled job to run your Data Deletion task on a schedule.

Provide a Job Name and specify your deletion criteria. Next, click Create DTS job or Schedule. Below dialog appears:



SEE ALSO
Manage Audit Data

AUTHOR
Janice Lee

LAST REVIEW DATE
21 August 2007

Labels:

...


How To Choose between ApexSQL Audit and ApexSQL Log

DESCRIPTION
ApexSQL has two auditing tools--ApexSQL Log and ApexSQL Audit. How do you know which one is for you? There is certainly a tradeoff when using one over the other. This article is an overview on how to choose between the two.

SOLUTION

ApexSQL Audit is trigger-based auditing tool. It helps users create audit triggers that react to DML operations and then store details of the operation into one or more auditing tables.

PROS
- You get total control over what tables you want to audit and what operations.
- Audit data is stored in SQL Server tables and can therefore be manipulated like any other SQL Server table; audit history is immediately available.
- You can write your own reporting system based on the audit data stored in SQL Server tables.
- We specially prevented auditing of system databases to avoid database crashes if something goes wrong (system tables locking, etc.)
- As a rule, DBAs always have full access to the data. Therefore, they can change data in the Audit tables or even truncate them.
- ApexSQL Audit has a separate reporting tool called ApexSQL Audit Viewer which can be purchased separately. ApexSQL Audit Viewer is a standalone reporting application for ApexSQL Audit. It can be distributed to team members and end-users who only need to view auditing reports and don't need access to the administrative features of ApexSQL Audit.

CONS
- It can possibly cause performance degradation--as is the nature of all TRIGGERS.


ApexSQL Log on the otherhand is transaction log-based, that is, it reads the transaction log to get audit data.

PROS
- If you are already working in FULL RECOVERY mode, then there is no downside on the space/performance.
- You can move transaction logs to another server and audit there
- Comes with a Data Recovery tool; better UNDO/recovery and is essentially maintenance free.
- You can schedule ApexSQL Log to read the transaction log on a schedule. Auditing doesn't happen right after the operation being audited happens giving you the option to do your auditing during offline hours. (Note: The only data that has to be captured in real time is additional login information--NT user name, application name and client host name--since this is not in the transaction log. This information is captured by ApexSQL Log's Connection Monitor after a new login is made. It has minimal overhead.)


CONS
- To use ApexSQL Log's auditing feature, your database should be in FULL RECOVERY mode. If you don't plan your maintenance right, your drives can get filled with transaction logs and this can have an impact on the performance. In the long run, there is a chance of running out of disk space. Switching to FULL RECOVERY is not a simple turn on/off thing. Once you switch to FULL RECOVERY, transaction log starts to grow so you have to prepare beforehand how to deal with that.
- Update operations

Both tools allow you to generate reports in various formats.

SEE ALSO
How to Synchronize a Database on a Schedule

AUTHOR
Janice Lee

LAST REVIEW DATE
03 December 2007

Labels: ,

...


Schedule Audit Report generation

DESCRIPTION
This KB article discusses how to schedule the generation of Audit reports in ApexSQL Audit.

SOLUTION
In Windows, create a scheduled task for ApexSQLAudit.com with parameters specifying your database and the report format you want (PDF, Excel, or CSV).

(1) To schedule a standard report:

apexsqlaudit.com /server:(local) /database:Northwind /reportformat:pdf /sreport /action:d

(2) To schedule an aggregate report

apexsqlaudit.com /server:(local) /database:Northwind /reportformat:pdf /areport /action:d


What is standard reporting?
Standard reporting provides a straightforward way to view data stored in the Audit log. The data is transactional and NOT row-based. This means that each Cell is a row in the Standard Report. This is done to provide a granular, before and after analysis of the effect of the audited action.

What is aggregate reporting?
Unlike Standard Reporting (which is Field level-based), Aggregate reporting is Transaction based. For example, an insert can generate 4 rows in the Standard report, that is, one row for each field affected; in Aggregate Reporting, it can only generate a maximum of one row.

In Aggregate reporting, transactions are always grouped rather than displayed individually.

How can you set a filter on reports via CLI?
This is described in detail on the help file (Command Line > Switches > Filter Options for Reports)

What does /action:d do?
It displays delete operations on the report.

If you omit connection details, does it login with integrated security automatically?
Yes. ApexSQL Audit logs in with integrated security automatically if connection details are not defined.

How can you determine where the report file is written to? What is the default dir?
The default directory is your current directory and not where the application is located.

SEE ALSO
How To Schedule Tasks in Windows XP

LAST REVIEW
20 August 2007

Labels:

...


Welcome to the ApexSQL Knowledge Base

Welcome to the ApexSQL Training Knowledge Base. Here you'll find tips, reviews, videos, and articles on how to get the most out of ApexSQL Tools and Microsoft SQL Server.

Labels: , , , , , , , , , , ,

...

© 2007 Apex SQL Tools All Rights Reserved | 1.919.968.8444 | Contact Us | Terms of Use