<2005 August>
SunMonTueWedThuFriSat
31123456
78910111213
14151617181920
21222324252627
28293031123
45678910

On this page...

Search

Links

Member of...


ASP Insiders

MVP Visual Developer ASP/ASP.NET

Enter CodeZone

Blog Categories

Microsoft

Blogroll

Deutsche Resourcen

Management

Sign In
 

#  Tuesday, 02 August 2005

On 12th of August, the Austrian .NET community is hosting a one-day conference on security, targeted at developers (no surprise here). The topics for NCC 2005 A include:

  • Threat Modeling
  • What's new in .NET 2.0 Security
  • What's new in SQL Server 2005 Security
  • What's new in Windows Vista Security

Quite a nice line-up I'd say. This event is supported by Microsoft Austria, so attending this event is free, except for your time, but I am sure security does warrant a day of your time! Sign up here

Tuesday, 02 August 2005 15:27:45 (W. Europe Daylight Time, UTC+02:00)  #    Comments [0]

 

The Microsoft ASP.NET Developer Center has the Provider Toolkit online. It sports the Access Provider as a C# class library project for download!
Tuesday, 02 August 2005 11:46:18 (W. Europe Daylight Time, UTC+02:00)  #    Comments [0]

 

This blog entry confirms my findings from last Thursday - VPC's virtual networking does not work with WinVi. That basically shot down my idea of using Vista as the primary OS on my laptop, aside from the really slow performance and its tendency to hog enormous amounts of memory. I would have put up with the latter two issues, but my VPC images do need network access (Subversion repository access for one).
Categories: this | Virtual PC
Tuesday, 02 August 2005 10:26:32 (W. Europe Daylight Time, UTC+02:00)  #    Comments [0]

 



#  Sunday, 31 July 2005

I spent this weekend in Bad Ischl together with other members of the #develop open source project. This was the first get-together under the "#develop developer days" umbrella, and most of the core team was able to attend the two-and-a-half day event.

Our focus was to talk about #develop 2.0 "Corsavy", feature-set wise as well as hashing out architectural issues not addressed yet. Aside from that, coding was the #1 priority: to tackle a couple of outstanding issues, such as Forms Designer or Refactoring support. Spending time in one room makes communication so much easier when you have to solve tricky issues that span multiple modules in our infrastructure. It definitely paid off to spend this weekend together.

Categories: .NET | 2 Ohhhh | this | Use the source Luke
Sunday, 31 July 2005 16:45:03 (W. Europe Daylight Time, UTC+02:00)  #    Comments [0]

 



#  Friday, 29 July 2005

One thing I didn't get around to demo at last week's CBC05 is the usage of profiles to remember and subsequently set the culture on ASP.NET pages. That's why I am documenting it now.

To get started, we need to have a profile that stores the user's preferred culture. So your profile in web.config looks could like this:

    <profile enabled="true" defaultProvider="myProfile">
      <providers>
        <add name="myProfile"
          type="System.Web.Profile.SqlProfileProvider"
          connectionStringName="NWConn"/>
      </providers>
      <properties>
        <add name="Culture" type="String" defaultValue="en-US" />
        <add name="Theme" type="String" />
      </properties>
    </profile>

The Culture profile setting is changed via a simple (hard-coded) dropdown list in default.aspx, which also displays a greeting pulled from a localized global resource, the culture code for verification purposes, as well as the current time formatted according to the respective locale:

The code for the button in default.aspx.cs is rather basic as you would have expected:

protected void Button1_Click(object sender, EventArgs e)
{
   Profile.Culture = DropDownList1.SelectedValue;

   // really nasty redirect to go back to this back and see the effect
   Response.Redirect(Request.Path + "?" + Server.UrlEncode(DateTime.Now.ToLongTimeString()));
}

The real magic for setting the culture so that formatting is done correctly, as well as the right resources being displayed, is done in a custom HttpModule, which needs to be registered in web.config:

    <httpModules>
      <add name="myProfileModule" type="ICSharpCode.Web.ApplyProfileToPageModule" />
    </httpModules>

