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
Tuesday, February 02, 2010
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
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
Tuesday, January 12, 2010

StructureMap is an excellent IoC tool; very powerful and easy to use. One thing that I think is lacking though is a way to create a custom lifecycle “strategy” (For lack of a better word). Currently you can specify a lifecycle and you can use one the hybrid lifecycles but this isn’t sufficient in some circumstances. In our code base we have ASP.NET web pages, WCF services, Windows services and console applications (And who knows what next, MVC?) and we have one registry for all these applications. We’re using NHibernate so we have different lifecycle needs for ISession in each type of application. Another side of a lifecycle is the end of it. We want to be able to explicitly end a lifecycle in our ASP.NET and WCF apps. So this is what I mean by a “strategy”.

Solution

One thing that’s really nice about StructureMap is that it’s really easy to extend. Jeremy et al have done a great job of creating a codebase that’s really easy to dive into and understand. So the following is a strategic lifecycle API that allows you to define a lifecycle strategy. I’ll first explain how to use it and then further down I’ll explain the code under the covers. Now I do want to give the disclaimer that I’m no StructureMap expert or anything, so there may be better or more “correct” ways to do this. If so, be sure to leave a comment if you know.

You can download the code here. The code that matters is in the StructureMapContrib project.

Lifecycle strategies can be defined with the LifecycleStrategiesAre() method which takes any number of ILifecycleStrategy parameters:

ObjectFactory.Configure(
    config => config.For<INumberGenerator>().
              LifecycleStrategiesAre(...).
              Use<NumberGenerator>());

This is simply a convenience extension method for the following:

ObjectFactory.Configure(
    config => config.For<INumberGenerator>().
              LifecycleIs(new StrategicLifecycle(...)).
              Use<NumberGenerator>());

StrategicLifecycle implements ILifecycle and contains the different lifecycle strategies. Now a LifecycleStrategy can take three pieces of information; first, a lambda that determines if the lifecycle is valid (If this is not specified it defaults to true). Second, a lambda that lazily creates the lifecycle. And third, a lambda that will deterministically dispose of the object cache (If this is not specified then the object cache is not deterministically disposed). The following is a strategy defined for ASP.NET pages:

new LifecycleStrategy(
    () => HttpContextLifecycle.HasContext() && HttpContext.Current.Handler is Page, 
    () => new HttpContextLifecycle(), 
    c => ((Page)HttpContext.Current.Handler).Unload += ((s,e) => c.DisposeAndClear())),

This strategy is only valid when there is a current HttpContext and when the handler is a Web.UI.Page. In this case we would use StructureMap’s HttpContextLifecycle. And we want to deterministically dispose of the object cache by hooking into the page Unload event. We can define other strategies to create a full lifecycle strategy as follows:

ObjectFactory.Configure(
    config => config.For<INumberGenerator>().
              LifecycleStrategiesAre(
                  new LifecycleStrategy(
                        () => HttpContextLifecycle.HasContext() && HttpContext.Current.Handler is Page, 
                        () => new HttpContextLifecycle(), 
                        c => ((Page)HttpContext.Current.Handler).Unload += ((s,e) => c.DisposeAndClear())),

                  new LifecycleStrategy(
                        WcfOperationLifecycle.HasContext, 
                        () => new WcfOperationLifecycle(), 
                        c => OperationContext.Current.OperationCompleted += ((s, e) => c.DisposeAndClear())),

                  new LifecycleStrategy(() => new ThreadLocalStorageLifecycle())).
              Use<NumberGenerator>());

Here we have a strategy that defines lifecycles for ASP.NET pages, WCF services and a fallback or default strategy of thread local storage. BTW, the WcfOperatonLifecycle is explained here. Notice that the thread local storage doesn't specify if it is valid or an explicit dispose handler. Since it’s a fall back strategy it is listed last and is always valid and the object cache will not be deterministically disposed. This registration looks a bit cluttered so I’ve encapsulated these strategies into their own classes which cleans things up a bit:

ObjectFactory.Configure(
    config => config.For<INumberGenerator>().
              LifecycleStrategiesAre(
                  new HttpContextAndPageLifecycleStrategy(),
                  new WcfOperationLifecycleStrategy(),
                  new LifecycleStrategy(() => new ThreadLocalStorageLifecycle())).
              Use<NumberGenerator>());

And that’s it. Now below, if you’re interested, we’ll examine the code behind this.

Implementation

It all starts with the StrategicLifecycle class:

public class StrategicLifecycle : ILifecycle
{
    private IEnumerable<ILifecycleStrategy> _strategies;

    public StrategicLifecycle(params ILifecycleStrategy[] strategies)
    { _strategies = strategies; }

    public void EjectAll()
    { ResolveLifecycle().EjectAll(); }

    public IObjectCache FindCache()
    { return ResolveLifecycle().FindCache(); }

    public string Scope
    { get { return "StrategicLifecycle"; } }

    private ILifecycle ResolveLifecycle()
    {
        var lifecycle = (from strategy in _strategies
                         where strategy.IsValid()
                         select strategy.Lifecycle).FirstOrDefault();
        if (lifecycle == null) throw
            new Exception("Unable to find a suitable lifecycle Strategy.");
        return lifecycle;
    }
}

This lifecycle dynamically chooses a valid lifecycle by calling the IsValid() method on all the ILifecycleStrategy’s passed in. The first one it finds is the winner.

Lifecycle strategies implement the ILifecycleStrategy interface which only has two members; IsValid() to determine it the lifecycle is valid in a particular circumstance and the Lifecycle property to return an instance of a lifecycle:

public interface ILifecycleStrategy
{
    bool IsValid();
    ILifecycle Lifecycle { get;}
}

This is the implementation of ILifecycleStrategy that I’m using:

public class LifecycleStrategy : ILifecycleStrategy
{
    private Func<bool> _isValid;
    private ILifecycle _lifecycle;
    private Func<ILifecycle> _create;
    private Action<IObjectCache> _dispose;

    public LifecycleStrategy(Func<ILifecycle> create, Action<IObjectCache> dispose) : this(() => true, create, dispose) { }
    public LifecycleStrategy(Func<bool> isValid, Func<ILifecycle> create) : this(isValid, create, null) { }
    public LifecycleStrategy(Func<ILifecycle> create) : this(() => true, create, null) { }

    public LifecycleStrategy(Func<bool> isValid, Func<ILifecycle> create, Action<IObjectCache> dispose)
    {
        _isValid = isValid;
        _create = create;
        _dispose = dispose;
    }

    public bool IsValid()
    {
        return _isValid();
    }

    public ILifecycle Lifecycle
    {
        get
        {
            if (_lifecycle == null)
                if (_dispose == null) _lifecycle = _create();
                else _lifecycle = new DisposableLifecycleProxy(_create(), _dispose);
            return _lifecycle;
        }
    }
}

This is simply a container for the lambdas passed in and for the lifecycle. The lifecycle is created lazily and cached. You’ll notice that if a deterministic dispose lambda is passed, the lifecycle is wrapped in a DisposableLifecycleProxy class. Here is that class:

public class DisposableLifecycleProxy : ILifecycle
{
    private ILifecycle _lifecycle;
    private Action<IObjectCache> _dispose;
    private Dictionary<IObjectCache, IObjectCache> _objectCaches = 
        new Dictionary<IObjectCache, IObjectCache>();

    public DisposableLifecycleProxy(ILifecycle lifecycle, Action<IObjectCache> dispose)
    {
        _lifecycle = lifecycle;
        _dispose = dispose;
    }

    public void CacheDisposed(IObjectCache objectCache)
    {
        if (!_objectCaches.ContainsKey(objectCache)) return;
        lock (_objectCaches) { _objectCaches.Remove(objectCache); }
    }

    public void EjectAll() { _lifecycle.EjectAll(); }

    public IObjectCache FindCache()
    {
        IObjectCache objectCache = _lifecycle.FindCache();

        // This is here to ensure the close lambda is only executed once
        // per object cache. Not sure of a better way to handle this.
        if (!_objectCaches.ContainsKey(objectCache))
        {
            ObjectCacheProxy proxy = new ObjectCacheProxy(this, objectCache);
            lock (_objectCaches) { _objectCaches.Add(objectCache, proxy); }
            _dispose(proxy);
        }

        return _objectCaches[objectCache];
    }

    public string Scope { get { return _lifecycle.Scope; } }

    // ────────────────────────── Nested Types ──────────────────────────

    public class ObjectCacheProxy : IObjectCache, IDisposable
    {
        private IObjectCache _objectCache;
        private DisposableLifecycleProxy _lifecycleProxy;
        private bool _disposed;

        public ObjectCacheProxy(DisposableLifecycleProxy lifecycleProxy, IObjectCache objectCache)
        {
            _objectCache = objectCache;
            _lifecycleProxy = lifecycleProxy;
        }

        public void DisposeAndClear() 
        {
            _objectCache.DisposeAndClear(); 
            Dispose();
        }

        public void Dispose()
        {
            if (_disposed) return;

            _disposed = true;
            _lifecycleProxy.CacheDisposed(_objectCache);
        }

        public int Count { get { return _objectCache.Count; } }
        public void Eject(Type pluginType, Instance instance) { _objectCache.Eject(pluginType, instance); }
        public object Get(Type pluginType, Instance instance) { return _objectCache.Get(pluginType, instance); }
        public bool Has(Type pluginType, Instance instance) { return _objectCache.Has(pluginType, instance); }
        public object Locker { get { return _objectCache.Locker; } }
        public void Set(Type pluginType, Instance instance, object value) { _objectCache.Set(pluginType, instance, value); }
    }        
}

This is the part I’m not all that fond of. It’s a bit too much acrobatics to do something really simple and I wasn't able to put any more effort into it because of time constraints. But it’s the only way I could figure out to transparently control the lifetime of an object cache. Essentially the dispose lambda is called the first time the FindCache() method is called. This class maintains a dictionary of all the object caches it’s called the dispose lambda on so that it only ever calls it once per object cache. Plus the object cache that is returned is wrapped in a proxy that will signal back that the object cache has been disposed and can be removed from the mapping. I wish there was something that indicated if the cache existed before you called FindCache(). That way you could tell if it was newly created and in this case call the explicit dispose lambda on it. For now this is my workaround.  

The rest of the classes in the StructureMapContrib project are just simple convenience classes and shouldn’t require any explanation.

Tuesday, January 12, 2010 6:04:12 PM (GMT Standard Time, UTC+00:00)  #   |  Comments [0]  |  Trackback

We have a RESTful and SOAPy API so having a WCF operation lifecycle in StructureMap was imperative. Creating lifecycles in StructureMap is cake. You can find some examples under the Pipeline namespace in the StructureMap source code. All you do is create a class that implements StructureMap.Pipeline.ILifecycle. Below is a lifecycle that is based on a WCF operation:

public class WcfOperationLifecycle : ILifecycle
{
    public static readonly string ITEM_NAME = "STRUCTUREMAP-INSTANCES";

    public void EjectAll()
    {
        FindCache().DisposeAndClear();
    }

    public IObjectCache FindCache()
    {
        if (!OperationContext.Current.OutgoingMessageProperties.ContainsKey(ITEM_NAME))
            OperationContext.Current.OutgoingMessageProperties.Add(ITEM_NAME, new MainObjectCache());
        return (IObjectCache)OperationContext.Current.OutgoingMessageProperties[ITEM_NAME]; 
    }

    public string Scope { get { return "WcfOperationLifecycle"; } }
}

I used the existing HttpContextLifecycle class as my starting point. The important part of this class is the FindCache() method which locates the object cache. As you can see above we are stashing the object cache in the outgoing message properties. I’m not sure what the significance of the Scope property is other than debugging perhaps, but from what I can see you just return a descriptive string.

Registering this is also very simple; simply specify this as the lifecycle you’d like to use:

ObjectFactory.Configure(
    config => config.For<INumberGenerator>().
              LifecycleIs(new WcfOperationLifecycle()).
              Use<NumberGenerator>());

That’s all there is to it!

Tuesday, January 12, 2010 4:49:09 PM (GMT Standard Time, UTC+00:00)  #   |  Comments [0]  |  Trackback
Saturday, January 09, 2010

Jimmy Bogard has written a couple of posts here and here discussing the registering partially closed generic types with StructureMap. These posts helped me solve a problem I was having which is a little bit different. To set the stage let me explain what we’re doing. First we have a generic repository interface:

public interface IRepository<TEntity> : IQueryable<TEntity> where TEntity : class
{
    TEntity Get(Guid id);
    void Save(TEntity entity);
    void Delete(TEntity entity);
    void DeleteSingle(IQueryable<TEntity> query);
    void DeleteMany(IQueryable<TEntity> query);
}

Then we will have an interface for a specific repository that inherits from the generic repository interface and includes convenience methods:

public interface IAccountRepository : IRepository<Account>
{
    void DeleteInactiveAccountsOlderThanTwoYears();
    void CreateAccountBasedOnExistingAccount(Account account);
    // Etc, etc, etc
}

Then we have the concrete class that implements the repository specific interface (The NHibernateRepositoryBase class implements the members defined by IRepository<TEntity> not show below):

public class AccountRepository : NHibernateRepositoryBase<Account>, IAccountRepository
{
    public void DeleteInactiveAccountsOlderThanTwoYears() {...};
    public void CreateAccountBasedOnExistingAccount(Account account) {...};
    // Etc, etc, etc    
}

So what I wanted is to scan our persistence assembly for any concrete types (IE: AccountRepository) that implement an interface (IE: IAccountRepository) that derives from a closed generic interface (IE: IRepository<Account>) that is of a particular open generic interface type (IE: IRepository<>). Clear as mud?? :) Simply put, I want to scan for IRepository<> and want to map IAccountRepository to AccountRepository. This is cake with StructureMap using a registration convention. BTW, I’m using StructureMap 2.5.4 and from what I understand you may need this version to do what I’m doing here.

I lifted the GenericConnectionScanner class (Which is what the ConnectImplementationsToTypesClosing convenience method uses) from the StructureMap code as my starting point and modified the logic:

public class DerivedOpenGenericInterfaceConnectionScanner : IRegistrationConvention
{
    private readonly Type _openType;

    public DerivedOpenGenericInterfaceConnectionScanner(Type openType)
    {
        _openType = openType;
        if (!_openType.IsInterface || !_openType.IsOpenGeneric())
            throw new ApplicationException(
                "This scanning convention can only be used with open generic interface types");
    }

    public void Process(Type type, StructureMap.Configuration.DSL.Registry registry)
    {
        if (!type.IsConcrete()) return;
        var derivedTypes = type.GetInterfaces().
                            Where(i => i.GetInterfaces().
                                    Any(i2 => i2.IsGenericType && 
                                              i2.GetGenericTypeDefinition() == _openType));
        if (derivedTypes.Count() > 0) registry.For(derivedTypes.First()).Add(type);
    }
}

The constructor takes the open generic interface type. The Process method is called for each type; we only want concrete types. We check the type for interfaces that derive from an interface that has a type definition of our open generic interface type. If one exists we map the derived interface type to the concrete type.

ObjectFactory.Initialize(
    x => x.Scan(
        config => {
             config.AssemblyContainingType(typeof(IRepository<>));
             config.With(new DerivedOpenGenericInterfaceConnectionScanner(typeof(IRepository<>)));
         }));

var accountRepo = ObjectFactory.GetInstance<IAccountRepository>();
System.Diagnostics.Debug.Assert(accountRepo != null && accountRepo is AccountRepository);

The above initialization scans the assembly containing our open generic interface type and specifies our registration convention using the With() method. That’s all there is to it!

Saturday, January 09, 2010 3:18:08 AM (GMT Standard Time, UTC+00:00)  #   |  Comments [0]  |  Trackback
Thursday, December 17, 2009

There are a couple of online developer resources that have really stood out. I’ve benefited from them greatly so I wanted to give them a shout out.

Blogging communities:

CodeBetter.com – As an aside Matthew Podwysocki blogs here. So if your interested in all sorts of functional goodness, this is the place for you.
LosTechies.com
Devlicio.us

Webcasts:

DimeCasts.net – This site, run by Derik Whittaker and contributed to by a bunch of really smart people, has a ton of great web casts around ten minutes each (Great for those with ADD) on different topics. Topics include IoC, NHibernate, TDD, CI, SOLID and a bunch of other snazzy acronyms. Lately I’ve been watching vids on NHibernate and StructureMap and they have been extremely helpful.

Thursday, December 17, 2009 5:40:11 PM (GMT Standard Time, UTC+00:00)  #   |  Comments [0]  |  Trackback
Saturday, November 14, 2009

I had a crazy situation where I couldn't modify an installation of SQL server nor could I uninstall it. So I did the dirty work of manually uninstalling it so that I could reinstall it with the components I needed. But when I did the reinstall the installer errored out! Turns out that for some reason about 1,300 registry keys related to the SQL server install had their security info wiped out (No owner, no permissions). I tried using subinacl to reset the owner and permissions but it appears that it cant understand 32 and 64 bit registry views so it could not even see the keys I needed altered. Manually fixing this was out of the question so I came up with some code to do it. Actually I didn't really come up with anything; a bunch of other people who are much smarter than me did and I just pieced together what they did... :) Also, I realize that it is probably possible to do this with the new API’s that were introduced with .NET 2.0 but I couldn't seem to figure out how to do it with registry keys and I didn’t have the time to dig into it further. So if you have the time to check those out you may be able to find a managed solution. Keith Brown has an excellent book which goes deeply into Windows security and the .NET API’s, I highly recommend it.

Here is an example of using the code to modify the permissions of a registry key. Note that for the local machine hive its not prefixed with “HKEY_LOCAL_MACHINE” but just “MACHINE”:

Security.GrantAdministratorsAccess(
    @"MACHINE\SOFTWARE\Microsoft\Windows\...\E53B08216D22271418A3F85F6654D6EE",
    Security.SE_OBJECT_TYPE.SE_REGISTRY_KEY);

Here is the method to make the administrators group the owner and give it permissions:

public static void GrantAdministratorsAccess(string name, SE_OBJECT_TYPE type)
{
    SID_IDENTIFIER_AUTHORITY sidNTAuthority = SECURITY_NT_AUTHORITY;

    // Create a SID for the BUILTIN\Administrators group.
    IntPtr sidAdmin = IntPtr.Zero;
    AllocateAndInitializeSid(ref sidNTAuthority, 2,
                             SECURITY_BUILTIN_DOMAIN_RID,
                             DOMAIN_ALIAS_RID_ADMINS,
                             0, 0, 0, 0, 0, 0,
                             ref sidAdmin);

    // Set full control for Administrators.
    EXPLICIT_ACCESS[] explicitAccesss = new EXPLICIT_ACCESS[1];
    explicitAccesss[0].grfAccessPermissions = ACCESS_MASK.GENERIC_ALL;
    explicitAccesss[0].grfAccessMode = ACCESS_MODE.SET_ACCESS;
    explicitAccesss[0].grfInheritance = NO_INHERITANCE;
    explicitAccesss[0].Trustee.TrusteeForm = TRUSTEE_FORM.TRUSTEE_IS_SID;
    explicitAccesss[0].Trustee.TrusteeType = TRUSTEE_TYPE.TRUSTEE_IS_GROUP;
    explicitAccesss[0].Trustee.ptstrName = sidAdmin;

    IntPtr acl = IntPtr.Zero;
    SetEntriesInAcl(1,
                    ref explicitAccesss[0],
                    0,
                    ref acl);

    Action<string, bool> setPrivilege = (privilege, allow) =>
    {
        IntPtr token = IntPtr.Zero;
        TOKEN_PRIVILEGES tokenPrivileges = new TOKEN_PRIVILEGES();
        OpenProcessToken(GetCurrentProcess(),
            TOKEN_ADJUST_PRIVILEGES | TOKEN_QUERY, out token);

        if (allow)
        {
            LUID luid;
            LookupPrivilegeValueA(null, privilege, out luid);
            tokenPrivileges.PrivilegeCount = 1;
            tokenPrivileges.Privileges = new LUID_AND_ATTRIBUTES[1];
            tokenPrivileges.Privileges[0].Luid = luid;
            tokenPrivileges.Privileges[0].Attributes = SE_PRIVILEGE_ENABLED;
        }

        AdjustTokenPrivileges(token, false, ref tokenPrivileges, 0,
            IntPtr.Zero, IntPtr.Zero);
        CloseHandle(token);
    };

    // Enable the SE_TAKE_OWNERSHIP_NAME privilege.
    setPrivilege(SE_TAKE_OWNERSHIP_NAME, true);

    // Set the owner in the object's security descriptor.
    SetNamedSecurityInfo(
        name,
        type,
        SECURITY_INFORMATION.OWNER_SECURITY_INFORMATION,
        sidAdmin,
        IntPtr.Zero,
        IntPtr.Zero,
        IntPtr.Zero);

    // Disable the SE_TAKE_OWNERSHIP_NAME privilege.
    setPrivilege(SE_TAKE_OWNERSHIP_NAME, false);

    // Modify the object's DACL,
    SetNamedSecurityInfo(
        name,
        type,
        SECURITY_INFORMATION.DACL_SECURITY_INFORMATION,
        IntPtr.Zero, IntPtr.Zero,
        acl,
        IntPtr.Zero);

    FreeSid(sidAdmin);
    LocalFree(acl);
}

Here are the native methods and constants:

[StructLayoutAttribute(LayoutKind.Sequential)]
private struct SID_IDENTIFIER_AUTHORITY
{
    [MarshalAsAttribute(UnmanagedType.ByValArray, SizeConst = 6, ArraySubType = UnmanagedType.I1)]
    public byte[] Value;
}

[StructLayoutAttribute(LayoutKind.Sequential)]
private struct TRUSTEE
{
    public System.IntPtr pMultipleTrustee;
    public MULTIPLE_TRUSTEE_OPERATION MultipleTrusteeOperation;
    public TRUSTEE_FORM TrusteeForm;
    public TRUSTEE_TYPE TrusteeType;
    public IntPtr ptstrName;
}

[StructLayoutAttribute(LayoutKind.Sequential)]
private struct EXPLICIT_ACCESS
{
    public ACCESS_MASK grfAccessPermissions;
    public ACCESS_MODE grfAccessMode;
    public uint grfInheritance;
    public TRUSTEE Trustee;
}

[StructLayoutAttribute(LayoutKind.Sequential)]
private struct TOKEN_PRIVILEGES
{
    public uint PrivilegeCount;
    [MarshalAsAttribute(UnmanagedType.ByValArray, SizeConst = 1, ArraySubType = UnmanagedType.Struct)]
    public LUID_AND_ATTRIBUTES[] Privileges;
}

[StructLayoutAttribute(LayoutKind.Sequential)]
private struct LUID_AND_ATTRIBUTES
{
    public LUID Luid;
    public uint Attributes;
}

[StructLayoutAttribute(LayoutKind.Sequential)]
private struct LUID
{
    public uint LowPart;
    public int HighPart;
}

private enum TRUSTEE_TYPE
{
    TRUSTEE_IS_GROUP,
}

private enum TRUSTEE_FORM
{
    TRUSTEE_IS_SID,
}

private enum MULTIPLE_TRUSTEE_OPERATION { }

public enum SE_OBJECT_TYPE
{
    SE_UNKNOWN_OBJECT_TYPE = 0,
    SE_FILE_OBJECT,
    SE_SERVICE,
    SE_PRINTER,
    SE_REGISTRY_KEY,
    SE_LMSHARE,
    SE_KERNEL_OBJECT,
    SE_WINDOW_OBJECT,
    SE_DS_OBJECT,
    SE_DS_OBJECT_ALL,
    SE_PROVIDER_DEFINED_OBJECT,
    SE_WMIGUID_OBJECT,
    SE_REGISTRY_WOW64_32KEY
}

[Flags]
private enum ACCESS_MASK : uint
{
    GENERIC_ALL = 0x10000000,
}

[Flags]
private enum SECURITY_INFORMATION : uint
{
    OWNER_SECURITY_INFORMATION = 0x00000001,
    DACL_SECURITY_INFORMATION = 0x00000004,
}

private enum ACCESS_MODE
{
    SET_ACCESS
}

private const string SE_TAKE_OWNERSHIP_NAME = "SeTakeOwnershipPrivilege";
private static SID_IDENTIFIER_AUTHORITY SECURITY_NT_AUTHORITY =
    new SID_IDENTIFIER_AUTHORITY() { Value = new byte[] { 0, 0, 0, 0, 0, 5 } };

private const UInt32 TOKEN_ADJUST_PRIVILEGES = 0x0020;
private const int NO_INHERITANCE = 0x0;
private const int SECURITY_BUILTIN_DOMAIN_RID = 0x00000020;
private const int DOMAIN_ALIAS_RID_ADMINS = 0x00000220;
private const int TOKEN_QUERY = 8;
private const int SE_PRIVILEGE_ENABLED = 2;

[DllImportAttribute("advapi32.dll", EntryPoint = "OpenProcessToken")]
[return: MarshalAsAttribute(UnmanagedType.Bool)]
private static extern bool OpenProcessToken(
    [InAttribute] 
    IntPtr ProcessHandle,
    uint DesiredAccess,
    out IntPtr TokenHandle);

[DllImportAttribute("advapi32.dll", EntryPoint = "AllocateAndInitializeSid")]
[return: MarshalAsAttribute(UnmanagedType.Bool)]
private static extern bool AllocateAndInitializeSid(
    [InAttribute] ref SID_IDENTIFIER_AUTHORITY pIdentifierAuthority,
    byte nSubAuthorityCount,
    uint nSubAuthority0,
    uint nSubAuthority1,
    uint nSubAuthority2,
    uint nSubAuthority3,
    uint nSubAuthority4,
    uint nSubAuthority5,
    uint nSubAuthority6,
    uint nSubAuthority7,
    ref IntPtr pSid);

[DllImportAttribute("kernel32.dll", EntryPoint = "CloseHandle")]
[return: MarshalAsAttribute(UnmanagedType.Bool)]
private static extern bool CloseHandle([InAttribute] IntPtr hObject);

[DllImportAttribute("kernel32.dll", EntryPoint = "GetCurrentProcess")]
private static extern IntPtr GetCurrentProcess();

[DllImportAttribute("advapi32.dll", EntryPoint = "FreeSid")]
private static extern IntPtr FreeSid([InAttribute] IntPtr pSid);

[DllImportAttribute("kernel32.dll", EntryPoint = "LocalFree")]
private static extern IntPtr LocalFree(IntPtr hMem);

[DllImportAttribute("advapi32.dll", EntryPoint = "LookupPrivilegeValueA")]
[return: MarshalAsAttribute(UnmanagedType.Bool)]
private static extern bool LookupPrivilegeValueA(
    [InAttribute] 
    [MarshalAsAttribute(UnmanagedType.LPStr)] 
    string lpSystemName,
    [InAttribute] 
    [MarshalAsAttribute(UnmanagedType.LPStr)] 
    string lpName,
    [OutAttribute] 
    out LUID lpLuid);

[DllImportAttribute("advapi32.dll", EntryPoint = "AdjustTokenPrivileges")]
[return: MarshalAsAttribute(UnmanagedType.Bool)]
private static extern bool AdjustTokenPrivileges(
    [InAttribute()] 
    IntPtr TokenHandle,
    [MarshalAsAttribute(UnmanagedType.Bool)] 
    bool DisableAllPrivileges,
    [InAttribute()] 
    ref TOKEN_PRIVILEGES NewState,
    uint BufferLength,
    IntPtr PreviousState,
    IntPtr ReturnLength);

[DllImport("advapi32.dll", CharSet = CharSet.Auto)]
private static extern int SetNamedSecurityInfo(
    string pObjectName,
    SE_OBJECT_TYPE ObjectType,
    SECURITY_INFORMATION SecurityInfo,
    IntPtr psidOwner,
    IntPtr psidGroup,
    IntPtr pDacl,
    IntPtr pSacl);

[DllImport("Advapi32.dll", EntryPoint = "SetEntriesInAclA",
 CallingConvention = CallingConvention.Winapi,
 SetLastError = true, CharSet = CharSet.Ansi)]
private static extern uint SetEntriesInAcl(
    int CountofExplicitEntries,
    ref EXPLICIT_ACCESS ea,
    uint OldAcl,
    ref IntPtr NewAcl);
.NET | C# | PInvoke | Security | Win32 API
Saturday, November 14, 2009 2:36:46 AM (GMT Standard Time, UTC+00:00)  #   |  Comments [0]  |  Trackback
Sunday, October 11, 2009

I’m working on an application where I’m sending output to a console window. If the output is an integer or double I wanted the print function to perform special formatting. For everything else just call .ToString(). Page 115 in Expert F# shows an example of how to do this sort of thing with pattern matching, here is an example (Stripped down for clarity):

let Print (t:obj) =
    let text =
        match t with
        | :? int -> (t :?> int).ToString("#,###")
        | :? double -> (t :?> double).ToString("#,###.0")
        | _ -> t.ToString()
    ...
    Console.Write(text)

Update: Like Don mentioned in the comments there is a much more succinct way to write this using “:? int as i”. Thanks Don!

let Print (t:obj) =
    let text =
        match t with
        | :? int as t -> t.ToString("#,###")
        | :? double as t -> t.ToString("#,###.0")
        | _ -> t.ToString()
    ...
    Console.Write(text)

A few points:

  1. The compiler complained that I didn’t have a type annotation on the parameter. Not sure why this is but book shows that annotating it as an obj does the trick.
  2. The :? <type> construct looks at the type of the value.
  3. The :?> operator casts the value down to a particular type.
.NET | F#
Sunday, October 11, 2009 6:39:53 PM (GMT Daylight Time, UTC+01:00)  #   |  Comments [2]  |  Trackback
Saturday, October 10, 2009

We have a number of Windows Services in our infrastructure, all of which have a frequency in their configuration. Originally this frequency was in milliseconds but this is a real pain since when you set or read the configuration you are always doing the math between milliseconds and hours/minutes/seconds. Then is occurred that we could probably use a TimeSpan in the configuration to represent frequency instead of an integer of milliseconds. The .NET configuration API has a built in converter for the TimeSpan class so all you have to do is set the configuration property type to TimeSpan and your good to go!

Here is the configuration class:

public class Section : ConfigurationSection
{
    private const string FREQUENCY = "frequency";

    [ConfigurationProperty(FREQUENCY)]
    public TimeSpan Frequency
    {
        get { return (TimeSpan)this[FREQUENCY]; }
    }
}

Here is the configuration, much easier to read/set:

<company>
  <services>
    <someService frequency="00:00:30"/>
  </services>
</company>

And the usage:

private Common.Timers.Timer _processTimer =
        new Common.Timers.Timer(
            Configuration.Manager.Current.SomeService.Frequency.TotalMilliseconds,
            Common.Timers.Timer.TimerElapseStartMode.Immediate,
            Common.Timers.Timer.TimerElapseReentranceMode.NonReentrant);
Saturday, October 10, 2009 3:33:27 PM (GMT Daylight Time, UTC+01:00)  #   |  Comments [0]  |  Trackback
Friday, September 18, 2009

I needed to be able to resize a WPF window but keep the aspect ratio. After scouring the internets I found an approach that involves hooking into the window messages and scaling when the window is resized (Thanks to whoever it was that originally came up with it). The solution below is derived from that approach. It determines the aspect ratio from the original window size and maintains it.

Implement the following in the window:

Xaml:

<Window ... SourceInitialized="Window_SourceInitialized" ... >
    ...
</Window>

Code behind:

public partial class Main : Window
{
    private void Window_SourceInitialized(object sender, EventArgs ea)
    {
        WindowAspectRatio.Register((Window)sender);
    }
    ...
}

