Wednesday, December 17, 2014

Adding simple trigger-based auditing to your SQL Server database

How do you track changes to data in your database? There are a variety of supported auditing methods for SQL Server, including comprehensive C2 security auditing, but what do you do if you're solving a business rather than a security problem, and you're interested in tracking the following kinds of information:
  • What data has been updated recently
  • Which tables have not been updated recently
  • Who modified the price of Steeleye Stout to $20 / unit, and when did they do it?
  • What was the unit price for Steeleye Stout before Jon monkeyed with it?
There are a number of ways to design this into your solution from the start, for example:
  • The application is designed so that all changes are logged
  • All data changes go through a data access layer which logs all changes
  • The database is constructed in such a way that logging information is included in each table, perhaps set via a trigger

What if we're not starting from scratch?

But what do you do if you need to add lightweight auditing to an existing solution, in which data can be modified via a variety of direct access methods? When I ran into that challenge, I decided to use Nigel Rivett's SQL Server Auditing triggers. I read about some concern with the performance impact, but this database wasn't forecasted to have a high update rate. Nigel's script works by adding a trigger for INSERT, UPDATE, and DELETE on a single table. The trigger catches data changes, then saves out the information (such as table name, the primary key values, the column name that was altered, and the before and after values for that column) to an Audit table.
I needed to track every table in the database, though, and I expected the database schema to continue to change. I was able to generalize the solution a bit, because the database convention didn't use any no compound primary keys. I created the script listed below, which loops through all tables in the database with the exception of the Audit table, of course, since auditing changes to the audit table is both unnecessary and recursive. I'm also skipping sysdiagrams; you could include any other tables you don't want to track to that list as well.
The nice thing about the script I'm including below is that you can run it after making some schema changes and it will make sure that all newly added tables are included in the change tracking / audit, too.
Here's an example of what you'd see in the audit table for an Update followed by an Insert. Notice that the Update shows type U and a single column updated, while the Insert (type I) shows all columns added, one on each row:
Sample Audit Data
While this information is pretty unstructured, it's not difficult to run some useful reports. For instance, we can easily find things like
  • which tables were updated recently
  • which tables have not been updated in the past year
  • which tables have never been updated
  • all changes made by a specific user in a time period
  • most active tables in a time period
While it's not as easy, it's possible to backtrack from the current state to determine the state of a row in a table at a certain point in time. It's generally possible to dig out the state of an entire table at a point in time, but a change table isn't a good a fit for temporal data tracking - the right solution there is to start adding Modified By and Modified On columns to the required tables.
Note that we're only tracking data changes here. If you'd like to track schema changes, take a look at SQL Server 2005's DDL triggers.

Enough talking, give us the script!

Sure. I'll repeat that there are some disclaimers to the approach -  performance, it'll only track changes to tables with a primary key, etc. If you want to know more about the trigger itself, I'd recommend starting with Nigel's article. However, it worked great for our project.


USE MYAWESOMEDATABASE
GO

IF NOT EXISTS(SELECT * FROM INFORMATION_SCHEMA.TABLES WHERE TABLE_NAME= 'Audit')
CREATE TABLE Audit
(
AuditID [int]IDENTITY(1,1) NOT NULL,
Type char(1), 
TableName varchar(128), 
PrimaryKeyField varchar(1000), 
PrimaryKeyValue varchar(1000), 
FieldName varchar(128), 
OldValue varchar(1000), 
NewValue varchar(1000), 
UpdateDate datetime DEFAULT (GetDate()), 
UserNamevarchar(128)
)
GO

DECLARE @sql varchar(8000), @TABLE_NAMEsysname
SET NOCOUNT ON

SELECT @TABLE_NAME= MIN(TABLE_NAME) 
FROM INFORMATION_SCHEMA.Tables 
WHERE 
TABLE_TYPE= 'BASE TABLE' 
AND TABLE_NAME!= 'sysdiagrams'
AND TABLE_NAME!= 'Audit'

WHILE @TABLE_NAMEIS NOT NULL
 BEGIN
EXEC('IF OBJECT_ID (''' + @TABLE_NAME+ '_ChangeTracking'', ''TR'') IS NOT NULL DROP TRIGGER ' + @TABLE_NAME+ '_ChangeTracking')
SELECT @sql = 
'
create trigger ' + @TABLE_NAME+ '_ChangeTracking on ' + @TABLE_NAME+ ' for insert, update, delete
as

