Thursday, 04 September 2008

PhluffyFotos v2 Released

We have just released an updated version of the SSDS sample application called 'PhluffyFotos'.  Clouds are fluffy and this is a cloud services application - get it?  This sample application is a ASP.NET MVC and Windows Mobile application showing how to build a photo tagging and sharing site using our cloud data service, SSDS.  For this update:

  • Updated to MVC Preview 4.  We have removed hardcoded links and used the new filtering capability for authorization.  Of course, Preview 5 was just (and just) released as we were putting this out the door.  I might update this to Preview 5 later, but it will not be a big deal to do so. 
  • Updated to add thumbnail support.  Originally, we just downloaded the entire image and resized to thumbnail size.  This drags down performance in larger data sizes, so we fixed it for this release.
  • Updated to use the SSDS blob support.  Blob support was recently added with the latest sprint.  Previously, we were using the 'base64Binary' attributes to store the picture data.  With the new blob support, you supply a content type and content disposition, which will be streamed back to you on request. 
  • Updated to use the latest SSDS REST library.  This library gives us the ability to use and persist CLR objects to the service and use a LINQ-like query syntax.  This library saved us a ton of time and effort in building the actual application.  All the blob work, querying, and data access was done using this library.

The sample is available for download at CodePlex, and a live version is available to play with at PhluffyFotos.com.  I am opening this one up to the public to upload photos.  Maybe I am playing with fire here, so we will see how well it goes.  Keep in mind that this is a sample site and I will periodically blow away the data.  The live version has an added feature of integrating a source code viewer directly into the application.

Friday, 27 July 2007

Discovering IIS7 Schema

One of the major changes introduced with IIS7 is the removal of the metabase.  This probably comes as a great relief to many of the admins and developers that struggled with coordinating configuration across multiple machines.  Instead of the metabase, IIS7 has chosen to schematize all the web server settings and host them centrally in a new XML file called applicationHost.config located at '%windir%\system32\inetsrv\config'.

The schema itself can be found in the 'schema' folder right below the 'config' directory.  This new centralized configuration file holds all the global default values for IIS7 as well as defines what sites, applications, virtual directories, app pools, etc. are on the server.

Let's take a look just a couple items I found in my applicationHost.config:

<applicationPools>
    <add name="DefaultAppPool" />
    <add name="Classic .NET AppPool" managedPipelineMode="Classic" />
    <applicationPoolDefaults>
        <processModel identityType="NetworkService" />
    </applicationPoolDefaults>
</applicationPools>

Here is the configuration of the application pools on my IIS7 server.  Let's see what happens if we just edit this directly and add a new application pool.

AppPool

If we open our new IIS Manager (Start > Run > inetmgr), we can see that this is all there is to it.

AppPoolsInManager

Further poking around will yield lists of sites, applications, and virtual directories as well - all described neatly in XML format.  Now, how did the IIS team put all this together?  Were they using their own black box implementation?  If we inspect the schema, we will find there is no magic here and the IIS team is leveraging its own schema system for IIS itself.  Opening the "IIS_Schema.xml" file found in the 'schema' directory shows us the exact settings available for 'applicationPools'.

  <sectionSchema name="system.applicationHost/applicationPools">
    <collection addElement="add" defaultElement="applicationPoolDefaults">
      <attribute name="name" type="string" required="true" isUniqueKey="true" validationType="applicationPoolName" />
      <attribute name="queueLength" type="uint" defaultValue="1000" validationType="integerRange" validationParameter="10,65535"/>
      <attribute name="autoStart" type="bool" defaultValue="true" />
      <attribute name="enable32BitAppOnWin64" type="bool" defaultValue="false" />
      <attribute name="managedRuntimeVersion" type="string" defaultValue="v2.0" />
      <attribute name="managedPipelineMode" type="enum" defaultValue="Integrated">
        <enum name="Integrated" value="0" />
        <enum name="Classic" value="1" />
      </attribute>
      <attribute name="passAnonymousToken" type="bool" defaultValue="true" />
      <element name="processModel">
        <attribute name="identityType" type="enum" defaultValue="NetworkService">
          <enum name="LocalSystem" value="0"/>
          <enum name="LocalService" value="1"/>
          <enum name="NetworkService" value="2"/>
          <enum name="SpecificUser" value="3"/>
        </attribute>
            <...SNIP...>
  </sectionSchema>

