mikeobrien.net Curriculum Vitae Blog Labs
Wednesday, March 03, 2010

We ran into a situation where we needed to resolve a mime type for a file extension in a RESTful service running under IIS6. We didn’t want to build a mapping ourselves somewhere but wanted to use a mapping that already existed. Here is a class that will do the mapping, using IIS as the source. You will need to add a reference to System.DirectoryServices and a reference to the “Active DS IIS Namespace Provider” COM component.

public static class MimeTypes
{
    private static Dictionary<string, string> _mimeTypes;

    public static string ResolveMimeTypeFromExtension(string extension)
    {
        LoadMimeTypeMapping();
        if (!extension.StartsWith(".")) extension = "." + extension;
        return _mimeTypes.ContainsKey(extension) ? _mimeTypes[extension] : null;
    }

    public static string ResolveExtensionFromMimeType(string mimeType)
    {
        LoadMimeTypeMapping();
        return _mimeTypes.ContainsValue(mimeType) ? 
            _mimeTypes.First(mapping => mapping.Value == mimeType).Key : null;
    }

    private static void LoadMimeTypeMapping()
    {
        if (_mimeTypes != null) return;

        _mimeTypes = new Dictionary<string, string>();

        DirectoryEntry path = new DirectoryEntry("IIS://localhost/MimeMap");
        PropertyValueCollection mimeMap = path.Properties["MimeMap"];

        foreach (var mapping in mimeMap.OfType<IISOle.IISMimeType>())
            _mimeTypes.Add(mapping.Extension, mapping.MimeType);            
    }
}
.NET | IIS 6
Wednesday, March 03, 2010 8:25:26 PM (GMT Standard Time, UTC+00:00)  #   |  Comments [0]  |  Trackback
Friday, February 19, 2010

I can never seem to remember the details of what the NTFS permissions do so I compiled a chart based on info from here and here that explains it.

Special permissions Full Control Modify Read & Execute List Folder Contents Read Write Description

Traverse Folder/Execute File

x

x

x

x

For folders: Traverse Folder allows or denies moving through folders to reach other files or folders, even if the user has no permissions for the traversed folders. (Applies to folders only.) Traverse folder takes effect only when the group or user is not granted the Bypass traverse checking user right in the Group Policy snap-in. (By default, the Everyone group is given the Bypass traverse checking user right.)

For files: Execute File allows or denies running program files. (Applies to files only).

Setting the Traverse Folder permission on a folder does not automatically set the Execute File permission on all files within that folder.

List Folder/Read Data

x

x

x

x

x

List Folder allows or denies viewing file names and subfolder names within the folder. List Folder only affects the contents of that folder and does not affect whether the folder you are setting the permission on will be listed. (Applies to folders only.)

Read Data allows or denies viewing data in files. (Applies to files only.)

Read Attributes

x

x

x

x

x

Allows or denies viewing the attributes of a file or folder, such as read-only and hidden. Attributes are defined by NTFS.

Read Extended Attributes

x

x

x

x

x

Allows or denies viewing the extended attributes of a file or folder. Extended attributes are defined by programs and may vary by program.

Create Files/Write Data

x

x

x

Create Files allows or denies creating files within the folder. (Applies to folders only).

Write Data allows or denies making changes to the file and overwriting existing content. (Applies to files only.)

Create Folders/Append Data

x

x

x

Create Folders allows or denies creating folders within the folder. (Applies to folders only.)

Append Data allows or denies making changes to the end of the file but not changing, deleting, or overwriting existing data. (Applies to files only.)

Write Attributes

x

x

x

Allows or denies changing the attributes of a file or folder, such as read-only or hidden. Attributes are defined by NTFS.

The Write Attributes permission does not imply creating or deleting files or folders, it only includes the permission to make changes to the attributes of a file or folder. In order to allow (or deny) create or delete operations, see Create Files/Write Data, Create Folders/Append Data, Delete Subfolders and Files, and Delete.

Write Extended Attributes

x

x

x

Allows or denies changing the extended attributes of a file or folder. Extended attributes are defined by programs and may vary by program.