declare @bit int ,
@field int ,
@maxfield int ,
@char int ,
@fieldname varchar(128) ,
@TableName varchar(128) ,
@PKCols varchar(1000) ,
@sql varchar(2000), 
@UpdateDate varchar(21) ,
@UserName varchar(128) ,
@Type char(1) ,
@PKFieldSelect varchar(1000),
@PKValueSelect varchar(1000)

select @TableName = ''' + @TABLE_NAME+ '''

-- date and user
select @UserName = system_user ,
@UpdateDate = convert(varchar(8), getdate(), 112) + '' '' + convert(varchar(12), getdate(), 114)

-- Action
if exists (select * from inserted)
if exists (select * from deleted)
select @Type = ''U''
else
select @Type = ''I''
else
select @Type = ''D''

-- get list of columns
select * into #ins from inserted
select * into #del from deleted

-- Get primary key columns for full outer join
select@PKCols = coalesce(@PKCols + '' and'', '' on'') + '' i.'' + c.COLUMN_NAME + '' = d.'' + c.COLUMN_NAME
fromINFORMATION_SCHEMA.TABLE_CONSTRAINTS pk ,
INFORMATION_SCHEMA.KEY_COLUMN_USAGE c
where pk.TABLE_NAME = @TableName
andCONSTRAINT_TYPE = ''PRIMARY KEY''
andc.TABLE_NAME = pk.TABLE_NAME
andc.CONSTRAINT_NAME = pk.CONSTRAINT_NAME