The WindowAspectRatio class:

using System;
using System.Windows;
using System.Windows.Interop;
using System.Runtime.InteropServices;
internal class WindowAspectRatio
{
    private double _ratio;

    private WindowAspectRatio(Window window)
    {
        _ratio = window.Width / window.Height;
        ((HwndSource)HwndSource.FromVisual(window)).AddHook(DragHook);
    }

    public static void Register(Window window)
    {
        new WindowAspectRatio(window);
    }

    internal enum WM
    {
        WINDOWPOSCHANGING = 0x0046,
    }

    [Flags()]
    public enum SWP
    {
        NoMove = 0x2,
    }

    [StructLayout(LayoutKind.Sequential)]
    internal struct WINDOWPOS
    {
        public IntPtr hwnd;
        public IntPtr hwndInsertAfter;
        public int x;
        public int y;
        public int cx;
        public int cy;
        public int flags;
    }

    private IntPtr DragHook(IntPtr hwnd, int msg, IntPtr wParam, IntPtr lParam, ref bool handeled)
    {
        if ((WM)msg == WM.WINDOWPOSCHANGING)
        {
            WINDOWPOS position = (WINDOWPOS)Marshal.PtrToStructure(lParam, typeof(WINDOWPOS));

            if ((position.flags & (int)SWP.NoMove) != 0 || 
                HwndSource.FromHwnd(hwnd).RootVisual == null) return IntPtr.Zero;

            position.cx = (int)(position.cy * _ratio);

            Marshal.StructureToPtr(position, lParam, true);
            handeled = true;
        }

        return IntPtr.Zero;
    }
}
.NET | WPF
Friday, September 18, 2009 4:00:41 PM (GMT Daylight Time, UTC+01:00)  #   |  Comments [0]  |  Trackback
Friday, August 07, 2009

Found an interesting post on how to develop an SSMS add-in.

Friday, August 07, 2009 2:24:32 AM (GMT Daylight Time, UTC+01:00)  #   |  Comments [0]  |  Trackback
Friday, July 31, 2009

I just had a requirement in the project I'm working on to get a data contract name and namespace from a type and found that there really isn't an easy, built in way to do it (Without actually serializing an instance of the type). After looking around with reflector I found the methods that the DataContractSerializer uses but found it was a little too complex and dangerous to try to strip the code from the framework or write my own (Especially when it comes to formulating generic type names). So I found a simple alterative which I don't really like but it works. Basically you instantiate the type in question and run it through the serializer and grab the root element name and namespace:

public class DataContractTypeInfo
{
    public DataContractTypeInfo()
    {
        Name = string.Empty;
        TypeNamespace = string.Empty;
    }

    private DataContractTypeInfo(string name, string typeNamespace)
    {
        Name = name;
        TypeNamespace = typeNamespace;
    }

    public string Name { get; private set; }
    public string TypeNamespace { get; private set; }

    public static DataContractTypeInfo Generate(Type type)
    {
        if (type.FullName.StartsWith("System.")) return new DataContractTypeInfo();
        if (type.ContainsGenericParameters) return new DataContractTypeInfo();
        DataContractSerializer serializer = new DataContractSerializer(type);
        MemoryStream objectStream = new MemoryStream();
        object instance = null;
        if (type.IsArray)
            Activator.CreateInstance(type, new object[] {0});
        else
            Activator.CreateInstance(type);
        serializer.WriteObject(objectStream, instance);
        objectStream.Position = 0;
        XDocument objectDocument = XDocument.Load(new XmlTextReader(objectStream));
        return new DataContractTypeInfo(objectDocument.Root.Name.LocalName,
            objectDocument.Root.Name.NamespaceName);
    }
}

This code took about 20 ms to get the info of a type that had about 5 members.

.NET | WCF
Friday, July 31, 2009 8:47:43 PM (GMT Daylight Time, UTC+01:00)  #   |  Comments [0]  |  Trackback
Monday, July 06, 2009

Recently I needed a regex to parse the command line. Something like this:

/param1="sfsdf  sdf sdfsdf  sdfsdf" /param2 =rstwertw /param3 = "rtwqert sdfas f"

I found a great regex on RegExLib by Richard Hauer for doing this. I made one minor tweak to allow whitespace between the name/value delimiter:

(?:\s*)(?<=[-|/])(?<name>\w*)\s*[:|=]\s*("((?<value>.*?)(?<!\\)")|(?<value>[\w]*))

Here it is in action:

string commandLineRegEx = 
    @"(?:\s*)(?<=[-|/])(?<name>\w*)\s*[:|=]\s*(""((?<value>.*?)(?<!\\)"")|(?<value>[\w]*))";
Regex regex = new Regex(commandLineRegEx);

MatchCollection matches = regex.Matches(
    "/param1=\"sfsdf  sdf sdfsdf  sdfsdf\" /param2 =rstwertw /param3 = \"rtwqert sdfas f\"");

foreach (Match match in matches)
    Console.WriteLine("{0}={1}", 
        match.Groups["name"].Value, 
        match.Groups["value"].Value);

Console.ReadKey();
image
Monday, July 06, 2009 9:51:21 PM (GMT Daylight Time, UTC+01:00)  #   |  Comments [0]  |  Trackback
Tuesday, April 21, 2009

A number of years ago I created a .NET library for a project that I was working on that enabled communication with HID devices. I posted the library in the Labs and was surprised at the response I got! Unfortunately it's not the prettiest code as it was written in haste for this project and I really haven't done anything with it since so it's in need of some TLC. I also don't really have time to commit to it now or in the near future. In light of this I've created a CodePlex project for the HID Library, committed the latest source and created a release. I'm hoping to pass this project on to others who have the time and interest to maintain/grow/support it. If you are interested please drop me a line (Click the little envelope in the upper right corner of the page next to "Sign In" or just leave a comment). The new CodePlex url is http://hidlibrary.codeplex.com/.


"thank you for your support"

 

image
Tuesday, April 21, 2009 4:11:58 PM (GMT Daylight Time, UTC+01:00)  #   |  Comments [1]  |  Trackback
Wednesday, April 08, 2009

Matthew Podwysocki's blog has been a great help to me in my quest to learn F# and FP concepts. He has a series of beginner posts (F# 101) that are very helpful:

Part 1 - Basic functional programming
Part 2 - Currying and Tuples
Part 3 - Scope, Recursion and Anonymous Functions
Part 4 - History of F#, Operators and Lists
Part 5 - Pattern Matching
Part 6 - Lazy Evaluation
Part 7 - Creating Types
Part 8 - Mutables and Reference Cells
Part 9 - Control Flow

I took the liberty of converting the posts into a PDF if you just want to print them all out and kill a few trees:

Adventures in FSharp - Podwysocki.pdf (364.22 KB)
.NET | F#
Wednesday, April 08, 2009 2:56:53 PM (GMT Daylight Time, UTC+01:00)  #   |  Comments [0]  |  Trackback
Wednesday, February 25, 2009

Checking for a specific .NET version is fairly simple with Wix. The following fragment illustrates how to make .NET 3.5 an installation requirement. Two things to note are: 1) The value is prefixed with a pound sign because it is a DWORD in the registry. The RegistrySearch element will prefix values differently depending on the registry data type. 2) The condition is only evaluated when installing, not uninstalling (By using the "Installed" variable). If for some reason your required version of .NET gets uninstalled you still want to be able to uninstall your app.

<Wix ... >
  <Product ... >
    <Package ... />

    <Property Id="NET_FRAMEWORK_INSTALLED">
      <RegistrySearch 
        Id='NetFrameworkCheck' 
        Type='raw'
        Root='HKLM' 
        Key='SOFTWARE\Microsoft\NET Framework Setup\NDP\v3.5' 
        Name='Install' />
    </Property>

    <Condition 
      Message=".NET Framework 3.5 is not installed, go pound salt.">
      Installed OR (NET_FRAMEWORK_INSTALLED = "#1" AND NOT Installed)
    </Condition>

    Do other things...
    
  </Product>
</Wix>
You can also check the exact version by looking at the "Version" reg value. Since this value is a string it will not be prefixed (Unless the first character is a pound sign, see the docs for more info).
.NET | WiX
Wednesday, February 25, 2009 1:20:56 AM (GMT Standard Time, UTC+00:00)  #   |  Comments [0]  |  Trackback
Wednesday, February 18, 2009

The DateTime.ParseExact() method has come in handy on a number of occasions. I really wish there was something similar for strings as sometimes you need to grab specific components of a string. You can use regex directly but that seems a little cumbersome. So here is an extension method that works like the DateTime.ParseExact() but returns an array of strings.

string value = "2/17/2009 10:57:42 AM...Executing file 26 of 81 files";
string[] parts = value.ParseExact("{0}...Executing file {1} of {2} files");
foreach (string part in parts)
    Console.WriteLine(part);
Console.ReadKey();
image 

Implementation:

public static class StringExtensions
{
    public static string[] ParseExact(
        this string data, 
        string format)
    {
        return ParseExact(data, format, false);
    }

    public static string[] ParseExact(
        this string data, 
        string format, 
        bool ignoreCase)
    {
        string[] values;

        if (TryParseExact(data, format, out values, ignoreCase))
            return values;
        else
            throw new ArgumentException("Format not compatible with value.");
    }

    public static bool TryExtract(
        this string data, 
        string format, 
        out string[] values)
    {
        return TryParseExact(data, format, out values, false);
    }

    public static bool TryParseExact(
        this string data, 
        string format, 
        out string[] values, 
        bool ignoreCase)
    {
        int tokenCount = 0;
        format = Regex.Escape(format).Replace("\\{", "{");

        for (tokenCount = 0; ; tokenCount++)
        {
            string token = string.Format("{{{0}}}", tokenCount);
            if (!format.Contains(token)) break;
            format = format.Replace(token,
                string.Format("(?'group{0}'.*)", tokenCount));
        }

        RegexOptions options = 
            ignoreCase ? RegexOptions.IgnoreCase : RegexOptions.None;

        Match match = new Regex(format, options).Match(data);

        if (tokenCount != (match.Groups.Count - 1))
        {
            values = new string[] { };
            return false;
        }
        else
        {
            values = new string[tokenCount];
            for (int index = 0; index < tokenCount; index++)
                values[index] = 
                    match.Groups[string.Format("group{0}", index)].Value;
            return true;
        }
    }
}
.NET | C#
Wednesday, February 18, 2009 7:11:40 AM (GMT Standard Time, UTC+00:00)  #   |  Comments [0]  |  Trackback
Wednesday, January 21, 2009

I have been reading The .NET Developer's Guide to Windows Security and it mentioned that as of .NET 1.1 a calling threads principal is not automatically propagated to a thread spun off by the ThreadPool using the QueueUserWorkItem method; it has to be manually set. Looks like this has changed as of .NET 2.0 as the following test shows. It automatically propagates when the ThreadPool initiates a call with a thread in the pool, when using the APM and manually creating threads:

 

// Set the executing threads principle\identity
Thread.CurrentPrincipal = new GenericPrincipal(
    new GenericIdentity("Louis De Broglie"), null);

Action<string> writeInfo = new Action<string>((n) =>
    Console.WriteLine(string.Format("{0} - {1}", n,
    Thread.CurrentPrincipal.Identity.Name)));

// Test the executing thread
writeInfo.Invoke("Main Thread");

// Test queueing a worker item on the thread pool
ThreadPool.QueueUserWorkItem(x => 
    writeInfo.Invoke("Thread Pool Initiated Thread"));

// Test making an async call
Action asyncCall = new Action(() => 
    writeInfo.Invoke("Async Initiated Thread"));

asyncCall.BeginInvoke(ar => asyncCall.EndInvoke(ar), null);

// Test manually creating a thread
new Thread(() => 
    {
        writeInfo.Invoke("Manually Created Thread");

        // Set a new principal
        Thread.CurrentPrincipal = new GenericPrincipal(
            new GenericIdentity("Erwin Schrödinger"), null);

        writeInfo.Invoke("Manually Created Thread, new identity");

        // Test queueing a worker item on the thread pool
        ThreadPool.QueueUserWorkItem(x =>
            writeInfo.Invoke("Thread Pool Initiated Thread from a new Thread"));

        // Test making an async call
        asyncCall = new Action(() =>
            writeInfo.Invoke("Async Initiated Thread from a new Thread"));

        asyncCall.BeginInvoke(ar => asyncCall.EndInvoke(ar), null);

        // Test manually creating a thread from a thread
        new Thread(() => 
            writeInfo.Invoke("Manually Created Thread from a new Thread")
            ).Start();
    }).Start();

Console.ReadKey();
 

image

Wednesday, January 21, 2009 12:08:51 AM (GMT Standard Time, UTC+00:00)  #   |  Comments [0]  |  Trackback
Tuesday, January 20, 2009

A few notes about identities from the standpoint of ASP.NET:

WindowsIdentity.GetCurrent() - This WindowsIdentity represents the OS thread identity or more specifically an account token (Not to be confused with Thread.CurrentPrincipal.Identity which is just a simple container for your convenience). This token represents a LSA (Local Security Authority) or Active Directory account. This will always be the process identity set in the App Pool configuration (AKA the App Pool identity) unless you are doing impersonation. This is the actual identity (Or Windows account token) that code runs as. As far as Windows Security is concerned this is the only identity that matters. The only way to "change" this is to do impersonation which is done on a thread by thread basis and should be reverted ASAP to the original identity to avoid a security hole (And resource leak because of unclosed handles). New threads always inherit the process token regardless of if the creating thread is impersonating another user (Something to remember when doing async calls in ASP.NET while impersonating).

Thread.CurrentPrinciple.Identity & HttpContext.Current.User.Identity - These are set by ASP.NET during the authentication phase and will either be...

  1. ...an Anonymous WindowsIdentity when doing just anonymous auth
  2. ...a GenericIdentity when doing forms auth (Which implies anon auth).
  3. ...a custom identity when doing custom auth (Which implies anon auth).
  4. ...a WindowsIdentity representing the authenticating user when doing any other types of auth such as Basic, Windows or Challenge-Response. These two properties actually point to the same instance of the identity. This will be the same as the OS thread only when you are doing impersonation.

Request.LogonUserIdentity - This is a WindowsIdentity representing the authenticating user, regardless of the authentication type. This will be the same as the OS thread only when you are doing impersonation. It will be the same as Thread.CurrentPrinciple.Identity & HttpContext.Current.User.Identity only when you are not doing anonymous authentication.

Here is a listing of the identities set by IIS7 auth in a number of configurations. They remained the same in both integrated and classic pipeline modes.

Anonymous (Specific User, which happens to be IUSR)

Source Type Return Type Authentication Type Identity Name
WindowsIdentity.GetCurrent() WindowsIdentity System.Security.Principal.WindowsIdentity Negotiate NT AUTHORITY\NETWORK SERVICE
Thread.CurrentPrincipal.Identity IIdentity System.Security.Principal.WindowsIdentity    
HttpContext.Current.User.Identity IIdentity System.Security.Principal.WindowsIdentity    
Request.LogonUserIdentity WindowsIdentity System.Security.Principal.WindowsIdentity   NT AUTHORITY\IUSR

Anonymous (Specific User, which happens to be IUSR), Impersonation

Source Type Return Type Authentication Type Identity Name
WindowsIdentity.GetCurrent() WindowsIdentity System.Security.Principal.WindowsIdentity Negotiate NT AUTHORITY\IUSR
Thread.CurrentPrincipal.Identity IIdentity System.Security.Principal.WindowsIdentity    
HttpContext.Current.User.Identity IIdentity System.Security.Principal.WindowsIdentity    
Request.LogonUserIdentity WindowsIdentity System.Security.Principal.WindowsIdentity   NT AUTHORITY\IUSR

Anonymous (App Pool Identity, which happens to be NETWORK SERVICE)