As we can see here, there are some basic typed attributes that describe our application pool.  They have things like types, default values, and even enumerations with possible values (managedPipelineMode is one such).  There really is no magic here.  Someone could very easily write a program that inspected the schema of IIS7 fully and presented all possible options just by inspecting this schema.

What should immediately come to mind as a developer is, "how can I leverage this system"?  If there is one word that describes IIS7, it is "Extensible".  In my next post, I will show you how to leverage this powerful schema system that IIS7 introduces for your own application purposes without code.

Tuesday, 03 April 2007

Expression Web and Blend on MSDN soon

Straight from Somasegar.  This is good news for developers trying to fit in with their visual counterparts.  Initially these were targeted at the professional designer instead of the developer.  I personally think that those two overlap quite a bit.  It was a good move to put this into developer's hands.  You can be sure that they will get used now...

Friday, 30 March 2007

IIS7 and 404.3 Error

Here is something that I am sure developers will run into as they start to create web sites on their local Vista boxes using IIS7.  I thought I would just put this out here to save people some time.  If you are like me, you will go to the 'Turn Windows features on or off' selection and simply check the IIS7 option like so:

If done correctly, this installs the ASP.NET environment and all the appropriate stuff.  If not, you get an interesting error when you browse to the first .aspx page on your site.  Specifically, you will get a nice 404.3 error similar to this:

The part that should tip you off that something is completely misconfigured  is the part of the the error message (which are sooo much nicer these days) where the module is being reported as the "StaticFileModule".  Static files are things like .html files, jpegs, etc. where we are not performing any server side logic.  We know that our .aspx files need to be processed by the .NET runtime, so we should see something else as the handler there.

Now, here comes the confusing part.  Bring up the IIS Manager (Windows Key > "Inetmgr"), and view the Handler Mappings for your site and you will see something similar to this:

Notice that all of the ASP.NET extensions are missing?  There are no handlers defined for the .aspx, .asmx, .ashx or any other .NET extensions.  If you bring up the handlers installed on the machine however, you will see that they are all just fine:

At this point, you may be like me and scratching your head asking, "why are my handlers not being inherited correctly"?  If you are like me, then you will probably try delete your web app and then re-add it back.  When that fails you will try to uninstall and reinstall IIS7 again.  When that doesn't work, you will try to reinstall ASP.NET manually from the command line using "aspnet_regiis -i" or something similar.  When that fails, you will spend hours on Google trying to see what other people have done.  It might also cross your mind to just add them manually to your configuration.  If you are like me, however, that seems dirty and you will keep trying.

To save you some time, it actually turns out it is pretty easy to fix.  Simply DELETE the "Default Web Site", and then ADD it back.  The Handlers will be re-applied correctly and your virtual directory or web site will have all the correct handlers installed.  It is confusing why this even happens with a fresh install, but it appears to be a frequent occurrence according to Google searches.  Coming from IIS 5.1 and 6, it might be counterintuitive to delete a site, but this is actually not a big deal in Vista since you can have as many of these as you like (no artificial limits anymore).  I hope this saves someone some time.

Note to the IIS7 teamman, it would really be nice if you had a button that said something like "apply inherited handlers" or something like that.

Friday, 09 February 2007

ASP.NET ObjectDataSource and LDAP

One of the neater abstractions we get using ASP.NET 2.0 is the ObjectDataSource. Essentially it allows us to specify our own objects or some arbitrary object graph as a datasource for databinding operations. Combined with the new GridView class it can be very powerful. Built in to both of these objects are methods for Selecting, Updating, Deleting, and Inserting. This allows you to plug-in your own code to manage each of these operations.

If we want to adapt this to support reading and updating (including adds and deletes) from AD or ADAM, we just need to put a few methods in place and hook them into the ObjectDataSource abstraction. The nice thing here is that it includes parameter support pretty easily. This allows us to add new values or update existing values. By specifying a data key (DataKeyNames) on the Gridview, it also allows us to uniquely index which object we are modifying.

I chose for this example to show a simple Select, Update, and Delete using a GridView and the ObjectDataSource. It only required me to configure 3 methods (one for each) and declaratively setup the parameters I would be using. I chose to use the 'objectGuid' for the key name since this is guaranteed to be unique and will always point me to the right object. However, I could also have used the DN as the key value in this case as well. If I had done that, it would have saved me a little bit of complication due to the need to rebind when using the GUID value for certain operations.