The Write Extended Attributes permission does not imply creating or deleting files or folders, it only includes the permission to make changes to the attributes of a file or folder. In order to allow (or deny) create or delete operations, see Create Files/Write Data, Create Folders/Append Data, Delete Subfolders and Files, and Delete.

Delete Subfolders and Files

x

Allows or denies deleting subfolders and files, even if the Delete permission has not been granted on the subfolder or file. (Applies to folders.)

Delete

x

x

Allows or denies deleting the file or folder. If you do not have Delete permission on a file or folder, you can still delete it if you have been granted Delete Subfolders and Files on the parent folder.

Read Permissions

x

x

x

x

x

x

Allows or denies reading permissions of the file or folder, such as Full Control, Read, and Write.

Change Permissions

x

Allows or denies changing permissions of the file or folder, such as Full Control, Read, and Write.

Take Ownership

x

Allows or denies taking ownership of the file or folder. The owner of a file or folder can always change permissions on it, regardless of any existing permissions that protect the file or folder.

Synchronize

x

x

x

x

x

x

Allows or denies different threads to wait on the handle for the file or folder and synchronize with another thread that may signal it. This permission applies only to multithreaded, multiprocess programs.

Friday, February 19, 2010 6:32:20 PM (GMT Standard Time, UTC+00:00)  #   |  Comments [0]  |  Trackback
Tuesday, February 09, 2010

The Visual Studio 2010 RC is available to MSDN subscribers and will be available to the public tomorrow.

http://weblogs.asp.net/scottgu/archive/2010/02/08/vs-2010-net-4-release-candidate.aspx

UPDATE: I’ve been playing around with the RC and it seems much faster. Loading/unloading a project and compile times are much better. From what I have seen so far today (With pretty limited use) if feels like its on par with 2008. I guess we’ll see more in the days ahead.

Tuesday, February 09, 2010 3:18:48 PM (GMT Standard Time, UTC+00:00)  #   |  Comments [0]  |  Trackback
Tuesday, February 02, 2010

I’m currently working on an F# library that will be accessed from C#. When doing this the obvious question is; “How will this look from C#?” This wasn't quite clear to me at first so I’ll go through a couple custom F# types and show how they are compiled.

Record type, Fermion.fs:

type Spin = 
    | Up = 0
    | Down = 1

type Class = 
    | Quark = 0
    | Lepton = 1

type Type = 
    ...
    | Electron = 6
    ...
type Fermion = 
    { spin: Spin; particleClass: Class; particleType: Type }
    member yada.Spin = yada.spin
    member v.Class = v.particleClass
    member v.Type = v.particleType
    member stuff.GetDescription() = 
        System.String.Format(
            "This {0} is a spin {1} {2}.", 
            stuff.particleType.ToString(), 
            stuff.spin.ToString(), 
            stuff.particleClass.ToString())

Using the record type in F#

let electron = { 
    spin = Spin.Down; 
    particleClass = Class.Lepton; 
    particleType = Type.Electron }

In Reflector:

public static class Fermion
{
    public sealed class Fermion : 
        IStructuralEquatable, 
        IComparable, 
        IStructuralComparable
    {
        internal Particles.Class particleClass@;
        internal Particles.Type particleType@;
        internal Particles.Spin spin@;

        public Fermion(
            Particles.Spin spin, 
            Particles.Class particleClass, 
            Particles.Type particleType)
        {
            this.spin@ = spin;
            this.particleClass@ = particleClass;
            this.particleType@ = particleType;
        }

        public string GetDescription()
        {
            return string.Format("This {0} is a spin {1} {2}.",
                this.particleType@.ToString(), 
                this.spin@.ToString(), 
                this.particleClass@.ToString());
        }

        public Particles.Class Class { get { return this.particleClass@; } }
        public Particles.Class particleClass { get { return this.particleClass@; } }
        public Particles.Type particleType { get { return this.particleType@; } }
        public Particles.Spin spin { get { return this.spin@; } }
        public Particles.Spin Spin { get { return this.spin@; } }
        public Particles.Type Type { get { return this.particleType@; } }

        public int CompareTo(Particles.Fermion obj);
        public sealed override int CompareTo(object obj);
        public sealed override int CompareTo(object obj, IComparer comp);
        public bool Equals(Particles.Fermion obj);
        public sealed override bool Equals(object obj);
        public sealed override bool Equals(object obj, IEqualityComparer comp);
        public override int GetHashCode();
        public sealed override int GetHashCode(IEqualityComparer comp);
    }
}

