ADSI, IIS and Windows 7+

Time for another one of my, please-don’t-forget-this-again posts.

I was running some code today that was calling the ADSI (Active Directory Service Interfaces)IIS://LocalHost/W3SVC. However I was getting access denied. After trying every admin user on this earthly realm I decided that access denied was a red-herring. I then realised that ADSI is an IIS6 only feature and not part of IIS7. Once I enabled the IIS6 compatibility features the code started working again.

Advertisements

Nice quote from Apple

I don’t know if it’s true or not, but apparently this is the letter you get when working for Apple. I thought I’d keep it around as I think it’s a good attitude;

There’s work and there’s your life’s work.

The kind of work that has your fingerprints all over it. The kind of work that you’d never compromise on. That you’d sacrifice a weekend for. You can do that kind of work at Apple. People don’t come here to play ¡t safe. They come here to swim in the deep end. They want their work to add up to something. Something big. Something that couldn’t happen anywhere else.

Welcome to Apple.

Windows 8 Release Preview – improvements but lacking

I’ve finally upgraded my version of Windows 8 and I wanted to see if has become a useful edition for the desktop user.

First off, it’s “preddy”. There have been a couple of subtle eye candy changes that are nice, not enough to recommend buying it but it’s nice. Once opened your are faced with the tablet UI, I mean Metro. Felt a little better, so I tried out the Weather application.

Annoyance #1 – Poor Feedback

I opened the Weather app and nothing happened. Actually since I am a developer I know what just happened. The initialisation of the application had taken too long and Windows had closed it. Now this will be new to desktop users as again we see the tablet UI in action. Phone/Tablet apps expect snappy responses to starting up. Mobile OS’ enforce this expectation by timing how long it takes the app to become responsive, too long and it simply kills it off. The problems here are a) no feedback, if at least said, “sorry that app was unresponsive, please try again” but no, just nothing b) Windows is expected to work on older kit that may not respond as fast as a dedicated mobile platform would.

Annoyance #2 – No .net 3

After witnessing the lack of feedback I felt I should blog about it. So off to install Live Writer. The first message I received was that I needed to install .net 3. Now whilst I understand that for a tablet you want to keep the software footprint as small as possible and that Metro is only .net 4 but in reality most desktop users will be using .net <4. So making me wait for it to be installing is a) annoying b) an example of Microsoft ignore the desktop user.

Annoyance #3 – corners vs. mouse

Back to Metro, and I’m purposely still using the mouse (my PC does support touch). Scrolling left I kept accidently bringing up the Start/Desktop menu in the bottom left corner. The reason is because I quickly “throw” the mouse pointer to the bottom left to scroll left (since Metro is heavily biased to horizontal scrolling). However, it’s quite hard to do that quickly and accurately enough to hit the scrollbar and not the start menu. Again, I feel MS have ignore the mouse user in the UX.

Annoyance #4 – vanishing scrollbar

Now this one is REALLY annoying. For example, I launched the People app which results in a large amount of horizontal scrolling. So I move my mouse to the bottom scrollbar and start reading and clicking to scroll through the list. Except I pause too long on a set of people and the scrollbar vanishes. But I’m reading the people so I just carry on clicking but nothing happens. I have to jiggle the mouse to get the scrollbar back. Come on MS this is terrible UX. Again, ignoring the desktop/mouse user.

Annoyance #5 – hotmail is better than mail

Next over to the mail tool. Hurray they’ve made it easier to see the different folders. Well done. Oh dear still cannot request to view the content of junk mal, how annoying. But the most annoying problem is the trickle feeding of items into the list. Normally when you open email tools all the mail arrives in one neat bundle. With Metro the emails trickle in as they’re observed by the system. From a UX point of view I’m trying to read the title of the latest item as it vanished off the bottom of the screen…but at a choppy rate, every time I catch up with it, it moves again. Terrible UX.

Annoyance #6 – metro, should promote clarity not noise

Still far too noisy with desktop apps. After installing Visual Studio 2010RC my Metro home looked like this;

image

So not only is it full of noise, I have not opened 90% of them, they were apps that were presumably launched by the installer. Come on MS, if you believe in Metro (as I do) then go back to the goals and give us what we need…please.

So in summary I’m still annoyed by Windows 8. To be fair I have seen some incremental improvements especially in the built in applications. However, MS really need to improve the core desktop UX as currently it is frustrating to use. I certainly would not recommend moving from Windows 7. There is still time to change, come on MS.

