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

The new office suite version 2007 comes with brand-new file formats. One of them is the new Access database format version 2007 with accdb extension. Of course there is a new connection string for those new access databases. You can use the connection string below to access your accdb databases through asp.net.

Provider=Microsoft.ACE.OLEDB.12.0;Data Source=C:\database1.accdb;Persist Security Info=False;

In addition, if you are using passwords to access your database, you can include it in your connection string like below;

Provider=Microsoft.ACE.OLEDB.12.0;Data Source=C:\database1.accdb;Jet OLEDB:Database Password=MyDbPassword;

However, your hosting provider will not be aware of this upgrade or probably you don’t want to install Access 2007 on your server. Actually, you don’t need to. Just install 2007 Office System Driver: Data Connectivity Components..

Hope this helps.

Monday, April 02, 2007 10:09:13 AM (GMT Standard Time, UTC+00:00)  #    Comments [0]   ASP.NET 2.0  | 
 Friday, March 30, 2007

Let’s answer the most popular question about UpdatePanels; "How can I update an UpdatePanel with JavaScript on client-side?" Officially there is no tool or library/interface providing this feature. However there is always a solution :) Before going under the hood, I will introduce you my simple solution; UpdatePanelJavaScriptExtender. You can download it and use JavaScript to update your UpdatePanel. Moreover you can send parameters to the code-behind too.

How to use the UpdatePanelJavaScript Extender?

Download the control (link at the end of the article) and add it to your toolbox. Visual Studio will automatically add AjaxControlToolkit reference to your web site as well. The UpdatePanelJavaScript Extender is build on AjaxControlToolkit Extender base libraries.
Secondly, just drag-n-drop the control to your web site.

<cc1:UpdatePanelJavaScriptExtender ID="UpdatePanelJavaScriptExtender1" runat="server" ClientCommand="UpdateMe" TargetControlID="UpdatePanel1" OnUpdate="UpdatePanelJavaScriptExtender1_Update"></cc1:UpdatePanelJavaScriptExtender>

The extender control has three properties. One of them is the well-know ajax extender property TargetControlID. The ID of the UpdatePanel, which will be refreshed with JavaScript, should be assigned to TargetControlID. The second property is ClientCommand. This is the name of the JavaScript command, which you will use to update the UpdatePanel assigned to TargetControlID. The final property is OnUpdate. OnUpdate property should have the name of the code-behind function to run when a client-side update request happens.

Client-side JavaScript command example;

UpdateMe(prompt('Write anything to pass to the UpdatePanel with JavaScript?', ''));

The function name is provided by the ClientCommand property of UpdatePanelJavaScript Extender. The javascript function can have only one parameter, however you can pass as many parameter as you want and any type of object by serializing them with JSON. Of course you will need to de-serialize it on the server-side.

Protected Sub UpdatePanelJavaScriptExtender1_Update(ByVal Sender As Object, ByVal E As System.EventArgs, ByVal parameter As String)    
    Label1.Text = parameter
 
End Sub

The server-side event handler has an extra parameter named as “parameter”. This is the parameter send by the JavaScript function. In our tutorial we are just asking the user to enter any string and passing it to the server side. On the server-side the parameter is transferred to Label1.Text property. Here, in the event handler you can do anything you want. The UpdatePanel will be refreshed after the onload event handler is completed.

The idea behind

When we put a TextBox control inside an UpdatePanel and set its AutoPostBack property to True, the textbox controls onchanged HTML event is filled by a special code causing an asynchronous postback. In order to simulate a client side UpdatePanel.Update function we will insert an invisible TextBox control inside our UpdatePanel and call the javascript function hidden inside onchanged event. The content of the above mentioned TextBox will be our parameter to send to server-side.

Hands-on-Lab

Welcome to the laboratory :) Now we will start building our UpdatePanelJavaScript Extender control. When you start a new ASP.NET AJAX Control Project you will have to edit two files. One of them is a JavaScript file which will work on the client side. The other one is the server side file, which I like the most as a Visual Basic developer :)

First of all, we will add some code to the JavaScript file. The default JavaScript file is already full of code. In order to let you understand what we need to add, I will put extra comment lines.