Some things to note:

  • This is a “record type” so a constructor is generated to set all the private fields. No initialization is performed other than this. So record types are essentially a DTO.
  • It is sealed.
  • When creating an instance of this type it it not necessary to explicitly specify it because of F# type inference.
  • The IComparable, IStructuralComparable and IStructuralEquatable interfaces are all automatically implemented by the F# compiler.
  • A namespace was not explicitly defined in the example so the type has no namespace and the type is nested in a static class with the name of the file it was declared in. If a namespace had been defined then this would not have been nested in a static class and would have simply resided under said namespace.
  • The identifiers (“v”, “yada”, “stuff”) which are equivalent to the “this” keyword in C# are all converted to "this" in the output. And as an aside they do not need to be the same throughout the type, just in the method or property declaration.
  • Fields are publicly exposed via a property that is named as you named the field in the F# source. The fields are suffixed with an “@”.
  • As an aside, enumerations must explicitly have a value defined or they will be compiled as discriminated unions.

Now lets mix things up a bit…

Constructed type, Fermion.fs:

namespace Particles

    type Spin = 
        | Up = 0
        | Down = 1

    type Class = 
        | Quark = 0
        | Lepton = 1

    type Type = 
        ...
        | Electron = 6
        ...
    type Fermion(spin: Spin, particleClass: Class, particleType: Type) = 
        let _description = System.String.Format(
                                "This {0} is a spin {1} {2}.", 
                                particleType.ToString(), 
                                spin.ToString(), 
                                particleClass.ToString())
        member yada.Spin = spin
        member v.Class = particleClass
        member v.Type = particleType
        member stuff.GetDescription() = _description

Using the constructed type in F#:

let electron = new Fermion(Spin.Down, Class.Lepton, Type.Electron)

In Reflector:

public class Fermion
{
    internal string _description;
    internal Class particleClass;
    internal Type particleType;
    internal Spin spin;

    public Fermion(Spin spin, Class particleClass, Type particleType)
    {
        this.spin = spin;
        this.particleClass = particleClass;
        this.particleType = particleType;
        this._description = string.Format("This {0} is a spin {1} {2}.", 
                    this.particleType.ToString(), 
                    this.spin.ToString(), 
                    this.particleClass.ToString());
    }

    public string GetDescription() { return this._description; }

    public Class Class {  get { return this.particleClass; } }
    public Spin Spin { get { return this.spin; } }
    public Type Type { get { return this.particleType; } }
}

Some things to note:

  • This is a “constructed type” so there is a constructor. You’re constructor code is simply put in the body of the type and not in a special function like C#.
  • Requires you to explicitly new up the type and pass the parameters in.
  • No interfaces get automatically implemented as in the case of the record type.
  • This class is not sealed.
  • This type was defined under a namespace so it is not wrapped in a static class.
C# | F#
Tuesday, February 02, 2010 6:16:27 PM (GMT Standard Time, UTC+00:00)  #   |  Comments [0]  |  Trackback
Tuesday, February 02, 2010 2:27:48 AM (GMT Standard Time, UTC+00:00)  #   |  Comments [0]  |  Trackback
Friday, January 29, 2010

The following is an implementation of a safe handle for a device info set:

type DeviceInfoSetSafeHandle() = 
    inherit SafeHandleMinusOneIsInvalid(true)
    [<DllImport("setupapi.dll")>]
    static extern bool SetupDiDestroyDeviceInfoList(IntPtr deviceInfoSet)
    override s.ReleaseHandle() = SetupDiDestroyDeviceInfoList(base.DangerousGetHandle())

