Main Page | Türkçe Blog | Delete Language Cookie 
Daron Yöndem - Monday, January 29, 2007
a developers draft...
 Monday, January 29, 2007

I was working on a project where I needed to use a repeater to list some records. Repeater is the most flexible tool when advanced UI and record editing options are needed. In order to provide rich user experience I decided to use Microsoft ASP.NET AJAX Extension library, actually meaning UpdatePanel. My main purpose is to provide an UpdatePanel for each record in Repeater. The user will be able to edit any record listed in Repeater but only edited records information will be refreshed in its own UpdatePanel. Additionally Repeater control will be in an extra UpdatePanel in order to populate Repeater without full page refresh.

In summary;

  • Repeater will be populated inside UpdatePanel
  • Each Repeater Item will contain an independent UpdatePanel.
  • Each record in repeater will be edited without full page or full repeater refresh.

First of all let’s see our markup code:

<asp:UpdatePanel ID="UpdatePanel1" runat="server" UpdateMode="Conditional">
        <ContentTemplate>
                    <
asp:Repeater ID="Repeater1" runat="server">

                        <ItemTemplate>
                            <asp:UpdatePanel UpdateMode="Conditional" ID="UpdatePanel2" runat="server">
                                <ContentTemplate>
                                    <asp:TextBox ID="TextBox1" runat="server"></asp:TextBox>
                                    <asp:Label ID="Label1" runat="server" Text="Label"></asp:Label>
                                    <asp:Button ID="Button2" runat="server" Text="Button" />
                                </ContentTemplate>
                            </asp:UpdatePanel>
                        </ItemTemplate>
                    </asp:Repeater>
                    <asp:Button ID="Button1" runat="server" Text="Button" OnClick="Button1_Click" />
        </ContentTemplate>                    
</asp:UpdatePanel>   

We will need some dummy data to populate our Repeater control. The code below is just creating a table with dummy data and binding it to Repeater.

    Protected Sub Button1_Click(ByVal sender As Object, ByVal e As System.EventArgs)
        Dim mytable As New Data.DataTable
        Dim mycolumn As New Data.DataColumn("MyData")
        mytable.Columns.Add(mycolumn)
        Dim myrow As Data.DataRow
        myrow = mytable.NewRow
        myrow.Item(0) = "Trial Row 1"
        mytable.Rows.Add(myrow)
        myrow = mytable.NewRow
        myrow.Item(0) = "Trial Row 2"
        mytable.Rows.Add(myrow)
       
myrow = mytable.NewRow
        myrow.Item(0) = "Trial Row 3"
        mytable.Rows.Add(myrow)
 
        Repeater1.DataSource = mytable
        Repeater1.DataBind()
    End Sub

It’s time to set up bindings for our Repeater control. Actually there is nothing special here; we are just accessing our UpdatePanel control from inside our Repeater in order to be able to access other controls which are inside UpdatePanels ContentTemplate. Finally we bind data to controls.

    Protected Sub Repeater1_ItemDataBound(ByVal sender As Object, ByVal e As System.Web.UI.WebControls.RepeaterItemEventArgs) Handles Repeater1.ItemDataBound
        If e.Item.ItemType = ListItemType.Item Or e.Item.ItemType = ListItemType.AlternatingItem Then
            Dim CurrentUpdatePanel As System.Web.UI.UpdatePanel = e.Item.FindControl("UpdatePanel2")
            Dim mylabel As System.Web.UI.WebControls.Label = CurrentUpdatePanel.FindControl("Label1")
            Dim mybutton As System.Web.UI.WebControls.Button = CurrentUpdatePanel.FindControl("Button2")
            mylabel.Text = e.Item.DataItem.item(0)
            mybutton.Text = "Update"
        End If
    End Sub

Here comes the tricky part. How we will handle button clicks? Remember, we have a ScriptManager on each AJAX based web page. The role of ScriptManager is to handle all requests etc. Hopefully our populated UpdatePanels should be handled by our ScriptManager as well. That’s why we are using ScriptManagers PreRender event. All AJAX based renders on our page will fire this event. But we don’t need to handle all renders. We just need the ones coming from our populated UpdatePanels inside Repeater1. In order to get the sender of PreRendering we use AsyncPostBackSourceElementID property of ScriptManager. The source controls rendered ID will contain our Repeaters and Buttons IDs. Additionally it will contain the row number of repeated ItemTemplate inside Repeater. That will be something like Repeater1$ctl01$Button2. After getting the row number from incoming ID we can access all data inside our Repeater. We can save, edit anything to database and let our ScriptManager render UpdatePanel with new values. In our example we are getting the value inside TextBox and transferring it to a Label.

    Protected Sub AnyClick(ByVal sender As Object, ByVal e As System.EventArgs) Handles ScriptManager1.PreRender
        Dim IncID As String = CType(sender, System.Web.UI.ScriptManager).AsyncPostBackSourceElementID.ToString
        Dim RowIndex As Integer = 0
        If IncID.IndexOf(Repeater1.ID) <> -1 And IncID.IndexOf("Button2") <> -1 Then
            IncID = IncID.Replace(Repeater1.ID & "$ctl", "")
            IncID = IncID.Replace("$Button2", "")
            RowIndex = CInt(IncID)
            Dim mytextbox As System.Web.UI.WebControls.TextBox = Repeater1.Items(RowIndex).FindControl("Textbox1")
            Dim mylabel As System.Web.UI.WebControls.Label = Repeater1.Items(RowIndex).FindControl("label1")
            mylabel.Text = mytextbox.Text
        End If
    End Sub

Now you have got a web page that never gets fully refreshed. You can populate the repeater without full page refresh and edit, save all records without even full repeater refresh. Finally I would like to remind you to not forget to set UpdateMode properties of UpdatePanels to "Conditional".

Have fun :)

Monday, January 29, 2007 2:19:33 PM (GMT Standard Time, UTC+00:00)  #    Comments [0]   AJAX | ASP.NET 2.0 | VB.NET  | 
 Saturday, January 27, 2007

Paging is one of the most important optimization techniques about bandwidth usage between SQL Server and IIS. How can we let a user navigate through a 2 million rows length datatable? Get all 2 million rows to IIS and bind it to GridView for ASP.NET based paging? That’s totally a bad idea to let IIS get all 2 million rows for each page view. We need to get only the data that our user want to see. Paging should be handled on SQL Server in order to get only visible data from SQL to IIS. Additionally this technique will provide faster page process.

First of all let’s think about what we were doing on MSSQL 2000 to be able to page our data on server side. One of the possibilities can be to generate the needed SQL Query in a stored procedure and execute it. A more proper solution is to build row numbers and query them. On SQL 2000 some developers were creating temporary tables to generate row numbers. For those using SQL 2000 I will suggest the following code.

SELECT Product_ID, Product_Name, Price,
(
SELECT COUNT(*) FROM Products e2 WHERE e2.Product_ID <= e.Product_ID) AS RowNumber
FROM
Products e
ORDER
BY Product_ID

You can get this query as a View and query it again to get specific records. The problem is when you just want to order your data by other fields except PK. SQL 2005 has a new feature for this problem.

SELECT Product_ID, Product_Name,
Price
, Row_Number() OVER (ORDER BY Price ASC) AS RowNumber
FROM
Products