Type.registerNamespace('UpdatePanelJavaScript');

UpdatePanelJavaScript.UpdatePanelJavaScriptBehavior = function(element) {
    UpdatePanelJavaScript.UpdatePanelJavaScriptBehavior.initializeBase(this, [element]);
    <!--Our CliendCommand Property variable-->
    this._ClientCommandValue = null;
}

UpdatePanelJavaScript.UpdatePanelJavaScriptBehavior.prototype = {
    initialize : function() {
        UpdatePanelJavaScript.UpdatePanelJavaScriptBehavior.callBaseMethod(this, 'initialize');
    },
    dispose : function() {
        UpdatePanelJavaScript.UpdatePanelJavaScriptBehavior.callBaseMethod(this, 'dispose');
    },
    <!--Our CliendCommand Property Code starts here-->
     get_ClientCommand : function() {
        return this._ClientCommandValue;
    },
    set_ClientCommand : function(value) {
        this._ClientCommandValue = value;
    }
    <!--Our CliendCommand Property Code ends here-->
}

UpdatePanelJavaScript.UpdatePanelJavaScriptBehavior.registerClass('UpdatePanelJavaScript.UpdatePanelJavaScriptBehavior', AjaxControlToolkit.BehaviorBase);
<!-- Our TextBox onchange event fires up here -->
UpdatePanelJavaScript.Update = function(HiddenBoxID, parameter) {
      var HiddenBox =$get(HiddenBoxID);
      if (typeof(parameter)=="undefined")
      {
            parameter = "RANDOMPARAM" + Math.random();
      };
      if (HiddenBox.value == parameter)
      {
            parameter = parameter + "RANDOMPARAM" + Math.random();
      };
      HiddenBox.value = parameter;
      var MyCommand = String(HiddenBox.onchange).replace('function anonymous()\n{\n','');
      MyCommand = MyCommand.replace('\n}','');
      MyCommand = MyCommand.replace('function onchange(event) {\njavascript:\n','');
      eval(MyCommand); };
<!-- Our TextBox onchange event cathcer ends up here -->

First, we need to add a private variable for ClientCommand and define set and get methods for it. This was the simple job. The hard one is to write the Update method attached to the UpdatePanelJavaScript namespace at the end of our code. The Update method gets two parameters. One of them is the ID of our hidden TextBox and the other one is the parameter to transfer to server-side. The code finds the hidden TextBox and transfers our parameter inside the TextBox. If the parameter is undefined we assign a random parameter with the prefix of "RANDOMPARAM". This is needed because if the content of the textbox doesn’t change we can’t do a postpack. In addition if the incoming parameter is equal to the content of the textbox we need to add a suffix to our parameter in order to get the textboxs content changed. Further on the onchange event of the TextBox is transferred to a string variable and unwanted codes are cleared. Finally, to start the postback we can launch the code with eval JavaScript function. This Update JavaScript function will be used by other JavaScript functions created by our server-side extender code.

Now is the time for our server-side code. The code-behind file of our extender controls comes with lots of codes as well. First, we will set our base TargetControlID type to UpdatePanel.

<TargetControlType(GetType(UpdatePanel))>

We will define a TextBox control to add to the target UpdatePanel. We need to define it with WithEvents keyword in order to handle its TextChanged event.

WithEvents MyTextBox As New System.Web.UI.WebControls.TextBox

Our extender control will have an Update event. The update event should be defined public. In addition our event will have a third parameter to transfer the incoming parameter from JavaScript, or the text property of our hidden TextBox.

Public Event Update(ByVal Sender As Object, ByVal E As EventArgs, ByVal parameter As String)

We need to define our ClientCommand property on the server-side as well.

        <ExtenderControlProperty()> _
        <DefaultValue("Update")> _
        Public Property ClientCommand() As String
            Get
                Return GetPropertyValue("ClientCommand", "")
            End Get
            Set(ByVal value As String)
                SetPropertyValue("ClientCommand", value)
            End Set
        End Property