It’s extremely trivial to set this up that it’s almost not worth blogging about but maybe someone can benefit from the example...

.NET | F#
Friday, January 29, 2010 4:40:39 AM (GMT Standard Time, UTC+00:00)  #   |  Comments [0]  |  Trackback

Functional programming never ceases to amaze me. The more I code in F# the more I’ve come to appreciate how succinct and terse you can write your code. I’ll sometimes start out with an imperative solution but there always seems to be a functional one that is fewer lines of code and much clearer. I’m working on rewriting a project in F#, that allows you to interact with USB HID devices, in order to learn F#. One of the things I ran into is creating an enumerable and disposable type that wraps a couple of API calls.

type DeviceInfoSet(connectedOnly:bool) = 
    let handle = GetDeviceInfoSet connectedOnly
    member private c.ToSeq = 
        Seq.unfold (fun index -> 
                            let info, more = GetDeviceInfo handle index
                            match more with
                            | true -> Some (info, index + 1)
                            | _ -> None
                    ) 0
    interface IEnumerable with
        member c.GetEnumerator () = c.ToSeq.GetEnumerator() :> IEnumerator
    interface IEnumerable<SP_DEVINFO_DATA> with
        member c.GetEnumerator () = c.ToSeq.GetEnumerator()
    interface IDisposable with
        member c.Dispose () = handle.Dispose()

Here we have a constructed class type that takes in a parameter required by the native call. Unlike a C# type definition, the construction doesn't occur in a constructor function but in the body of the type. The ToSeq property generates the sequence. I absolutely love the unfold function, it is so powerful. Here the native method requires an integer to be incremented until an error code is returned to indicate that there are no more records (Not shown). As long as there are more records we return the item and increment the index. Once there are no more we return None. Now we get to the interface implementation. This is pretty straight forward, the only thing you have to do with the non generic IEnumerable implementation is downcast it to IEnumerator with the :> operator.

Here is an example of the usage:

let enumerate = 
    use devices = new DeviceInfoSet(false)
    devices |> Seq.iter (fun item -> Console.WriteLine(item.ClassGuid.ToString()))
The “use” keyword is equivalent to a using statement in C#. Once the “devices” value goes out of scope it is disposed of. 
.NET | F#
Friday, January 29, 2010 4:28:40 AM (GMT Standard Time, UTC+00:00)  #   |  Comments [0]  |  Trackback
Monday, January 25, 2010

The Studio 1735 does indeed support 8Gb of RAM. The spec says no and there has been some uncertainty on the web about which notebooks based on the Santa Rosa chipset support it. My bios revision is A04 and I’m running Server 2008 R2. You can pick up the RAM here at Newegg for a decent price.

image

image

Monday, January 25, 2010 6:26:02 PM (GMT Standard Time, UTC+00:00)  #   |  Comments [0]  |  Trackback
Saturday, January 23, 2010

Our database scripts reside in our SVN repo and when we do an svn update we want to have a friendly reminder if they’ve been modified by another developer (so that we can sync up our local database). Client hook scripts seemed like a perfect choice for this, as did a PowerShell script. I ran into many quirks while trying to make this happen, one of which was that TSVN captures the output of a hook script in order to catch errors. This means that you cant really use hook scripts OOB for displaying a message. If your interested in having a setting in TSVN to change this behavior, please post a comment here.  Although in PowerShell we can issue a command to start up a new PowerShell instance to run our script, freeing us from the shackles of TSVN:

powershell.exe -command "& {start-process powershell.exe (([system.environment]::GetCommandLineArgs()|ForEach-Object -process { '\"{0}\"' -f $_ })[3..([system.environment]::GetCommandLineArgs().Length-1)])}" "-file" "C:\MyScript.ps1"

This command deals with some other quirks that I ran into. One is that the $args variable contains improperly parsed command line arguments when used in a -command. It doesn’t respect quoted qualifiers and splits on spaces even when a parameter is quote qualified. Also they need to be requalified before they are passed to the script or you run into the same issue. The command also drops the first few parameters as these are not needed and cause problems.