This guy lives in App_Code\ApplyProfileToPageModule.cs, and looks like this:

using System;
using System.Configuration;
using System.Web;
using System.Web.Security;
using System.Web.UI;
using System.Web.UI.WebControls;
using System.Web.UI.HtmlControls;
using System.Threading;
using System.Globalization;

namespace ICSharpCode.Web
{
 public class ApplyProfileToPageModule : IHttpModule
 {
  public void Dispose()
  {
   // currently, does nothing
  }

  public void Init(HttpApplication context)
  {
    context.PreRequestHandlerExecute += AppPreRequestHandlerExecute;
  }

  private void AppPreRequestHandlerExecute(object sender, EventArgs e)
  {
   Page p = HttpContext.Current.Handler as Page;

   if (null != p)
   {
      ProfileCommon pc = (ProfileCommon)HttpContext.Current.Profile;

      string cultureName = pc.Culture;

      CultureInfo culture = new CultureInfo(cultureName);

      Thread.CurrentThread.CurrentUICulture = culture;
      Thread.CurrentThread.CurrentCulture = culture;

      // You can set the Theme exactly the same way, shown below:
      // p.Theme = pc.Theme;
   }
  }
 }
}

In PreRequestHandlerExecute, I can access the profile, and go ahead and read the culture that is defined. Then all you need to do is set the CurrentUICulture as well as CurrentCulture of the CurrentThread. Done.

By the way, this event is also your ticket to set the Theme for a Page - if you have defined the user's preferred theme in her profile. Neat way of doing this.

LocalizationModule.zip (6.09 KB)

Categories: 2 Ohhhh | ASP.NET
Friday, 29 July 2005 11:00:03 (W. Europe Daylight Time, UTC+02:00)  #    Comments [2]

 



#  Thursday, 28 July 2005

Finished installing WinVi Beta 1 on my IBM X31. It always pays off to have spare partitions when you do OS Beta testing on a regular basis.

IE7 already annoys me - dasBlog (or ASP.NET to be more precise) doesn't know about this browser and thus only presents me we an HTML input box instead of FTB. Well, Firefox will find its way onto this box rather sooner than later anyways.

Vista defaults to a US keyboard on initial startup (surprising, but no showstopper for me). Well, and it didn't find my onboard wireless. This I definitely need to fix, because I want to use it for work.

Categories: Newsbites | this
Thursday, 28 July 2005 15:16:03 (W. Europe Daylight Time, UTC+02:00)  #    Comments [0]

 

Did you know that the Membership API isn't limited to being used inside ASP.NET 2.0 applications? That you can also use it in say a Console application? This is actually very useful, because that spells automated administration for me.

In order to demo this, I set out and created a very simple Web application that lists users registered with the Membership system:

This simply calls Membership.GetAllUsers() and we are set. More interesting is web.config (partial view):

  <connectionStrings>
    <add name="NWConn"
connectionString="Data Source=cbc05vpc\cbc05;Initial Catalog=Northwind;User=sa;Password=P@ssw0rd"/>
  </connectionStrings>
  <system.web>
    <membership defaultProvider="myMembership">
      <providers>
        <clear/>
        <add name="myMembership"
          applicationName="DemoApp"
          connectionStringName="NWConn"
          type="System.Web.Security.SqlMembershipProvider, System.Web, Version=2.0.0.0, ..." />
      </providers>
    </membership>

This is using the stock SqlMembershipProvider, and stores data inside the Northwind database. Pretty vanilla, except for one important attribute: applicationName. Because one Membership database can hold accounts for multiple applications, we need to define the name here unless we want to end up with guessing that name for the console application.

Now let's switch to the Console application. It obviously needs to reference System.Web.dll:

Secondly, it needs an App.Config file (this time, in full glory):