Now, we will write the server-side code to set the properties of our hidden TextBox and add it to the UpdatePanel. The visibility and display CSS properties should be hidden and none. On the second step we will create a label control and put our JavaScript code inside it. This is the only way I was able to create control specific code for each extender instance on the same page. The JavaScript file created inside our project will be used globally by all extenders on the web page, nevertheless we need separated codes for each extender to let the user update different panels attached to different extenders. We are creating a JavaScript function pointing to our global Update function inside our JavaScript file by getting the function name from ClientCommand property and transferring the ID of our extenders hidden TextBox. This is one of the tricky parts of this extender control.

        Private Sub UpdatePanelJavaScriptExtender_Init(ByVal sender As Object, ByVal e As System.EventArgs) Handles Me.Init
            MyTextBox.AutoPostBack = True
            MyTextBox.Style.Add("visibility", "hidden")
            MyTextBox.Style.Add("display", "none")
            Dim TargetPanel As System.Web.UI.UpdatePanel = Me.TargetControl
            TargetPanel.ContentTemplateContainer.Controls.Add(MyTextBox)
            Dim script As New System.Web.UI.WebControls.Label
            Dim builder As New System.Text.StringBuilder
            builder.AppendLine("<script language='javascript' type='text/javascript'>")
            builder.Append("function ")
            builder.Append(Me.ClientCommand)
            builder.AppendLine("(parameter) {")
            builder.Append("UpdatePanelJavaScript.Update('")
            builder.Append(MyTextBox.ClientID)
            builder.AppendLine("', parameter);")
            builder.AppendLine("};")
            builder.AppendLine("</script>")
            script.Text = builder.ToString
            Me.Controls.Add(script)
        End Sub

Finally, we will handle our hidden TextBoxs TextChanged event in order to get its Text and transfer as a parameter. We will raise our own event with extra parameter. If the incoming parameter is a random one generated by our JavaScript code, we will delete it. If the incoming parameter contains a random parameter in order to allow sending same parameter to cause postpack, we will just remove the random parameter and send the rest to the user.

        Sub Control_TextChanged(ByVal sender As Object, ByVal e As System.EventArgs) Handles MyTextBox.TextChanged
            Dim SenderControl As System.Web.UI.WebControls.TextBox = sender
            If SenderControl.Text.IndexOf("RANDOMPARAM") <> -1 Then
                If SenderControl.Text.IndexOf("RANDOMPARAM") = 0 Then
                    RaiseEvent Update(Me, e, "")
                Else
                    RaiseEvent Update(Me, e, SenderControl.Text.Substring(0, SenderControl.Text.IndexOf("RANDOMPARAM")))
                End If
            Else
                RaiseEvent Update(Me, e, SenderControl.Text)
            End If
        End Sub

Here is the final code of our code-behind file.

Imports System
Imports System.ComponentModel
Imports System.Web.UI
Imports System.Web.UI.WebControls
Imports AjaxControlToolkit
 
#Region "Assembly Resource Attribute"
<Assembly: System.Web.UI.WebResource("UpdatePanelJavaScript.UpdatePanelJavaScriptBehavior.js", "text/javascript")>
#End Region
 