Keep in mind that this is just a simple sample of how this can be done and is not something that should be put into production as-is. The whole point of this is to show how the GridView gives us easy updating and reading of values, while the ObjectDataSource is used as our abstraction for operations on data. In the past, this would not have worked well because the DataGrid was so geared towards relational data like SQL. It would have been much more convoluted to get the same functionality. Being able to write only 3 methods and have working ASP.NET viewing and editing application is pretty neat.

You can download the sample here.

Wednesday, 27 December 2006

Doug Reilly will be missed

I learned today that fellow MVP Doug Reilly (Douglas J Reilly) recently lost his battle with cancer.  I remember from the last two MVP conferences sitting and talking with Doug at meals and being amazed at how self-effacing and sincere this guy was.  He was an old timer in the tech industry to be sure, but with such depth of experience and insight that it was always a pleasure to sit and listen to him speak.  There are some personalities in MVP program that drive me nuts with their egos, but never Doug.  A more level-headed, humble, and genuinely nice person would be hard to find.  Everyone will miss Doug's contributions to the .NET community for sure, but I will miss his personality and presence the most.

Tuesday, 31 October 2006

Configuring Kerberos Delegation

One of the challenges to using something like System.DirectoryServices with web apps is managing the security context.  By default, your web application runs with the security context of a local account (often ASPNET or NETWORK SERVICE).  Those accounts are not domain accounts (unless you did something stupid like install IIS on a domain controller), so naturally any code that attempts to read or write to Active Directory is going to fail when the security context is unknown.

First of all, there are many approaches to getting your code in web apps to work.  I am not going to go into all of them, it would take far too long of a post.  Whenever possible, I tell people to use a trusted subsystem model, where the application runs with the desired security context.  When that is not possible, or the application requires fine-grain ACL control (or auditing), you need to actually get the client's security context down through the layers, which means we have to use delegation.

We can break down how to configure delegation based on the deployment of your IIS server.  I am talking about IIS6 here, but this would apply to some degree to IIS5 as well (sans App Pool).  I am also going to make the assumption that your IIS server is a member of a domain with appropriate trust relationships if necessary.  Kerberos delegation doesn't really work without this.

Step 1:  Determine the current security context of your IIS application

You should be able to rattle this off (it is that important to know), but if you are unsure, just open your IIS MMC (Start > Run > 'inetmgr'), find your application and check which application pool it is in (Properties > Virtual Directory > Application Pool).

Next, you should find this application pool in the MMC and check the identity (Properties > Identity).  It might be set to a predefined local account (e.g. NETWORK SERVICE), or it might be set explicitly to some other account.

This is your unmanaged security context.  Now, depending on the type of account this is, we will configure Kerberos delegation differently.  The next two steps 2 and 2a, work slightly differently depending on what your current security context has been determined to be.

Step 2: Is your current security context a local account (i.e. non-domain account like NETWORK SERVICE)?

