Carlos Aguilar's Blog
-
Free Sudoku Game for Windows
A couple of years ago a friend of mine introduced me to a game called Sudoku, and immediately I loved it. As any good game its rules are very simple, basically you have to lay out the numbers from 1 to 9 horizontally in a row without repeating them, while at the same time you have to layout the same 1 to 9 numbers vertically in a column, and also within a group (a 3x3 square).
-
IIS Reports for IIS Manager 7
I have just uploaded a new application that extends IIS Manager 7 for Windows Vista and Windows Longhorn Server that adds a new Reports option that gives you a few reports of the server and site activity. Its features include:
-
Recent Tasks in IIS Manager 7
Talking to a good friend of mine (Daniel) about random geeky stuff, suddenly he showed me one of the features he considered very useful from the Windows Vista Control Panel. Basically they have a "Recent Tasks" at the bottom where they keep track of all the features you have used sorted by most recently used. He then suggested that we should do something similar inside IIS Manager 7 for those of us that have "task-amnesia" or are just to busy to search for it in the Control Panel.
-
Extending the TreeView in IIS 7 in Windows Vista
InetMgr exposes several extensibility points that developers can use to plug-in their own features and make them look and feel just as the built-in functionality. One of those extensibility features is the hierarchy tree view and is exposed mainly through three classes:
-
See you at TechEd
Tomorrow I'll be leaving for Boston to attend TechEd 2006. This time I will be showing off the new user interface we have been creating for IIS 7, including its tons of new features as well as the new extensibility API that we have created for developers using managed code.
-
http://www.IIS.net is live!
Today we launched our first public team web site. http://www.IIS.net
In this web site we are publishing a lot of interesting content, from walkthroughs to videos targeting IT professionals, Web Hosters and of course my favorite… developers. -
The new Configuration System in IIS 7
Today I was planning on talking about the configuration classes that I purposedly skipped in my last post, but I realized it would be better to explain a little bit more about the new configuration system used in IIS 7.
First of all, many of you (as me) will be extremely happy to know that the old "monolithic-centralized-admin only" metabase is dead, we have got rid of it for a much better configuration store. Now, before you feel panic, let me assure you that we haven’t just killed it and forget about the thousands of lines of scripts or custom tools built using the old metabase API’s (such as ABO), for that we have created something we called ABOMapper which will allow all of those applications to keep running transparently, since it will auto-magically translate the old calls to the metabase to actually modify the new configuration system.
So what is this new configuration system? Well for those of you who have been working with ASP.NET for the past years, you will feel right at home and happy to know that we are moving to used the exact same concept as ASP.NET does .config files.
ApplicationHost.config
At the root level we have a file called ApplicationHost.config that lives in the same directory of IIS (typically <windows>\System32\InetSrv\ directory). This is the main configuration file for IIS, this is where we store things like the list of sites, applications, virtual directories, general settings, logging, caching, etc.
This file has two main groups of settings:- system.applicationHost: Contains all the settings for the activation service, basically things like the list of application pools, the logging settings, the listeners and the sites. These settings are centralized and can only be defined within applicationHost.config.
- system.webServer: Contains all the settings for the Web server, such as the list of modules and isapi filters, asp, cgi and others. These settings can be set in applicationHost.config as well as any web.config (provided the Override Mode settings are set to allow)
Administration.config
This is also a file located in the IIS directory where we store delegation settings for the UI, including the list of modules (think of it as a UI Add-in) available, and other things like administrators.
Web.config
Finally the same old web.config from asp.net has gotten smarter and now you will be able to include server settings along with your asp.net settings.
Why is this important?
Well, as I said at the beginning the old metabase could only be accessed by administrators, so in order for someone to change a settings as simple as the default document for a specific application (say you want to change it to be index.aspx), you would need to be an administrator or call the administrator to do the changes.
With this new distributed configuration system I can now safely modify the web.config within my application and have it my own way without disturbing anyone else. Furthermore, since it lives in my own web.config along with the content of my application I can safely XCopy the whole application and now even the web server settings are ready. No longer the case of going to InetMgr and start setting everything manually or creating a bunch of scripts to do that.
So how does this actually looks like:
In applicationHost.config my Sites section looks as follows:<sites>This basically defines a site that has a root application with a virtual directory that points to \inetpub\wwwroot. This site is listening on any IP address on port 80.
<site name="Default Web Site" id="1">
<application path="/" applicationPool="DefaultAppPool">
<virtualDirectory path="/" physicalPath="c:\inetpub\wwwroot" />
</application>
<bindings>
<binding protocol="HTTP" bindingInformation="*:80:" />
</bindings>
</site>
</sites>
Say I wanted to add a new application and make it listen also in port 8080.<sites>Just by adding the previous markup, I can now browse to http://localhost:8080/MyApp
<site name="Default Web Site" id="1">
<application path="/" applicationPool="DefaultAppPool">
<virtualDirectory path="/" physicalPath="c:\inetpub\wwwroot" />
</application>
<application path="/MyApp" applicationPool="DefaultAppPool">
<virtualDirectory path="/" physicalPath="d:\MyApp" />
</application>
<bindings>
<binding protocol="HTTP" bindingInformation="*:80:" />
<binding protocol="HTTP" bindingInformation="*:8080:" />
</bindings>
</site>
</sites>
IIS Settings in web.config
More interesting I can now add a file called web.config to c:\MyApp\web.config, and set the content to be:<configuration>And with this change, my application now will respond using index.aspx whenever /MyApp is requested.
<system.webServer>
<defaultDocument>
<files>
<clear />
<add value="Index.aspx" />
</files>
</defaultDocument>
</system.webServer>
</configuration>
You can extrapolate from this that all the IIS settings for your application including authentication, authorization, asp and cgi settings, the list of modules, custom errors, etc can be configured within your web.config and never have to request changes to administrators again.
Of course this brings the question, isn’t this insecure? The answer is no, by default all the IIS sections (except DefaultDocuments) is locked at the applicationHost.config, meaning no one can change them within their web.config unless explicitly changed by the administrator. The cool thing is that the administrator can change it and customize it per application allowing certain apps to change settings while preventing others from doing it. All this can be done through plain config using Notepad or using the very cool NEW InetMgr (which I will blog about it later)
Finally, the following image shows the hierarchy of config files for each url.
Now that I have shown a high level overview of how configuration works in IIS 7, I will finally blog about the API to actually change this settings programmatically using Managed code and Microsoft.Web.Administration.dll -
Microsoft.Web.Administration in IIS 7
While creating the new administration stack in IIS 7, we were looking into the different ways users could manipulate the server configuration as well as the new runtime information available in IIS 7 (Internally we call this RSCA-Runtime State and Control API) from managed code, and we realized we needed to provide a simpler and more straight forward API that developers could consume from managed code. Microsoft.Web.Administration is the answer to this problem. This API is designed to be simple to code against in an “intellisense-driven” sort of way. At the root level a class called ServerManager exposes all the functionality you will need.
To show the power and simplicity of this API, let’s look at some samples below. To try this samples just create a new Console Application in Visual Studio and add a reference to Microsoft.Web.Administration.dll that can be found at IIS directory (%WinDir%\System32\InetSrv).
Please note that the following code is based on Windows Vista Beta 2 code and will likely change for the release candidate versions of Windows Vista since we have planned several enhancements to simplify the API and expose more features into it.
The following picture shows the main objects (excluding Configuration related classes).
Creating a Site
ServerManager iisManager = new ServerManager();This basically creates an instance of the ServerManager class and uses the Add method in the Sites collection to create a new site named "NewSite" listening at port 8080 using http protocol and content files are at d:\MySite.
iisManager.Sites.Add("NewSite", "http", "*:8080:", "d:\\MySite");
iisManager.Update();
One thing to note is that calling Update is a requirement since that is the moment when we persist the changes to the configuration store.
After running this code you have now a site that you can browse using http://localhost:8080
Adding an Application to a siteServerManager iisManager = new ServerManager();
iisManager.Sites["NewSite"].Applications.Add("/Sales", "d:\\MyApp");
iisManager.Update();
This sample uses the Sites collection Indexer to get NewSite site and uses the Applications collection to add a new http://localhost:8080/Sales application.
Creating a Virtual DirectoryServerManager iisManager = new ServerManager();
Application app = iisManager.Sites["NewSite"].Applications["/Sales"];
app.VirtualDirectories.Add("/VDir", "d:\\MyVDir");
iisManager.Update();
Runtime State and Control
Now, moving on to the new Runtime state and control information we also expose in this objects information about their current state as well as the ability to modify them. For example, we expose the list of W3WP processes running (Worker processes) and what I think is really cool, we even expose the list of requests currently running. Stopping a Web SiteServerManager iisManager = new ServerManager();
iisManager.Sites["NewSite"].Stop();
Recyciling an Application PoolServerManager iisManager = new ServerManager();
iisManager.ApplicationPools["DefaultAppPool"].Recycle();
Getting the list of executing requestsServerManager iisManager = new ServerManager();Another big thing on this API is the ability to edit the “.config” files using a simple API, this includes the ability of modifying the main applicationHost.config file from IIS, web.config files from asp.net as well as machine.config and other config files (such as administration.config). However I will talk about them in a future post.
foreach(WorkerProcess w3wp in iisManager.WorkerProcesses) {
Console.WriteLine("W3WP ({0})", w3wp.ProcessId);
foreach (Request request in w3wp.GetRequests(0)) {
Console.WriteLine("{0} - {1},{2},{3}",
request.Url,
request.ClientIPAddr,
request.TimeElapsed,
request.TimeInState);
}
} -
The evil WinForms Splitter
Beware of SplitPosition.
Today I spent quite some time debugging an issue in the new product I am working on.
Well, to summarize what I was seeing in our UI is that for some reason certain information that I was expecting to be there when a TreeNode was expanded, it just wasn’t there. It was completely surprising to me, since in that particular code path, we do not start multiple threads or use Application.DoEvents nor anything like that, basically all we do is a simple assignment in the TreeView after select event, something like:
private void OnTreeViewAfterSelect(object sender, TreeViewEventArgs e) {
_myObject = DoSomeProcessing();
}
However, for some reason in another event handler of our TreeView, _myObject was not set. How can this be?
Well, after quite some interesting time with VS 2005 (which rocks!), the problem was due to an interesting raise condition caused by (believe it or not) a WinForms Splitter. What was happening is that DoSomeProcessing changed some properties, that caused the UI to perform a layout and inside that code, we set the SplitterPosition property of the Splitter. Well, surprise-surprise, Splitter calls Application.DoEvents in its property setter!!!.
What DoEvents does is basically lets Windows pop the next message from the windows message pump and process it, so the next event was actually fired, and _myObject ended up not being set.
To illustrate the problem with a simple sample, try this code:
(Just copy the code and paste it into notepad.
Save it as TestApp.cs and compile it using “csc.exe /target:winexe TestApp.cs”)
using System;
using System.Drawing;
using System.Threading;
using System.Windows.Forms;
namespace TestApp {
public class Form1 : Form {
private TreeView _treeView;
private Label _label;
private Splitter _splitter;
private Button _someButton;
[STAThread]
static void Main() {
Application.Run(new Form1());
}
public Form1() {
InitializeComponent();
// Just add some nodes...
TreeNode node = _treeView.Nodes.Add("Node 1");
node.Nodes.Add("Node 1.1");
node.Nodes.Add("Node 1.2");
_treeView.Nodes.Add("Node 2");
}
private void InitializeComponent() {
_treeView = new TreeView();
_splitter = new Splitter();
_label = new Label();
_someButton = new Button();
SuspendLayout();
// treeView1
_treeView.Dock = DockStyle.Left;
_treeView.Location = new Point(5, 28);
_treeView.TabIndex = 1;
_treeView.AfterSelect += new TreeViewEventHandler(OnTreeViewAfterSelect);
_treeView.BeforeSelect += new TreeViewCancelEventHandler(OnTreeViewBeforeSelect);
// splitter
_splitter.Location = new Point(126, 28);
_splitter.TabIndex = 1;
_splitter.TabStop = false;
// label1
_label.BackColor = SystemColors.Window;
_label.BorderStyle = BorderStyle.Fixed3D;
_label.Dock = DockStyle.Fill;
_label.Location = new Point(129, 28);
_label.TabIndex = 2;
// button1
_someButton.Dock = DockStyle.Top;
_someButton.Location = new Point(5, 5);
_someButton.TabIndex = 0;
// Form
ClientSize = new Size(500, 400);
Controls.Add(_label);
Controls.Add(_splitter);
Controls.Add(_treeView);
Controls.Add(_someButton);
ResumeLayout(false);
}
private void OnTreeViewAfterSelect(object sender, TreeViewEventArgs e) {
_label.Text = "Node selected:" + e.Node.Text;
}
private void OnTreeViewBeforeSelect(object sender, TreeViewCancelEventArgs e) {
// Just sleep 500ms to simulate some work
Thread.Sleep(500);
// Now update the SplitPosition
_splitter.SplitPosition = 100;
// simulate 500ms of more work ...
Thread.Sleep(500);
}
}
}
Colorized by: CarlosAg.CodeColorizer
Run it and select the TreeView, notice how ugly everything works.
Basically every time you select a different node you will get an ugly flickering, getting to see how selection jumps from the newly selected node to the last selected node, and then back to the new selected node.
Well, luckily in Visual Studio 2005, there is a new class called SplitContainer that simplifies everything.
It even adds new features, such as letting you set a MaxSize for both the left panel and the right panel, and many more features. Best of all, there is no Application.DoEvents in their code, so you can have code that behaves deterministically.
Bottom line, you do want to use SplitContainer if at all possible. -
See you at PDC
Well, I’m really excited to be heading to PDC’05, it sure promise to be an interesting one where we can finally show off so many new technologies we have been working so hard during this past few months to create.