<?xml version="1.0" encoding="utf-8" ?>
<configuration>
  <connectionStrings>
    <add
      name="NWConn" connectionString="Data Source=cbc05vpc\cbc05;Initial Catalog=Northwind;User=sa;Password=P@ssw0rd"/>
  </connectionStrings>
  <system.web>
    <membership defaultProvider="myMembership">
      <providers>
        <clear/>
        <add name="myMembership"
           applicationName="DemoApp"
           connectionStringName="NWConn"
           type="System.Web.Security.SqlMembershipProvider, System.Web, ..." />
      </providers>
    </membership>
  </system.web>
</configuration>

As you can see, I simply copied its contents verbatim from the previously shown web.config. All we now need is to access the Membership API inside our application:

using System;
using System.Collections.Generic;
using System.Text;
using System.Web.Security;

namespace TheConsoleApp
{
 class Program
 {
   static void Main(string[] args)
   {
     MembershipUserCollection muc = Membership.GetAllUsers();
     foreach (MembershipUser mu in muc)
      Console.WriteLine(mu.UserName + " " + mu.Email);
   }
 }
}

Surprise, surprise - it works as expected:

Done.

MembershipEverywhere.zip (19.28 KB)

Categories: 2 Ohhhh | ASP.NET
Thursday, 28 July 2005 14:27:21 (W. Europe Daylight Time, UTC+02:00)  #    Comments [2]

 



#  Wednesday, 27 July 2005

This post is again motivated by last week's Community Bootcamp on ASP.NET 2.0, the CBC05. I presented "Under the Covers - Exploring Internals, Page Lifecycle and the Compilation Mode" from TechEd, using the samples that Simon Calvert provided me with (special thanks fly out to Simon, Ben Miller and Rich Ersek @MS for providing us with material - I know I can be a royal pain in the posterior... sometimes at least).

The talk included a demo of a database-backed virtual path provider (files don't come from the file system but a database, dynamically). Somehow we started talking about how cool it would be if you could test your Web sites without checking them out from source control in the first place - by simply writing a virtual path provider that goes to the repository on demand. I wrote that idea down.

Actually, I didn't think I'd get around to doing that. But yesterday I decided to pester one of my devs on the #develop project, namely Daniel Grunwald. He has implemented the Subversion addin for our 2.0 version, so he had experience with NSvn, the managed API for talking to Subversion. I sent a stripped down version of the vpath provider to him, and asked him to replace database code with NSvn code where appropriate.

It didn't take long, and I had a command-line verified version back, and all I had to do was make sure that it works with ASP.NET 2.0. There were a few problems I ran into (like Subversion is case-sensitive and I didn't want that for the Web scenario). Some of the issues arose simply because client and Web developers have different backgrounds. Talk about path separators. Or directories where you have to drop assemblies.

Now, let's stop talking, let's take a look at the provider in action:

SvnVPathProvider.wmv (3.76 MB)

Want to get your hands on that DemoSiteSvn directory with the current rendition of the SubversionVirtualPathProvider? No problem, just a couple of notes up front on what you should be aware of:

  • Only file names are currently treated specially for casing. Ie directories still do react in a case sensitive way.
  • The file name cracking code needs to be reviewed. Currently, this is a quick hack.
  • appSettings need to be placed in a separate .config file. Reason is that web.config cannot be obtained via a VirtualPathProvider, and thus this file has to be checked out separately. And I don't want to get in the way of automating this by requiring entries in web.config.
  • Package it as an assembly, so only the \bin folder needs to be copied to get up and running.
  • The VirtualPathProvider requires (at the very least) anonymous access to the repository. Passing security tokens is not implemented.

With those notes out of the way, thanks fly out to the ASP.NET team for providing me with the sample of their virtual path provider in the first place. It has been a tremendous help to get this thing off the ground. And maybe in turn this sample will help others to get started:

SvnVppDemo.zip (972.37 KB)

Installation note: the two DLLs in the system32 folder need to be dropped in the respective folder of your system. Do not place them into \bin. Unless you want to get into trouble, that is.