Source Type Return Type Authentication Type Identity Name
WindowsIdentity.GetCurrent() WindowsIdentity System.Security.Principal.WindowsIdentity Negotiate NT AUTHORITY\NETWORK SERVICE
Thread.CurrentPrincipal.Identity IIdentity System.Security.Principal.WindowsIdentity    
HttpContext.Current.User.Identity IIdentity System.Security.Principal.WindowsIdentity    
Request.LogonUserIdentity WindowsIdentity System.Security.Principal.WindowsIdentity   NT AUTHORITY\NETWORK SERVICE

Anonymous (App Pool Identity, which happens to be NETWORK SERVICE), Impersonation

Source Type Return Type Authentication Type Identity Name
WindowsIdentity.GetCurrent() WindowsIdentity System.Security.Principal.WindowsIdentity Negotiate NT AUTHORITY\NETWORK SERVICE
Thread.CurrentPrincipal.Identity IIdentity System.Security.Principal.WindowsIdentity    
HttpContext.Current.User.Identity IIdentity System.Security.Principal.WindowsIdentity    
Request.LogonUserIdentity WindowsIdentity System.Security.Principal.WindowsIdentity   NT AUTHORITY\NETWORK SERVICE

Anonymous, Physical Path Credentials, LSA User

Source Type Return Type Authentication Type Identity Name
WindowsIdentity.GetCurrent() WindowsIdentity System.Security.Principal.WindowsIdentity Negotiate NT AUTHORITY\NETWORK SERVICE
Thread.CurrentPrincipal.Identity IIdentity System.Security.Principal.WindowsIdentity    
HttpContext.Current.User.Identity IIdentity System.Security.Principal.WindowsIdentity    
Request.LogonUserIdentity WindowsIdentity System.Security.Principal.WindowsIdentity   HOST\username

Anonymous, Impersonation, Physical Path Credentials, LSA User

Source Type Return Type Authentication Type Identity Name
WindowsIdentity.GetCurrent() WindowsIdentity System.Security.Principal.WindowsIdentity NTLM HOST\username
Thread.CurrentPrincipal.Identity IIdentity System.Security.Principal.WindowsIdentity    
HttpContext.Current.User.Identity IIdentity System.Security.Principal.WindowsIdentity    
Request.LogonUserIdentity WindowsIdentity System.Security.Principal.WindowsIdentity   HOST\username

Basic, LSA User (Same for AD user)

Source Type Return Type Authentication Type Identity Name
WindowsIdentity.GetCurrent() WindowsIdentity System.Security.Principal.WindowsIdentity Negotiate NT AUTHORITY\NETWORK SERVICE
Thread.CurrentPrincipal.Identity IIdentity System.Security.Principal.WindowsIdentity Basic HOST\username
HttpContext.Current.User.Identity IIdentity System.Security.Principal.WindowsIdentity Basic HOST\username
Request.LogonUserIdentity WindowsIdentity System.Security.Principal.WindowsIdentity Basic HOST\username

Impersonation, Basic Auth, and LSA User (Classic Pipeline Mode or Integrated Pipeline and validateIntegratedModeConfiguration=false)

Source Type Return Type Authentication Type Identity Name
WindowsIdentity.GetCurrent() WindowsIdentity System.Security.Principal.WindowsIdentity NTLM HOST\username
Thread.CurrentPrincipal.Identity IIdentity System.Security.Principal.WindowsIdentity Basic HOST\username
HttpContext.Current.User.Identity IIdentity System.Security.Principal.WindowsIdentity Basic HOST\username
Request.LogonUserIdentity WindowsIdentity System.Security.Principal.WindowsIdentity Basic HOST\username

Impersonation, Basic Auth, and AD User (Classic Pipeline Mode or Integrated Pipeline and validateIntegratedModeConfiguration=false)

Source Type Return Type Authentication Type Identity Name
WindowsIdentity.GetCurrent() WindowsIdentity System.Security.Principal.WindowsIdentity Kerberos DOMAIN\username
Thread.CurrentPrincipal.Identity IIdentity System.Security.Principal.WindowsIdentity Basic DOMAIN\username
HttpContext.Current.User.Identity IIdentity System.Security.Principal.WindowsIdentity Basic DOMAIN\username
Request.LogonUserIdentity WindowsIdentity System.Security.Principal.WindowsIdentity Basic DOMAIN\username

Forms, Anonymous Auth

Source Type Return Type Authentication Type Identity Name
WindowsIdentity.GetCurrent() WindowsIdentity System.Security.Principal.WindowsIdentity Negotiate NT AUTHORITY\NETWORK SERVICE
Thread.CurrentPrincipal.Identity IIdentity System.Security.Principal.GenericIdentity    
HttpContext.Current.User.Identity IIdentity System.Security.Principal.GenericIdentity    
Request.LogonUserIdentity WindowsIdentity System.Security.Principal.WindowsIdentity   NT AUTHORITY\IUSR
 
Windows, LSA User (Same for AD user)
 
Source Type Return Type Authentication Type Identity Name
WindowsIdentity.GetCurrent() WindowsIdentity System.Security.Principal.WindowsIdentity Negotiate NT AUTHORITY\NETWORK SERVICE
Thread.CurrentPrincipal.Identity IIdentity System.Security.Principal.WindowsIdentity Negotiate HOST\username
HttpContext.Current.User.Identity IIdentity System.Security.Principal.WindowsIdentity Negotiate HOST\username
Request.LogonUserIdentity WindowsIdentity System.Security.Principal.WindowsIdentity Negotiate HOST\username

Impersonation, Windows Auth, and LSA User (Classic Pipeline Mode or Integrated Pipeline and validateIntegratedModeConfiguration=false)

Source Type Return Type Authentication Type Identity Name
WindowsIdentity.GetCurrent() WindowsIdentity System.Security.Principal.WindowsIdentity NTLM HOST\username
Thread.CurrentPrincipal.Identity IIdentity System.Security.Principal.WindowsIdentity Negotiate HOST\username
HttpContext.Current.User.Identity IIdentity System.Security.Principal.WindowsIdentity Negotiate HOST\username
Request.LogonUserIdentity WindowsIdentity System.Security.Principal.WindowsIdentity Negotiate HOST\username

Impersonation, Windows Auth, and AD User (Classic Pipeline Mode or Integrated Pipeline and validateIntegratedModeConfiguration=false)

Source Type Return Type Authentication Type Identity Name
WindowsIdentity.GetCurrent() WindowsIdentity System.Security.Principal.WindowsIdentity Kerberos DOMAIN\username
Thread.CurrentPrincipal.Identity IIdentity System.Security.Principal.WindowsIdentity Negotiate DOMAIN\username
HttpContext.Current.User.Identity IIdentity System.Security.Principal.WindowsIdentity Negotiate DOMAIN\username
Request.LogonUserIdentity WindowsIdentity System.Security.Principal.WindowsIdentity Negotiate DOMAIN\username

.NET | IIS 7
Tuesday, January 20, 2009 8:46:56 PM (GMT Standard Time, UTC+00:00)  #   |  Comments [2]  |  Trackback
Friday, January 02, 2009

While reading CLR via C# I picked up a couple of interesting tidbits about the using block that I never realized. First you can declare/instantiate multiple objects as long as they are of the same type and second you can pass in objects that have been declared outside the block. Not sure how useful these would be but interesting none the less. I think more useful would be allowing the developer to declare/instantiate multiple objects of different types.

class Program
{
    static void Main(string[] args)
    {
        Stuff stuff = new Stuff();

        using (
            Stuff stuff1 = new Stuff(),
            stuff2 = new Stuff(),
            stuff3 = stuff)
        {
        }
    }
}

class Stuff : IDisposable
{
    #region IDisposable Members

        public void Dispose() { }

    #endregion
}
.NET | .NET 3.5 | C#
Friday, January 02, 2009 10:23:04 PM (GMT Standard Time, UTC+00:00)  #   |  Comments [1]  |  Trackback
Thursday, October 30, 2008

The latest version of the Enterprise Library can be downloaded here. I'm happy to find the bug where the XmlLogFormatter was not escaping invalid characters has been fixed!

Thursday, October 30, 2008 2:39:12 AM (GMT Standard Time, UTC+00:00)  #   |  Comments [0]  |  Trackback
Tuesday, October 28, 2008

Adding custom token handlers to the LAB TextFormatter is fairly simple. The following formatter adds an "arrow" token (" --> ") to  the formatter.

using Microsoft.Practices.EnterpriseLibrary.Common.Configuration;
using Microsoft.Practices.EnterpriseLibrary.Logging.Configuration;
using Microsoft.Practices.EnterpriseLibrary.Logging.Formatters;

namespace MyLibrary.Logging.EnterpriseLibrary
{
    [ConfigurationElementType(typeof(CustomFormatterData))]
    public class CustomTextFormatter : TextFormatter
    {
        #region Private Fields

            private static readonly Dictionary<string, TokenHandler<LogEntry>> tokenHandlers =
                new Dictionary<string, LogEntry>>();

        #endregion

        #region Constructors

            static CustomTextFormatter()
            {
                tokenHandlers["arrow"] = GenericTextFormatter<LogEntry>
                    .CreateSimpleTokenHandler(" --> ");
            }

            public CustomTextFormatter(NameValueCollection parameters)
                : this(parameters.Get("template")) { }

            public CustomTextFormatter() : this(null, tokenHandlers) { }

            public CustomTextFormatter(string template) : this(template, tokenHandlers) { }

            protected CustomTextFormatter(string template, Dictionary<string, TokenHandler<LogEntry>>
                extraTokenHandlers) : base(template, extraTokenHandlers) { }

        #endregion    
    }
}

A few things to note: 1) If you want to define the formatter in configuration, you must add the CustomFormatterData attribute to the class. Don't try to add the the TextFormatterData attribute as I did (Because I did not pay close enough attention to the documentation!) and spend hours in Reflector trying to figure out why a TextFormatter object is created and not the derived type... This, by the way, has to do with the Assembler attribute on the nnnFormatterData class. This attribute references an assembler class that will instantiate the specific type (In this case the XmlLogFormatter), NOT the one specified in configuration. You could also define your own custom FormatterData and Assembler classes but the using the CustomFormatterData class is much simpler. 2) Again, if you want to define the formatter in configuration, you will need to add the constructor that accepts the NameValueCollection of configuration parameters. You can then grab the template parameter from this collection. 3) Create a static list of handlers that gets initialized once by a static constructor. There is no need to keep recreating these objects every time the formatter is created.

To define the formatter in configuration, specify the class reference like you normally would, just point to the new class. You can now use the token you defined in your class.

<formatters>
  <add 
    name="EventLogFormatter" 
    template="Timestamp{arrow}{timestamp}&#xD;&#xA;Message{arrow}{message}&#xD;&#xA; ..."
    type="MyLibrary.Logging.EnterpriseLibrary.CustomTextFormatter, MyLibrary"
     />
</formatters>

The result is as follows:

image

Now obviously you'll want to do more than add a simple token. In our next installment we will show you how to add a parameterized token. See you next time.

Tuesday, October 28, 2008 4:13:34 AM (GMT Standard Time, UTC+00:00)  #   |  Comments [0]  |  Trackback
Wednesday, October 22, 2008

I have been having XmlTraceListener woes... None of which are showstoppers just major time wasters! The following bug is fixed as of version 4.1! The first of which has to do the message. The message is not escaped and/or CDATA qualified. So if you have an ampersand or greater/less than sign in the message it will throw this cryptic error:

An error occurred while parsing EntityName. Line x, position y.

I ended up manually running the log entry object through the Format() method on the XmlLogFormatter class to get the raw xml and see what exactly it was complaining about. Sure enough there was an ampersand. Adding an extension method to the string class and manually escaping the LogEntry message alleviated this to some degree. Bad thing is though, the message is escaped for all listeners and you probably don't want to see HTML entities in your event log entry or email message. I think the only way around this would be to write your own xml trace listener.

namespace MyApp.Runtime.Extensions
{
    public static class String
    {
        public static string EscapeUnsafeXmlCharacters(this string value)
        {
            return value.Replace("<", "&lt;").Replace(">", "&gt;").Replace("&", "&amp;");
        }
    }
}

Issue #2 has to do with where the log file is saved. The FlatFileTraceListner actually saves the log file relative to the application root (Where the .config file is). Take a look at the RootFileNameAndEnsureTargetFolderExists() method in the FormattedTextWriterTraceListener class (The FlatFileTraceListener's base class). Before it passes the filename to it's base class constructor, it runs it through this method. The XmlTraceListener on the other hand does not follow this pattern which had me going nuts trying to figure out what I was doing wrong (Thinking that it just wasn't saving at all). I wasn't getting any errors from the XmlTraceListener (More on this below) so I started to get the feeling that perhaps it was writing to the log but just not where I expected. So I fired up Process Monitor and didn't see any log writes. Then I switched the app (It was a web application project BTW) to use the built in web server instead of IIS. Ran everything again and voilà:

image

So it was saving it somewhere else, but only when running under the built in web server. Looking at the code in reflector you can see that, unlike the FormattedTextWriterTraceListener, the XmlWriterTraceListener does not modify the path to be the application root before it passes it to it's base class constructor. So the directory ends up being that of the entry assembly. Bottom line is you have to supply an explicit path when you're using the XmlTraceListener in a web application.

This leads me to the third oddity; where it would save running under the builtin web server but not IIS. The base class, TextWriterTraceListener, calls the EnsureWriter() method (Shown below) before writing to the file. If it returns true it writes the entry, otherwise it doesn't. Notice that if there is a UnauthorizedAccessException it just returns false and then subsequently, in the calling Write method, silently skips writing. When I was using IIS as my web server (And the code was running as the Network Service account) I didn't see any exceptions and no log writes were showing up in Process Monitor. Which was very confusing! But when I switched over to using the built in web server (Which was obviously running as my interactive account) I saw the log writes. So when it was running under the Network Service account it obviously did not have permissions to save the log file to wherever it was trying to save it and no exception was raised... Very confusing behavior this. Reminds me of the advice in Jeffrey Richter's CLR Via C# book not to ever swallow exceptions! So keep that in mind, if you don't see any errors and log writes with the XmlTraceListner, it may be permissions and/or path related.

Well, hopefully this wasn't too long winded and hopefully it clears up some oddities with the XmlTraceListener.

public class TextWriterTraceListener : TraceListener
{
    public override void Write(string message)
    {
        if (this.EnsureWriter())
        {
            if (base.NeedIndent)
            {
                this.WriteIndent();
            }
            this.writer.Write(message);
        }
    }
    internal bool EnsureWriter()
    {
        bool flag = true;
        if (this.writer == null)
        {
            flag = false;
            if (this.fileName == null)
            {
                return flag;
            }
            Encoding encodingWithFallback = GetEncodingWithFallback(new UTF8Encoding(false));
            string fullPath = Path.GetFullPath(this.fileName);
            string directoryName = Path.GetDirectoryName(fullPath);
            string fileName = Path.GetFileName(fullPath);
            for (int i = 0; i < 2; i++)
            {
                try
                {
                    this.writer = new StreamWriter(fullPath, true, encodingWithFallback, 0x1000);
                    flag = true;
                    break;
                }
                catch (IOException)
                {
                    fileName = Guid.NewGuid().ToString() + fileName;
                    fullPath = Path.Combine(directoryName, fileName);
                }
                catch (UnauthorizedAccessException)
                {
                    break;
                }
                catch (Exception)
                {
                    break;
                }
            }
            if (!flag)
            {
                this.fileName = null;
            }
        }
        return flag;
    }

    // Other members removed for brevity...
}
Wednesday, October 22, 2008 4:54:38 AM (GMT Daylight Time, UTC+01:00)  #   |  Comments [0]  |  Trackback
Wednesday, October 08, 2008

If you have a host name set in your hosts file pointing to your loop back address and you are trying to connect to your local SQL Server instance with this host name using Windows Auth (SSPI) you may receive one of the following errors depending on how you have things configured:

"Login failed for user ''. The user is not associated with a trusted SQL Server connection."

Or

Login failed for user 'NT AUTHORITY\ANONYMOUS LOGON'

There could be a number of things causing this error (here, here, here and here) but it in the specific scenario noted above it's probably that an alias is not set for the SQL Server. I'm not sure exactly why or how this works or why the above scenario would have an issue but creating an alias seems to resolve it. In fact if you specify "localhost" or the loopback address as the server name it works fine (Without the alias). Also when connecting to a remote SQL Server with a host name defined in the hosts file it works fine as well. hmmmm.... I really couldn't find any info on this specific scenario and creating the alias seems to resolve it so I finally gave up. If you have any more info on why this would happen please leave a comment. You can set the alias as follows:

  1. 1) Open the SQL Server Configuration Manager under Start|Programs| Microsoft SQL Server 20xx| Configuration Tools| SQL Server Configuration Manager.
  2. 2) Under the SQL Native Client Configuration node select Aliases.
  3. 3) Right-click and select “New Alias…”.
  4. 4) Enter the following information and press OK:
    1. Alias Name: sql.somedomain.com
    2. Port No: 1433
    3. Protocol: TCP/IP
    4. Server: localhost

The connection string would be as follows:

server=sql.somedomain.com;database=SomeDatabase;Integrated Security=SSPI

Wednesday, October 08, 2008 9:19:05 PM (GMT Daylight Time, UTC+01:00)  #   |  Comments [0]  |  Trackback
Saturday, July 26, 2008

I'm working on a media center application right now that I want to run kiosk style; topmost and fullscreen. This is amazingly simple to do in WPF, simply set the Topmost property to true, the WindowState property to Maximized and the WindowStyle to None.

.NET | .NET 3.5 | C# | WPF
Saturday, July 26, 2008 1:21:30 AM (GMT Daylight Time, UTC+01:00)  #   |  Comments [0]  |  Trackback
Tuesday, June 17, 2008

Telerik has a very nice online code converter here. I've recently been converting VB.NET code to C# and this tool seems to be able to convert code that many of the others out there cannot. The only thing it seems to miss is the parens when converting indexer callers. So it doesn't convert the VB.NET myDataReader("Name") to the C# myDataReader["Name"]. Not a huge deal though.

Tuesday, June 17, 2008 7:54:22 PM (GMT Daylight Time, UTC+01:00)  #   |  Comments [0]  |  Trackback

Rick Strahl's .NET Rocks presentation on AJAX and jQuery (that he mentioned in May) has been published. Check it out.

.NET | AJAX | jQuery
Tuesday, June 17, 2008 4:49:31 PM (GMT Daylight Time, UTC+01:00)  #   |  Comments [0]  |  Trackback
Wednesday, May 21, 2008

Reachmail (the company I work for) is looking for a senior ASP.NET/C# developer. If you are a progressive developer who is a true geek, really understands OO and patterns and is looking for a change, browse to the link below to apply. We are currently located in Naperville but will be moving to downtown Chicago the 1st of July (Within walking distance of Union and Ogilvie). We really need someone who knows their stuff and doesn't require hand holding. Although we need someone who is able to work independently we don't want an independent person (IE "cowboy"); they must be a team player or they wont last long. We have a relaxed environment and a lot of growth.

The software is a permission based email marketing SAAS written primarily in classic ASP with a SQL Server 2005 back end. Parts of the system are written in VB.NET and C#. One of our goals is to get the application converted over to ASP.NET/C# and rearchitect much of the system. All of our existing .NET code has been upgraded to 3.5 and new development is obviously in 3.5 and C#.

 

.NET | C#
Wednesday, May 21, 2008 4:42:58 PM (GMT Daylight Time, UTC+01:00)  #   |  Comments [0]  |  Trackback
Wednesday, November 14, 2007

Evidently the aspnet_compiler.exe does not care about .refresh files (From my tests and what I read on the internets). It would be nice if it did as it would reduce the steps needed to build a WSP (Web Site Project) on a build server. I ended up just manually copying the assemblies into the bin folder before the build as follows in this nant script:

<mkiisdir dirpath="..\BabelFish.ServiceHost.Web" vdirname="BabelFish.ServiceHost.Web" />

<copy todir="..\BabelFish.ServiceHost.Web\bin">
    <
fileset basedir="..\BabelFish.Services\bin">
        <
include name="*.dll" />
    </
fileset>
</
copy>

<exec program="C:\WINDOWS\Microsoft.NET\Framework\${framework.version}\aspnet_compiler.exe" useruntimeengine="true">
    <
arg value="-p" />
    <
arg value="..\BabelFish.ServiceHost.Web" />
    <
arg value="-v" />
    <
arg value="BabelFish.ServiceHost.Web" />
</
exec>

<deliisdir vdirname="BabelFish.ServiceHost.Web" />

Wednesday, November 14, 2007 6:33:25 PM (GMT Standard Time, UTC+00:00)  #   |  Comments [0]  |  Trackback
Friday, November 09, 2007

I have been wanting to dig into F# for quite some time and finally got an opportunity. My first stab at it implements the calculation of kinetic energy given a weight in lbs, speed in mph and output in kJ. Pretty basic, but ya gotta start some where right? :)

KineticEnergy.zip (.95 KB)

// Get info from the user
do Printf.printf "Enter the weight (LBS): "
let m = read_line()
do Printf.printf "Enter the velocity (MPH): "
let mph = read_line()

// Pound to kilogram conversion
let kg lbs = lbs / 2.2

// Miles/h to Meters/s conversion
let mps mph = (((mph * 1.6) * 1000.0) / 60.0) /60.0

// Kinetic energy calculation
let Ek m v = (0.5 * m * (v * v)) / 1000.0

// Show me the money
do Printf.printf "\nEk = %fkJ\n\n" (Ek (kg (float_of_string m)) (mps (float_of_string mph)))

// Wait! Let me see the answer...
do Printf.printf "Press enter to continue..."
let x = read_line()

Friday, November 09, 2007 9:52:37 PM (GMT Standard Time, UTC+00:00)  #   |  Comments [0]  |  Trackback
Tuesday, October 09, 2007

I love WiX, but I hate that you have to specify the id's and short filenames! This really slows you down when you have a lot of files to add. I have read that these may be optional in v3 and auto generated by the compiler. Until then you could use this Visual Studio addin that that allows you to randomly generate and insert id's and short filenames as well as insert some common tags with the aformentioned attributes randomly filled in. n-joy!

Visual Studio 2005

Installer: WiXHelperAddin.EXE (217.21 KB)
Source: WiXHelperSource.zip (258.91 KB)

Visual Studio 2008

Installer: WiXHelperAddin2008.EXE (217 KB)
Source: WiXHelperSource2008.zip (63.89 KB)

PS: Also, check out the GUID inserter (Which also appears in the image below...); this is very helpful for WiX development!

image

Tuesday, October 09, 2007 2:41:54 AM (GMT Daylight Time, UTC+01:00)  #   |  Comments [0]  |  Trackback

I do this often enough to forget how to do it (And where I've seen how to do it!). Rick Strahl has a nice post about adding icons to custom Visual Studio addins; the about box icon and the icons that appear in menus.

http://www.west-wind.com/WebLog/posts/3862.aspx

Tuesday, October 09, 2007 1:42:59 AM (GMT Daylight Time, UTC+01:00)  #   |  Comments [0]  |  Trackback
Tuesday, September 18, 2007

Here is a simple method to invert an HTML color:

private static string InvertHTMLColor(string htmlColor)

{

htmlColor = htmlColor.Replace("#", string.Empty).Trim();

if (string.IsNullOrEmpty(htmlColor) || htmlColor.Length != 6)

     throw new ArgumentException("Invalid HTML color.");

return string.Format("#{0}{1}{2}",

     InvertChannel(htmlColor.Substring(0, 2)),

     InvertChannel(htmlColor.Substring(2, 2)),

     InvertChannel(htmlColor.Substring(4, 2)));

}

private static string InvertChannel(string channel)

{

channel = channel.Trim();

if (string.IsNullOrEmpty(channel) || channel.Length != 2)

     throw new ArgumentException("Invalid color channel.");

int a = int.Parse(channel.Substring(0, 1), System.Globalization.NumberStyles.HexNumber);

int b = int.Parse(channel.Substring(1, 1), System.Globalization.NumberStyles.HexNumber);

return (255 - ((16 * a) + b)).ToString("X");

}

.NET | C#
Tuesday, September 18, 2007 5:26:53 PM (GMT Daylight Time, UTC+01:00)  #   |  Comments [1]  |  Trackback
Tuesday, August 21, 2007

Attached is the source for a simple TCP proxy server. I whipped it up pretty quickly so it probably needs some refactoring if you plan to use it in production. The server class is loosely based on the Cassini implementation. You can set the listen port and forward host/port in the app config:

<configuration>

    <appSettings>

        <add key="listenPort" value="443"/>

        <add key="forwardHost" value="wush.net"/>

        <add key="forwardPort" value="443"/>

    </appSettings>

</configuration>

image

TCPProxy.zip (24.81 KB)
Tuesday, August 21, 2007 6:42:09 PM (GMT Daylight Time, UTC+01:00)  #   |  Comments [0]  |  Trackback
Tuesday, July 17, 2007

If you are programmatically updating the value of a lookup field and it doesn't seem to update, you need to trip "dirty" flag on that field. If you don't, SP wont know that the list item needs to be updated. Basically all you do is set the field to itself and this will mark the field as dirty. Here is an example:

SPFieldLookupValueCollection lookupValues;

lookupValues = (SPFieldLookupValueCollection)listItem["MyLookupField"];

lookupValues.Add(new SPFieldLookupValue(1, "SomeLookupValue"));

// Set the lookup field back to itself to mark it dirty

listItem["MyLookupField"] = lookupValues;

listItem.Update();

Tuesday, July 17, 2007 6:35:37 AM (GMT Daylight Time, UTC+01:00)  #   |  Comments [0]  |  Trackback
Monday, July 16, 2007

The Stopwatch Class, another great .NET 2.0 feature I keep forgetting to use so I'll blog about it (And hopefully I'll remember ;)... This is a great class for performance monitoring, instead of declaring a start time and subtracting it from the end time, etc. The following snippet checks the performance difference in doing a square root and a tangent over a number of iterations. Internally, when the stopwatch is started, the ticks of the current time are set as the start timestamp. When it is stopped the start ticks and end ticks (Current time) are subtracted and the private elapsed time field (A Long) is updated. The elapsed field is only reset when you explicitly call Reset() as it is accumulative. The public Elapsed property conveniently returns a TimeSpan.

int iterations = 10000000;

 

Stopwatch stopwatch = new Stopwatch();

stopwatch.Start();

 

// Do something...

for (int index = 0; index < iterations; index++)

{ Math.Sqrt(index); }

 

stopwatch.Stop();

 

Console.WriteLine(string.Format("Square root took {0} " +

    "milliseconds for {1} iterations.",

    stopwatch.Elapsed.Milliseconds, iterations));

 

// Do something else...

stopwatch.Reset();

stopwatch.Start();

 

for (int index = 0; index < iterations; index++)

{ Math.Tan(index); }

 

stopwatch.Stop();

 

Console.WriteLine(string.Format(@"Tangent took {0} " +

    "milliseconds for {1} iterations.",

    stopwatch.Elapsed.Milliseconds, iterations));

 

Console.ReadKey();

Monday, July 16, 2007 5:19:51 PM (GMT Daylight Time, UTC+01:00)  #   |  Comments [0]  |  Trackback
Friday, July 13, 2007

I have seen a lot of posts on this and they all say something along the lines of 'simply go and set the path to the base vhd...'. Well, being a Virtual Server user, it wasn't as obvious to do as it is with VPC.  To do it in VS you need to...

1) Copy the VS 2008 VM to a folder in your VS2005 path and add it.

2) Copy the base VM (Which can be downloaded here) to a folder in your VS2005 path.

image

3) Under "Virtual Disks" click "Inspect", select the VS2008 vhd and click "Inspect".

image

4) The "Parent virtual hard disk(s)" property will show a link indicating that the parent drive could not be found. Click this link to set the location of the drive.

image

image

5) Once selected, click "Update parent path", start the VM and Login with administrator/P2ssw0rd.

Friday, July 13, 2007 5:24:51 PM (GMT Daylight Time, UTC+01:00)  #   |  Comments [0]  |  Trackback
Wednesday, July 11, 2007

Someone asked me how to enable the (Fully functioning) web designer in a class library. Honestly I think using a WAP is all you need to do. It will give you a fully functioning web designer and will generate a DLL. If you already have a class library project that you want to now add web pages and user controls too just follow the instructions here (Under the section "Creating a hybrid VSeWSS/WAP Project") but instead add the following ProjectTypeGuids element below (In green). This will turn your class library project into a WAP.

<PropertyGroup>

<Configuration Condition=" '$(Configuration)' == '' ">Debug</Configuration>

<Platform Condition=" '$(Platform)' == '' ">AnyCPU</Platform>

<ProductVersion>8.0.50727</ProductVersion>

<SchemaVersion>2.0</SchemaVersion>

<ProjectTypeGuids>{349c5851-65df-11da-9384-00065b846f21};{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}</ProjectTypeGuids>

<ProjectGuid>{26E7042F-79CF-4782-86E2-7D1C914E164A}</ProjectGuid>

<OutputType>Library</OutputType>

<AppDesignerFolder>Properties</AppDesignerFolder>

<RootNamespace>ClassLibraryWithWebDevelopment</RootNamespace>

<AssemblyName>ClassLibraryWithWebDevelopment</AssemblyName>

</PropertyGroup>

Wednesday, July 11, 2007 6:03:30 PM (GMT Daylight Time, UTC+01:00)  #   |  Comments [0]  |  Trackback
Friday, July 06, 2007

Attached is a simple contact generator (And source) that creates random contact data in CSV format. The data generated, although random, is pretty realistic as address and phone numbers correspond correctly and other values are sampled from a realistic set of data. The data generated appears as follows:

"Index","Id","FirstName","LastName","FullName","Username","Username2","Password","Email1","Email2","Phone1","Phone2","Fax1","Fax2","Address1","City1","State1","Zip1","Address2","City2","State2","Zip2"
"1","{c0d4079c-50c7-4214-a094-b09d51b9d143}","Raven","Huddle","Raven Huddle","rhuddle","raven.huddle","13af04ae","raven.huddle@aol.com","raven.huddle@earthlink.net","(303) 998-8084","(718) 229-7963","(303) 998-5593","(718) 229-4928","84596 Brimm BLVD","Boulder","CO","80302","36863 Noakes LN","Flushing","NY","11364"
"2","{74e80927-a654-4010-9020-7098452b4193}","Rhonda","Reitz","Rhonda Reitz","rreitz","rhonda.reitz","3282e152","rhonda.reitz@btinternet.com","rhonda.reitz@verizon.net","(907) 252-0297","(703) 242-6715","(907) 252-0163","(703) 242-9363","89079 Sterrett PL","Soldotna","AK","99669","41346 Mccauley HWY","Vienna","VA","22181"
"3","{742a3ad4-e1e8-44ed-a6a0-1654981e0c9b}","Ruth","Mcnemar","Ruth Mcnemar","rmcnemar","ruth.mcnemar","16548a78","rmcnemar@aol.com","rmcnemar@verizon.net","(305) 541-2410","(704) 892-5466","(305) 541-4633","(704) 892-3899","93562 Bruno BLVD","Miami","FL","33129","45829 Meadowview HWY","Davidson","NC","28036"
"4","{d72fb280-66cf-49a8-81bb-f5da4a096614}","Jimmy","Kizer","Jimmy Kizer","jkizer","jimmy.kizer","3528671c","jkizer@verizon.net","jimmy.kizer@earthlink.net","(704) 854-4523","(734) 797-4218","(704) 854-9102","(734) 797-8335","98044 Meadows HWY, Suite 370","Gastonia","NC","28054","50311 Pamona LN","Livonia","MI","48150"
"5","{90409c90-c967-4b1f-b66c-6b9f31043303}","Kiehl","Gillum","Kiehl Gillum","kgillum","kiehl.gillum","18fa1042","kiehl.gillum@gmail.com","kiehl.gillum@rediffmail.com","(320) 679-6636","(810) 863-2970","(320) 679-3672","(810) 863-2871","2578 Claywood BLVD","Mora","MN","55051","54794 Rockledge PKWY, Suite 945","Roseville","MI","48035"
"6","{f47a479c-d0a9-43d8-84aa-97970b0c4892}","Walletta","Spivey","Walletta Spivey","wspivey","walletta.spivey","37cdece6","wspivey@hotmail.com","wspivey@bellsouth.net","(218) 723-8749","(650) 357-1721","(218) 723-8142","(650) 357-7306","7061 Baypointe AVE","Duluth","MN","55802","59277 Mack HWY","San Mateo","CA","94403"
"7","{f2b1687a-78ce-437b-baa0-2b959ee260d5}","Chauncey","Slemp","Chauncey Slemp","cslemp","chauncey.slemp","1b9f960c","cslemp@comcast.net","cslemp@charter.net","(412) 393-0962","(916) 492-0473","(412) 393-2712","(916) 492-1842","11544 Dumesnil CIR","Pittsburgh","PA","15222","63760 Tiburon PL, Suite 814","Sacramento","CA","95814"
"8","{19189dab-e300-42d2-8580-c4216fcaafb3}","Roxanne","Bond","Roxanne Bond","rbond","roxanne.bond","3a7372b0","roxanne.bond@msn.com","roxanne.bond@aol.com","(336) 506-3075","(308) 652-9124","(336) 506-7181","(308) 652-6278","16027 Continental CIR","Burlington","NC","27215","68242 Burning BLVD","Orleans","NE","67647"
"9","{7703a831-1f56-43cd-87ea-c998fcb52682}","Elvie","Cissell","Elvie Cissell","ecissell","elvie.cissell","1e451bd6","elvie.cissell@charter.net","ecissell@cox.net","(917) 344-5189","(770) 242-7876","(917) 344-1751","(770) 242-0814","20509 Tivoli RD, Suite 491","New York","NY","10041","72725 Perlman LN","Norcross","GA","30071"
"10","{0aed5fd3-70e8-41e0-bbc4-418d122a590b}","Newman","Peters","Newman Peters","npeters","newman.peters","216c4fb","npeters@earthlink.net","npeters@hotmail.com","(719) 530-7302","(281) 944-6628","(719) 530-6221","(281) 944-5249","24992 Oak LN","Salida","CO","81201","77208 Bolsa BLVD","Houston","TX","77037"

Installer: SetupContactGenerator.EXE (833.81 KB)

Source: ContactGeneratorSource.zip (584.5 KB)

Friday, July 06, 2007 4:29:07 PM (GMT Daylight Time, UTC+01:00)  #   |  Comments [0]  |  Trackback
Thursday, July 05, 2007

I must say, the OOB development experience in SharePoint has been less than desirable. I feel like MS has given us a number of tools but left us in the lurch figuring out how to use them, and its not always obvious how. One thing I have wanted to do is use the designer to develop web parts and deploy them with the click of a button. The VSeWSS have made the "deploy with the click of the button" part possible but the designer part has not been so obvious. How can you marry a designer experience with the VSeWSS ease of solution deployment? I'll show you how...

For Starters

The following information utilizes the Visual Studio Extensions for WSS (VSeWSS) which can be downloaded here. VSeWSS only offers a subset of the features available with solution deployment but offers "one touch" deployment OOB. Creating your own solutions manually will give you more options but may be more work than its worth (Unless you have found some nifty 3rd party tool or created your own). So the following information will strictly use what VSeWSS has to offer. VSeWSS can only run on a Windows Server 2003 box with MOSS 2007 & Visual Studio 2005 installed (Although it can be hacked to run on XP, most of the features do not work). VSeWSS may have problems if MOSS 2007 was not installed as a standalone server, so says the download notes and my experience with it. Although I have a colleague who has used it in a farm configuration and not had an issue.

Creating a blank VSeWSS Project & Web Part

Obviously you cant use the designer with a web part but you can with a Web User Control (This is the thought behind SmartParts). So lets start off by creating a project from an empty VSeWSS template.

image

Next add a new Web Part from the VSeWSS templates.

image

Now your probably thinking "Now add a Web User Control, yada yada yada", right? Wrong! If you have gone down this path before you will probably discover a couple of things; first the Web User Control is not available as a new item in a VSeWSS project. This can be worked around fairly easily by modifying the templates available to the class library project type or by creating the user control in a Web Application Project (WAP) and copy the files over, either way hacky. Second, you will discover that the designer does not behave as it does in a WAP or web site. For example your code behind and designer classes are not linked together and when you double click a control the default event code is generated in the ascx file instead of the code behind. This and a number of other quirks render this method almost as bad as just coding your entire control in the Web Part (Almost, but not quite). So how do we get the designer to work properly? .

Creating a hybrid VSeWSS/WAP Project

We need to create a hybrid VSeWSS/WAP project. This requires that you either have VS2005 SP1 installed or the WAP extensions installed (If you decided not to wait 5 hours for SP1 to install...). In order to make your VSeWSS project also a WAP project you will need to adjust the project type in the .xxproj file. To do this, right click the project we just created an select "Unload Project". It may ask you to save, press yes.

image

Once the project is unloaded, right click it again and select "Edit xxxxxxxxxxx.xxproj".

image

Once you have opened the project file you will need to add in the WAP guid into the ProjectTypeGuids element under the first PropertyGroup. This guid, {349c5851-65df-11da-9384-00065b846f21}, should be the second guid in the list (Shown in bold/green below), the first one being the VSeWSS project guid. All the guids in this element should be separated by a semicolon as shown below.

<Project DefaultTargets="Build" xmlns="http://schemas.microsoft.com/developer/msbuild/2003">

  <PropertyGroup>

    <ProductVersion>8.0.50727</ProductVersion>

    <SchemaVersion>2.0</SchemaVersion>

    <ProjectGuid>{7A3CF036-DC02-4868-8CBA-A88E75552372}</ProjectGuid>

    <ProjectTypeGuids>{9E5D3E2D-E4E2-418e-8D80-2F0DA9A94F9A};{349c5851-65df-11da-9384-00065b846f21};{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}</ProjectTypeGuids>

    <Configuration Condition=" '$(Configuration)' == '' ">Debug</Configuration>

    <Platform Condition=" '$(Platform)' == '' ">AnyCPU</Platform>

    <OutputType>Library</OutputType>

    <RootNamespace>MyGroovySharePointLibrary</RootNamespace>

    <AssemblyName>MyGroovySharePointLibrary</AssemblyName>

    <SignAssembly>true</SignAssembly>

    <AssemblyOriginatorKeyFile>Properties\Temporary.snk</AssemblyOriginatorKeyFile>

  </PropertyGroup>

 After this has been set, right click the the project again and select "Reload Project". Click yes to save when prompted.

image

Now close out of Visual Studio, save your project when prompted. Restart Visual Studio and open your project.

VSeWSS Deployment

Now your probably thinking "Now add a Web User Control, yada yada yada", right? Well, yes, you can now add a Web User Control and its designer will work properly. But we want to be able to deploy it strictly with VSeWSS and its solution builder. In order to do this we will need to install the user control with a Module, so lets do that first. Right click your project and add a new Module. I will generically call it UserControls as I will want to add more user controls to it as I add web parts.

image

Once your module is created you can delete the "sample.txt" file from the UserControls folder. Now right click the UserControls folder and click Add --> New Item and select the standard Web User Control.

image

Next open the module.xml in the UserControls folder and add a reference to your newly created user control.

<Elements xmlns="http://schemas.microsoft.com/sharepoint/">

  <Module Name="UserControls" Url="UserControls" Path="">

    <File Url="MyGroovyUserControl.ascx" />

  </Module>

</Elements>

The Url attribute in the Module element specifies the relative path on the SharePoint site where the file will be deployed to. In this case I chose a sub folder called "UserControls".

Creating the User Control and Linking the Web Part

Now, add a label to your User Control called CurrentTime (Or whatever you want to call it...). And set it, in the control load event, to the current time.

namespace MyGroovySharePointLibrary.UserControls

{

    public partial class MyGroovyUserControl : System.Web.UI.UserControl

    {

        protected void Page_Load(object sender, EventArgs e)

        {

            CurrentTime.Text = DateTime.Now.ToString();

        }

    }

}

Since the VSeWSS Solution Builder creates a solution that installs only the project assembly to the GAC (Which is lame indeed) you will need to add an assembly directive to the user control, before the control directive is defined. If you do not add it before the control directive your control will fail to load as it will not have a reference to the project assembly in the GAC.

<%@ Assembly Name="MyGroovySharePointLibrary, Version=1.0.0.0, Culture=neutral, PublicKeyToken=9f4da00116c38ec5" %>

<%@ Control Language="C#" AutoEventWireup="true" CodeBehind="MyGroovyUserControl.ascx.cs" Inherits="MyGroovySharePointLibrary.UserControls.MyGroovyUserControl" %>

<asp:Label ID="CurrentTime" runat="server" Text="Label"></asp:Label>

To obtain the public key token you can run the sn.exe utility in the SDK with the -T parameter and the path to the assembly. For example:

image

Next, override the CreateChildControls method of your web part and load the user control with the Page.LoadControl method. UPDATE: Thanks to Charles for pointing out that you also need to remove (If your not using it) the default Render(...) override. The WebPart template has this defined and by default it does not call the base implementation so ya get nothing displayed!

namespace MyGroovyWebPart

{

    [Guid("cc2a1b52-324a-4a20-bca8-0d512f8348b4")]

    public class MyGroovyWebPart :

        System.Web.UI.WebControls.WebParts.WebPart

    {

        public MyGroovyWebPart()

        {

            this.ExportMode = WebPartExportMode.All;

        }

 

        protected override void CreateChildControls()

        {

            string userControl = "/UserControls/MyGroovyUserControl.ascx";

            try

            {

                Controls.Add(this.Page.LoadControl(userControl));

            }

            catch (Exception exception)

            {

                string message = string.Format("{0} failed to load: {1}",

                    userControl,

                    exception.Message);

                Controls.Add(new LiteralControl(message));

            }

        }

    }

}

Now hit F5 and deploy!

image

As you can see, this method gives you the benefit of the designer and VSeWSS solution deployment. The full source of the sample can be downloaded here:

MyGroovySharePointLibrary.zip (417.78 KB)
Thursday, July 05, 2007 6:18:06 AM (GMT Daylight Time, UTC+01:00)  #   |  Comments [8]  |  Trackback
Tuesday, June 26, 2007

Normally I like to create a stand alone, abstract BLL assembly that can be used by multiple components (ASP.NET, WinForms, Windows Service, etc), nothing new, standard procedure. Well the VSeWSS Solution builder will only load and reference the VSeWSS project assembly in the SharePoint Solution. Pretty lame if you ask me! You would think that it would package all referenced assemblies not just the project assembly, how hard is that?? So you ether have to house all your code in the VSeWSS assembly or deploy referenced assemblies separately to the SP web front ends. If you forget about this, any code that tries to call code in the referenced assembly will throw a generic "File Not Found" exception in SP.

I sincerely hope there is a newer version of VSeWSS coming down the pike. It has the potential to be a really great tool for SP development but the limitations I keep encountering are seriously lessening its value. This is just another example of that.

Tuesday, June 26, 2007 9:42:04 PM (GMT Daylight Time, UTC+01:00)  #   |  Comments [0]  |  Trackback
Friday, June 22, 2007

Another SharePoint anomaly... Will they ever end??? So I have had this strange issue where doing a deploy of a VSeWSS project does not seem to update the SharePoint site for certain elements like schemas. I have to retract/remove the solution manually from SP, close/reopen Visual Studio (Otherwise I would get a null ref error), then redeploy to see changes. The VSeWSS deploy process does an iisreset (Which I tried manually doing as well) but the updates do not appear without following the steps mentioned. I checked the SP database and SP hive and the elements in question were deployed... So the only thing I could think of is that these elements must cached in memory, which was baffling since an iisreset should clear that out (Right?). Well I finally got the bright idea to verify that iisreset was in fact closing out the IIS service process completely. And lo an behold it was not! After further investigation I found that the “Windows Remote Management (WS-Management)” service, which depends on IIS, was preventing a complete exit of the inetinfo process. I'm not sure what the iisreset was actually doing all along (It said it successfully reset the IIS services), possibly just recycling the AppDomain(s)? But in that case wouldn't SP release cached elements upon termination of the AppDomain(s)? Not really sure, but what I am sure of is that stopping and disabling the the WRM service allowed inetinfo to completely close when the service was restarted by iisreset. And voilà! My changes!

Incidentally I am running Virtual Server 2005 which is monitored by the "Virtual Machine Manager Agent" service. This service depends on the WRM service. So disabling the WRM service will disable your VMMA service. You might want to let your network admin know you need this disabled or it might reappear.

Friday, June 22, 2007 10:22:26 PM (GMT Daylight Time, UTC+01:00)  #   |  Comments [0]  |  Trackback
Monday, June 18, 2007

This error almost drove me over the edge... The SharePoint properties pane in Visual Studio would show the error "An error occured trying to load the page. Guid should contain 32 digits with 4 dashes (xxxxxxxx-xxxx-xxxx-xxxx-xxxxxxxxxxxx)"

image

 

After pulling much of my hair out (And doing some trial & error testing) I realized that the problem was that the pane was looking to see if there were any new web parts added to the project each time it loaded. I had added an abstract WebPart base class which some of my other WebParts would inherit from. Problem was this abstract WebPart class was not decorated with the Guid attribute, which is evidently required by the SharePoint property page. I added the Guid attribute and the error goes away.

 

[Guid("9D5AFDE3-F3A3-4947-AC6F-5D66CEF0D2F6")]

public abstract class ListBoundWebPart : System.Web.UI.WebControls.WebParts.WebPart

{ ... }

The only problem is this WebPart base class is now included in the SharePoint Solution as a feature. I haven't found a way as of yet to exclude it.

Monday, June 18, 2007 5:16:21 PM (GMT Daylight Time, UTC+01:00)  #   |  Comments [0]  |  Trackback
Wednesday, June 06, 2007

Having just built a couple of VS2005 addins I wanted to share a couple of resources that really helped me:

Creating Menu Bitmaps and AboutIcons for Add-ins in Visual Studio .NET 2005
Creating a CommandBar and adding Commands to it in a VS.NET Add-in
Visual Studio 2005 Automation Samples

Hopefully when I get more time I can post a walk through. Many thanks to Rick Strahl who seems to always have good info on how to do advanced development in .NET! 9 times out of 10 I'll find something on his blog/site, great resource!

Wednesday, June 06, 2007 8:07:19 PM (GMT Daylight Time, UTC+01:00)  #   |  Comments [0]  |  Trackback
Thursday, April 12, 2007

So I am trying to write log information to an XML document using the XmlTextWriter.  When it reaches a certian size I want it closed out and archived. What I mean by "closed out" is that while the log file is "open" the root element is not closed so that I can keep adding entries over a period of time. In other words:

<?xml version="1.0"?>
<log>
    <entry date="1/1/2007">Yada yada yada</entry>
    <entry date="1/1/2007">Yada yada yada</entry>
    ...


Then once its full I will write the closing root element and rename it:

<?xml version="1.0"?>
<log>
    <entry date="1/1/2007">Yada yada yada</entry>
    <entry date="1/1/2007">Yada yada yada</entry>
    ...
    <entry date="1/1/2007">Yada yada yada</entry>
</log>

Well the XmlTextWriter automatically closes out all open elements when you close it. Looking in Reflector reveals what is happening behind the scenes:

public override void Close()
{
   try
   {
      this.AutoCompleteAll();
   }
   catch {}
   finally
   {
      this.currentState = State.Closed;
      this.textWriter.Close();
   }
}

First the AutoCompleteAll() method is called, then the underlying stream is closed. The AutoCompleteAll() method is as follows:

private void AutoCompleteAll()
{
   if (this.flush)
   {
      this.FlushEncoders();
   }
   while (this.top > 0)
   {
      this.WriteEndElement();
   }
}

Doesent look like there is any official way to explicitly close only the elements you want to close, its just automatically done for you when you close the writer. The only work around I could figure out is to explicitly close the elements I want closed, then close the base stream (Not the XmlTextReader). This works but IMO its a little hackey since the code in the Close() method could potentially change in the future and you could end up circumventing some code that you might want executed when your done with the reader.

.NET | C# | VB.NET | XML/XSL
Thursday, April 12, 2007 8:01:42 PM (GMT Daylight Time, UTC+01:00)  #   |  Comments [0]  |  Trackback
Friday, March 23, 2007

I have been working with the new custom configuration classes in .NET 2.0 and they really make creating custom xml configuration a snap. They are a little quirky to use at first but once you get past the initial learning curve they really make the job a lot easier.

One thing I really wanted to figure out is how to use these new classes to read files other than the default app/web.config. For example if you have one config file that might be shared between exes or if a config file is pulled from a URL. Its actually pretty easy to do.

First create your custom configuration file. It will look exactly the same as a web/app.config file except it will only contain your custom section(s). Create a section handler element identifying the custom section handler and the name of the section. Again, nothing different from doing this in the app/web.config.

<?xml version="1.0" encoding="utf-8" ?>
<configuration>
 <configSections>
  <section name="mySettings" type="CustomConfigHandler.MySettingSection, CustomConfigHandler"/>
 </configSections>
 <mySettings>
  <someSetting someAttribute="This is an attribute value from Settings1.config"/>
 </mySettings>
</configuration>

Next create a Configuration object that points to your file by passing in an ExeConfigurationFileMap with the ExeConfigFilename set.

// Create an exe file map containing the path to your config file
ExeConfigurationFileMap FileMap = new ExeConfigurationFileMap();
FileMap.ExeConfigFilename = "MySystem.config";

// Create a configuration object that is tied to your custom config file.
Configuration Config = ConfigurationManager.OpenMappedExeConfiguration(FileMap, ConfigurationUserLevel.None);

// Create the custom config section handler
MySettingSection MySettings = (MySettingSection)Config.GetSection("mySettings");

Console.WriteLine(MySettings.SomeSetting.SomeAttribute);


The entire source can be downloaded here:

ExternalConfigFile.zip (40.24 KB)
.NET | C# | Configuration | VB.NET
Friday, March 23, 2007 8:30:17 PM (GMT Standard Time, UTC+00:00)  #   |  Comments [0]  |  Trackback
Wednesday, February 14, 2007

I had a baffling problem arise today. Here is the scenario; I have a .NET WinForms app with a WebBrowser control. The WebBrowser control loads a web page that contains an embedded Flash movie. I need to send keystrokes to the Flash movie from the WinForms app. Now MS provides the SendKeys class under the Windows.Forms namespace for this very purpose, but in this instance it doesent pass them on to the Flash movie (Although it does pass them to HTML elements in the page). Hmmmmmm... A little digging in Reflector uncovers the reason. The SendKeys class internally calls the SetKeyboardState() native method to send the keyboard input. Here is what MSDN says about that call:

The SetKeyboardState function copies a 256-byte array of keyboard key states into the calling thread's keyboard input-state table. This is the same table accessed by the GetKeyboardState and GetKeyState functions. Changes made to this table do not affect keyboard input to any other thread.

I'm no expert on how embedded ActiveX controls work within a web page in IE but I bet the Flash control is not running in the same thread as the browser UI. And in the case of using the WebBrowser control, not in the UI thread of the WinForms app. So SendKeys will not be able to send keystrokes to embedded Flash in a WebBrowser control. Just a guess, but it seems that is what is happening here. Well, scratch that, I just checked Spy++ and everything is running under the WinForm UI thread including the Flash ActiveX control. So at this point I have no idea why SendInput() works but SetKeyboardState() doesent (And thus the SendKeys class), very strange indeed! If anyone knows for sure, please leave a comment! :)

So the other option is calling the SendInput method. FYI, this method supersedes the keybd_event method. Here is a sample of the code required to send keystrokes to the foreground window. Remember, you must make sure that the WebBrowser control has focus for it to receive the keystrokes (As does the Flash control in the web page, see further down for more info).

private void Main_Load(object sender, EventArgs e)
{
    WebBrowserControl.Navigate(@"file://C:\Temp\Flash.html");
    Timer.Enabled = true;
}

private int Index = 0;

private void Timer_Tick(object sender, EventArgs e)
{
    Index++;

    NativeMethods.INPUT[] structInput = new NativeMethods.INPUT[1];

    structInput[0] = new NativeMethods.INPUT();
    structInput[0].type = NativeMethods.INPUT_KEYBOARD;
    structInput[0].ki.wScan = 0;
    structInput[0].ki.time = 0;
    structInput[0].ki.dwFlags = 0;
    structInput[0].ki.dwExtraInfo = NativeMethods.GetMessageExtraInfo();
    structInput[0].ki.wVk = NativeMethods.VK_RIGHT;

    // Key up every other pass
    if (Index % 2 == 0)
    {
        structInput[0].ki.dwFlags = NativeMethods.KEYUP;
    }

    NativeMethods.SendInput(1, structInput, Marshal.SizeOf(structInput[0]));
}

The basic native method & struct declarations are as follows. PInvoke.NET has a nice definition of all of these.

public const int INPUT_KEYBOARD = 1;
public const int KEYUP = 2;

public const int VK_LEFT = 0x25;
public const int VK_UP = 0x26;
public const int VK_RIGHT = 0x27;
public const int VK_DOWN = 0x28;


[StructLayout(LayoutKind.Sequential)]
public struct MOUSEINPUT
{
    int dx;
    int dy;
    int mouseData;
    int dwFlags;
    int time;
    IntPtr dwExtraInfo;
}

[StructLayout(LayoutKind.Sequential)]
public struct KEYBDINPUT
{
    public short wVk;
    public short wScan;
    public int dwFlags;
    public int time;
    public IntPtr dwExtraInfo;
}

[StructLayout(LayoutKind.Sequential)]
public struct HARDWAREINPUT
{
    int uMsg;
    short wParamL;
    short wParamH;
}

[StructLayout(LayoutKind.Explicit)]
public struct INPUT
{
    [FieldOffset(0)]
    public int type;
    [FieldOffset(4)]
    public MOUSEINPUT mi;
    [FieldOffset(4)]
    public KEYBDINPUT ki;
    [FieldOffset(4)]
    public HARDWAREINPUT hi;
}

[DllImport("user32.dll", SetLastError = true)]
public static extern uint SendInput(uint nInputs, INPUT[] pInputs, int cbSize);

[DllImport("user32.dll", SetLastError = false)]
public static extern IntPtr GetMessageExtraInfo();

The only other thing you need to do to make this completely automated is to set focus on the Flash movie in the web page using JavaScript. Simply call the focus method of the Flash control as follows:

window.document.MyFlash.focus();

The entire project can be downloaded here.

.NET | C# | Flash | Win32 API
Wednesday, February 14, 2007 10:31:15 PM (GMT Standard Time, UTC+00:00)  #   |  Comments [4]  |  Trackback
Tuesday, February 06, 2007

For those of you who still use SMS Installer the following script enables you to detect if a certian version of the .NET Framework is installed on the machine. Just switch over to the "Script Editor", copy the text from the following file and paste it where you want it. Basically it only extracts and runs the redist if the desired version is not installed. This makes the setup run a lot faster for users who will already have a particular version of the framework installed.

DOTNETSMS.txt (6.23 KB)
Tuesday, February 06, 2007 5:49:33 AM (GMT Standard Time, UTC+00:00)  #   |  Comments [0]  |  Trackback
Monday, January 29, 2007

There is a new version of the Hid Library in the labs. It has been converted to .NET 2.0 and includes a bug fix. This bug fix involved how the vendor and product id were cast in the structure consumed by the Hid API. So some devices like Logitec's gamepads would not be recognized by their product and vendor id's. Now that issue is resolved. N-joy!

USB Hid Device Library

.NET | C# | USB HID | VB.NET
Monday, January 29, 2007 10:36:12 PM (GMT Standard Time, UTC+00:00)  #   |  Comments [27]  |  Trackback
Tuesday, January 09, 2007

I was looking over a peice of my code today and noticed I had some finalization code in a try-finally block but there was a code path that had a return statement. So I thought, "thats a bug because I'm jumping out of the method before the finally block is called!". Silly me! MSDN says "Control is always passed to the finally block regardless of how the try block exits". For some reason I always thought that the finally block was bypassed when you exited a method via the return statement... :-S

.NET | C# | VB.NET
Tuesday, January 09, 2007 5:02:49 PM (GMT Standard Time, UTC+00:00)  #   |  Comments [0]  |  Trackback
Thursday, January 04, 2007

Removing special chars (Control chars 0-31 and extended ASCII 127-255) is pretty easy to do with a regular expression. Simply select chars that are not in the range of ASCII 32-126 (Hex 20-7E) and replace these chars with an empty string.

Regex SpecialCharExpression = new Regex(@"[^\x20-\x7E]");
string NewData = SpecialCharExpression.Replace(OldData, string.Empty);

Here is a working example:

class Program
{
   static void Main(string[] args)
   {
      string OldData = string.Empty;

      for (int Index = 0; Index < 256; Index++)
      {
         OldData += ((char)Index).ToString();
      }

      Regex SpecialCharExpression = new Regex(@"[^\x20-\x7E]");
      string NewData = SpecialCharExpression.Replace(OldData, string.Empty);

      Console.WriteLine("Length: " + NewData.Length);
      Console.WriteLine(NewData);
      Console.ReadKey();

   }
}

.NET | C# | VB.NET
Thursday, January 04, 2007 6:47:38 PM (GMT Standard Time, UTC+00:00)  #   |  Comments [0]  |  Trackback
Wednesday, January 03, 2007

I really have to remember to use the IsNullOrEmpty method in the string class. I keep forgetting to use it so I figure if I blog about it I'll remember.. ;)

// Why do this...
if (MyString != null && MyString.Length > 0) {...}

// When you could do this???
if (string.IsNullOrEmpty(MyString) == false) {...}

And while we are on the subject, the .NET framework defines a lot of nice constants for us to use instead of defining our own or using literals. See if one exists in a class near you... Here are a couple of examples:

// Why use the "" literal when you can use
String.Empty;

// = "\"
System.IO.Path.DirectorySeparatorChar;

// = "/"
System.IO.Path.AltDirectorySeparatorChar;

// Returns char[] {'"', ...}
System.IO.Path.GetInvalidPathChars();

// Returns char[] {'"', ...}
System.IO.Path.GetInvalidFileNameChars();

.NET | C# | VB.NET
Wednesday, January 03, 2007 9:59:05 PM (GMT Standard Time, UTC+00:00)  #   |  Comments [0]  |  Trackback
Tuesday, December 26, 2006

Ran into a weird problem with the following code. When I atempted to save the bitmap I recieved a "Parameter is not valid" error. I snagged this code from a VB.NET app I wrote and translated it, so I knew that it worked.

Bitmap ChartImage = GeneratePieChart(...);

EncoderParameter QualityParam = new EncoderParameter(System.Drawing.Imaging.Encoder.Quality, 100);
EncoderParameters EncoderParams = new EncoderParameters();
EncoderParams.Param[0] = QualityParam;

MemoryStream ChartStream = new MemoryStream();

ChartImage.Save(ChartStream, GetEncoderInfo("image/jpeg"), EncoderParams);

Rob Gruen ran into the same issue and fortunately blogged about it here. Long story short the quality in the EncoderParamater must explicitly passed as a long:

EncoderParameter QualityParam = new EncoderParameter(System.Drawing.Imaging.Encoder.Quality, 100L);

.NET | C# | Graphics
Tuesday, December 26, 2006 7:40:39 PM (GMT Standard Time, UTC+00:00)  #   |  Comments [1]  |  Trackback
Monday, December 18, 2006

This should actually be "System.Runtime.CompilerServices.IndexerName" from what I can tell. It appears that there is a typo in the MSDN docs (And elsewhere on the web) unless I'm just totally missing something here... Supposedly its in the mscorlib.dll but I couldnt seem to find a "CSharp" class anywhere under System.Runtime.CompilerServices either in v1.1 or v2.0. And other CSharp classes elsewhere did not contain the "IndexerName" attribute. Weird. The truth is out there...

.NET | C#
Monday, December 18, 2006 11:00:22 PM (GMT Standard Time, UTC+00:00)  #   |  Comments [0]  |  Trackback
Sunday, December 17, 2006

I needed an efficient and performant way to keep track of the current number of files/folders in a folder. Directory.GetFiles() was out of the question for a number of reasons. So I ended up using a two step process. First grab the current number of files/folders in the folder using the FindFirstFile() and FindNextFile() Win32 API calls (Which is what Directory.GetFiles() uses under the covers.). These increment the file counter. Then immediately after that completes, activate a FileSystemWatcher to monitor file creation and deletion. These events respectively increment or decrement the counter. I have been putting this through the ringer and it seems to do the job superbly.

Interesting observation about the FindNextFile() method; this method will continue to grab files as long as they exist in the directory, it’s not like it’s working from some sort of static snapshot of the files created by FindFirstFile() when it is called. So in other words if other files are added to the folder that match the criteria of your filter while you are in the process of iterating with FindNextFile(), FindNextFile() will eventually “find” them. Although this seems implied by the name of both the method calls, you never know what might actually be going on under the hood…

The following code illustrates how to do this. Note that there can potentially be a significant performance hit when a folder is first enumerated. This is especially true when the file/folder count gets past the hundreds of thousands. But once the folder is first enumerated the FSW will keep track of the additional creates/deletes, no need to re-enumerate.

class Program
{

   static FileSystemWatcher _Watcher = new FileSystemWatcher();
   static int _Count = 0;

   static void Main(string[] args)
   {

      _Watcher.Filter = "*.*";
      _Watcher.Path = @"D:\Temp";

      _Watcher.Created += new FileSystemEventHandler(OnCreated);
      _Watcher.Deleted += new FileSystemEventHandler(OnDeleted);

      NativeMethods.FindData FileInfo = new NativeMethods.FindData();

      IntPtr FileHandle = NativeMethods.FindFirstFile(@"D:\Temp\*.*", FileInfo);

      do
      {
         if (FileInfo.fileName != "." && FileInfo.fileName != "..") { _Count++; }
      } while (NativeMethods.FindNextFile(FileHandle, FileInfo) == true);

      NativeMethods.FindClose(FileHandle);
      _Watcher.EnableRaisingEvents = true;

      do
      {
         Console.WriteLine("Total Files: " + _Count.ToString());
      } while (Console.ReadLine() != "q");

   }

   private static void OnCreated(object source, FileSystemEventArgs e)
   {
      _Count++;
   }

   private static void OnDeleted(object source, FileSystemEventArgs e)
   {
      _Count--;
   }

}

class NativeMethods
{
   // Declares a class member for structure element.
   [StructLayout(LayoutKind.Sequential, CharSet = CharSet.Auto)]
   public class FindData
   {
      public int fileAttributes = 0;
      // creationTime was an embedded FILETIME structure.
      public int creationTime_lowDateTime = 0;
      public int creationTime_highDateTime = 0;
      // lastAccessTime was an embedded FILETIME structure.
      public int lastAccessTime_lowDateTime = 0;
      public int lastAccessTime_highDateTime = 0;
      // lastWriteTime was an embedded FILETIME structure.
      public int lastWriteTime_lowDateTime = 0;
      public int lastWriteTime_highDateTime = 0;
      public int nFileSizeHigh = 0;
      public int nFileSizeLow = 0;
      public int dwReserved0 = 0;
      public int dwReserved1 = 0;
      [MarshalAs(UnmanagedType.ByValTStr, SizeConst = 256)]
      public String fileName = null;
      [MarshalAs(UnmanagedType.ByValTStr, SizeConst = 14)]
      public String alternateFileName = null;
   }