Namespace UpdatePanelJavaScript
 
    <Description("Creates JavaScript interface simulating UpdatePanel.Update()")> _
    <Designer(GetType(UpdatePanelJavaScriptDesigner))> _
    <ClientScriptResource("UpdatePanelJavaScript.UpdatePanelJavaScriptBehavior", "UpdatePanelJavaScript.UpdatePanelJavaScriptBehavior.js")> _
    <TargetControlType(GetType(UpdatePanel))> _
    Public Class UpdatePanelJavaScriptExtender
        Inherits ExtenderControlBase
 
        WithEvents MyTextBox As New System.Web.UI.WebControls.TextBox
        Public Event Update(ByVal Sender As Object, ByVal E As EventArgs, ByVal parameter As String)
 
        <ExtenderControlProperty()> _
        <DefaultValue("Update")> _
        Public Property ClientCommand() As String
            Get
                Return GetPropertyValue("ClientCommand", "")
            End Get
            Set(ByVal value As String)
                SetPropertyValue("ClientCommand", value)
            End Set
        End Property
 
        Private Sub UpdatePanelJavaScriptExtender_Init(ByVal sender As Object, ByVal e As System.EventArgs) Handles Me.Init
            MyTextBox.AutoPostBack = True
            MyTextBox.Style.Add("visibility", "hidden")
            MyTextBox.Style.Add("display", "none")
            Dim TargetPanel As System.Web.UI.UpdatePanel = Me.TargetControl
            TargetPanel.ContentTemplateContainer.Controls.Add(MyTextBox)
            Dim script As New System.Web.UI.WebControls.Label
            Dim builder As New System.Text.StringBuilder
            builder.AppendLine("<script language='javascript' type='text/javascript'>")
            builder.Append("function ")
            builder.Append(Me.ClientCommand)
            builder.AppendLine("(parameter) {")
            builder.Append("UpdatePanelJavaScript.Update('")
            builder.Append(MyTextBox.ClientID)
            builder.AppendLine("', parameter);")
            builder.AppendLine("};")
            builder.AppendLine("</script>")
            script.Text = builder.ToString
            Me.Controls.Add(script)
        End Sub

        Sub Control_TextChanged(ByVal sender As Object, ByVal e As System.EventArgs) Handles MyTextBox.TextChanged
            Dim SenderControl As System.Web.UI.WebControls.TextBox = sender
            If SenderControl.Text.IndexOf("RANDOMPARAM") <> -1 Then
                If SenderControl.Text.IndexOf("RANDOMPARAM") = 0 Then
                    RaiseEvent Update(Me, e, "")
                Else
                    RaiseEvent Update(Me, e, SenderControl.Text.Substring(0, SenderControl.Text.IndexOf("RANDOMPARAM")))
                End If
            Else
                RaiseEvent Update(Me, e, SenderControl.Text)
            End If
        End Sub
    End Class
 
End Namespace

Hope this control helps and makes your life easier :) If you don't need any of the features of this extender, but only to simulate a click on a button or textbox you can use the code below.

onclick="<%= ClientScript.GetPostBackEventReference(new PostBackOptions(TextBox1, "")) %>"

The advantage of the extender is that you don’t need to add any specific button or textbox in order to cause a postback and handle it. Moreover you get a simple JavaScript function with a parameter passing to server-side, which you can use everywhere on your page.

UpdatePanelJavaScript.zip (492.89 KB)

Friday, March 30, 2007 10:56:15 PM (GMT Standard Time, UTC+00:00)  #    Comments [6]   AJAX | ASP.NET 2.0  | 
 Monday, March 26, 2007

When a user clicks on “Login” button of your login page the password and the user name will be send in plain text format. As a result any sniffer will be able to get this vital information. Below you see the data send to the server from a page containing a TextBox for user password in an UpdatePanel.

{"Password":"MyHiddenPass"}

The most popular solution is to provide a SSL certificate for a login domain containing the login page. However, this choice is a waste of money if you just want to secure the passwords of your users, but not all the page.

Let’s meet the solution; client-side MD5 encryption. In order to avoid sniffers, you can easily encrypt the user password on the client-side with a JavaScript library and post it to the server. Below is the result;

{"Password":" afb5bcf186d39b00d94917df57b9c593 "}

Now we will have an insider look at how we do this. At http://pajhome.org.uk/crypt/md5/ you can download the MD5 JavaScript library prepared by Paul Johnston. First of all, you need to add the file to your web page. We will use the hex_md5(); method of the library. The method gets a String type parameter and returns an encrypted Hex-String value back. On the example below we will use an ASP.NET AJAX Extension PageMethod to validate the password. The login button and password textbox will be inside an UpdatePanel.

      <asp:ScriptManager EnablePageMethods="true" ID="ScriptManager1" runat="server">
        <Scripts>
          <asp:ScriptReference Path="md5.js" />
        </Scripts>
      </asp:ScriptManager>
      <script language="javascript" type="text/javascript">
      function Validate()
      {
        // Get the password entered in the page
        var Pass = $get("MyPass").value;
        // Encrypte the password
        var MD5 = hex_md5(Pass);
        // Run ValidateLogin PageMethod to validate the password
        PageMethods.ValidateLogin(MD5, Done);
      }
      function Done(result)
      {
        // Alert the boolean result returned from PageMethod
        alert(result);
      }
      </script>
      <asp:UpdatePanel ID="UpdatePanel1" runat="server">
        <ContentTemplate>
          <asp:TextBox ID="MyPass" runat="server"></asp:TextBox>
          <input id="BtnLogin" type="button" value="Login" onclick="Validate();" />
        </ContentTemplate>
      </asp:UpdatePanel>