This is a very cool function. We are not allowed to get row numbers depending on any specific order column. You can set two or more columns for order rules and you can get row numbers without depending on any PK. So how do we query the result and get only specific rows?

WITH NumberedRows AS (
SELECT
Product_ID, Product_Name,
Price
, Row_Number() OVER (ORDER BY Price ASC) AS RowNumber
FROM
Products)
SELECT
* FROM NumberedRows
where
RowNumber > 2 and RowNumber < 5

Say welcome to another new feature of SQL2005 :) Common Table Expression. Actually this feature is creating kind of temporary table on the fly and we are allowed to query it instantly. Here it is :) You have your page data.

Saturday, January 27, 2007 4:12:22 PM (GMT Standard Time, UTC+00:00)  #    Comments [0]   SQL 2005  | 
 Friday, January 26, 2007

“A deadlock is a situation wherein two or more competing actions are waiting for the other to finish, and thus neither ever does. It is often seen in a paradox like 'the chicken or the egg'.” says Wikipedia and yes :) they are right. In SQL world deadlock refers to a specific condition when two or more queries are waiting for each other to release a datatable or a row. Actually we can’t prevent a deadlock in many situations but we can handle them by SQL 2005 TRY/CATCH blocks.

RETRY:
BEGIN
TRY
    BEGIN TRANSACTION
        -- DO SOME BAD ACTION CAUSING DEADLOCK
    COMMIT TRANSACTION
END
TRY
BEGIN
CATCH
    SET @Err = @@ERROR
    IF @Err = 1205
        ROLLBACK TRANSACTION
        INSERT INTO ErrorLog (ErrID, ErrMsg)
        VALUES (@Err, 'Deadlock recovery attempt.')
        WAITFOR DELAY '00:00:10'
        GOTO RETRY
    IF @Err = 2627
        SET @ErrMsg = 'PK Violation.'
    IF @ErrMsg IS NULL
        SET @ErrMsg = 'Other Error.'
    INSERT INTO ErrorLog (ErrID, ErrMsg)
    VALUES (@Err, @ErrMsg)
END
CATCH

TRY/CATCH block will catch errors and IF blocks will check what kind of error is happened. If that is a deadlock error we cancel our current transaction and use WAITFOR function to wait for 10 seconds to retry our query. This is actually an endless loop till there is no deadlock error. Notice that we are logging each error to an error table to check what’s happening.

In conclusion, deadlocks are easy to handle and be logged in SQL 2005 with TRY/CATCH blocks. In the other hand I would suggest you to check logs and analyze what’s causing deadlock and prevent getting deadlocks if possible without TRY/CATCH blocks :) for better performance.

Friday, January 26, 2007 4:50:12 PM (GMT Standard Time, UTC+00:00)  #    Comments [0]   SQL 2005  | 
 Saturday, January 20, 2007

Commenting is something very easy to abuse on weblogs. Additionally if you just set your Commenting API to function properly like I did, hopefully you will get a lot of comment spam. In order to stop that continuing spam on my weblog I just instantly shut downed Commenting feature :) After some little research I found out that’s only the commenting API which is needed to be disabled. Now I’m turning back Commenting on and I will keep API off. I’m sorry for all my visitors about their comments, because taking Commenting to off and on again caused BasBlog to delete all current comments.

Saturday, January 20, 2007 3:23:33 PM (GMT Standard Time, UTC+00:00)  #    Comments [0]   General  | 
 Monday, January 15, 2007

Let’s say you are building an online application where your customer will share his business documents with his own customers. Documents contain sensitive information about business flow. We need to secure all the information and ensure that only permitted customers can download shared files.

Easy to imagine that we can’t use normal file link downloads. There should be no download links that can be transferred from one user to another. Customers shouldn’t give or mail download link to each other etc. We could use integrated Windows Authentication but our customer is using a shared hosting plan. We need to use forms authentication and have no chance to redirect all file extensions to ASP.NET from IIS.

Solution is to stream download files through ASP.NET response, so we can control users permissions and react. Just put an ASP.NET button on your web page. Write your permission control codes and if that is ok stream your file with the code below.

Dim myFile As System.IO.FileInfo = New System.IO.FileInfo(myFilePath)
Response.Clear()
Response.AddHeader("Content-Disposition", "attachment; filename=" & _
      Replace(myFile.Name, ".resources", ""))
Response.AddHeader("Content-Length", myFile.Length.ToString())
Response.ContentType = "application/octet-stream"
Response.WriteFile(myFile.FullName)
Response.End()

Monday, January 15, 2007 10:58:05 AM (GMT Standard Time, UTC+00:00)  #    Comments [0]   ASP.NET 2.0  | 
 Monday, January 08, 2007

Thanks to MSDN Coding4Fun team for their support presenting my “How to take screenshot (thumbnail) of a web site with ASP.NET 2.0?” article on their official weblog. Actually their title “Web Site Mini Me” was a funny metaphor for web site screenshot thumbnails. That is confusing this first article from me on their blog was totally developed for fun like their name is Coding4Fun.

Monday, January 08, 2007 9:55:36 PM (GMT Standard Time, UTC+00:00)  #    Comments [0]   General  | 
 Sunday, January 07, 2007

Many times web developers need to restart their web application. Sometimes that’s needed to clear session variables or just clear .NET cache. The most known method to restart a web application is to change web.config file or just rename it to something different and back again. ASP.NET engine watches asp.net files and if there is any minor or major change it automatically restarts the application. Hopefully our programmatic solution wouldn’t need us to log into FTP and rename or change files.

System.Web.HttpRuntime.UnloadAppDomain()

This method will just unload our application. If you just put this method in an ASP.NET web button you are totally done. So when will our application reloaded? Actually if you click your button it will first launch our method and unload application. Further on the web page we are on at that moment will be reloaded as well, because we just clicked a button and the web page should refresh. After launching our method the page refresh process will cause our application to reload as well.

The best feature of this method is that we can handle application restarts in Global.asax events. There are some other methods to restart application programmatically but actually they are about to kill applications, so application end event doesn’t launch. Our method is the most friendly application restart method letting all global application events to run before restart.

Sunday, January 07, 2007 11:30:50 AM (GMT Standard Time, UTC+00:00)  #    Comments [0]   ASP.NET 2.0  | 
 Friday, December 22, 2006

How to capture screenshot of a web site as a Thumbnail with ASP.NET 2.0? Capturing screenshots with Windows application are very easy but how to capture a web sites screenshot? Imagine we load the given web site in our application and take a screenshot of it. To load the needed web site we can use WebBrowser component of .NET 2.0 Framework and use .DrawToBitmap method to get a bitmap picture of current web site. The scenario works well in Windows applications but how we do this in a web site?

Never forget that ASP.NET and Windows Forms applications are all about .NET Framework. So theoretically we can do all the things in an ASP.NET application like we do in Windows Forms. The idea behind our solution will be to initialize a hidden WebBrowser component and load our web site inside it to be able to get screenshot. Of course we will fight against many further problem.