If you are running IIS as a local account, you should understand that your application will still have an Active Directory identity on the network.  It will be that of the IIS machine account.  Keith Brown has a good write-up on this if you need more clarification why this happens.  Here are the steps to allow the current IIS server to delegate.

  1. IIS server must be a member of the domain and <identity impersonate="true"/> should be in web.config
  2. Set IIS server computer account in AD Users & Computers MMC as "Trusted for Delegation"
  3. IIS Server must be rebooted for this policy to take effect.
  4. Integrated Windows Authentication only must be selected for site / virtual directory
  5. IIS must not have NTLM only set as authentication method (this is usually not a problem, NEGOTIATE is default, so unless you specifically ran a script to change this, don't worry about it).
  6. IIS server name either must match exactly account name in AD, or SetSPN tool should be used in cases where IIS site is set as alternative name (e.g. server is called server01.domain.com, and website is called www.application.com).

Step 2a: Is your current security context a domain account?

  1. IIS server must be a member of the domain and <identity impersonate="true"/> should be in web.config
  2. Set Domain's App Pool Identity account in AD Users & Computers MMC as "Trusted for Delegation"
  3. SetSPN must be used to add SPN to domain service account (e.g. "HTTP/www.myapplication.com").
  4. Integrated Windows Authentication only must be selected for site / virtual directory
  5. IIS must not have NTLM only set as authentication method (this is usually not a problem, NEGOTIATE is default, so unless you specifically ran a script to change this, don't worry about it).

Step 3:  Make sure your clients are configured to use Kerberos

The final step to getting this all to work is to make sure your clients are configured such that they will attempt Kerberos.  This requires a few items to check.

  1. Client must be using IE 5.x+. If client is running IE 6, ensure that "Enable Integrated Windows Authentication (requires restart)" is selected from Tools > Internet Options > Advanced.
  2. Web site MUST be recognized as Local Intranet (not Internet Zone) or Trusted site to client. Since Kerberos is not really considered an internet protocol, IE does not even try Kerberos if the current zone is determined to be Internet.  If necessary, specifically add this to Local Intranet sites list.
  3. Client account must not be marked as "Sensitive, Do not Delegate" in AD Users and Computers MMC.  Smart administrators often mark their admin accounts with this option to prevent them from being abused.  Delegation will fail if you (the client) are trying to delegate one of these types of credentials.

Troubleshooting

The service principal name (SPN) can be a tripping point for a lot of applications.  Load balancing IIS servers adds additional complication as well.  I would really recommend reading Keith's explanation of Kerberos and how it works.  This should make it clear what the SPN is and why it is necessary.

Finally, Microsoft has a support article out there that is fairly decent.  Check it out if you have problems.

Thursday, 17 August 2006

The Case of the Missing Vdir

Yesterday, for most of the day, this blog site was down.  It was throwing an error that essentially said that my virtual directory was missing.  It was a bit stranger than that, but pretty close.  I have not been the biggest fan of my current provider.  I feel like their tech support is lacking and they are missing key tools that other provider's offer for self-management.  As an example, there is no way short of calling tech support to get a vdir created.  That seems pretty rudimentary to me.

After demanding more than a simple "it's working now" answer, I found out that an 'orphaned application cleaner' was run on their servers which managed to remove my vdir as an IIS application.  When I finally noticed it (of course they didn't notice), it only took about an hour to get it restored.  The part that really peeved me was the explanation from them.  It was written in the same manner as most passive voice, it's-not-my-fault prose that we have come to expect from our government.

A virtual directory for the blog folder had been created. However, it was not configured as an application in IIS.

This seems eerily similar to how the government describes casualties (note the passive voice that deflects responsibility):

3 soldiers lives were lost yesterday in a roadside explosion.

By contrast, I would have readily accepted this explanation:

We screwed the pooch.  Yesterday we ran a poorly tested application on the production servers that wiped out a number of our customer's applications.  Sorry about that, it won't happen again.

Well, that is really wishful thinking... I suppose.

Friday, 05 May 2006

Self Service Updates in Active Directory

Sometimes AD Administrators would like to allow end users to update and maintain their own information in the directory.  Of course, this is not without risk – more adventurous users will change their title to “Chief Code Monkey” or something perhaps even less professional.  I was an ‘Executive Vice-President’ myself for some period of time and it made for some interesting phone conversations with co-workers that did not know me personally (it turns out people are pretty fearful of talking directly to EVPs).

However, by default, users have permission over a property set in the schema that allows them to update attributes on their own user object.  If these permissions have not been updated from the default, the user will generally have free reign to update their own personal information.  Which attributes, you ask?  Earlier I demonstrated a way to determine what attributes are available on a given class.  This involved finding the object we wanted in the directory and programmatically inspecting the schema.  It turns out there is another way to achieve the same thing, and with a twist – allow us to see which attributes we can update ourselves.

Active Directory (and ADAM) contain a couple attributes called ‘allowedAttributes’ and ‘allowedAttributesEffective’ that tell us all of the attributes on a given object and all of the attributes on a given object that we are allowed to update, respectively.  The first one, ‘allowedAttributes’ produces the exact output as inspecting the OptionalProperties and MandatoryProperties together (without distinction, however).  It gets more interesting with the second one, because it opens the possibility that we can easily generate a dynamic UI to allow the user to update any attributes where their permission allows.

Here is one such example:

<%@ Assembly Name="System.DirectoryServices, Version=2.0.0000.0, Culture=neutral, PublicKeyToken=b03f5f7f11d50a3a" %>

<%@ Import Namespace="System.DirectoryServices" %>

<%@ Import Namespace="System.Text" %>

<html>

<head>

 

    <script language="c#" runat="server">

 

        static string adsPath = "LDAP://dc=yourdomain,dc=com";

 

        private void Page_Load(object sender, System.EventArgs e)

        {

            if (!Page.IsPostBack)

            {

                SearchResult sr = FindCurrentUser(new string[] { "allowedAttributesEffective" });

 

                if (sr == null)

                {

                    msg.Text = "User not found...";

                    return;

                }

 

                int count = sr.Properties["allowedAttributesEffective"].Count;

 

                if (count > 0)

                {

                    int i = 0;

                    string[] effectiveAttributes = new string[count];

 

                    foreach (string attrib in sr.Properties["allowedAttributesEffective"])

                    {

                        effectiveAttributes[i++] = attrib;

                    }

 

                    sr = FindCurrentUser(effectiveAttributes);

 

                    foreach (string key in effectiveAttributes)

                    {

                        string val = String.Empty;

 

                        if (sr.Properties.Contains(key))

                        {

                            val = sr.Properties[key][0].ToString();

                        }

 

                        GenerateControls(key, val, parent);

                    }

                }

            }

            else

            {

                UpdateControls();

            }

        }

 

        private SearchResult FindCurrentUser(string[] attribsToLoad)

        {

            //parse the current user's logon name as search key

            string sFilter = String.Format(

                "(&(objectClass=user)(objectCategory=person)(sAMAccountName={0}))",

                User.Identity.Name.Split(new char[] { '\\' })[1]

                );

 

            DirectoryEntry searchRoot = new DirectoryEntry(

                adsPath,

                null,

                null,

                AuthenticationTypes.Secure

                );

 

            using (searchRoot)

            {

                DirectorySearcher ds = new DirectorySearcher(

                    searchRoot,

                    sFilter,

                    attribsToLoad,

                    SearchScope.Subtree

                    );

 

                ds.SizeLimit = 1;

 

                return ds.FindOne();

            }

        }

 

        private void GenerateControls(string attrib, string val, Control parent)

        {

            parent.Controls.Add(new LiteralControl("<div>"));

 

            TextBox t = new TextBox();

            t.ID = "c_" + attrib;

            t.Text = val;

            t.CssClass = "txt";

 

            Label l = new Label();

            l.Text = attrib;

            l.AssociatedControlID = t.ID;

            l.CssClass = "lbl";

 

            parent.Controls.Add(l);

            parent.Controls.Add(t);

            parent.Controls.Add(new LiteralControl("</div>"));

        }

 

        private void UpdateControls()

        {

            SearchResult sr = FindCurrentUser(new string[] { "cn" });

 

            if (sr != null)

            {

                using (DirectoryEntry user = sr.GetDirectoryEntry())

                {

                    foreach (string key in Request.Form.AllKeys)

                    {

                        if (key.StartsWith("c_"))

                        {

                            string attrib = key.Split(new char[] { '_' })[1];

                            string val = Request.Form[key];

 

                            if (!String.IsNullOrEmpty(val))

                            {

                                Response.Output.Write("Updating {0} to {1}<br>", attrib, val);

                                user.Properties[attrib].Value = val;

                            }

                        }

                    }

                    user.CommitChanges();

                }

            }

 

            btnSubmit.Visible = false;

            Response.Output.Write("<br><br><a href=\"{0}\">&lt;&nbsp;Back</a>", Request.Url);

        }

 

    </script>

 

    <style>

 

    .lbl

    {

        margin-left: 25px;

        clear: left;

        width: 250px;

    }

 

    .txt

    {

        width: 250px;

    }

</style>

</head>

<body>

    <form id="main" runat="server">

        Data for user:

        <%=User.Identity.Name%>

        <br>

        <br>

        <asp:Label ID="msg" runat="server" />

        <asp:Panel ID="parent" runat="server" />

        <asp:Button ID="btnSubmit" runat="server" Text="Update" />

    </form>

</body>

</html>

Pretty easy, eh?  Sure, this one was whacked together in about 20 minutes, but you could create something similar that takes care of the single- vs. multi-value attribute treatment and make it a whole lot prettier with a little more effort.

This should be fairly obvious – but it bears mentioning:  This requires you to use Integrated Windows Authentication with impersonation and your IIS server must be set for delegation.  The whole point of this exercise was to allow the user to update their own information using their own credentials.  Using a service account will show you what attributes the service account has permission to update on the object.

(thanks Paul for the css – yeah, I am teh suck on UI)

 

Monday, 24 April 2006

The next IIS provider

Scott Guthrie has some good news for the ADSI folks that have struggled so much with the IIS provider until now.  These new, managed APIs for IIS should replace all the spackle that was crusted onto ADSI to wedge the IIS provider into that model.  Granted, this is not really available yet - but at least relief it in sight.

Thursday, 26 January 2006

Strange DasBlog Error Fixed

Previously I was getting an intermittent error with DasBlog that would cause the entire site to freeze up.  Scott Hanselman was kind enough to point out the bug and suggest that I upgrade the binaries to fix it:

“This happens if, IMMEDIATELY FOLLOWING AN APP RECYCLE, a category page is hit, rather than a page in the root. The HttpModule thinks that the AppDomain is starting up with the category page as it's root and chaos ensues.”

I have been waiting a few weeks to ensure that this patch indeed fixed it, and it appears to be golden now.

Thanks Scott!

Monday, 16 January 2006

Back online

Well, it was bound to happen.  I was using free .NET 2.0 beta hosting and the account was expiring.  I had to switch servers and providers in order to keep my mail and site intact.  Now that that transistion has occurred, hopefully I will get around to posting some more interesting tidbits.

 

Saturday, 10 December 2005

Strange DasBlog Error

This blog site which has been quite neglected while I work on the book occasionally gets a bizarre error.  I have not had a chance to look into it at all and it is not reproducible in any way that I know. It just seems to occur randomly and usually after a long period of time.  Here is the stack trace:

[DirectoryNotFoundException: Could not find a part of the path 'C:\Inetpub\wwwroot\dunnry.com\wwwroot\dasblogce\category\SiteConfig\blockedips.config'.]
   System.IO.__Error.WinIOError(Int32 errorCode, String maybeFullPath) +1885372
   System.IO.FileStream.Init(String path, FileMode mode, FileAccess access, Int32 rights, Boolean useRights, FileShare share, Int32 bufferSize, FileOptions options, SECURITY_ATTRIBUTES secAttrs, String msgPath, Boolean bFromProxy) +916
   System.IO.FileStream..ctor(String path, FileMode mode, FileAccess access, FileShare share, Int32 bufferSize, FileOptions options) +115
   System.IO.StreamReader..ctor(String path, Encoding encoding, Boolean detectEncodingFromByteOrderMarks, Int32 bufferSize) +85
   System.IO.StreamReader..ctor(String path) +117
   newtelligence.DasBlog.Web.Core.IPBlackList.GetBlockedIPs(String configPath) in C:\dev\DasBlog CE\source\newtelligence.DasBlog.Web.Core\IPBlackList.cs:62
   newtelligence.DasBlog.Web.Core.IPBlackList.GetBlockedIPs(HttpContext context) in C:\dev\DasBlog CE\source\newtelligence.DasBlog.Web.Core\IPBlackList.cs:37
   newtelligence.DasBlog.Web.Core.IPBlackList.HandleBeginRequest(Object sender, EventArgs evargs) in C:\dev\DasBlog CE\source\newtelligence.DasBlog.Web.Core\IPBlackList.cs:102
   System.Web.SyncEventExecutionStep.System.Web.HttpApplication.IExecutionStep.Execute() +92
   System.Web.HttpApplication.ExecuteStep(IExecutionStep step, Boolean& completedSynchronously) +64

If anyone has seen this and knows what’s up, shoot me an email.

Wednesday, 19 October 2005

What attributes are available on my Active Directory Object?

The question arises occasionally on how to dynamically determine what attributes are available for a given object in Active Directory (typically the user object).  This is a different question than what attributes are actually populated with a value on an instance of the object.  We can find what attributes are defined for an object by naturally looking into the schema for the object.  This can be by inspecting the schema partition and searching for the class, or by taking an instance of the object and accessing the schema.

I will present the latter method in which we have an instance of an object and we wish to determine the available attributes (again, not necessarily populated).

using System;
using System.DirectoryServices;
using System.Reflection;
 
 
DirectoryEntry searchRoot = new DirectoryEntry(
    adsPath,
    null,
    null,
    AuthenticationTypes.Secure
    );
 
using (searchRoot)
{
    DirectorySearcher ds = new DirectorySearcher(
        searchRoot,
        "(sAMAccountName=Ryan_Dunn)"
        );
 
    ds.SizeLimit = 1;
 
    SearchResult sr = null;
 
    using (SearchResultCollection src = ds.FindAll())
    {
        if (src.Count > 0)
            sr = src[0];
    }
 
    if (sr != null)
    {
        using (DirectoryEntry user = sr.GetDirectoryEntry())
        using (DirectoryEntry schema = user.SchemaEntry)
        {
            Type t = schema.NativeObject.GetType();
 
            object optional = t.InvokeMember(
                "OptionalProperties",
                BindingFlags.Public | BindingFlags.GetProperty,
                null,
                schema.NativeObject,
                null
                );
 
            if (optional is ICollection)
            {
                foreach (string s in ((ICollection) optional))
                {
                    WL("Optional: {0}", s);
                }
            }
 
            object mand = t.InvokeMember(
                "MandatoryProperties",
                BindingFlags.Public | BindingFlags.GetProperty,
                null,
                schema.NativeObject,
                null
                );
 
            if (mand is ICollection)
            {
                foreach (string s in ((ICollection) mand))
                {
                    WL("Mandatory: {0}", s);
                }
            }
        }
    }
}

This code will take the user object I find and then iterate through all the attributes defined for this object type (in this case the user object).

 

Tuesday, 04 October 2005

MVP Conference Wrap-Up

I spent the better part of last week in Redmond and surrounding communities for the MVP Conference.  It was a nice to be able to put a face to so many online personas.  For the most part it appears that a lot of the content was also presented at PDC with a few exceptions.  My overall thoughts are that there are a number of exciting technologies – I suppose the only frustration is that there is little indication in so many cases of when the stuff will actually be shipped.

Things I am looking forward to:

  • Windows Workflow Foundation (WWF) – I think this has snuck under the radar a bit, but should present some great new capabilities to enterprise developers.  I can think of a project right now that could desperately use this.
  • Indigo (WCF) –  I hate the new name, but WCF looks very promising.
  • LINQ – I know that Frans is not a big fan of DLINQ, but I am looking forward to learning more about this particular technology.  Unfortunately, since I did not attend this session I will admit to a paucity of knowledge here.

 

Wednesday, 17 August 2005

On Installing DasBlog

Heeding Scott’s advice, I decided to install DasBlog last weekend.  I had expected the installation to take some time, so I was not really prepared when I had DasBlog up and running in approximately 10 mins.  With the help of DotText2DasBlog, most of the content was moved over automatically.  I say mostly, because the tool was unable to move all the content and I did not feel like digging into the source to figure out why.

Why did I move?  I wanted a change and an update from my very old version of .Text.  However, I was not interested in installing all of CS including the forums and picture gallery.  I also wanted to break the SQL Server dependency.

All in all, DasBlog appears to be a very finely tuned and specific app for a single user blog.  I love the XCOPY deployment and the management is a snap.  I was blown away by how fast it was to get up and running.  Great job guys.

 

Monday, 25 July 2005

Data Source Control Series in ASP.NET

Nikhil has wrapped up his excellent series on on creating Data Source controls.  A very well-written and informative guide.  Check it out.

 

Monday, 18 July 2005

Working with Server Intellect

So far, so good!  They responded within an hour or so to my helpdesk ticket and got it right the first time.  The website seems snappy as well and much faster than my current provider.

Good job guys.  I am planning a strategy now on how to transition my stuff from my current provider to Server Intellect.

Sunday, 17 July 2005

Working with Server Intellect Part I

Server Intellect is a new hosting provider for me on another site.  I have not done too much with them yet, but so far I am impressed with how easy the hosting administration has been.  Whatever tool these guys have selected is pretty good and very intuitive.

I submitted my first help desk ticket today, so we will see how fast they are.

 

Friday, 11 March 2005

Mozilla is dead, long live Firefox

BetaNews is reporting that Mozilla Developers have officially announced that they will cease work on the Mozilla monolith (they call it a suite). As a Firefox user, and a sometimes Thunderbird user I can say with confidence... "who cares?". I remember giving the Mozilla "suite" a shot sometime ago and the speed (or lack thereof) and bloat made me uninstall it quite quickly. Maybe they can pour those resources into Firefox to make it even better (and keep it the svelte little number that it is).