On the server side, we will encrypt the text “TruePassWord” as a modal of a right password and compare it to the incoming one.

<System.Web.Services.WebMethod()> _
  Shared Function ValidateLogin(ByVal Password As String) As Boolean
    'Encoder to convert our stored Password to IOStream
    Dim encoder As New UTF8Encoding()
    'MD5 Service
    Dim MD5 As New System.Security.Cryptography.MD5CryptoServiceProvider
    'The right password
    Dim PasswordToControl As Byte() = MD5.ComputeHash(encoder.GetBytes("TruePassWord"))
    'Converting our right password to HEX
    Dim Right As New StringBuilder()
    For i As Integer = 0 To PasswordToControl.Length - 1
      Right.Append(PasswordToControl(i).ToString("x2"))
    Next i
    'Comparing the right password and the incoming one.
    If Right.ToString = Password Then
      Return True
    Else : Return False
    End If
  End Function

We are done. Hope this helps.

Monday, March 26, 2007 9:39:00 AM (GMT Standard Time, UTC+00:00)  #    Comments [1]   AJAX | ASP.NET 2.0  | 
 Sunday, March 25, 2007

We are all proud of web search engines. You get millions of search results each time you search for something, great, right? NO. I was searching for a redistributable package of Visual Web Developer since two months in order to distribute it with my upcoming AJAX book. Finally yesterday I found it, or the right keywords to search on Google :(

You can download the ISO and IMG files of the products below in http://msdn.microsoft.com/vstudio/express/support/install/

Visual Web Developer Express
Visual Basic 2005 Express Edition
Visual C# 2005 Express Edition
Visual C++ 2005 Express Edition
Visual J# 2005 Express Edition

By the way, thanks to Scott Guthrie, answering my spam mails :P concerning the subject.

Sunday, March 25, 2007 6:19:44 AM (GMT Standard Time, UTC+00:00)  #    Comments [0]   ASP.NET 2.0 | VB.NET  | 
 Friday, February 23, 2007
I had a great time presenting for a few hours to the Istanbul Technical University Informatics Club this past Friday. I covered three topics Web Design Essentials, ASP.NET Essentials, the Future of Web.

Web Design Essentials
This talk covered the purposes of a web design, conceptual differences among web and graphic designers, tools and technologies used for building web sites like Expressions Web.
Click here to download the slides and demo codes of this talk.
You can download Expression Web Trial on http://www.microsoft.com/products/expression/en/expression-web/default.mspx

ASP.NET Essentials
This talk covered main aspects of server side programming and advantages of ASP.NET in contrast with classical ASP.
Click here to download the slides and demo codes of this talk.
You can download Visual Web Developer Express for free on http://msdn.microsoft.com/vstudio/express/vwd/

The Future of Web
This talk covered ASP.NET AJAX Extension and Windows Presentation Foundation on Everywhere (WPF/E). Click to download the slides and demo codes of this talk.
You can learn more about AJAX on http://ajax.asp.net and WPF/E on http://msdn2.microsoft.com/en-us/asp.net/bb187358.aspx

Thanks again to everyone who attended my talks. I really had a great time and hope you did too! 
Friday, February 23, 2007 10:07:20 PM (GMT Standard Time, UTC+00:00)  #    Comments [0]   General  | 
 Saturday, February 17, 2007

WebUserControls inside web sites are essential tools to create large scale web applications. One of the most popular questions about WebUserControls is “How do I transfer parameters to my WebUserControl?” Actually there are some easy solutions if you will transfer string type parameters. First of all you can use querystring. Secondly you can add attributes to your usercontrol.

        Dim mycontrol As UserControl = Page.LoadControl("WebUserControl.ascx")
        mycontrol.Attributes.Add("Parameter", "This is the value")

You can easily get those parameter values inside your UserControls and use them. However attributes can contain only string data.

        Response.Write("This is the value = " & Me.Attributes.Item("Parameter"))

We need a real .NET solution for our problem. We should be able to transfer any type of .NET object and variable from our web form to user control. Let’s think about it again. WebUserControls are just .NET Classes in their nature and parameters are normally properties of classes. So why don’t we create a property for out WebUserControls class? For instance we will try to transfer a ScriptManager control from main web form to user control in order to use main pages ScriptManager controls events in UserControl. That will be challenging :)

    Private withevents MainManager As System.Web.UI.ScriptManager
 
    Public Property SManager() As System.Web.UI.ScriptManager
        Get
            Return MainManager
        End Get
        Set(ByVal value As System.Web.UI.ScriptManager)
            MainManager = value
        End Set
    End Property