What is left to say? Oh, the source code, of course! I thought you might be interested in reading it online instead of having to download an almost 1MB-size file first. Here it is (App_Code\SubversionVirtualPathProvider.cs):

using System;
using System.IO;
using System.Collections;
using System.Globalization;
using System.Configuration;
using System.Text;
using System.Web;
using System.Web.Util;
using System.Web.Hosting;
using System.Web.Caching;
using NSvn.Core;
using NSvn.Common;

namespace ICSharpCode.Web.Providers
{
public class SubversionVirtualPathProvider : VirtualPathProvider
{
#region class HashCodeCombiner
internal sealed class HashCodeCombiner
        {
            // Start with a seed
            private long _combinedHash = 5381;
            
            internal void AddLong(long l)
            {
                _combinedHash = ((_combinedHash << 5) + _combinedHash) ^ l;
            }
            
            internal string CombinedHashString
            {
                get
                {
                    return _combinedHash.ToString("x", CultureInfo.InvariantCulture);
                }
            }
}
#endregion

#region class SubversionVirtualFile
internal class SubversionVirtualFile : VirtualFile
    {
        string fullPath;
        DirectoryEntry entry;
            
        public SubversionVirtualFile(string virtualPath, string fullPath, DirectoryEntry entry)
                : base(virtualPath)
        {
            this.fullPath = fullPath;
            this.entry = entry;
        }
            
        public override bool IsDirectory {
            get {
                return entry.NodeKind == NodeKind.Directory;
            }
        }
            
        public override Stream concat()
        {
            Client client = new Client();
            MemoryStream ms = new MemoryStream();
            client.Cat(ms, fullPath, Revision.Head);

            // .Cat closes the stream, so we have to copy it
            MemoryStream ms2 = new MemoryStream(ms.GetBuffer());
            ms2.Position = 0;
            return ms2;
        }
}
#endregion

public static void AppInitialize()
    {
        SubversionVirtualPathProvider provider = new SubversionVirtualPathProvider();
        HostingEnvironment.RegisterVirtualPathProvider(provider);
    }
        
    string GetSvnFullpath(string virtualPath)
    {
        if (bool.Parse(ConfigurationManager.AppSettings["svnvppStripVdir"]))
        {
            // this will break root Webs, StripVdir should be the default however
            int pos = virtualPath.IndexOf('/', 1);
            virtualPath = virtualPath.Substring(pos, virtualPath.Length - pos);
        }

        return ConfigurationManager.AppSettings["svnvppRepositoryUrl"]
            + virtualPath;
        }

    string GetSvnFullpath(string virtualPath, string fileName)
    {
        return FixupSvnFullpath(GetSvnFullpath(virtualPath), fileName);
    }

    // Subversion is case sensitive, this we switch the filename here
    string FixupSvnFullpath(string svnPath, string fileName)
    {
        int pos = svnPath.LastIndexOf('/');
        string parentDirectory = svnPath.Substring(0, pos + 1);
        return parentDirectory + fileName;
    }
        
    DirectoryEntry GetEntry(string virtualPath)
    {
        Client svnClient = new Client();
        string fullPath = GetSvnFullpath(virtualPath);
        int pos = fullPath.LastIndexOf('/');
        string parentDirectory = fullPath.Substring(0, pos);
        string entryName = fullPath.Substring(pos + 1);

        try
        {
            DirectoryEntry[] entries = svnClient.List(parentDirectory, Revision.Head, false);
            foreach (DirectoryEntry entry in entries) 
            {   
                if (0 == String.Compare(entry.Path, entryName, true))
                        return entry;
            }

            return null;
        }
        catch (SvnClientException ex)
        {
            if (ex.ErrorCode == 160013) // parent directory not found
                return null;

            throw;
        }
    }
        
        public override bool FileExists(string virtualPath)
        {
            DirectoryEntry e = GetEntry(virtualPath);
            if (e != null)
                return e.NodeKind == NodeKind.File;

            return Previous.FileExists(virtualPath);
        }
        