Dim MyBrowser As New WebBrowser
MyBrowser.ScrollBarsEnabled = False
MyBrowser.Size = New Size(1027, 768)
MyBrowser.Navigate(”http://www.deveload.com”)
Dim myBitmap As New Bitmap(1024, 768)
Dim DrawRect As New Rectangle(0, 0, 1024, 768)
MyBrowser.DrawToBitmap(myBitmap, DrawRect)

After defining our WebBrowser variable we set some properties like ScrollBarsEnabled to false and the size of our browser. We call navigate method and open the web site “www.deveload.com”. On next we define our BitMap variable, drawing surface and use DrawToBitmap method to get our screenshot.

It seems all ok but if you run this application you will get many errors. First problem is that we didn’t wait for the web site to get loaded. We just took an instant screenshot after calling the web site. Normally we should wait for the web site to be loaded totally.

MyBrowser.Navigate(Me.URL)
While MyBrowser.ReadyState <> WebBrowserReadyState.Complete
     Application.DoEvents()
End While

After starting to load our web site we will just take a dummy loop to wait the web site to be loaded totally. Why we are using Application.DoEvents() is a trick I will explain later on. An other problem is that our WebBrowser control is actually a COM object. We need to be in a Single Threaded process to be able to use WebBrowser freely. All of our screen taking code should be handled in an independent thread.

Dim NewTh As New Threading.Thread(AddressOf DoIt)
NewTh.SetApartmentState(Threading.ApartmentState.STA)
NewTh.Start()

Let’s get back to our last code where we used a loop to wait our WebBrowser control. Think about it again. We have got a single thread and going in a loop to wait our web site to load. Normally our loop would lock our application and thread would wait for the loop to finish to be able to render our WebBrowser component further on. So why isn’t that happening like that? Application.DoEvents() is the answer. This method will let us to render our control while our loop is in process.

Finnaly we will use a classical approach to resize our screenshot to a thumbnail size.

Dim imgOutput As System.Drawing.Image = myBitmap
Dim oThumbNail As System.Drawing.Image = New Bitmap(twidth, theight, imgOutput.PixelFormat)
Dim g As Graphics = Graphics.FromImage(oThumbNail)
g.CompositingQuality = Drawing2D.CompositingQuality.HighSpeed
g.SmoothingMode = Drawing2D.SmoothingMode.HighSpeed
g.InterpolationMode = Drawing2D.InterpolationMode.HighQualityBilinear
Dim oRectangle As Rectangle = New Rectangle(0, 0, twidth, theight)
g.DrawImage(imgOutput, oRectangle)

In the code above we define imgOutput and assign our original image to it, which is named myBitmap. twidth, theight are our target size variables. We create a grapics object from a dummy image having our destination size. We set some properties of graphics object and make the render with DrawImage method.

Now let’s see the complete solution as an independent Class.

Imports System
Imports System.Drawing
Imports System.Drawing.Imaging
Imports System.Windows.Forms
Imports System.Diagnostics
 
Namespace GetSiteThumbnail
 
    Public Class GetImage
        Private S_Height As Integer
        Private S_Width As Integer
        Private F_Height As Integer
        Private F_Width As Integer
        Private MyURL As String
 
        Property ScreenHeight() As Integer
            Get
                Return S_Height
            End Get
            Set(ByVal value As Integer)
                S_Height = value
            End Set
        End Property
 
        Property ScreenWidth() As Integer
            Get
                Return S_Width
            End Get
            Set(ByVal value As Integer)
                S_Width = value
            End Set
        End Property
 
        Property ImageHeight() As Integer
            Get
                Return F_Height
            End Get
            Set(ByVal value As Integer)
                F_Height = value
            End Set
        End Property
 
        Property ImageWidth() As Integer
            Get
                Return F_Width
            End Get
            Set(ByVal value As Integer)
                F_Width = value
            End Set
        End Property
 
        Property WebSite() As String
            Get
                Return MyURL
            End Get
            Set(ByVal value As String)
                MyURL = value
            End Set
        End Property
 
        Sub New(ByVal WebSite As String, ByVal ScreenWidth As Integer, ByVal ScreenHeight As Integer, ByVal ImageWidth As Integer, ByVal ImageHeight As Integer)
            Me.WebSite = WebSite
            Me.ScreenWidth = ScreenWidth
            Me.ScreenHeight = ScreenHeight
            Me.ImageHeight = ImageHeight
            Me.ImageWidth = ImageWidth
        End Sub
 
        Function GetBitmap() As Bitmap
            Dim Shot As New WebPageBitmap(Me.WebSite, Me.ScreenWidth, Me.ScreenHeight)
            Shot.GetIt()
            Dim Pic As Bitmap = Shot.DrawBitmap(Me.ImageHeight, Me.ImageWidth)
            Return Pic
        End Function
    End Class
 
    Class WebPageBitmap
        Dim MyBrowser As WebBrowser
        Dim URL As String
        Dim Height As Integer
        Dim Width As Integer
        Dim Ready As Boolean
 
        Sub New(ByVal url As String, ByVal width As Integer, ByVal height As Integer)
            Me.Height = height
            Me.Width = width
            Me.URL = url
            MyBrowser = New WebBrowser
            MyBrowser.ScrollBarsEnabled = False
            MyBrowser.Size = New Size(Me.Width, Me.Height)
        End Sub
 
        Sub GetIt()
            MyBrowser.Navigate(Me.URL)
            While MyBrowser.ReadyState <> WebBrowserReadyState.Complete
                Application.DoEvents()
            End While
        End Sub
 
        Function DrawBitmap(ByVal theight As Integer, ByVal twidth As Integer) As Bitmap
            Dim myBitmap As New Bitmap(Width, Height)
            Dim DrawRect As New Rectangle(0, 0, Width, Height)
            MyBrowser.DrawToBitmap(myBitmap, DrawRect)
            Dim imgOutput As System.Drawing.Image = myBitmap
            Dim oThumbNail As System.Drawing.Image = New Bitmap(twidth, theight, imgOutput.PixelFormat)
            Dim g As Graphics = Graphics.FromImage(oThumbNail)
            g.CompositingQuality = Drawing2D.CompositingQuality.HighSpeed
            g.SmoothingMode = Drawing2D.SmoothingMode.HighSpeed
            g.InterpolationMode = Drawing2D.InterpolationMode.HighQualityBilinear
            Dim oRectangle As Rectangle = New Rectangle(0, 0, twidth, theight)
            g.DrawImage(imgOutput, oRectangle)
            Try
                Return oThumbNail
            Catch ex As Exception
            Finally
                imgOutput.Dispose()
                imgOutput = Nothing
                MyBrowser.Dispose()
                MyBrowser = Nothing
            End Try
        End Function
    End Class
 
End Namespace

And the last part, how to use our class in our web application:

Partial Class _Default
    Inherits System.Web.UI.Page
 
    Protected Sub Button1_Click(ByVal sender As Object, ByVal e As System.EventArgs) Handles Button1.Click
        Dim NewTh As New Threading.Thread(AddressOf DoIt)
        NewTh.SetApartmentState(Threading.ApartmentState.STA)
        NewTh.Start()
    End Sub
 
    Sub DoIT()
        Try
            Dim thumb As New GetSiteThumbnail.GetImage("http://www.deveload.com", 1024, 768, 320, 240)
            Dim x As System.Drawing.Bitmap = thumb.GetBitmap()
            x.Save("C:\Inetpub\wwwroot\screeny\deveload.jpg")
        Catch ex As Exception
            Dim y As System.IO.StreamWriter = System.IO.File.CreateText("C:\Inetpub\wwwroot\screeny\error.txt")
            y.WriteLine(ex.Message & vbCrLf & ex.Source)
            y.Flush()
            y.Close()
        End Try
    End Sub
End Class

The code above is creating an instance of our Class and trying to get a screenshot. If any error happens it will create a text file and write the error inside it. Do not forget that the class DoIT is working as a separated thread.

Happy X-Mas ;)