Poor mans ORM

Recently I’ve been looking at and hearing about data abstraction code that basically just calls a stored procedure and populates an objects on the way back. No identity management, just a simple mapper. I thought about using AutoMapper but as an intellectual exercise I wanted to see how easy (or not) it was to write a single helper that could move data from the stored procedure to an object based on convention. Here is the result;

public TCollection Load<TCollection, TItem>(string procedureName, params object[] arguments) where TCollection : IList
{
  this.connectionString = ConfigurationManager.ConnectionStrings["MyProject"].ConnectionString;
  TCollection instance = (TCollection)Activator.CreateInstance(typeof(TCollection));
  IList list = instance as IList;
  if (list == null)
  {
    throw new ArgumentOutOfRangeException("procedureName");
  }
  procedureName = "mySchema." + procedureName;
  using (SqlDataReader reader = ExecuteProcedure(procedureName, arguments))
  {
    while (reader.Read())
    {
      TItem item = (TItem)Activator.CreateInstance(typeof(TItem));
      for (int i = 0; i < reader.FieldCount; i++ )
      {
        string fieldName = reader.GetName(i);
        object value = reader[i];
        SetValue(item, fieldName, value);
        list.Add(item);
      }
    }
  }
  return instance;
}

The code assumes you’ll be getting objects representing lists of something <TCollection,TItem> and that the properties match the result set columns. The ExecuteProcedure command takes the arguments and maps them to the stored procedure arguments, easy enough to write. The SetValue is a little more involved;

private static void SetValue(object instance, string propertyName, object value)
{
  Type type = instance.GetType();
  PropertyInfo property = type.GetProperty(propertyName);
  var descriptor = TypeDescriptor.GetProperties(instance)[propertyName];
  TypeConverter converter = descriptor.Converter;
  if (converter != null)
  {
    property.SetValue(instance, converter.ConvertFrom(value), null);
  }
  else
  {
    property.SetValue(instance, value, null);
  }
}
  

The code uses standard reflection methods to set the property of the instance. The complication is the converter. If you are using a type that isn’t directly represented by a .net variant of a SQLType then you’ll need to use a converter. For example the following Id type needs its accompanying type converter (thanks to Chris Hannon)

public class MyItem
{
    [TypeConverter(typeof(MyIdTypeConverter))]
    public MyId Id { get; set; }
}
public class MyIdTypeConverter : TypeConverter
{
    public override object ConvertFrom(ITypeDescriptorContext context,
            System.Globalization.CultureInfo culture,
            object value)
  {
      if (value is int)
        return new MyId((int)value);
      else if (value is MyId)
        return value;
      return base.ConvertFrom(context, culture, value);
  }
}
 

So there you go, not eactly pain free but if you have a number of stored procedures and classes and you’re not overly worried about the performance hit of reflection then perhaps something like this will fit.

Quick tip, compress images

Today I was trying to send a Word document that had a couple of innocuous looking diagrams in it. The document was 8Mb. The images was greatly inflating the size. Examining the images I could see that Word was dynamically scaling them down but how do you tell Word to just save the picture at the resulting scale? Well in Word 2010 double click the picture and select the ‘Compress’ ribbon button and NOT the ‘Size’ ribbon.

MVC does not find the controller

In a previous post I talked about using MVC’s controller injection to drop in DLLs that contain controller classes. It allows for a nice separation leading onto creating a composite UI. I was happily using this mechanism when it just refused to load a controller from an additional DLL. I still do not understand why it doesn’t work but my workaround is to override the ControllerFactory. Here is a quick example of this, please note I’ve hardcoded the condition for the sake of this example.

protected void Application_Start()         
{
  ControllerBuilder.Current.SetControllerFactory(new MyControllerFactory());
  AreaRegistration.RegisterAllAreas();
  RegisterGlobalFilters(GlobalFilters.Filters);
  RegisterRoutes(RouteTable.Routes);
} 
     
public class MyControllerFactory : System.Web.Mvc.DefaultControllerFactory
{
protected override Type GetControllerType(System.Web.Routing.RequestContext requestContext, string controllerName)         
{             
  if (controllerName == "Library")
  {                                 
    Type reflib = Type.GetType("LibraryUI.Library,LibraryUI");
    return reflib;                              
  }             
  return base.GetControllerType(requestContext, controllerName);         
  }              
} 

Note: setcontrollerfactory is a bit old school, should be using the IoC of choice…I’ll need to look into a bit more, but for now this works