-- Get primary key fields select for insert
select @PKFieldSelect = coalesce(@PKFieldSelect+''+'','''') + '''''''' + COLUMN_NAME + '''''''' 
fromINFORMATION_SCHEMA.TABLE_CONSTRAINTS pk ,
INFORMATION_SCHEMA.KEY_COLUMN_USAGE c
where pk.TABLE_NAME = @TableName
andCONSTRAINT_TYPE = ''PRIMARY KEY''
andc.TABLE_NAME = pk.TABLE_NAME
andc.CONSTRAINT_NAME = pk.CONSTRAINT_NAME

select @PKValueSelect = coalesce(@PKValueSelect+''+'','''') + ''convert(varchar(100), coalesce(i.'' + COLUMN_NAME + '',d.'' + COLUMN_NAME + ''))''
from INFORMATION_SCHEMA.TABLE_CONSTRAINTS pk ,    
INFORMATION_SCHEMA.KEY_COLUMN_USAGE c   
where  pk.TABLE_NAME = @TableName   
and CONSTRAINT_TYPE = ''PRIMARY KEY''   
and c.TABLE_NAME = pk.TABLE_NAME   
and c.CONSTRAINT_NAME = pk.CONSTRAINT_NAME 

if @PKCols is null
begin
raiserror(''no PK on table %s'', 16, -1, @TableName)
return
end

select @field = 0, @maxfield = max(ORDINAL_POSITION) from INFORMATION_SCHEMA.COLUMNS where TABLE_NAME = @TableName
while @field < @maxfield
begin
select @field = min(ORDINAL_POSITION) from INFORMATION_SCHEMA.COLUMNS where TABLE_NAME = @TableName and ORDINAL_POSITION > @field
select @bit = (@field - 1 )% 8 + 1
select @bit = power(2,@bit - 1)
select @char = ((@field - 1) / 8) + 1
if substring(COLUMNS_UPDATED(),@char, 1) & @bit > 0 or @Type in (''I'',''D'')
begin
select @fieldname = COLUMN_NAME from INFORMATION_SCHEMA.COLUMNS where TABLE_NAME = @TableName and ORDINAL_POSITION = @field
select @sql = ''insert Audit (Type, TableName, PrimaryKeyField, PrimaryKeyValue, FieldName, OldValue, NewValue, UpdateDate, UserName)''
select @sql = @sql + '' select '''''' + @Type + ''''''''
select @sql = @sql + '','''''' + @TableName + ''''''''
select @sql = @sql + '','' + @PKFieldSelect
select @sql = @sql + '','' + @PKValueSelect
select @sql = @sql + '','''''' + @fieldname + ''''''''
select @sql = @sql + '',convert(varchar(1000),d.'' + @fieldname + '')''
select @sql = @sql + '',convert(varchar(1000),i.'' + @fieldname + '')''
select @sql = @sql + '','''''' + @UpdateDate + ''''''''
select @sql = @sql + '','''''' + @UserName + ''''''''
select @sql = @sql + '' from #ins i full outer join #del d''
select @sql = @sql + @PKCols
select @sql = @sql + '' where i.'' + @fieldname + '' <> d.'' + @fieldname 
select @sql = @sql + '' or (i.'' + @fieldname + '' is null and  d.'' + @fieldname + '' is not null)'' 
select @sql = @sql + '' or (i.'' + @fieldname + '' is not null and  d.'' + @fieldname + '' is null)'' 
exec (@sql)
end
end
'
SELECT @sql
EXEC(@sql)
SELECT @TABLE_NAME= MIN(TABLE_NAME) FROM INFORMATION_SCHEMA.Tables 
WHERE TABLE_NAME> @TABLE_NAME
AND TABLE_TYPE= 'BASE TABLE' 
AND TABLE_NAME!= 'sysdiagrams'
AND TABLE_NAME!= 'Audit'
END



REF:
http://weblogs.asp.net/jongalloway/adding-simple-trigger-based-auditing-to-your-sql-server-database

Saturday, November 29, 2014

Session-State Modes

ASP.NET session state supports several different storage options for session data. Each option is identified by a value in the SessionStateMode enumeration. The following list describes the available session state modes:
  • InProc mode, which stores session state in memory on the Web server. This is the default.
  • StateServer mode, which stores session state in a separate process called the ASP.NET state service. This ensures that session state is preserved if the Web application is restarted and also makes session state available to multiple Web servers in a Web farm.
  • SQLServer mode stores session state in a SQL Server database. This ensures that session state is preserved if the Web application is restarted and also makes session state available to multiple Web servers in a Web farm.
  • Custom mode, which enables you to specify a custom storage provider.
  • Off mode, which disables session state.

Monday, November 24, 2014

JSON serialization error [maxJsonLength property.]

In my previous project I need to retrieve ticket  from Web service.When I request the web service it return a ticket as JSON format.Some time I need to retrieve more than 10 lacks ticket per requet.In that time I got the following error

Exception information:
Exception type: InvalidOperationException
Exception message: Error during serialization or deserialization using the JSON JavaScriptSerializer. The length of the string exceeds the value set on the maxJsonLength property.
Solution is 
            We need to set Maximum allowed length of json response in Web.config file 
The MaxJsonLength property cannot be unlimited, is an integer property that defaults to 102400 (100k).



You can set the MaxJsonLength property on your web.config
<configuration>
   <system.web.extensions>
       <scripting>
           <webServices>
               <jsonSerialization maxJsonLength="50000000"/>
           </webServices>
       </scripting>
   </system.web.extensions>
</configuration>

Display image from database in Image control without using Generic Handler in ASP.Net

how to display images stored in database in ASP.Net Image control 

 byte[] bytes = (byte[])GetData("SELECT Data FROM tblFiles WHERE Id =" + id).Rows[0]["Data"];
        string base64String = Convert.ToBase64String(bytes, 0, bytes.Length);
        Image1.ImageUrl = "data:image/png;base64," + base64String;

A correlation name must be specified for the bulk rowset in the from clause.



A correlation name must be specified for the bulk rowset in the from clause.

While inserting image files into a SQL Server database table using the OPENROWSET function, I got the following error message from the SQL engine.
Msg 491, Level 16, State 1, Line 5
A correlation name must be specified for the bulk rowset in the from clause.
I soon realized that the error message is asking for a alias name for the OPENROWSET select statement.



A correlation name must be specified for the bulk rowset in the from clause.

While inserting image files into a SQL Server database table using the OPENROWSET function, I got the following error message from the SQL engine.
Msg 491, Level 16, State 1, Line 5
A correlation name must be specified for the bulk rowset in the from clause.
I soon realized that the error message is asking for a alias name for the OPENROWSET select statement.



Here is the t-sql script that is causing the error message :
INSERT INTO Files(fname, [file])
SELECT 'T-SQL-Enhancements-in-SQL-Server-2008', * FROM OPENROWSET(
  BULK N'C:\T-SQL-Enhancements-in-SQL-Server-2008.jpg', SINGLE_BLOB
)

And the below sql script displays how the correct statement should be built.
Take your attention on the "rs" alias name at the end of the script.
INSERT INTO Files(fname, [file])
SELECT 'T-SQL-Enhancements-in-SQL-Server-2012', * FROM OPENROWSET(
  BULK N'C:\T-SQL-Enhancements-in-SQL-Server-2012.jpg', SINGLE_BLOB
) rs

 examples
--INSERT
INSERT INTO  [dbo].[TsOnProfile]([Photo])SELECT * FROM OPENROWSET( BULK N'C:\1.png', SINGLE_BLOB) rs 

--update
update [dbo].[TsOnProfile] set[Photo]= (SELECT * FROM OPENROWSET(
  BULK N'C:\1.png', SINGLE_BLOB
) rs)

ref:
http://www.kodyaz.com/articles/correlation-name-for-bulk-rowset-in-from-clause.aspx

Tuesday, November 4, 2014

How to use ParameterBuilder with BeginGroup and EndGroup

Summary

Use this methods when you want to group search queries.

The query will be formatted to something like this:

Select * from Survey_Customer where SurveyHeaderID = XXX And ( (FirstName=xxx) or (LastName=xxx) or ...))



       TList<SurveyCustomer> scList = new TList<SurveyCustomer>();

            SurveyCustomerParameterBuilder pb = new SurveyCustomerParameterBuilder();
            pb.AppendEquals(SurveyCustomerColumn.SurveyHeaderId, surveyHeaderId.ToString());            
              
            pb.BeginGroup("And");
            pb.Junction = ""; // need this empty space after calling BeginGroup
            pb.AppendLike(SurveyCustomerColumn.Company, "%" + keyword + "%");
            pb.Junction = "or";
            pb.AppendEquals(SurveyCustomerColumn.FirstName, keyword);
            pb.Junction = "or";
            pb.AppendEquals(SurveyCustomerColumn.LastName, keyword);
            pb.Junction = "or";
            pb.AppendEquals(SurveyCustomerColumn.EmailAddress, keyword);
            pb.Junction = "or";
            pb.AppendLike(SurveyCustomerColumn.Comments, "%" + keyword + "%");
            pb.Junction = "or";
            pb.AppendLike(SurveyCustomerColumn.Note1, "%" + keyword + "%");
            pb.Junction = "or";
            pb.AppendLike(SurveyCustomerColumn.Url, "%" + keyword + "%");
            try // this needs to go in a try catch since db is expecting a long and user might type in a 'string'
            {
                long surveyCustomerId = long.Parse(keyword);
                pb.AppendEquals(SurveyCustomerColumn.SurveyCustomerId, surveyCustomerId.ToString());
                pb.Junction = "or";
            }
            catch (Exception ex)
            {
                // not a valid long
            }
            pb.Junction = ""; // need this empty space before calling EndGroup
            pb.EndGroup();

            scList = DataRepository.SurveyCustomerProvider.Find(pb.GetParameters());