Friday, December 22, 2006 1:51:27 PM (GMT Standard Time, UTC+00:00)  #    Comments [3]   ASP.NET 2.0  | 
 Thursday, December 21, 2006

I know this is a really strange title up here but that was the first question coming into my mind when I heard Microsoft chooses to use JSON (JavaScript Object Notation) in ASP.NET AJAX Extension to move data between server and client. Actually this decision is of course a very clever decision, because JSON provides better bandwidth conservation. Microsoft has added JSON-based serialization classes to ASP.NET AJAX recently, but for our example we will use an online conversion tool at http://www.thomasfrank.se/xml_to_json.html

We will use the default example coming from our online convertor. The following is the xml data we will convert to JSON.

<animals>
     <dog>
          <name>Rufus</name>
          <breed>labrador</breed>
     </dog>
     <dog>
          <name>Marty</name>
          <breed>whippet</breed>
     </dog>
     <cat name="Matilda"/>
</animals>

And this is the converted JSON data.

{
    animals:{
        dog:[
            {
                name:'Rufus',
                breed:'labrador'
            },
            {
                name:'Marty',
                breed:'whippet'
            }
        ],
        cat:{
            name:'Matilda'
        }
    }
}

It seems like JSON data is longer but that's not. If we just save the XML data in a XML file and JSON in a JavaScript file; (do not forget to save data after eliminating all spaces in data which are only added to be more human readable) XML data is 162 byte and JSON is 133 byte. The difference between two formats data sizes will be higher on higher data amount.

An other positive side of JSON is that JSON is ready to be used in JavaScript. In JavaScript, XML must be parsed into DOM. Once we have constructed the DOM tree, we still have to loop through it to create corresponding JavaScript objects. In JSON we just get our data and use eval JavaScript function and we get all our data in JavaScript objects.

That’s why Microsoft chooses to use JSON in his AJAX (Asynchronous JavaScript and XML) Extension for ASP.NET. But where is the XML part of AJAX? :) That’s gone. We got a better solution that actually doesn’t have any brand-new name, better just carrying the well-known old name AJAX.

Thursday, December 21, 2006 9:37:08 PM (GMT Standard Time, UTC+00:00)  #    Comments [0]   AJAX  | 
 Sunday, December 17, 2006

Actually that's a very cool question. After having Microsoft SQL Express free edition, the default Membership Provider for .NET 2.0 has been changed to SQL2005. What if we need to use the old style access databases. There can be possible situations where you just need to handle 10 or maybe only 5 users in your web application and even that is free using an SQL database could be unneeded.

The providers contained in ASP.NET 2.0 Beta 1 have been imported to an independant project to serve the same functionality from the ASP.NET 2.0 Beta 1. You can just download the C# project from this web site or direct download from this url. The project is the source code imported from Beta 1, so you will need to compile the project to be able to use in different projects. The download packet includes needed Web.Config sample setting file as well.

To be able to use Access Membership Provider, first you need to compile the provider and add the generated DLL file as a reference to your project. Secondly add provided Access database to your project or just import all tables in given database to your own database. Finally add all the settings in given sample Web.Config file to your own Web.Config. Do not forget to edit your own Connection String for your access file. Now you can just start to use your access database for all Membership Provider needed functionalities like Role Manager, Profile and Web Part Personalization.

A little note; go to WebSite / ASP.NET Configuration menu in your Visual Studio 2005 to be able to manage users and roles.

Sunday, December 17, 2006 12:36:56 PM (GMT Standard Time, UTC+00:00)  #    Comments [0]   ASP.NET 2.0  | 
 Sunday, May 28, 2006

One of my first articles on my blog has been already published on "The Code Project" web site and now the same article "Anonymous Personalization Trick in Web Parts" is on ASP.NET Official Web Site. I’m very glad to see my contribution on ASP.NET Official Web Site. Hope this engage my enthusiasm and eagerness to share information that helps out people.

The article is on main page now, but will be further on the past article list.

Sunday, May 28, 2006 1:22:44 PM (GMT Standard Time, UTC+00:00)  #    Comments [0]   General  | 
 Friday, May 19, 2006

This was always the main problem of web programmers using shared hosting plans with shared SQL databases. If the company you are working doesn’t provide any back-up solution or just provides some with manual interaction :) like you need to send a mail telling them to back-up your database the scenario gets dramatic. We need absolutely our own back-up system.

The first step is to get the remote data to our local machine. First we need to have an SQL Server 2005 Express Edition installed on our own local PC and a SQL Server 2005 Standart to just create our SSIS data transfer package file. The data transfer should work like in my article “How to schedule and run database transfers in SQL Express like in SQL Agent Job Scheduling Service in SQL Server 2005 Standard”. After having scheduled the data transfer Job our second job is to schedule a back-up for our local database.

The SQL Command to back-up our database is below;

BACKUP DATABASE [MyDatabaseName] TO  DISK = N'C:\MyBackUpFile.bak' WITH  RETAINDAYS = 10, NOFORMAT, NOINIT,  NAME = N'Any Description like Full Database Backup', SKIP, NOREWIND, NOUNLOAD,  STATS = 10
GO

The parameter “RETAINDAYS” is very important. 10 means that back-ups will not be stored in our back-up file if they are older than 10 days. This way our back-up file will include the last 10 days back-ups. We need to save this SQL command into any TXT file and store somewhere safe with .sql extansion.

We need to save this SQL command into any TXT file and store somewhere safe with .sql file extansion. Now time to lunch our back-up from command prompt.

sqlcmd -S "MyMachine\MySQLInstance" -E -i "C:\MySQLBackUp_CommandFile.sql"

You can now schedule this command with windows scheduler and have your back-up of remote SQL with two scheduled tasks.

Friday, May 19, 2006 8:53:48 PM (GMT Standard Time, UTC+00:00)  #    Comments [0]   SQL 2005  | 
 Monday, May 15, 2006

This article will describe how Integration Services Packages can be scheduled on a PC running SQL Server Express Edition. However Integration Services Packages can’t build on SQL Server Express Edition Installed PCs because Express Editions software packages do not include Integration Services. You need to build packages on a SQL Server Standard Edition installed PC and copy package files. So why do we need an alternative solution for scheduling if we have got Standard Edition installed? Doesn’t it come with an agent too? Yes, it does. But what if you need to schedule these packages on a remote machine? You need to install SQL Standard again, and buy extra license? We don’t want to buy an extra licence, so we need an alternative.

MS SQL Server Express Edition comes in two different editions;

  • SQL Server 2005 Express Edition
  • SQL Server 2005 Express Edition with Advanced Services