        public override bool DirectoryExists(string virtualDir)
        {
            DirectoryEntry e = GetEntry(virtualDir);
            if (e != null)
                return e.NodeKind == NodeKind.Directory;
            return Previous.FileExists(virtualDir);
        }
        
        // Obtain the file. This will only be called if the hash that we return is
        // different than that the runtime holds on to as a cached indicator.
        public override VirtualFile GetFile(string virtualPath)
        {
            DirectoryEntry e = GetEntry(virtualPath);
            if (e != null)
                return new SubversionVirtualFile(virtualPath, GetSvnFullpath(virtualPath, e.Path), e);
            // Default to the previous implementation
            return Previous.GetFile(virtualPath);
        }
        
        /// ///////////////////////////////////////////////////////////////
        /// Return a hash value indicating a key to test this file and dependencies have not been
        /// modified
        public override string GetFileHash(string virtualPath, IEnumerable virtualPathDependencies)
        {
            HashCodeCombiner hashCodeCombiner = new HashCodeCombiner();
            
            ArrayList unrecognizedDependencies = new ArrayList();
            
            foreach (string virtualDependency in virtualPathDependencies)
            {
                DirectoryEntry e = GetEntry(virtualDependency);
                if (e != null) {
                    hashCodeCombiner.AddLong(e.Size);
                    hashCodeCombiner.AddLong(e.CreatedRevision);
                } else {
                    unrecognizedDependencies.Add(unrecognizedDependencies);
                }
            }
            
            string result = hashCodeCombiner.CombinedHashString;
            
            if (unrecognizedDependencies.Count > 0)
            {
                result += Previous.GetFileHash(virtualPath, unrecognizedDependencies);
            }
            
            return result;
        }
        
        /// ///////////////////////////////////////////////////////////////
        /// The cache dependency is a specialized object that means that the runtime
        /// can perform file monitoring and change notifications directly
        public override CacheDependency GetCacheDependency(string virtualPath, IEnumerable virtualPathDependencies, DateTime utcStart)
        {
            // This VPP does not create CacheDependencies
            DirectoryEntry e = GetEntry(virtualPath);
            if (e != null)
                return null;
            
            return Previous.GetCacheDependency(virtualPath, virtualPathDependencies, utcStart);
        }
    }
}

 

Categories: 2 Ohhhh | ASP.NET | Community | Subversion
Wednesday, 27 July 2005 08:18:56 (W. Europe Daylight Time, UTC+02:00)  #    Comments [0]

 



#  Tuesday, 26 July 2005
The registration for this year's .NET Community Conference in Austria went live today (register here, it's free). The thread of this years rendition is security: threat modeling, .NET 2.0 security features, SQL Server 2005 security and more. Definitely worth your time, if you have time to spare, join us on 12th of August in Vienna!
Tuesday, 26 July 2005 15:37:13 (W. Europe Daylight Time, UTC+02:00)  #    Comments [1]

 

Script Callbacks were also part of my "Advanced ASP.NET 2.0" day at the Community Bootcamp 2005 in Bad Ischl. Aside from showing the usual callback sample, I decided that something more useful was in order. That is why I went a tad further by showing off the controls introduced in the RefreshPanel GotDotNet workspace. I came across those a while back when reading articles on Bertrand Le Roy's blog:

Of course we did labs on CallbackProxy and RefreshPanel, the latter one is described in this blog entry (again, a streamlined version of the lab done by Alexander Schoeppl).

Let's start with the result we wanted to achieve:

The render date only acts as a "proof" that no Postback happened, the dropdown control lists all customers in Northwind and is also populated up front. The GridView control, however, is filled using out of band calls. Instead of hacking your own ugly JavaScript, we did that using the RefreshPanel control.

Step 1: Copy RefreshPanel.dll

First, copy RefreshPanel.dll to the \bin directory of your site. You can get it here.

Step 2: Set up a connection string in web.config

We will use that later both in markup and code beside file:

<connectionStrings>
 <add name="NorthwindConnectionString"
connectionString="Data Source=cbc05vpc\cbc05;Initial Catalog=Northwind;User=sa;Password=P@ssw0rd"/>
</connectionStrings>

Step 3: ShowCustomerOrders.aspx

Basically, "organized" in three sections (separated by a blank line):

<%@ Page Language="C#" AutoEventWireup="true" 
CodeFile="ShowCustomerOrders.aspx.cs" Inherits="Show_Customer_Orders"
Title="Callback Demo" %>
<%@ Register TagPrefix="rp" Namespace="MyControls.RefreshPanel"
Assembly="RefreshPanel" %>
<html xmlns="http://www.w3.org/1999/xhtml" >
<head runat="server">
    <title>Untitled Page</title>
</head>
<body>
    <form id="form1" runat="server">
    <div>
        Render Date: <asp:Literal ID="Literal1" runat="server"></asp:Literal>
        <br />
       
        <asp:DropDownList ID="DropDownList1" runat="server"
DataSourceID="SqlDataSource1" DataTextField="CustomerID"
DataValueField="CustomerID">
        </asp:DropDownList>
<asp:SqlDataSource ID="SqlDataSource1" runat="server"
ConnectionString="<%$ ConnectionStrings:NorthwindConnectionString %>"
            SelectCommand="SELECT [CustomerID] FROM [Customers]">
</asp:SqlDataSource>
        <rp:RefreshButton ID="MyButton" RefreshPanelID="RFPanel1"
            runat="server"
            ClientRefreshArgument="this.form.DropDownList1.options[this.form.DropDownList1.selectedIndex].value"
            Text="Show Orders"/>
        <br />
       
        <rp:RefreshPanel runat="server" ID="RFPanel1" OnRefreshing="FillData">
            <asp:GridView ID="GridView1" runat="server">
            </asp:GridView>
        </rp:RefreshPanel>
    </div>
    </form>
</body>
</html>

Register imports the RefreshPanel control suite for us, the Label and DropDown are also very straightforward. The RefreshPanel control itself contains a single GridView control, and it is linked to the server-side method FillData which we will examine in the next step. The RefreshButton is responsible for activating the out of band call back to the server - that's also where we get the value from the dropdown control, and pass it as an event argument to FillData.

Note that the control names are hardcoded, in the real world we'd build that string dynamically, because otherwise we'd get into trouble, eg with master pages.

Step 4: ShowCustomerOrders.aspx.cs

Page_Load is trivial, we are only interested in FillData:

public void FillData(object sender, RefreshingEventArgs e)
{
string connectionString = ConfigurationManager.ConnectionStrings["NorthwindConnectionString"].ToString();

string sqlCmd = "Select * from Orders where customerID = @CustomerID";

SqlConnection conn = new SqlConnection(connectionString);

SqlCommand cmd = new SqlCommand(sqlCmd, conn);
cmd.Parameters.AddWithValue("@CustomerID", (string)e.EventArgument);

conn.Open();
SqlDataReader reader = cmd.ExecuteReader();

GridView1.DataSource = reader;
GridView1.DataBind();
reader.Close();
conn.Close();
}

No magic in our code, but: RefreshPanel takes care of giving us a GridView control to work with, and shipping the resulting HTML to the client - and inserting it into the page. Very, very neat indeed.

CallbackDemo.zip (43.51 KB)

Categories: 2 Ohhhh | ASP.NET | this | Training and Conferences
Tuesday, 26 July 2005 15:24:14 (W. Europe Daylight Time, UTC+02:00)  #    Comments [0]

 



© Copyright 2017 Christoph Wille

newtelligence dasBlog 2.3.9074.18820
Subscribe to this weblog's RSS feed with SharpReader, Radio Userland, NewsGator or any other aggregator listening on port 5335 by clicking this button.   RSS 2.0|Atom 1.0  Send mail to the author(s)

 
Don't contact us via this (fleischfalle@alphasierrapapa.com) email address.