We created our Property and put it inside our main partial class of the UserControl. We defined a ScriptManager control which is private for our page and defined with WithEvents keyword in order to handle its events. The property SManager is getting a ScriptManager typed value and assigning it to our private MainManager variable. From now on we can use the MainManager control like it is created inside our WebUserControl, however in reality the control is in main web form.

The purpose of choosing ScriptManager as an example is that in my "Embed UpdatePanel inside Repeater" article you need to handle ScriptManager events and access ScriptManager properties to solve your problem and actually that is impossible if you are working inside a WebUserControl. The ability to transfer a .NET control with his events to a UserControl will totally solve the problem.

In the second step we need to assign some value to UserControls property from inside our main web form. How? The answer is easy if you added the UserControl to your web page statically.

<%@ Register Src="WebUserControl.ascx" TagName="WebUserControl" TagPrefix="uc1" %>

<uc1:WebUserControl ID="WebUserControl1" runat="server" />

WebUserControl1.SManager = ScriptManager1

The properties of the UserControl will be added to IntelliSense menus in Visual Studio. On the other hand if you are adding UserControls to your web form in the dynamic way IntelliSense will not work at all.

        Dim mycontrol As UserControl = Page.LoadControl("WebUserControl.ascx")
        mycontrol.GetType().GetProperty("SManager").SetValue(mycontrol, ScriptManager1, Nothing)
        PlaceHolder1.Controls.Add(mycontrol)

Reflection is the keyword. The second line in the code above is our trick. However I will not get into details of reflection for instance. If you think you need more information just google it :)

Saturday, February 17, 2007 6:18:34 PM (GMT Standard Time, UTC+00:00)  #    Comments [0]   ASP.NET 2.0 | VB.NET  | 
 Tuesday, February 06, 2007

From the day one with AJAX we had the same problem; “Back button is not working!” AJAX caused a new experience for me, I never noticed that so many people are used to Back and Forward buttons in browsers, however browsers history can’t handle XMLHttpReuqest –no back, forward button-. As we all know there are some tricky solutions to solve this problem, nevertheless there wasn’t a complete and easy to use solution for ASP.NET developers.

And voila :) UpdateHistory control from Nikhil Kothari –Microsoft Web/ASP.NET Team Architect- solves all of our problems in a crossbrowser way. The solutions uses an hidden IFRAME for Internet Explorer (which is not needed and used for Mozilla) and changes IFRAMEs URL by adding anchors to create history data. Further on, a JavaScript timer checks for changes made by browsers Back and Forward buttons and calls additional XMLHttpRequest which can be handled in server-side. Secondly there is a built-in checker for the first time load of the page, which gives us the opportunity to use the solution as a unique URL identifier for our AJAX pages. Meaning you will have a separate URL for marked AJAX rendered pages.

The control was built by Nikhil before the release of AJAX Extension but it is updated yesterday :) Let’s see how to use it.

-First of all, download the sample application and binaries from Nikhil’s web site. The package contains some other cool controls as well, which we will not discuss at the moment. You can just check them out for further usage.