Our main problem is that SQL Express Edition or -with Advanced Services do not include SQL Agent Job Scheduling Service. The agent is only available in SQL Server Standart Edition and -Enterprise. Let’s say you created your “Integration Services Package” with “Business Intelligence Development Studio” coming with “SQL Server 2005 Standart Edition”. While creating your package choose "User Password Protected". Copy your file to the root on your remote machine like "C:\MyPackage.dtsx". This PC should have installed "SQL Server 2005 Express Edition with Advanced Services" and "Microsoft SQL Server 2005 Express Edition Toolkit". Those are all free to download on MS web site. The toolkit includes "Connectivity Components", so we can use our DTSX. Open the command line and run;

   dtexec /f "C:\MyPackage.dtsx" /de MyPassword

That's all :) You just started the package. You can get more information about dtexec Utility on MSDN.

Scheduling?! What about using Windows Scheduler? :)

Monday, May 15, 2006 5:48:20 PM (GMT Standard Time, UTC+00:00)  #    Comments [1]   SQL 2005  | 
 Tuesday, May 09, 2006
That’s not a new problem but after discovering that Internet Explorer 7 Beta 2 supports transparent PNG very well we will use them soon anywhere. Firefox and all other alternative browsers are already supporting transparent PNG files, so the only missing browser is IE6. I will not go through deep description how this problem is solved. It’s all about “DXImageTransform.Microsoft.AlphaImageLoader” which only works for Internet Explorer and uses DirectX for rendering.

Create a new text file named png.htc and paste the code below;

<public:component>
<public:attach event="onpropertychange" onevent="propertyChanged()" />
<script>

var supported = /MSIE (5\.5)|[6789]/.test(navigator.userAgent) && navigator.platform == "Win32";
var realSrc;
var blankSrc = "images/blank.gif";

if (supported) fixImage();

function propertyChanged() {
if (!supported) return;

var pName = event.propertyName;
if (pName != "src") return;
// if not set to blank
if ( ! new RegExp(blankSrc).test(src))
fixImage();
};

function fixImage() {
// get src
var src = element.src;

// check for real change
if (src == realSrc) {
element.src = blankSrc;
return;
}

if ( ! new RegExp(blankSrc).test(src)) {
// backup old src
realSrc = src;
}

// test for png
if ( /\.png$/.test( realSrc.toLowerCase() ) ) {
// set blank image
element.src = blankSrc;
// set filter
element.runtimeStyle.filter = "progid:DXImageTransform.Microsoft.AlphaImageLoader(src='" + src + "',sizingMethod='scale')";
}
else {
// remove filter
element.runtimeStyle.filter = "";
}
}

</script>
</public:component>

Now you can use you image tags like thise;

<img alt="" src="images/name.png" width=282 height=73 style="behavior: url('images/png.htc');" />

And don’t forget to place an empty spacer gif to "images" directory.

If you have got tons of images needing this style you can use a CSS class like;

IMG
{
      behavior: url('images/png.htc');
}

You think we are done? :) How about transparent PNG files that you used for table backgrounds etc.? You can’t give them styles. For background files we will use an different way. Create a text file named “png.js” and paste the code below;

if (navigator.platform == "Win32" && navigator.appName == "Microsoft Internet Explorer" && window.attachEvent) {
window.attachEvent("onload", alphaBackgrounds);
}

function alphaBackgrounds(){
var rslt = navigator.appVersion.match(/MSIE (\d+\.\d+)/, '');
var itsAllGood = (rslt != null && Number(rslt[1]) >= 5.5);
for (i=0; i<document.all.length; i++){
var bg = document.all[i].currentStyle.backgroundImage;
if (itsAllGood && bg){
if (bg.match(/\.png/i) != null){
var mypng = bg.substring(5,bg.length-2);
document.all[i].style.filter = "progid:DXImageTransform.Microsoft.AlphaImageLoader(src='"+mypng+"', sizingMethod='scale')";
document.all[i].style.backgroundImage = "url('/assets/images/x.gif')";
}
}
}
}

And now include your file to your web form.

<!--[if lt IE 7.]>
<script defer type="text/javascript" src="images/png.js"></script>
<![endif]-->

The End :)

Tuesday, May 09, 2006 1:23:55 PM (GMT Standard Time, UTC+00:00)  #    Comments [0]   General  | 
 Sunday, May 07, 2006

AutoComplete is a very nice feature for general purpose web forms. The question is how can we build an Auto-Complete friendly web form? Normally there is nothing to do. All INPUTs on a web forms are automatically set up for Auto-Complete. The web browser will store the data entered and the name of input tag in a safe place, with encryption. All information entered on our web forms Inputs is stored for a future use when a web page with same inputs reloads. So what is the problem? :)

Let’s sat we build up a new member sign-up page for our new portal. Probably the user has already signed up for multiple web sites and already entered his name, surname etc. How about giving our new visitors the opportunity to auto-complete our form with their ancient auto-complete data based on other web pages? Of course we assume that other web sites were already well configured with Auto-Complete features.

The total solution is vCard. :) vCard  is a standard way to refer to common personal information. vCard is a registered trademark of the Internet Mail Consortium, and it is not MS Internet Explorer specific. We can use the VCARD_NAME attribute of INPUT tags, which sets or retrieves the vCard values for AutoComplete.

    <INPUT TYPE="text" NAME="MyMail" VCARD_NAME="vCard.Email">

The standard vCard attribute list is as below;

vCard.Cellular vCard.Company vCard.Department
vCard.DisplayName vCard.Email vCard.FirstName
vCard.Gender vCard.Home.City vCard.Home.Country
vCard.Home.Fax vCard.Home.Phone vCard.Home.State
vCard.Home.StreetAddress vCard.Home.Zipcode vCard.Homepage
vCard.JobTitle vCard.LastName vCard.MiddleName
vCard.Notes vCard.Office vCard.Pager
vCard.Business.City vCard.Business.Country vCard.Business.Fax
vCard.Business.Phone vCard.Business.State vCard.Business.StreetAddress
vCard.Business.URL vCard.Business.Zipcode

For more information you can check MSDN.

 
Sunday, May 07, 2006 6:22:18 PM (GMT Standard Time, UTC+00:00)  #    Comments [0]   General  | 
 Saturday, May 06, 2006

Think about a web site with restricted access. One of the main security problem is the login page. First we need to prevent BruteForce attacks, the solution is captcha controls. The second problem can be packet sniffing, the solution is to use https. But what about the browsers “Auto-Complete” feature? Is that all dependant to users settings? Hopefully No!

You can either specify Auto-Complete features state for a total form or just for specific controls.

<form action="dosomething4m" autocomplete="off">
<input type=
"text" name="MyName">
<input type=
"text" name="MyPass">
<input type=
"submit" value="Submit">
</form>

<form action="dosomething4m">
<input type=
"text" name="MyName">
<input type=
"text" name="MyPass" autocomplete="off">
<input type=
"submit" value="Submit">
</form>

Saturday, May 06, 2006 5:20:42 PM (GMT Standard Time, UTC+00:00)  #    Comments [0]   General  | 
 Tuesday, May 02, 2006