Saturday, November 1, 2014

Checkbox does not change its checked value after postback

 have a checkbox from where I get the checked value but the first time works great but then I doesn't change at all after postback and always returns true.
I'm just doing this

bool accepted = this.chkAccepted.Checked;
My checkbox is inside a control. Not repeater not directly in a page.
<asp:CheckBox ID="chkAccepted" runat="server" Checked="true"/>Accepted

The first time it starts checked = true. I click my button first postback and work fine, then I uncheck, click my button but the checked is still true.
The first time it starts checked = true. I uncheck the checkbox and I click my button first postback and work fine, then I check, click my button but the checked is true, then I uncheck again and is always checked = true.
So, what is the bug for this?
I have another checkbox in the same control which has no Checked property initialized and always works fine. So how can I solve this problem please?



I realized that it's a .NET bug after some research. So when the property Checked of the checkbox is set to true in the aspx, this causes the problem. So, I removed this property and in the Page_Load event(server side) I initialized the checkboxes as true inside a Page.IsPostBack == false. And that's solved my problem.


solved

<asp:CheckBox ID="chkRem"  value="true" runat="server" Text="تذكرني"  />
  <asp:HiddenField ID="chkremHid" runat="server" />


<script>
   //check box for login
            $('#chkRem').change(function () {
                if ($('#chkRem').prop('checked'))
                    $('#chkremHid').val("True");
                else
                    $('#chkremHid').val("False");
            });