-Add the control through nStuff.UpdateControls.dll file to your toolbox and drag and drop one UpdateHistory control to your web page. This control will not be visible when the page is rendered.

-Add an event handler name for OnNavigate event of UpdateHistory. The final mark-up should be like this;

<nStuff:UpdateHistory ID="UpdateHistory1" runat="server" OnNavigate="HistoryNavigate">
    </nStuff:UpdateHistory>

-Secondly, go to your code-behind file and create your event handler. In the event handler you will get an EntryName representing which marked AJAX request is navigated in browser. We will see how to mark pages later on. In the event handler we get our EntryName, render our content and refresh the UpdatePanel. In order to get server side Update method working you need to set your UpdatePanels UpdateMode to Conditional.

    Protected Sub HistoryNavigate(ByVal sender As Object, ByVal e As nStuff.UpdateControls.HistoryEventArgs)
        Dim SelIn As Integer = 0
        If String.IsNullOrEmpty(e.EntryName) = False Then
            SelIn = Int32.Parse(e.EntryName)
        End If
        Dim InhaltControl As UserControl
        InhaltControl = Page.LoadControl("content.ascx")
        InhaltControl.Attributes.Add("ID", SelIn)
        InhaltControl.Attributes.Add("Part", "Main")
        UpdatePanel1.ContentTemplateContainer.Controls.Clear()
        UpdatePanel1.ContentTemplateContainer.Controls.Add(InhaltControl)
        UpdatePanel1.Update()
    End Sub

-Finally let’s mark pages -AJAX requests-.

        UpdateHistory1.AddEntry(e.Item.Attributes("PrimaryKey"))

We are done. That’s so easy to integrate this solution which solves all the cross browser problems as well. In addition, try to copy one of the URLs with anchors on it and past on a new browser window. You will see the page is rendered like the user has navigated to the page. This is another aspect of this cool UpdateHistory control, which provides unique URL identification feature as well.

Thanks to Nikhil Kothari for brilliant work.

Update (02/07/2006) : If you somehow get JavaScript errors in your page when you add Nikhil's control check if your project has debug=true setting in web.config. Try to set your project debug=false and see what happens. Hopefully you will get your problem solved. Actually I got no idea why this happens :(

Tuesday, February 06, 2007 8:58:37 AM (GMT Standard Time, UTC+00:00)  #    Comments [1]   AJAX | ASP.NET 2.0  | 
 Monday, February 05, 2007

I’m publishing some of my articles on codeproject.com as well. One of them is “How to take screenshot (thumbnail) of a web site with ASP.NET 2.0?” John K. made a very creative solution out of my article by adding some color analysis. His solution is taking the screenshot of a web site and getting the colors which are mainly used in the sites design. This solution can help web designer to get some premade color schemes. Check it out on www.todotoh.com/rgb/rgbanalysis.aspx. Very good work John!

Monday, February 05, 2007 5:57:16 PM (GMT Standard Time, UTC+00:00)  #    Comments [1]   General  | 
 Thursday, February 01, 2007

Have you ever need to build a specific web search engine searching only your target web sites? Let’s say you want to build a web site searching only your favorite Programming web sites. Of course you can add many more features to your search engine like commenting search results, ranking, tagging etc. In this article we will talk about building a simple google like search engine with Live Search Services.

Live Search Services are in Beta status at the moment. Live Search provides you an easy to use XML web service to query www.live.com search engine. In order to be able to use this service first you need to register your Application on http://search.msn.com/developer. When you register your application you will get an AppID. This is what you will use in your application to be able to connect Live Search XML Services.

After creating your new project to build your own search engine add http://soap.search.msn.com/webservices.asmx?wsdl as a web reference. Our example search engine will search only for websites we specify. We will use the search template of XXXX (site:www.xxx.com or site:www.yyy.com) You can find many more search templates for live.com in http://msdn2.microsoft.com/en-us/library/aa905321.aspx.

Function GetSearchQuery(ByVal SearchWord) As String
        Dim Writer As New System.Text.StringBuilder
        Writer.Append(SearchWord)
        Writer.Append(" (")
        Writer.Append("site:")
        Writer.Append("codeproject.com")
        Writer.Append(" OR ")
        Writer.Append("site:")
        Writer.Append("msdn.com")
        Writer.Append(" OR ")
        Writer.Append("site:")
        Writer.Append("asp.net")
        Writer.Append(")")
        Return Writer.ToString