ASP.NET 2.0 comes with lots of premaid components. One of them is the well-known Calendar. The problem with Calendar is that day and month names are placed by .NET engine. How can this easy to use function be a problem? :)

The situation is that you have got an English web site and used a Calendar on it but the users browser and system settings are set to German. .NET Engine will automatically fill your calendar with German day and month names. All seems ok? No. Your web site is totally in English but only the calendar is German. Isn’t that strange? So how can we solve this problem?

We need to manually set the culture of our web site the way it never changes.

For a single page:<%@ Page Culture="en-US" UICulture="en" %>

For total web application: <globalization culture="en-US" uiCulture="en" />

Culture controls formatting of dates and numbers whereas UICulture controls resource loading; translated text and localized control properties like color or font.

You can find a list of culture codes in http://msdn2.microsoft.com/en-US/library/system.globalization.cultureinfo.aspx.

Tuesday, May 02, 2006 7:41:07 AM (GMT Standard Time, UTC+00:00)  #    Comments [0]   ASP.NET 2.0  | 
 Monday, May 01, 2006

You don’t need to translate day or month names for your multilingual web site or software. Just try the code below the get the right names for specified cultures.

DimGetNames As NewSystem.Globalization.CultureInfo("fr-FR")
GetNames.DateTimeFormat.GetMonthName(1)
GetNames.DateTimeFormat.GetDayName(1)

You can check culture code list by http://msdn2.microsoft.com/en-US/library/system.globalization.cultureinfo.aspx.

Monday, May 01, 2006 8:06:29 AM (GMT Standard Time, UTC+00:00)  #    Comments [1]   ASP.NET 2.0 | VB.NET  | 
 Monday, April 17, 2006

Web masters are shocked seeing their flash web sites with strange borders on mouse over. This is the mandatory patch surprise of Microsoft. April 11, 2006, Windows XP (KB912945) patch description is as follows;

"After you install this update, you cannot interact with ActiveX controls from certain Web pages until these controls are enabled. To enable an ActiveX control, manually click the control."

They are right :) Users can't click flash movies and a strange border is visible each time we roll over flash movies. Microsoft has changed the way ActiveX controls work in Internet Explorer. The change affects all interactive ActiveX controls, Flash movie (SWF) content in a web page. This change is in response to the patent claims by EOLAS regarding applications that can run within a web page.

To avoid infringing on the EOLAS patent, either:
-The ActiveX applications must not be solely within the web page.
-The user must click on the ActiveX content to active it.

The only way webmasters can use is the external flash movie implementation. There are some workarounds in MSDN. Microsoft’s recommendation is to rewrite HTML codes that replace the object and embed tags with external JavaScript.

Changing all HTML codes are hard work, so we need an easier way. We need to write down all embed tags which are already in our page, hmm?? So why don’t we just replace them?

 window.onload = function(){
 
    if (document.getElementsByTagName) {
         var objs
= document.getElementsByTagName("object");
 
    for (i=0; i<objs.length; i++) {
         objs[i].outerHTML
= objs[i].outerHTML;
         }
     }
 }

That’s all. Don’t forget that we cant run this code within our web page. We need it to be in separated JS file and include to our page. The problem is totatlly with IE. We don’t need to start this process if the user is a FireFox etc user.

 <!--[if gte IE 6]>
 <script src="refreshSWF.js"></script>
 <![endif]-->

You think that’s done? No. We got a new problem with our solution. As we are creating our embed controls alone, we need to dispose them too. We need to add some more code to our external JS file.

window.onunload = function() {
     if (document.getElementsByTagName) {
         var objs = document.getElementsByTagName("object");
         for (i=0; i<objs.length; i++) {
             objs[i].outerHTML = "";
         }
     }
 }

The End :)

Check out Adobe's web page for additional information about solution on embedded content in HTML: http://www.adobe.com/devnet/activecontent/articles/devletter.html

Monday, April 17, 2006 1:33:58 PM (GMT Standard Time, UTC+00:00)  #    Comments [0]   General  | 
 Sunday, December 18, 2005

In all kind of web sites we are using lots of links to external web sites. What if those web sites aren’t online? Maybe just for some hours, or just for some days or weeks etc. Our link will work fine but the linked web site will not launch. This means we got a broken link for that moment. Let’s check the web sites availability first and then redirect the user.

         Dim WebLink As String = "http://www.deveload.com"
         Dim Available As Boolean = False
         Try
             If My.Computer.Network.IsAvailable Then
                 If My.Computer.Network.Ping(WebLink) Then
                     Available = True
                 Else
                     Available = False
                 End If
             End If
         Catch ex As Exception
             Available = False
         End Try
         If Available Then Response.Redirect(WebLink)

After checking the availability, we can easily redirect our client. Have fun with it :)

Sunday, December 18, 2005 5:46:23 PM (GMT Standard Time, UTC+00:00)  #    Comments [0]   ASP.NET 2.0  | 
 Wednesday, December 07, 2005

Sometimes we need to dispose objects in VB.NET to be able to use the resources again which are used before or just to free those resources. Many classes in .NET have .dispose method for this purpose. In C# v1.1 was a keyword "Using" which makes the dispose process to launch automatically after the needed code launch with needed object finishes. We have got this useful keyword in VB.NET v2.0 too.

Another problem was with functions using their own objects. If two objects from different functions use same resources in our application we strongly need to dispose those objects to be able to use same resources in each function with different objects. So what’s the problem? We can write Dispose methods and that’s done. No! That’s not. .NET Framework doesn’t suddenly dispose objects, it just takes in queue. We need to place our dispose code in a "Finnaly" tag in Try-Catch block, so it will strongly disposed. And there is the replacement with "Using" keyword. After a "Using" block, our dispose method will run strongly like in a "Finally" block.

Code in VB.NET 1.1:

         Dim cnn As Data.SqlClient.SqlConnection = Data.GetMyConn()
         Try
             cnn.Open()
             'Actions
         Finally
             cnn.Close()
             cnn.Dispose()
         End Try

Code in VB.NET 2.0:

         Using cnn As Data.SqlClient.SqlConnection = Data.GetMyConn()
             cnn.Open()
             'Actions
             cnn.Close()
         End Using

Wednesday, December 07, 2005 6:09:21 PM (GMT Standard Time, UTC+00:00)  #    Comments [0]   VB.NET  | 
 Wednesday, November 23, 2005

The problem is clear; we have got lots of buttons on our web form, but one of them should be DEFAULT :) Maybe we have got a search engine in our web site and settings for search criteria and a "Search" button. It’s not all; we have got another textbox and "Add" button which adds the e-mail address from that textbox to our mail list database. So when the cursor is on search box the default button should be "Search" button and when the cursor is on mail list textbox the default button to submit should be "Add" button.

The solution was very easy in classical ASP, we were just building different forms for each part of our web site. In ASP.NET 1.1 we couldn’t have different forms so we were building some tricky javascript :) to handle all key presses.

And now the miracle comes :) ASP.NET 2.0 has a special attribute for this problem. Just take a look at the HTML code below;

            <form defaultbutton="Search" runat="server" ID="Form1">
                   <asp:textbox id="SearchField" runat="server" />
                   <asp:textbox id="Criterias" runat="server" />
                   <asp:button id="Search" text="Search" runat="server" />
                   <asp:panel id="MailPanel" defaultbutton="Add" runat="server">
                         <asp:textbox id="Mail" runat="server" />
                         <asp:button id="Add" text="Add Mail" runat="server" />
                   </asp:panel>
             </form>