</script>



in code behind
use the hidden field value instead chekbox
c#
string check = chkremHid.Value;



Friday, October 31, 2014

How to get the DataKey value in RowDataBound event for GridView



Please try with following code.
protected void GridView3_RowDataBound(object sender, GridViewRowEventArgs e)
    {
        if (e.Row.RowType == DataControlRowType.DataRow)
        {
            string lsDataKeyValue = GridView3.DataKeys[e.Row.RowIndex].Values[0].ToString();
        }
    }

How to Get DataKey value of a Row in RowDataBound or RowCommand Event in ASP.Net GridView control ?


We will normally set the primary key field to the DataKeyNames property of GridView control to identify the row. This little code snippet will help us to find the data keys assocciated with a row in DataBound and RowCommand event in codebehind file.

Refer the below code,
ASPX
  <asp:GridView ID="gvUsers" runat="server" AutoGenerateColumns="False"
            DataKeyNames="UserID" OnRowDataBound="gvUsers_RowDataBound"
            RowStyle-CssClass="Row" onrowcommand="gvUsers_RowCommand">
                    <Columns>                     
                        <asp:BoundField DataField="FirstName" HeaderText="First Name" ReadOnly="True" />
                        <asp:BoundField DataField="LastName" HeaderText="Last Name" ReadOnly="True" />    
                         <asp:BoundField DataField="Email" HeaderText="Email" ReadOnly="True" />
                         <asp:TemplateField>
                         <ItemTemplate>
                        <asp:Button runat="server" Text="SELECT" CommandName="Select" />                            
                        </ItemTemplate>
                         </asp:TemplateField>                      
                    </Columns>                  
                    <HeaderStyle BackColor="#F06300" Font-Bold="True" ForeColor="#FFFFCC" />
     </asp:GridView>

RowDataBound Event
protected void gvUsers_RowDataBound(object sender, GridViewRowEventArgs e)
    {      
        if (e.Row.RowType == DataControlRowType.DataRow)
        {
            object objTemp = gvUsers.DataKeys[e.Row.RowIndex].Value as object;
            if (objTemp != null)
            {
                string id = objTemp.ToString(); //Do your operations
            }
         
        }
    }

RowCommand Event
    protected void gvUsers_RowCommand(object sender, GridViewCommandEventArgs e)
    {
      Control ctl = e.CommandSource as Control;
      GridViewRow CurrentRow = ctl.NamingContainer as GridViewRow;
      object objTemp = gvUsers.DataKeys[CurrentRow.RowIndex].Value as object;
      if (objTemp != null)
      {
          string id = objTemp.ToString(); //Do your operations
      }
    }

call a JQuery function from code behind in C#

I want to call this JQuery function from C# code behind

ScriptManager.RegisterStartupScript(this.Page, this.GetType(), "myfunction", "myFunction(params...);", true);

Saturday, September 20, 2014

Why clear both CSS?

Why do we need to use the CSS property clear with a value of both?
Example:
.clear { 
    clear:both; 
}

 won't be explaining how the floats work here (in detail), as this question generally focuses on Why use clear: both; OR what does clear: both; exactly do...
I'll keep this answer simple, and to the point, and will explain to you graphically why clear: both; is required or what it does...
Generally designers float the elements, left or to the right, which creates an empty space on the other side which allows other elements to take up the remaining space.

Why do they float elements?

Elements are floated when the designer needs 2 block level elements side by side. For example say we want to design a basic website which has a layout like below...
enter image description here
Live Example of the demo image.
Code For Demo

HTML:

<header>
    Header
</header>
<aside>
    Aside (Floated Left)
</aside>
<section>
    Content (Floated Left, Can Be Floated To Right As Well)
</section>
<!-- Clearing Floating Elements-->
<div class="clear"></div>
<footer>
    Footer
</footer>

CSS:

* { /* Not related to floats / clear both, used it for demo purpose only */
    box-sizing: border-box;
    -moz-box-sizing: border-box;
    -webkit-box-sizing: border-box;
}

header, footer {
    border: 5px solid #000;
    height: 100px;
}