So all you have to do is create a hook script under TSVN settings and paste in the above command (With the path to your script) and your good to go. I suggest checking the “Hide the script...” checkbox as this call will cause an initial console window to popup and disappear if you don't.

image

Saturday, January 23, 2010 4:08:48 AM (GMT Standard Time, UTC+00:00)  #   |  Comments [0]  |  Trackback
Wednesday, January 13, 2010

Our entities all have modified and created dates associated with them and we wanted these set automatically. I settled on using an interceptor which is discussed by Ray Houston here and a caveat (Actually just some fine print I would have missed) discussed here by Jan Van Ryswyck.

All you do is create a class that inherits from NHibernate.EmptyInterceptor (Which itself implements IInterceptor and allows you to only handle the things you want to handle) and override the the methods you want to handle. In our case we just needed inserts (OnSave) and updates (OnFlushDirty). Return true on those methods only if you made a modification otherwise return false. I created and interface that identifies an entity:

public interface IEntity
{
    Guid Id { get; }
    DateTime Modified { get; set; }
    DateTime Created { get; set; }
}

... and we only operate on entities that implement this interface:

public class EntityInterceptor : EmptyInterceptor
{
    public override bool OnSave(object entity, object id, object[] state, 
        string[] propertyNames, NHibernate.Type.IType[] types)
    {
        if (!(entity is IEntity)) return false;

        var created = DateTime.Now;
        SetState<IEntity>(propertyNames, state, x => x.Created, created);
        SetState<IEntity>(propertyNames, state, x => x.Modified, created);
        return true;
    }

    public override bool OnFlushDirty(object entity, object id, object[] currentState,
         object[] previousState, string[] propertyNames, NHibernate.Type.IType[] types)
    {
        if (!(entity is IEntity)) return false;

        SetState<IEntity>(propertyNames, currentState, x => x.Modified, DateTime.Now);
        return true;
    }

    private void SetState<T>(string[] propertyNames, object[] state, 
        Expression<Func<T, object>> property, object value)
    {
        var index = Array.IndexOf(propertyNames, property.GetPropertyName());
        if (index == -1) return;
        state[index] = value;
    }
}

The key is to set the state in OnSave and the currentState in OnFlushDirty to the new value, do not modify the entity. The names of the values are held in the propertyNames array, thus the need for the SetState method to lookup the index of the property you want to modify. One thing I didn't like about my first incarnation were the magic strings for the property names. So I shamelessly ripped off some code from Gabriel Schenkers post on Dynamic vs Static Reflection (A really good read!) to allow me to pass an expression instead of a magic string. I turned it into extension methods as follows:

public static class ExpressionExtensions
{
    public static string GetPropertyName<T>(this Expression<Func<T, object>> expression)
    {
        var memberExpression = expression.GetMemberExpression();
        var propertyInfo = memberExpression.Member as PropertyInfo;
        return propertyInfo == null ? null : propertyInfo.Name;
    }

    public static MemberExpression GetMemberExpression<T>(
                      this Expression<Func<T, object>> expression)
    {
        MemberExpression memberExpression = null;
        if (expression.Body.NodeType == ExpressionType.Convert)
        {
            var body = (UnaryExpression)expression.Body;
            memberExpression = body.Operand as MemberExpression;
        }
        else if (expression.Body.NodeType == ExpressionType.MemberAccess)
        {
            memberExpression = expression.Body as MemberExpression;
        }
        if (memberExpression == null)
        {
            throw new ArgumentException("Not a member access", "member");
        }
        return memberExpression;
    }
}

Fluently registering the interceptor is as follows:

_sessionFactory =
    Fluently.Configure().
        Database(persistenceConfigurer).
        Mappings(m => m.FluentMappings.AddFromAssembly(Assembly.GetExecutingAssembly())).
        ExposeConfiguration(config => config.Interceptor = new EntityInterceptor()).
        BuildSessionFactory();
Wednesday, January 13, 2010 9:41:59 PM (GMT Standard Time, UTC+00:00)  #   |  Comments [0]  |  Trackback
Creative Commons License