By default, the Audit Trail system uses the client time stamping. When
an Audit Data Item is saved to the data
storage, the ModifyOn property is initialized with the time of the
computer which has been used to perform the change. It causes information
inauthenticity, because two changes made at the same time can be saved as if
they were made at different moments (for example, if these computers are in the
different time zones). To avoid this effect, you should use server-side time
stamping. To do this, you need to replace the default Local Audit Timestamp
Strategy with a server side time stamp strategy. This topic demonstrates how to
implement a custom Audit Timestamp Strategy, and set it for the Audit Trail
system.
To implement an Audit Timestamp Strategy, you should implement the
IAuditTimestampStrategy interface. Further on, you'll see how to
implement a Timestamp Web Service and MSSql Server Timestamp Strategy.
Show Me |
The complete sample project is available in the DevExpress Code Central
database at http://www.devexpress.com/example=E1808.
Depending on the target platform type (ASP.NET, WinForms, etc), you can either
run this example online or download an auto-executable
sample. |
Timestamp Web Service
- Add an Asp.NET Web Service to your solution.
- Add the GetTime method to the new service's implementation:
|
[WebService(Namespace = "http://localhost/TimestampService/")]
[WebServiceBinding(ConformsTo = WsiProfiles.BasicProfile1_1)]
public class TimestampWebService : System.Web.Services.WebService {
[WebMethod]
public DateTime GetTime() {
return DateTime.Now;
}
}
<WebService(Namespace:="http://localhost/TimestampService/"), _
WebServiceBinding(ConformsTo:=WsiProfiles.BasicProfile1_1)> _
Public Class TimestampWebService
Inherits System.Web.Services.WebService
<WebMethod()> _
Public Function GetTime() As DateTime
Return DateTime.Now
End Function
End Class
|
C# |
[WebService(Namespace = "http://localhost/TimestampService/")]
[WebServiceBinding(ConformsTo = WsiProfiles.BasicProfile1_1)]
public class TimestampWebService : System.Web.Services.WebService {
[WebMethod]
public DateTime GetTime() {
return DateTime.Now;
}
}
|
VB |
<WebService(Namespace:="http://localhost/TimestampService/"), _
WebServiceBinding(ConformsTo:=WsiProfiles.BasicProfile1_1)> _
Public Class TimestampWebService
Inherits System.Web.Services.WebService
<WebMethod()> _
Public Function GetTime() As DateTime
Return DateTime.Now
End Function
End Class
|
- For the WebService attribute, specify the required URL (see the code
above).
- Set a Web reference to the new Web Service project to the application
module.
- In the application module, implement a WebServiceTimestampStrategy
class. It's demonstrated in the following code:
|
using System;
using AuditServerSideTimestampingDemo.Module.TimestampService;
using DevExpress.Persistent.AuditTrail;
using DevExpress.Xpo;
namespace MySolution.Module {
public class WebServiceTimestampStrategy : IAuditTimestampStrategy {
DateTime cachedTimestamp;
#region IAuditTimestampStrategy Members
public DateTime GetTimestamp(AuditDataItem auditDataItem) {
return cachedTimestamp;
}
public void OnBeginSaveTransaction(Session session) {
try {
TimestampWebService service = new TimestampWebService();
cachedTimestamp = service.GetTime();
}
catch {
throw new Exception(
"The TimestampWebService cannot be accessed. Make sure that it is running.");
}
}
#endregion
}
}
Imports System
Imports AuditServerSideTimestampingDemo.Module.TimestampService
Imports DevExpress.Persistent.AuditTrail
Imports DevExpress.Xpo
Namespace MySolution.Module
Public Class WebServiceTimestampStrategy
Implements IAuditTimestampStrategy
Private cachedTimestamp As DateTime
#Region "IAuditTimestampStrategy Members"
Public Function GetTimestamp(ByVal auditDataItem As AuditDataItem) As DateTime _
Implements IAuditTimestampStrategy.GetTimestamp
Return cachedTimestamp
End Function
Public Sub OnBeginSaveTransaction(ByVal session As Session) _
Implements IAuditTimestampStrategy.OnBeginSaveTransaction
Try
Dim service As TimestampWebService = New TimestampWebService()
cachedTimestamp = service.GetTime()
Catch
Throw New Exception( _
"The TimestampWebService cannot be accessed. Make sure that it is running.")
End Try
End Sub
#EndRegion
End Class
End Namespace
|
C# |
using System;
using AuditServerSideTimestampingDemo.Module.TimestampService;
using DevExpress.Persistent.AuditTrail;
using DevExpress.Xpo;
namespace MySolution.Module {
public class WebServiceTimestampStrategy : IAuditTimestampStrategy {
DateTime cachedTimestamp;
#region IAuditTimestampStrategy Members
public DateTime GetTimestamp(AuditDataItem auditDataItem) {
return cachedTimestamp;
}
public void OnBeginSaveTransaction(Session session) {
try {
TimestampWebService service = new TimestampWebService();
cachedTimestamp = service.GetTime();
}
catch {
throw new Exception(
"The TimestampWebService cannot be accessed. Make sure that it is running.");
}
}
#endregion
}
}
|
VB |
Imports System
Imports AuditServerSideTimestampingDemo.Module.TimestampService
Imports DevExpress.Persistent.AuditTrail
Imports DevExpress.Xpo
Namespace MySolution.Module
Public Class WebServiceTimestampStrategy
Implements IAuditTimestampStrategy
Private cachedTimestamp As DateTime
#Region "IAuditTimestampStrategy Members"
Public Function GetTimestamp(ByVal auditDataItem As AuditDataItem) As DateTime _
Implements IAuditTimestampStrategy.GetTimestamp
Return cachedTimestamp
End Function
Public Sub OnBeginSaveTransaction(ByVal session As Session) _
Implements IAuditTimestampStrategy.OnBeginSaveTransaction
Try
Dim service As TimestampWebService = New TimestampWebService()
cachedTimestamp = service.GetTime()
Catch
Throw New Exception( _
"The TimestampWebService cannot be accessed. Make sure that it is running.")
End Try
End Sub
#EndRegion
End Class
End Namespace
|
- Create an instance of the WebServiceTimestampStrategy class and
assign it to the AuditTrailService.Instance.TimestampStrategy property.
In the code below, this is performed for the Windows Forms application.
Actually, you can do it for the ASP.NET application as well.
|
static void Main() {
MySolutionWindowsFormsApplication application = new MySolutionWindowsFormsApplication();
IAuditTimestampStrategy timeStampStrategy = new WebServiceTimestampStrategy();
AuditTrailService.Instance.TimestampStrategy = timeStampStrategy;
application.Setup();
}
Shared Sub Main()
Dim _application As MySolutionWindowsFormsApplication = New MySolutionWindowsFormsApplication()
Dim timeStampStrategy As IAuditTimestampStrategy = New WebServiceTimestampStrategy()
AuditTrailService.Instance.TimestampStrategy = timeStampStrategy
_application.Setup()
End Sub
|
C# |
static void Main() {
MySolutionWindowsFormsApplication application = new MySolutionWindowsFormsApplication();
IAuditTimestampStrategy timeStampStrategy = new WebServiceTimestampStrategy();
AuditTrailService.Instance.TimestampStrategy = timeStampStrategy;
application.Setup();
}
|
VB |
Shared Sub Main()
Dim _application As MySolutionWindowsFormsApplication = New MySolutionWindowsFormsApplication()
Dim timeStampStrategy As IAuditTimestampStrategy = New WebServiceTimestampStrategy()
AuditTrailService.Instance.TimestampStrategy = timeStampStrategy
_application.Setup()
End Sub
|
- Run the application. Check that the implemented code works.
MSSql Server Timestamp Strategy
To get the time, you can use the MSSql server. For this purpose, use the
Session.Connection property that returns the
System.Data.IDbConnection which is associated with the session, and cast
it by the SqlConnection type. To get time on the MSSql server, use the
GETDATE() function. The following code demonstrates the entire
MSSqlServerTimestampStrategy class implementation:
|
using System;
using System.Data.SqlClient;
using DevExpress.Xpo;
using DevExpress.Persistent.AuditTrail;
namespace MySolution.Module {
public class MSSqlServerTimestampStrategy : IAuditTimestampStrategy{
DateTime cachedTimestamp;
#region IAuditTimestampStrategy Members
public DateTime GetTimestamp(AuditDataItem auditDataItem) {
return cachedTimestamp;
}
public void OnBeginSaveTransaction(Session session) {
SqlCommand command = new SqlCommand("select getdate()", (SqlConnection)session.Connection);
cachedTimestamp = (DateTime)command.ExecuteScalar();
}
#endregion
}
}
Imports System
Imports System.Data.SqlClient
Imports DevExpress.Xpo
Imports DevExpress.Persistent.AuditTrail
Namespace MySolution.Module
Public Class MSSqlServerTimestampStrategy
Implements IAuditTimestampStrategy
Private cachedTimestamp As DateTime
#Region "IAuditTimestampStrategy Members"
Public Function GetTimestamp(ByVal auditDataItem As AuditDataItem) As DateTime _
Implements IAuditTimestampStrategy.GetTimestamp
Return cachedTimestamp
End Function
Public Sub OnBeginSaveTransaction(ByVal session As Session) _
Implements IAuditTimestampStrategy.OnBeginSaveTransaction
Dim command As SqlCommand = New SqlCommand("select getdate()", _
CType(session.Connection, SqlConnection))
cachedTimestamp = CDate(command.ExecuteScalar())
End Sub
#EndRegion
End Class
End Namespace
|
C# |
using System;
using System.Data.SqlClient;
using DevExpress.Xpo;
using DevExpress.Persistent.AuditTrail;
namespace MySolution.Module {
public class MSSqlServerTimestampStrategy : IAuditTimestampStrategy{
DateTime cachedTimestamp;
#region IAuditTimestampStrategy Members
public DateTime GetTimestamp(AuditDataItem auditDataItem) {
return cachedTimestamp;
}
public void OnBeginSaveTransaction(Session session) {
SqlCommand command = new SqlCommand("select getdate()", (SqlConnection)session.Connection);
cachedTimestamp = (DateTime)command.ExecuteScalar();
}
#endregion
}
}
|
VB |
Imports System
Imports System.Data.SqlClient
Imports DevExpress.Xpo
Imports DevExpress.Persistent.AuditTrail
Namespace MySolution.Module
Public Class MSSqlServerTimestampStrategy
Implements IAuditTimestampStrategy
Private cachedTimestamp As DateTime
#Region "IAuditTimestampStrategy Members"
Public Function GetTimestamp(ByVal auditDataItem As AuditDataItem) As DateTime _
Implements IAuditTimestampStrategy.GetTimestamp
Return cachedTimestamp
End Function
Public Sub OnBeginSaveTransaction(ByVal session As Session) _
Implements IAuditTimestampStrategy.OnBeginSaveTransaction
Dim command As SqlCommand = New SqlCommand("select getdate()", _
CType(session.Connection, SqlConnection))
cachedTimestamp = CDate(command.ExecuteScalar())
End Sub
#EndRegion
End Class
End Namespace
|
Create an instance of the MSSqlServerTimestampStrategy class and
assign it to the AuditTrailService.Instance.TimestampStrategy property.
It was demonstrated above for the WebServiceTimestampStrategy class.