aside {
    float: left;
    width: 30%;
    border: 5px solid #000;
    height: 300px;
}

section {
    float: left;
    width: 70%;
    border: 5px solid #000;
    height: 300px;
}

.clear {
    clear: both;
}
Note: You might have to add headerfooterasidesection (and other HTML5 elements) as display: block; in your stylesheet for explicitly mentioning that the elements are block level elements.

Explanation:

I have a basic layout, 1 header, 1 side bar, 1 content area and 1 footer.
No floats for header, next comes the aside tag which I'll be using for my website sidebar, so I'll be floating the element to left.
Note: By default, block level element takes up document 100% width, but when floated left or right, it will resize according to the content it holds.
  1. Normal Behavior Of Block Level Element
  2. Floated Behavior Of Block Level Element
So as you note, the left floated div leaves the space to its right unused, which will allow the div after it to shift in the remaining space.
  1. div's will render one after the other if they are NOT floated
  2. div will shift beside each other if floated left or right
Ok, so this is how block level elements behave when floated left or right, so now why is clear: both;required and why?
So if you note in the layout demo - in case you forgot, here it is..
I am using a class called .clear and it holds a property called clear with a value of both. So lets see why it needs both.
I've floated aside and section elements to the left, so assume a scenario, where we have a pool, whereheader is solid land, aside and section are floating in the pool and footer is solid land again, something like this..
Floated View
So the blue water has no idea what the area of the floated elements are, they can be bigger than the pool or smaller, so here comes a common issue which troubles 90% of CSS beginners: why the background of a container element is not stretched when it holds floated elements. It's because the container element is aPOOL here and the POOL has no idea how many objects are floating, or what the length or breadth of the floated elements are, so it simply won't stretch.
  1. Normal Flow Of The Document
  2. Sections Floated To Left
  3. Cleared Floated Elements To Stretch Background Color Of The Container
I've provided 3 examples above, 1st is the normal document flow where red background will just render as expected since the container doesn't hold any floated objects.
In the second example, when the object is floated to left, the container element (POOL) won't know the dimensions of the floated elements and hence it won't stretch to the floated elements height.
enter image description here
After using clear: both;, the container element will be stretched to its floated element dimensions.
enter image description here
Another reason the clear: both; is used is to prevent the element to shift up in the remaining space.
Say you want 2 elements side by side and another element below them... So you will float 2 elements to left and you want the other below them.
  1. div Floated left resulting in section moving into remaining space
  2. Floated div cleared so that the section tag will render below the floated divs

1st Example

enter image description here

2nd Example

enter image description here
Last but not the least, the footer tag will be rendered after floated elements as I've used the clear class before declaring my footer tags, which ensures that all the floated elements (left/right) are cleared up to that point.
ref:
http://stackoverflow.com/questions/12871710/why-clear-both-css

Tuesday, August 26, 2014

arrange the numbers in input name element array after remove one of it by js

I want after add a input and remove it, arrange the numbers in input name element array by jQuery but don't work for me after remove input. How can fix it?

Answer


I guess that you want to re-number the inputs after a remove, so that the array is made of contiguous numbers.
I have rewritten some things, among which the renumbering function, using an index contextual to the parent function.
function removeidx(context, clss, type) {
    var remove = $(context).closest(clss);
    remove.fadeOut('slow', function () {
        $(this).remove();
        var idx = 0;
        $(clss).each(function () {
            var checkBoxes = $('input[type="' + type + '"]', this);
            checkBoxes.each(function () {
                var name = $(this).attr('name');
                name = name.replace(/\d+/, idx);
                $(this).attr('name', name);
                idx = idx + 1;
            });
        });
    });
}

$(document).on('click change', 'a.adding', function (e) {
    e.preventDefault();
    var idx = $('.Row').length;
    $('.ffdd').append('<div class="Row"> <input name="arr[' + idx + '][]" type="text" value=""> <a href="#" class="remove_row" title="remove this row">Remove</a></div>');
});

$('.ffdd').on('click', 'a', function (e) {
    removeidx(this, '.Row', 'text');
})
You can see a working version there : http://jsfiddle.net/8sVWp/

ref 
http://stackoverflow.com/questions/14600150/arrange-the-numbers-in-input-name-element-array-after-remove-one-of-it-by-js

MS in Computer Science with paid training in USA company