This is something very easy, but needed so much :) You can define a default button for your general ASP.NET form and partial default buttons for each panel object. We got our search engines default button as a default button for our general page and a mail list default button for only mail list panel.

Wednesday, November 23, 2005 5:15:50 PM (GMT Standard Time, UTC+00:00)  #    Comments [1]   ASP.NET 2.0  | 
 Tuesday, November 22, 2005

One of the best features in SQL2005 is the integrated CLR .NET languages support. What does it mean? You can use your common .NET programming language to code stored procedures in SQL 2005. In SQL2000 it was possible only with standard SQL statements. Let’s create our first Stored Procedure.

Launch Visual Studio 2005 and open a new SQL Server Project. Add a new Stored Procedure to your project.

        Using cnn As New SqlClient.SqlConnection("context connection=true")
             cnn.Open()
             Dim cmd As SqlClient.SqlCommand = New SqlClient.SqlCommand("SELECT * FROM Table_1", cnn)
             SqlContext.Pipe.ExecuteAndSend(cmd)
        End Using

Be carefull about our Conntection String. We do not define any specific connection string. Our stored procedure is already in SQL server, so we dont need to connect it again, we just use the default context connection.

Now Build your project and deploy it with "Build / Deploy" menu in VS2005.

      Msg 6263, Level 16, State 1, Line 4
      Execution of user code in the .NET Framework is disabled. Enable "clr enabled" configuration option.

This is the next error you will get. By default .NET Framwork is disabled in SQL2005. Explore "SQL Server 2005/Configuration Tools/Surface Area Configuration" in your Start menu. Select "Surface Area Configuration for Features", You will find "CLR Integration" option, activate it and save.

Done :) You can now just run your new stored procedure.

      EXECUTE [dbo].[StoredProcedure1]

The first run will be a little slow; because CLR will compile your stored procedure but next runs will be more effective.

Tuesday, November 22, 2005 10:27:36 AM (GMT Standard Time, UTC+00:00)  #    Comments [0]   ASP.NET 2.0 | SQL 2005 | VB.NET  | 
 Monday, November 14, 2005

Yesterday I posted the article "Anonymous Personalization Trick in Web Parts" to my blog. Same time I posted my article to "The Code Project" web site. Today I’m just shocked seeing that my article is accepted and ported from “Unedited Reader Contributions” section to the general ASP.NET How-to part. Why shocked? There is about hundreds of articles waiting for acceptance since months. :) Thanks to the Code Project Team and about 900 visitors that read my article in just 1 day.  Hope this be an encouragement for me to write more articles. :)

If you have got a Code Project account, let's vote my article at http://www.codeproject.com/aspnet/anonywebparts.asp

Monday, November 14, 2005 6:12:25 PM (GMT Standard Time, UTC+00:00)  #    Comments [0]   General  | 
 Sunday, November 13, 2005

ASP.NET 2.0 provides a Web Parts framework, allowing programmers easily integrate drag’n drop menus etc in their web portals. This framework is easy to use and all client based design settings are stored by ASP.NET data providers in an easy way. The developer has nothing to do with the save or load process of web parts design based settings. This article will not cover how we can use Web Parts. It’s possible to find lots of article around web about Web Parts.

ASP.NET 2.0 Web Parts framework is working with Membership framework as well as with Forms or Windows authentication modes. The problem is that, if you don’t want to use any authentication mode, you can’t use Web Parts. The client user, who will able to change the web sites design with web parts, should be authenticated. If not ASP.NET Web Parts framework can’t save users design settings with data providers and with that reason doesn’t allow even to switch design mode.

The Idea Behind

If we just need that all users connecting to our web site should be authenticated, we need to register all users to our web sites authentication system. We will use Forms Authentication and provide some tricky way. Users will be registered with our site in a hidden way with some cookie. We will recognize our visitors with their cookie and authenticate them automatically to get web parts design options available for them.

Hidden Authentication

First we will set up our web site for Forms Authentication. You just need to modify you Web.Config file as below;

        <!--
            The <authentication> section enables configuration
            of the security authentication mode used by
            ASP.NET to identify an incoming user.
        -->
        <authentication mode="Forms" />

We will provide for each visiter a cookie to recognize users identity to be able to show them their design settings. We need an identity name for each visiter. We will create a random guide number to use as identity.

                Dim MyCookieName As String = "Reminder"
                Dim MyCookie As System.Web.HttpCookie = Request.Cookies(MyCookieName)
                Dim UserID As String
                UserID = System.Guid.NewGuid.ToString.Replace("-", "")
                MyCookie = New System.Web.HttpCookie(MyCookieName, UserID)
                MyCookie.Expires = DateTime.Now.AddYears(10)
                Response.Cookies.Add(MyCookie)

Our cookie name is “Remdiner”. You can change the name for your projects. Our Cookie Data is the random guide name “UserID” that we generated by .NET Frameworks “System.Guid.NewGuid” class. Now we can programmatically recognize our visitor each time they visit our web portal.

We should now authenticate our user with his Guid Name "UserID" to our Forms Authentication system. In normal situation ASP.NET uses cookies to store forms authentication data. We will just simulate that process manually.

                Dim authTicket As FormsAuthenticationTicket = New FormsAuthenticationTicket(1, UserID, DateTime.Now, DateTime.Now.AddSeconds(30), False, "roles")
                Dim encryptedTicket As String = FormsAuthentication.Encrypt(authTicket)
                authCookie = New HttpCookie(FormsAuthentication.FormsCookieName, encryptedTicket)
                Response.Cookies.Add(authCookie)

Now our user is authenticated to our web site with forms authentication and can access Web Parts design properties.

We will have lots of visitors designing our web site for themselves and then just never visit again our web site or just delete their cookie and loose their identity as well as their design settings. So why do we need to store all visitors design settings if they even don’t visit our web site since last year? With the code below we connect manually to ASP.NET Membership data store and delete users settings and profile manually, checking the last activity date of user.

            Dim LastDate As Date = Date.Now.AddYears(-1)
           
            Dim cnn As System.Data.SqlClient.SqlConnection = New System.Data.SqlClient.SqlConnection(ConfigurationManager.ConnectionStrings("LocalSqlServer").ConnectionString)
            Dim cmd As System.Data.SqlClient.SqlCommand
            cmd = New System.Data.SqlClient.SqlCommand("DELETE FROM aspnet_PersonalizationPerUser where UserID IN (SELECT UserID from aspnet_Users where [LastActivityDate] < @Date)", cnn)
            cmd.Parameters.Add("@Date", Data.SqlDbType.DateTime)
            cmd.Parameters.Item("@Date").Value = LastDate
            Try
                cnn.Open()
                cmd.ExecuteNonQuery()
            Catch ex As Exception
                Response.Write(ex.Message)
            Finally
                cnn.Close()
            End Try
           
            cmd = New System.Data.SqlClient.SqlCommand("DELETE FROM aspnet_Users where [LastActivityDate] < @Date", cnn)
            cmd.Parameters.Add("@Date", Data.SqlDbType.DateTime)
            cmd.Parameters.Item("@Date").Value = LastDate
            Try
                cnn.Open()
                cmd.ExecuteNonQuery()
            Catch ex As Exception
                Response.Write(ex.Message)
            Finally
                cnn.Close()
                cmd.Dispose()
                cnn.Dispose()
            End Try