   [DllImport("Kernel32.dll", CharSet = CharSet.Auto)]
   public static extern IntPtr FindFirstFile(String fileName, [In, Out] 
   FindData findFileData);

   [DllImport("Kernel32.dll", CharSet = CharSet.Auto)]
   public static extern bool FindNextFile(IntPtr hFindFile, [In, Out] 
   FindData findFileData);

   [DllImport("kernel32.dll", CharSet = CharSet.Auto)]
   public static extern bool FindClose(IntPtr hndFindFile);

}

.NET | C#
Sunday, December 17, 2006 8:45:09 PM (GMT Standard Time, UTC+00:00)  #   |  Comments [0]  |  Trackback
Wednesday, November 22, 2006

So I'm implementing an interface, defined in an assembly written in VB.NET, on a class in an assembly written in C#. The interface defines a number of events. VB.NET event declaration doesent require you to define the corresponding delegate (as C# does) so the question is where does the VB.NET compiler declare it for you after compilation? Well it seems that the delegate definition is declared right in the interface. This could be confusing for someone who doesent know VB.NET since C# does not allow the declaring of types within an interface whereas VB.NET does.

Here IDataInputDevice is an interface residing in an assembly written in VB.NET with three events defined. The corresponding delegate definitions are defined right within the interface.

.NET | C# | VB.NET
Wednesday, November 22, 2006 11:39:52 PM (GMT Standard Time, UTC+00:00)  #   |  Comments [0]  |  Trackback
Monday, November 20, 2006

I was looking over a code sample for reading from/writing to a serial port here at the MS support site. The VB.NET sample creates a SerialPort object within a using statement but then explicitly closes the SerialPort which is kind of an oxymoron. After doing a little investigation I found that the SerialPort class inherits from the Component class which implements IDisposable. The Dispose method in the Component class calls the Dispose(bool disposing) method which is overriden by the SerialPort class. The overriden method closes the SerialPort. In fact the Close method just turns around and calls this overriden method. Long story short, SerialPort.Dispose closes the serial port, so no need to explicitly close it within a using statement.

Reflected Component.Dispose method:

public void Dispose()
{
    this.Dispose(true);
    GC.SuppressFinalize(this);
}

Reflected SerialPort.Dispose method:

protected override void Dispose(bool disposing)
{
    if (disposing && this.IsOpen)
    {
        this.internalSerialStream.Flush();
        this.internalSerialStream.Close();
        this.internalSerialStream = null;
    }
    base.Dispose(disposing);
}

Monday, November 20, 2006 11:02:38 PM (GMT Standard Time, UTC+00:00)  #   |  Comments [0]  |  Trackback
Friday, November 10, 2006

One of the shortcuts of C# (And now in VB.NET 2005) I love is the using statement. For those not familiar with it, it allows you to create objects within the scope of the using block and then once the block completes execution, calls the Dispose method on all the specified objects if they implement IDisposable. This occurs even if an exception is thrown. From what I understand, the using block in the resulting IL is a try/finally block, where the object disposal takes place in the finally.

This is perfect for working with a DataReader and instances where we want to make sure a database connection is closed right after a call. Since the Dispose method on a DataReader and Connection object call their own Close method they will be implicitly closed when we exit the using block, regardless of errors.

string ConnectionString = "server=127.0.0.1;database=duwamish7vb;Trusted_Connection=true";

using (SqlConnection Conn = new SqlConnection(ConnectionString))
{

    Conn.Open();

    SqlCommand Command = new SqlCommand("SELECT Name FROM Authors",Conn);

    using (SqlDataReader Reader = Command.ExecuteReader())
    {

        Authors.DataTextField = "Name";
        Authors.DataSource = Reader;
        Authors.DataBind();

    }

    Command = new SqlCommand("SELECT Subject FROM Books", Conn);

    using (SqlDataReader Reader = Command.ExecuteReader())
    {

        Books.DataTextField = "Subject";
        Books.DataSource = Reader;
        Books.DataBind();

    }

}

.NET | C# | VB.NET
Friday, November 10, 2006 9:17:27 PM (GMT Standard Time, UTC+00:00)  #   |  Comments [0]  |  Trackback

I have seen a lot of debate about VB.NET and C# and which one is "better". Before I started coding in C# I had some prejudice about it, but it’s interesting to see how my viewpoint has in some cases changed, and in others not changed after making the switch.

My viewpoint before switching over:

  • .NET languages are as MS put it a "lifestyle choice".
  • Many C# programmers think a little too much of themselves, projecting an elitist status as if a VB.NET developer knows nothing about OOD/OOP, design patterns and are just script kiddies.
  • Case sensitivity within a language is moronic, inelegant and causes ambiguity.
  • VB.NET is a very expressive language, like reading a book whereas C# looks like a bunch of ugly symbols.
  • And what’s with that stupid semi-colon anyway??

My viewpoint after switching over:

  • I still think it’s a lifestyle choice. I’m sure some C# purists will probably say I "don’t know enough about C#" or "that sounds like something a VB programmer would say". :-) The power of the .NET framework is, in my opinion, expressed well in both languages except for a few things here and there. Especially now with the release of v2.0 it’s not about whether or not you use a particular language syntax, it’s really about knowing how to develop .NET applications and about programming and design principles.
  • I still think some C# programmers think too much of themselves. I do realize however that the majority of VB.NET programmers come from the VB6/VBScript world, a world I am from. Many of those individuals carry a lot of baggage with them and do not have a good grasp of OO, design patterns, etc and are just not skilled developers. Many of them are the script kiddie type because it was so easy to pound out code in those languages, didnt require a whole lot of skill. But don’t judge a book by its cover. I think there are a lot of developers who came from that world who have embraced the principles, now present in the .NET framework (Not just a particular language syntax), that Java and C++ programmers have practiced and enjoyed for years.
  • I've not noticed the case sensitivity in C#… In fact in cases where I have not had VS prettying up my VB code I manually format my code anyway. Not even an issue. Ambiguity is definitely a possibility but I think a good developer would avoid that for clarity.
  • I actually now like all those "ugly symbols" over the expressive and verbose VB syntax… Very strange because that was one of my biggest prejudices aside from case sensitivity. It’s just a lot simpler and once you get used to it it’s not hard to read. If you are only familiar with the expressive syntax of VB it is hard to follow. I feel like I have much more flexibility over how I structure my code. Even going back to do maintenance on VB.NET code is less than enjoyable now that I have been working with C#.
  • Ok, the semi-colon is a little annoying at first but you get to the point where you don’t even think about it. It’s actually very nice in instances where you have a large string literal or a long line of code.

Bottom line is, "...just listen to your heart. That's what I always do". Dont be caught up in the hype that coding in VB.NET makes you a script kiddie. But I would seriously recomend, if you are a VB.NET developer who has not learned C#, to at least give it a try. You might be very surprised at how much you like the syntax over VB.

.NET | C# | VB.NET
Friday, November 10, 2006 8:25:01 PM (GMT Standard Time, UTC+00:00)  #   |  Comments [0]  |  Trackback
Tuesday, November 07, 2006

I ran into an issue today where I was coding in a class under a particular namespace but couldn’t access a class in another namespace that only differed by its namespace root. Here is what it looked like:

MyApp.Common.MyClass // Class I want to reference (For a unit test)

TestSuite.MyApp.Common.MyClass // the class I'm coding in (A unit test...)

When I referenced MyApp.Common.MyClass it was actually resolving to TestSuite.MyApp.Common.MyClass. So if you want to reference the former, you need to use the "global::" prefix as follows:

global::MyApp.Common.MyClass

.NET | C#
Tuesday, November 07, 2006 8:49:11 PM (GMT Standard Time, UTC+00:00)  #   |  Comments [0]  |  Trackback
Wednesday, October 11, 2006

The following is a breakdown of 4 basic bitwise operators; NOT, OR, XOR and AND.

NOT

NOT produces the inverse of a binary value. For example:

1 will be 0 and 0 will be one. In C# NOT operations are only allowed on Boolean values. The NOT operator is an exclamation point (!).

bool i = true;

Console.WriteLine(!i);

// returns false

OR

OR produces a 1 if either corresponding bit is 1. This means that if both are one or if only one is 1 the result is 1. If both are zero then the result is zero. For example:

In C# the OR operator is the pipe (|).

int i = 23; // 010111
int z = 45; // 101101

Console.WriteLine(i | z);

// 63 - 111111

XOR

XOR (Or Exclusive OR) produces a 1 if either corresponding bit is 1 but not both, in other words mutually exclusive. This means that 1 and 0 or 0 and 1 will be 1. 0 and 0, 1 and 1 will produce 0. For example:

In C# the XOR operator is the caret (^).

int i = 23; // 010111
int z = 45; // 101101

Console.WriteLine(i ^ z);

// 58 - 111010

AND

AND produces a 1 only if both corresponding bits are 1, otherwise it produces a 0. For example:

In C# the AND operator is the ampersand (&).

int i = 23; // 010111
int z = 45; // 101101

Console.WriteLine(i & z);

// 5 - 000101


 

.NET | Binary | C#
Wednesday, October 11, 2006 9:07:13 PM (GMT Daylight Time, UTC+01:00)  #   |  Comments [0]  |  Trackback
Tuesday, October 10, 2006

I recently had the opportunity to work with a 2d area scanner (aka Bar Code Reader) in a .NET application. Previously our client used proprietary software that just plain stunk so we decided to write our own software. One very cool thing I discovered while working on this project was that many USB devices (Like bar code scanners, joysticks, game pads, mice, keyboards, etc) sport a Human Interface Device (HID) interface. This interface communicates using the standard HID protocol defined by the USB Implementers Forum. The cool thing about this is that one standard device driver can be written and used for all USB HID devices on a particular platform. Normally you would have to write your own device driver or use an existing one to communicate with a USB device, ouch! USB HID eliminates that requirement. Windows ships with a standard USB HID device driver and automatically makes the HID interface available when a USB HID device is plugged into the system. Nothing to install, no device driver to write, yay! Windows also has a fairly easy to use API (Although a little quirky) for communicating with HID devices. This site, run by Jan Axelson, has a lot of good information on communicating with USB HID devices. His book, USB Complete, is also an invaluable resource, I would definitely recommend it if you will be doing HID development on any platform.

I have an HID .NET library available here if you want to skip most of the gory details and get right down to business. I have used this library in production and have not had any issues, please let me know if you have any feedback. Using this library, while encapsulating most of the underlying details, will require you to understand the format of data contained in the payload of the reports sent to and from the device. HID’s communicate using "reports" which are analogous to packets in network terminology. The reports themselves are a standard USB HID data structure although the payload of these reports will be specific to the device or device type. Usually the payload data format can be found in the device SDK and/or by simply analyzing the payload data the device sends.

The following library, developed for the HHP IT4600/IT4800 area scanner, uses the aforementioned HID library.

IT4XXXScanner.zip (1.98 MB)
Tuesday, October 10, 2006 9:15:40 PM (GMT Daylight Time, UTC+01:00)  #   |  Comments [4]  |  Trackback

Have you ever wanted to embed an HTTP server into your application? For example let’s say you have a Windows service that you want to administer or monitor (Google desktop is a good example of this). Or let’s say you have an application that requires an alternate interface such a kiosk application. Wouldn’t it be great to have an embedded HTTP server that would allow you to provide a web interface for your application without requiring IIS and without requiring you to write a web server? If so then Lomez is your friend!

Lomez is an in-process HTTP server that allows you to create virtual directories, serve static content from a file or embedded resource and expose any object by implementing the HTTPHandler interface. It loosely resembles ASP.NET to allow you to use it with ease.

Ok, enough of the spiel… Basically I have a number of applications I work with that I would love to have HTTP access to, especially Windows services. I have looked high and low but have not found a library to allow me to do this. So at that point I figured I would have to develop something myself and Lomez was born. I have successfully used this library in a production kiosk framework (At 2 tradeshows so far) and it has worked like a champ. The current version of the library can be found here. I would love to hear any feedback you might have on it.

I consider the current version more of a proof of concept and would really like to rewrite it from the ground up. So hopefully I can begin doing that soon. I would really like to include basic authentication, challenge/response and SSL in the next version. I would also like to optimize the HTTP pipeline so it is lean -n- mean. It’s definitely not right now.

Anyways, if you end up on this page because you are looking for an in-process HTTP server for .NET please let me know your thoughts. And if you decide to use the library, let me know what you think of it.

Thanks!

The Management

Tuesday, October 10, 2006 8:04:45 PM (GMT Daylight Time, UTC+01:00)  #   |  Comments [1]  |  Trackback
Monday, September 25, 2006

I have been running into this problem lately where I try to create a VSS source control binding on a project that already has a binding (Albeit an incorrect one). When I try to bind the project I get this error:

"One or more of the project's destination paths are invalid. To open this solution, you must specify valid paths for each project. The error was "The Web at 'http://localhost/yada-yada-yada' already contains a project. You need to choose another location for your Web project.".

So I have found a solution in a number of blogs/forums that seems to work. Basically you need to remove the source control information for the project in question in the solution file. The lines will look like this:

SccProjectUniqueName1 = http://localhost/SolutionName/SolutionName.csproj
SccLocalPath1 = .
CanCheckoutShared = true
SccProjectEnlistmentChoice1 = 2

Then decrement the SccNumberOfProjects value by 1. Once this has been done, manually reset the binding and your golden!

Monday, September 25, 2006 5:24:36 PM (GMT Daylight Time, UTC+01:00)  #   |  Comments [1]  |  Trackback
Saturday, September 23, 2006

Sometimes when reading binary files, integers will be stored in the big endian format, especially if the file or the application creating it was initially built on a Sun or Mac machine. Intel systems normally store integers in little endian format. Thus the .NET framework does not have built in functionality to read in big endian integers (As of v1.1). One simple solution is to read the integer into a byte array and use the Array.Reverse function to simply reverse the order of the bytes. Then use the BitConverter class to turn the bytes into an integer. For example:

Dim Data As Byte()
Dim Value As Long

Redim Data(3) '--> 32 bit integer

'--> Big endian value of 360
'--> Equals Hx0168
Data(0) = 0 '--> Hx0 = 0, Most significant byte
Data(1) = 0 '--> Hx0 = 0
Data(2) = 1 '--> Hx01 = 1
Data(3) = 104 '--> Hx68 = 104, Least significant byte

Array.Reverse(Data)

'--> Now it looks like this, little endian style:
'--> Data(0) = 104, Most significant byte
'--> Data(1) = 1
'--> Data(2) = 0
'--> Data(3) = 0, Least significant byte

Value = BitConverter.ToInt32(Data, 0)

'--> Value = 360

You can read more about "endianness" here.

Saturday, September 23, 2006 3:11:05 AM (GMT Daylight Time, UTC+01:00)  #   |  Comments [0]  |  Trackback

The library found here allows you to obtain the physical coordinates of a zip code. This can be useful when dealing with weather or map related services that require a latitude and longitude as input but where the user would be providing a zip code. This small library (With a footprint of about 650k) contains the zip code to coordinate mapping as a binary resource embedded in the DLL, so no additional files or interaction with a web service is required. The data contained in the library was obtained through the US Census Bureau and is current as of the year 2000. If a zip code is not contained in the data the nearest match is returned.

Saturday, September 23, 2006 2:00:06 AM (GMT Daylight Time, UTC+01:00)  #   |  Comments [0]  |  Trackback
Creative Commons License