End Function

The GetSearchQuery is the function where we are building our search filter. The function is getting the real search keyword and adding our filters with a StringBuilder and returning the final search template. In this function you can connect to any database to get searchable site list while building your final search filter.

Our Live Search Function will first create a table structure to return as the results in a bindable datatable. Secondly we will create needed objects to send a search request and populate our search filter with GetSeatchQuery function. Finally we will cycle through our response and get all results added to our datatable.

Function GetResults(ByVal SearchWord As String, ByVal CountNumber As Integer) As DataTable
        Dim MyData As New DataTable("Results")
        Dim MyColumn As New DataColumn("Title")
        MyData.Columns.Add(MyColumn)
        MyColumn = New DataColumn("Description")
        MyData.Columns.Add(MyColumn)
        MyColumn = New DataColumn("DisplayURL")
        MyData.Columns.Add(MyColumn)
        MyColumn = New DataColumn("URL")
        MyData.Columns.Add(MyColumn)
 
        Dim MySearchEngine As New MSNSearchService
        Dim MySearchRequest As New SearchRequest
        MySearchRequest.AppID = "XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX"
 
        Dim MySourceRequest(0) As SourceRequest
        MySourceRequest(0) = New SourceRequest
        MySourceRequest(0).Count = CountNumber
 
        MySourceRequest(0).Source = SourceType.Web
        MySourceRequest(0).ResultFields = ResultFieldMask.All
        MySearchRequest.Query = GetSearchQuery(SearchWord)
        MySearchRequest.Requests = MySourceRequest
        MySearchRequest.CultureInfo = "en-US"
        Dim MySearchResponse As New SearchResponse
        MySearchResponse = MySearchEngine.Search(MySearchRequest)
 
        For Each IncResponse As SourceResponse In MySearchResponse.Responses
            Dim MyResults() As live.search.Result
            MyResults = IncResponse.Results
 
            Dim ResultRow As DataRow
            If IncResponse.Total > 0 Then
                For Each MyResult As Result In MyResults
                    ResultRow = MyData.NewRow
                    ResultRow.Item(0) = MyResult.Title
                    ResultRow.Item(1) = MyResult.Description
                    ResultRow.Item(2) = MyResult.DisplayUrl
                    ResultRow.Item(3) = MyResult.Url
                    MyData.Rows.Add(ResultRow)
                Next
            End If
        Next
        Return MyData
    End Function

You can bind GetResults function to any data control in your web applications. For further information y can look at MSDN Live SDK about how to get extra fields and search results from live search on http://msdn2.microsoft.com/en-us/library/bb264574.aspx.

Thursday, February 01, 2007 12:34:46 PM (GMT Standard Time, UTC+00:00)  #    Comments [0]   ASP.NET 2.0  | 
 Tuesday, January 30, 2007

After having installed Vista Business on my main laptop and desktop pcs I noticed there is some DNS caching problems. I was using Vista till long time on my virtual pc but actually didn’t try to surf on internet. In Windows XP Pro when I had the feeling that the web site I’m trying to reach is not reachable because of my pc I was just going to “Network Connections” and click “Repair”. It refreshes my local DNS cache and when I hit F5 for the next time it instantly gets the web site I was trying and getting errors before about 30 seconds :)

The actually problem is Vista has no such a fast “Repair” function like XP. When I tried Vista repair functions it takes really long time. The fast solution I found is the command below.

ipconfig /flushdns

Open Command Prompt with admin rights and flush your dns instantly. I would suggest to keep that command prompt up and running all the time. That’s strange but that’s what I’m doing. I’m using this technique about 50 times per day. If anyone has any other suggestion, shoot it :)

Tuesday, January 30, 2007 11:45:32 AM (GMT Standard Time, UTC+00:00)  #    Comments [0]   General  | 
 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  | 
Copyright © 2010 Daron Yöndem. Tüm hakları saklıdır.