The complete solution is below;

    Sub Page_Load(ByVal sender As Object, ByVal e As System.EventArgs)
                          
        If Page.IsPostBack = False Then
            Dim authCookie As HttpCookie = Request.Cookies(FormsAuthentication.FormsCookieName)
            If authCookie Is Nothing Then
                Dim MyCookieName As String = "Reminder"
                Dim MyCookie As System.Web.HttpCookie = Request.Cookies(MyCookieName)
                Dim UserID As String
                If MyCookie Is Nothing Then
                    UserID = System.Guid.NewGuid.ToString.Replace("-", "")
                    MyCookie = New System.Web.HttpCookie(MyCookieName, UserID)
                    MyCookie.Expires = DateTime.Now.AddYears(10)
                    Response.Cookies.Add(MyCookie)
                Else
                    UserID = MyCookie.Value
                End If
                Dim authTicket As FormsAuthenticationTicket = New FormsAuthenticationTicket(1, UserID, DateTime.Now, DateTime.Now.AddSeconds(30), False, "roles")
                Dim encryptedTicket As String = FormsAuthentication.Encrypt(authTicket)
                authCookie = New HttpCookie(FormsAuthentication.FormsCookieName, encryptedTicket)
                Response.Cookies.Add(authCookie)
                Response.Redirect(Request.Url.ToString)
            End If
           
            Dim LastDate As Date = Date.Now.AddYears(-1)
           
            Dim cnn As System.Data.SqlClient.SqlConnection = New System.Data.SqlClient.SqlConnection(ConfigurationManager.ConnectionStrings("LocalSqlServer").ConnectionString)
            Dim cmd As System.Data.SqlClient.SqlCommand
        
            cmd = New System.Data.SqlClient.SqlCommand("DELETE FROM aspnet_PersonalizationPerUser where UserID IN (SELECT UserID from aspnet_Users where [LastActivityDate] < @Date)", cnn)
            cmd.Parameters.Add("@Date", Data.SqlDbType.DateTime)
            cmd.Parameters.Item("@Date").Value = LastDate
            Try
                cnn.Open()
                cmd.ExecuteNonQuery()
            Catch ex As Exception
                Response.Write(ex.Message)
            Finally
                cnn.Close()
            End Try
           
            cmd = New System.Data.SqlClient.SqlCommand("DELETE FROM aspnet_Users where [LastActivityDate] < @Date", cnn)
            cmd.Parameters.Add("@Date", Data.SqlDbType.DateTime)
            cmd.Parameters.Item("@Date").Value = LastDate
            Try
                cnn.Open()
                cmd.ExecuteNonQuery()
            Catch ex As Exception
                Response.Write(ex.Message)
            Finally
                cnn.Close()
                cmd.Dispose()
                cnn.Dispose()
            End Try
        End If
    End Sub

The scenario starts with checking the Forms Authentication cookie. If we already authenticated the user, we need nothing to do. If there isn’t Forms Authentication cookie, we check further if we got our identity cookie. If there is an identity cookie “Reminder”, we can load users identity and authenticate it with forms authentication. This way, all users ancient design settings comes automatically to our web portal. If the user doesn’t have our “Reminder” cookie, we create an identity and store it for that user and authenticate it with the new identity to the authentication system.

After having done all this process, we check for ancient users and delete ones, which doesn’t have at least 1 year activity on our web portal.

Conclusion

You just need to use this system on the "Page_Load" event of your web forms where you are using web parts design properties. Have fun using this tricky method on your future portal developments.

Sunday, November 13, 2005 12:48:04 PM (GMT Standard Time, UTC+00:00)  #    Comments [4]   ASP.NET 2.0  | 
 Saturday, November 12, 2005

Welcome to my first blog article :) After having started to a new portal project, I just discovered that Visual Studio doesn't recognize SQL Server 2005 on my machine with default settings. So the reason was the SQL2005 installation on my machine. Because of my need to continue using my SQL2000, which was installed already with default instance name on my machine, the SQL2005 was installed with a different instance name. This means that; the name of the machine is the instance name of SQL2000 and the name of the SERVER/SQL05 is the SQL2005 instance name. And the real problem was that the Visual Studio could not find the instance name whıch I had given at the begining of the installation of SQL2005 and could not be connected to the SERVER/SQL05 by default.

Why do we need default settings? The problem started when I just tried to add a WebPartManager to a web form file. After compiling the page the error given was;

An error has occurred while establishing a connection to the server.  When connecting to SQL Server 2005, this failure may be caused by the fact that under the default settings SQL Server does not allow remote connections. (provider: SQL Network Interfaces, error: 26 - Error Locating Server/Instance Specified)

After having long researches I found a lot of different data provider designs for WebPartManager, but I only needed to point ASP.NET default SQL direction to my SQL2005 with default ASP.NET dataproviders.

The solution is;

<connectionStrings>
<
remove name="LocalSqlServer"
<
add name="LocalSqlServer" connectionString="SERVER=SERVER\SQL05;Integrated Security=true;Initial Catalog=projectdb" providerName="System.Data.SqlClient"
</
connectionStrings>

You need to add the above code to your Web.Config file. The code first removes default SQL settings from your application and then adds new settings by providing a new connection string. Keep in mind that this setting doesn’t affect your independent SQL codes and connections in your project. This is only for asp.net personalization and membership data provider. You can use the same database for your project stuff and personalization data of web parts or just create an other database.

Now let's recompile our project and see what happens;

Could not find stored procedure 'dbo.aspnet_CheckSchemaVersion'.

In normal conditions ASP.NET should create a new database for you to use for personalization. The database created would contain all needed tables and stored procedures that ASP.NET would use. But after changing the default settings, we directed ASP.NET to a manually created database. So do we need to create all those stored procedures and tables manually? No. We got a hidden tool for that. Explore "C:\WINDOWS\Microsoft.NET\Framework\v2.0.50727\aspnet_regsql.exe". You should select your SQL2005 instance and your database, the wizard will care rest of it.

Have fun using web parts ;) You can take a look at http://msdn.microsoft.com/asp.net/default.aspx?pull=/library/en-us/dnvs05/html/webparts.asp about Web Parts in ASP.NET 2.0.

Saturday, November 12, 2005 10:01:29 AM (GMT Standard Time, UTC+00:00)  #    Comments [2]   ASP.NET 2.0  | 
 Friday, November 11, 2005

As a developer its very usual to check other developers blogs for common problems or just some interesting content or news :) Of course its nice to get content that people prepare for community, but this information sharing process should be something reciprocal. So this is the idea behind this new blog. Hope I get the chance to write my first article soon.

Friday, November 11, 2005 12:48:54 PM (GMT Standard Time, UTC+00:00)  #    Comments [0]   General  | 
Copyright © 2010 Daron Yöndem. Tüm hakları saklıdır.