Thursday, November 06, 2008

Be wary of them the 3rd Party Components

I've been burned once and seen other projects burn because of wrong choice of 3rd party components.

My project - that was shot to hell - had to depend on a 3rd party component [Let's call it WiseImport ;)] from reading data from a competing product [MarketLeader]. We were doing an import wizard and Legal warned us not to use any of the SDKs exposed by the competitor [Legal moves in mysterious ways especially when the competitor offers the same kind of tool as an add-in]. But it was somehow okay to use the third party component.

The version 1.0 of the wizard used WiseImport successfully and in his infinite wisdom our Architect mandated us to go with the same product. Now, we required master-detail information from the MarketLeader. Alas, late in the game we found that the master & detail information are available separately but there was no way to link them to each other. The creator of WiseImport was a 2-person company that was successfully bullied into [I guess nothing motivates people like a threat of multi-million dollar law suit] looking at the problem at a war footing.

Well, let's just say he was near tears when he wrung his hands and said this was a bug in the MarketLeader product and he would only be able to provide a fix when the MarketLeader fixes its SDK. [And, of course, he was sorry as hell and was willing to refund the license fees ... I'm sure minuscule in comparison with "multi-million dollars"]

Oh, yes, the rest is history [along with the project that is].

In another instance, where I was called in as outside expert to look at the performance issues, I found, to my dismay the control used does not care about its ViewState size. I thought that these guys should be held criminally responsible for such a shoddy code. I'm no lawyer [probably explains why I don't make much money], so as a compromise, I had to hold the team responsible for their gross negligence. In the end, I thought I'll frame some guidelines - or at least warn people of the careless use of 3rd party components.

  1. Evaluate the component per your current and future needs
  2. Make sure it is functionally fit for your requirements
  3. Gather metrics - if you're using a ASP.Net Server Control use Fiddler2 / WDH that support #2
  4. Don't be influenced by what is being used currently
  5. Don't go by popularity of the component or just because you've used it in your previous project
  6. Make sure you can get support when required [not everyone have the threat of a multi-million dollar law suit in their arsenal]
  7. Can they roll a custom build to fix your issue?
  8. What is your backup plan if the component have to be replaced?
  9. Have you identified a suitable alternative?
  10. Does your design isolate the 3rd party component so you can plug & play?

I'm sure all the above may appear overkill. Let me assure you, they're not. You'll probably thank god [and your stars] for the sense you had to do the above. Or when the project fails [more aptly when the s**t hits the fan], you'll at least have covered your bases.

Friday, August 15, 2008

Addicted to my 24" Monitor

Guess I am getting a bit too addicted to the extra real estate.  The code in my blog looks awful on smaller monitor/window.  Will have to go back and reformat I guess when I have time.

[Rhino] Mock Anomalies: SetupResult.For to Lambda - "No Dice"

I had probably jumped to some conclusions with my earlier post.  While it's true GenerateStub<T>() refuses to accomodate SetupResult, the below testcase passes:

[TestMethod]
public void GenerateStubAndSetupResult()
{
    //With GenerateStub() alone, SetupResult fails with
    //IDemo stub = (IDemo)MockRepository.GenerateStub<IDemo>();
    IDemo stub = new MockRepository().Stub<IDemo>();
 
    int j = 0;
 
    SetupResult
        .For<string>(stub.ReturnStringNoArgs())
        .Do((Func<string>)(() => { return (++j).ToString(); }));
 
    SetupResult
        .For<string>(stub.ReturnStringWithInt32Arg(300)).IgnoreArguments()
        .Do((Func<int, string>)((arg) => { return string.Format("000{0}", arg); }));
 
    stub.Replay();
    Assert.AreEqual("1", stub.ReturnStringNoArgs());
    Assert.AreEqual("2", stub.ReturnStringNoArgs());
    Assert.AreEqual("000400", stub.ReturnStringWithInt32Arg(400));
    Assert.AreEqual("000500", stub.ReturnStringWithInt32Arg(500));
} 

Let's take our previous code and rewrite it, using the lesson above:

[TestMethod]

public void TestSetupStubOnceCallMultipleTimes2()
{
    //IDemo partialStub = MockRepository.GenerateStub<IDemo>();
    IDemo partialStub = new MockRepository().Stub<IDemo>();
 
    //This line does not work unless I have called the above .Stub<IDemo>
    //partialStub
    //    .Stub<IDemo, string>((x) => { return x.ReturnStringWithInt32Arg(30); })
    //    .IgnoreArguments()
    //    .Do(
    //        (Func<int, string>)((arg) =>
    //        {
    //            return string.Format(
    //                "{0}{1}",
    //                new string('0', 6 - arg.ToString().Length), arg);
    //        })
    //    );
 
    //If I comment the above line out, it gives me this error on SetupResult below
    //Test method ThinkFarAhead.LearningMocking.Expectations.SetupResult2.TestRhinoAndMoq.Working threw exception:
    //System.InvalidOperationException: Invalid call, the last call has been used or 
    //no call has been made (make sure that you are calling a virtual (C#) / Overridable (VB) method)..
    //This error occurs both when I create the Stub using MockRepository.GenerateStub<IDemo>() or new MockRepository().Stub<IDemo>()
    //SetupResult.For((Action<IDemo>)(x => x.ReturnStringWithInt32Arg(30))).IgnoreArguments()
    //  .Do((Func<int, string>)((arg) =>
    //  {
    //      return string.Format(
    //          "{0}{1}",
    //          new string('0', 6 - arg.ToString().Length), arg);
    //  }
    //    ));
 
    SetupResult
        .For(partialStub.ReturnStringWithInt32Arg(20))
        .IgnoreArguments()
        .Do((Func<int, string>)((arg) =>
            {
                return string.Format(
                    "{0}{1}",
                    new string('0', 6 - arg.ToString().Length), arg);
            }
        ));
 
    partialStub.Replay();
    Assert.AreEqual("000020", partialStub.ReturnStringWithInt32Arg(20));
    Assert.AreEqual("000030", partialStub.ReturnStringWithInt32Arg(30));
    Assert.AreEqual("000040", partialStub.ReturnStringWithInt32Arg(40));
}

[Rhino] Mock Anomalies: Setup Stub Once Call Multiple Times - Must Call .Stub<T> and SetupResult

I was hooking up multiple times because otherwise it was giving me grief.  Here's the test that seems to work the way I intended (for setting up a stub method once and call it multiple times.

[TestMethod]
public void TestSetupStubOnceCallMultipleTimes()
{
    //IDemo partialStub = MockRepository.GenerateStub<IDemo>();
    IDemo partialStub = new MockRepository().Stub<IDemo>();
 
    //This line does not work unless I have called the above .Stub<IDemo>
    partialStub
        .Stub<IDemo, string>((x) => { return x.ReturnStringWithInt32Arg(30); })
        .IgnoreArguments()
        .Do(
            (Func<int, string>)((arg) =>
            {
                return string.Format(
                    "{0}{1}",
                    new string('0', 6 - arg.ToString().Length), arg);
            })
        );
 
    //If I comment the above line out, it gives me this error on SetupResult below
    //Test method ThinkFarAhead.LearningMocking.Expectations.SetupResult2.TestRhinoAndMoq.Working threw exception:
    //System.InvalidOperationException: Invalid call, the last call has been used or 
    //no call has been made (make sure that you are calling a virtual (C#) / Overridable (VB) method)..
    //This error occurs both when I create the Stub using 
    //MockRepository.GenerateStub<IDemo>() or new MockRepository().Stub<IDemo>()
    SetupResult.For((Action<IDemo>)(x => x.ReturnStringWithInt32Arg(30))).IgnoreArguments()
      .Do((Func<int, string>)((arg) =>
      {
          return string.Format(
              "{0}{1}",
              new string('0', 6 - arg.ToString().Length), arg);
      }
        ));
 
 
    partialStub.Replay();
    Assert.AreEqual("000020", partialStub.ReturnStringWithInt32Arg(20));
    Assert.AreEqual("000030", partialStub.ReturnStringWithInt32Arg(30));
    Assert.AreEqual("000040", partialStub.ReturnStringWithInt32Arg(40));
}

Thursday, August 14, 2008

Mocking Anomalies: Can't Override Non-Virtual Methods (Ans: Partial Stubs?)

The problem I am facing currently is that I and my team are working simultaneously on interdependent pieces of the system under development. My piece was depending on a piece of my colleague's and one of his methods was throwing a "NotImplementedException".

Wanted to mock just that method so I could proceed with testing my work.

Here's how the code looks in Rhino:

    1 using System;
    2 using Microsoft.VisualStudio.TestTools.UnitTesting;
    3 using Rhino.Mocks;
    4 
    5 namespace ThinkFarAhead.LearningMocking
    6 {
    7     [TestClass]
    8     public class TestRhinoAndMoq
    9     {
   10         [TestMethod]
   11         public void TestPartialMock()
   12         {
   13             Demo partialMock = new MockRepository().PartialMock<Demo>();
   14             partialMock
   15                 .Stub<Demo, string>(x => x.ReturnStringNoArgs())
   16                 .Do((Func<string>)delegate { return "somevalidstring"; });
   17 
   18             partialMock.Replay();
   19             Assert.AreEqual(partialMock.ReturnStringNoArgs(), "somevalidstring");
   20         }
   21 
   22         [TestMethod]
   23         public void TestPartialStub()
   24         {
   25             IDemo partialStub = MockRepository.GenerateStub<IDemo>();
   26             partialStub
   27                 .Stub<IDemo, string>(x => x.ReturnStringNoArgs())
   28                 .Do((Func<string>)delegate { return "somevalidstring"; });
   29 
   30             partialStub.Replay();
   31             Assert.AreEqual(partialStub.ReturnStringNoArgs(), "somevalidstring");
   32         }
   33     }
   34 
   35     public interface IDemo
   36     {
   37         string ReturnStringNoArgs();
   38         string ReturnStringWithInt32Arg(int arg);
   39     }
   40 
   41     public class Demo : IDemo
   42     {
   43         public virtual string ReturnStringNoArgs()
   44         {
   45             throw new NotImplementedException();
   46         }
   47 
   48         public string ReturnStringWithInt32Arg(int arg)
   49         {
   50             return string.Format("{0}{1}", new string('0', 6 - arg.ToString().Length), arg);
   51         }
   52     }
   53 }

As you can see both the tests pass. Let's remove 'virtual' from:

   45 public string ReturnStringNoArgs()

Now, as expected, TestPartialMock fails.

Test method ThinkFarAhead.LearningMocking.TestRhinoAndMoq.TestPartialMock threw exception: System.NotImplementedException: The method or operation is not implemented..

Oh yeah, we've been told that it's a constraint imposed by Castle Dynamic Proxy [actually CLR]. Hey, I don't want to fight the system, all I want is to wring the functionality I need from the framework.

Also, consider the below behaviour:

            System.Diagnostics.Debug.WriteLine(partialMock.ReturnStringWithInt32Arg(20)); // will print "000020" 
            System.Diagnostics.Debug.WriteLine(partialMock.ReturnStringWithInt32Arg(30)); // will print "000030" 

With stub, you will have to setup two different expectations: [I'm not sure I need to! I've posted this question on the forum. Will provide the link later]

    partialStub
        .Stub<IDemo, string>((Func<IDemo, string>)delegate(IDemo x) { return x.ReturnStringWithInt32Arg(20); })
        .IgnoreArguments()
        .Do((Func<int, string>)
            delegate(int arg)
            {
                return string.Format(
                    "{0}{1}",
                    new string('0', 6 - arg.ToString().Length), arg);
            }
        );
 
    partialStub
        .Stub<IDemo, string>((Func<IDemo, string>)delegate(IDemo x) { return x.ReturnStringWithInt32Arg(30); })
        .IgnoreArguments()
        .Do((Func<int, string>)
            delegate(int arg)
            {
                return string.Format(
                    "{0}{1}",
                    new string('0', 6 - arg.ToString().Length), arg);
            }
        );
 
    partialStub.Replay();
    System.Diagnostics.Debug.WriteLine(partialStub.ReturnStringWithInt32Arg(20)); // will return "000020"             
    System.Diagnostics.Debug.WriteLine(partialStub.ReturnStringWithInt32Arg(30)); // will return "000030" 

Even if I do not have to setup multiple times, once for each argument, if the logic is non-trivial, replicating the same logic on the Stub method would be VERY inconvenient. Not to mention dependencies if needed. Stub per Fowler's definition is supposed to just return "canned" responses right? [Aside: This is a classic example of theory superceded by common sense. If you're supposed to return "canned" responses, you better be prepared to anticipate each argument. Guess that's what Fakes do. We're trying to implement a 'Fake' by using Rhino's Stub. Oh, well, we're getting derailed by jargon now]

OK, where does it all lead to? Well, It seems we need a PartialStub [Jargon again? :)]. Hm...or is there a better way?

How about this: One that will delegate [not the C# one, the one that managers practice ;)] calls to the original object when no expectations are set. And override them when specified.

Let's define our "wanna be" syntax, shall we?

With Rhino:

        [TestMethod]
        public void TestPartialStub()
        {
            Demo demo = new Demo();
            IDemo partialStub = MockRepository.GenerateStub<IDemo>(demo);
            partialStub
                .Stub<IDemo, string>(x => x.ReturnStringNoArgs())
                .Do((Func<string>)delegate { return "somevalidstring"; });
 
            partialStub.Replay();
 
            //Route calls to the actual object 
            Assert.AreEqual(partialStub.ReturnStringWithInt32Arg(20), "000020");
            Assert.AreEqual(partialStub.ReturnStringWithInt32Arg(30), "000030");
 
            //Call the Stub override 
            Assert.AreEqual(partialStub.ReturnStringNoArgs(), "somevalidstring");
        }
With Moq:
        [TestMethod]
        public void TestPartialStubMoq()
        {
            Demo demo = new Demo();
            Mock<IDemo> repo = new Mock<IDemo>(demo);
            IDemo partialStub = repo.Object;
 
            repo.Expect<string>(x => x.ReturnStringNoArgs()).Returns("somestringbydefault");
            Assert.IsTrue(partialStub.ReturnStringWithInt32Arg(10), "000010");
            Assert.IsTrue(partialStub.ReturnStringNoArgs(), "somestringbydefault");
        }

I would like to add this functionality to both Rhino & Moq with both Ayende and Daniell asking me to contribute. Hope I'll get something done over the weekend. Let me know what you think.

Monday, July 21, 2008

CAS & RefusedSet of permissions

I granted assemblies with a particular Strong Name "Full Trust" both in "My Computer" and "Intranet" zone.  When I run them out of VS.Net IDE they run with full set of permissions.  But, the moment I specify one or more permissions as "requisites" on my assembly, I get SecurityException (s) for the permissions I didn't mention on my assembly.

  1. I used .Net Framework 2.0 Configuration Wizard to grant all assemblies (in MyComputer zone as I'm debugging in my IDE)  that has a particular Strong Name.
  2. Now, I go ahead and specify a single pre-requisite for the assembly:
    • [assembly: SqlClientPermission(SecurityAction.RequestMinimum, Unrestricted = true)]
  3. I run the application
  4. A tell-tale security warning appears signifying the assembly is no longer running under "Full Trust" CAS-1
    • Warning: Indicates assembly is no longer running under "Full Trust"
  5. I specify UI permissions now:
    • [assembly: UIPermission(SecurityAction.RequestMinimum, Unrestricted=true)

    CAS-2

    • Fig 2: UIPermission granted.  No warning messages
  6. The warning disappears
  7. As soon as I move to the next step in the wizard [where it requires a ConfigurationPermission], it throws a SecurityException CAS-3
    • Fig 3: Exception due to ConfigurationPermission denied
  8. But when I remove all CAS permission request declarations, the code appears to run with "Full Trust"

CAS-4

    • Fig 4: All access granted [including ConfigurationPermission]  

This leads me to wonder if the permissions I do not specify on the assembly become part of the permissions refused!

Wednesday, July 16, 2008

Castle Windsor RC3 Woes Continued...

 

Now, I'm asking WindsorContainer to pickup from the default configuration file as it supposed to:

   45         public static IDbCreator GetDBCreator()
   46         {
   47             WindsorContainer container = new WindsorContainer(); //WindsorConfigFile);
   48             IDbCreator creator = container.Resolve<IDbCreator>(UserPreferences.Instance.LocalDataStoreChosen);
   49             return creator;
   50         }
 
With this result:
 
CastleWindsor-2 
 
Of course, AppDomain.CurrentDomain.SetupInformation.ConfigurationFile is pointing to a valid *.dll.config file and is having all keys:
 
      <component id="DbTypeSql"
            service="ThinkFarAhead.WordReporter.Data.IDbCreator"
            type="ThinkFarAhead.WordReporter.Data.SqlDbCreator, ThinkFarAhead.WordReporter.Data">
      </component>

Castle Windsor RC3 Detests MSTest?: DeserializeElement cannot process element configSections

 

I'm exasperated getting Castle Windsor to work with MSTest.  For once, it's not the other way around :)  Here's the partial code tries to resolve a database provider using Windsor.  The App.config in my MSTest project is copied to a TestResults folder with a *.dll.config extension [I didn't know .Net started allowing .dll.config files.  Well may not be, but that's a topic for another post!). 

Here's my app.config [ThinkFarAhead.WordReporter.Data.UnitTest.dll.config]:

    1 <?xml version="1.0"?>
    2 <configuration>
    3   <configSections>
    4     <section name="castle"
    5         type="Castle.Windsor.Configuration.AppDomain.CastleSectionHandler, Castle.Windsor" />
    6 
    7   </configSections>
    8 
    9   <castle>
   10     <components>
   11       <component id="DbTypeSql"
   12             service="ThinkFarAhead.WordReporter.Data.IDbCreator"
   13             type="ThinkFarAhead.WordReporter.Data.SqlDbCreator, ThinkFarAhead.WordReporter.Data">
   14       </component>
   15       <component id="DbTypeOracle"
   16             service="ThinkFarAhead.WordReporter.Data.IDbCreator"
   17             type="ThinkFarAhead.WordReporter.Data.OracleDbCreator, ThinkFarAhead.WordReporter.Data">
   18       </component>
   19       <component id="DbTypeOledb"
   20             service="ThinkFarAhead.WordReporter.Data.IDbCreator"
   21             type="ThinkFarAhead.WordReporter.Data.OleDbDbCreator, ThinkFarAhead.WordReporter.Data">
   22       </component>
   23       <component id="DbTypeOdbc"
   24             service="ThinkFarAhead.WordReporter.Data.IDbCreator"
   25             type="ThinkFarAhead.WordReporter.Data.OdbcDbCreator, ThinkFarAhead.WordReporter.Data">
   26       </component>
   27     </components>
   28   </castle>
   29 </configuration>
Here's the code that tries to inject dependencies:

   37         private static string WindsorConfigFile;
   38         static DbCreatorFactory()
   39         {
   40             WindsorConfigFile = AppDomain.CurrentDomain.SetupInformation.ConfigurationFile; //  set // "Windsor.config"; //string.Format(@"{0}\Windsor.Config", Path.GetDirectoryName(Assembly.GetExecutingAssembly().CodeBase));
   41         }
   42 
   43         //Removed statically typed enum [that cannot be extended at runtime]
   44         //Here at least other clients can pass anything
   45         public static IDbCreator GetDBCreator()
   46         {
   47             WindsorContainer container = new WindsorContainer(WindsorConfigFile);
   48             IDbCreator creator = container.Resolve<IDbCreator>(UserPreferences.Instance.LocalDataStoreChosen);
   49             return creator;
   50         }

Here's my MSTest code:

   69         [TestMethod]
   70         public void CheckObjectCreation()
   71         {
   72             string[] databaseTypes = new string[] { "DbTypeSql", "DbType.Oracle" }; //, "DbType.Oledb", "DbType.Odbc"};
   73             Type [] dbCreators = new Type [] { typeof(SqlDbCreator), typeof(OracleDbCreator)}; //, typeof(OracleDbCreator), typeof(OleDbDbCreator)
   74             for (int i = 0; i < databaseTypes.Length; i++)
   75             {
   76                 UserPreferences.Instance.LocalDataStoreChosen = databaseTypes[i];
   77                 if(!(DbCreatorFactory.GetDBCreator() == dbCreators[i]))
   78                 {
   79                     Assert.Fail(string.Format("Type {0} instantiated incorrectly for key {1}", dbCreators[i].ToString(), databaseTypes[i]));
   80                 }
   81             }
   82         }

It fails with:

CastleWindsor-1

 

Technorati Tags: ,

Sunday, July 13, 2008

Tip: ScriptSharp and $(ScriptPath)

If you're using Script# "Class Library in a Web Site" template, you need to make sure you're Script# Projects are located inside the "bin\Scripts" of the Web site. Yes, you heard me right. If you want a reusable class library or simply want to use the scripts generated on multiple Web projects on the same solution, use either "Class Library" or "Atlas Class Library". I thought I had found a bug when I couldn't find the script files. Here's the complete analysis for the brave: 1) Select Script# "Class Library in a Web Site" template

2) Type the following it the default "Class1.cs" created
    1 // Class1.cs
    2 //
    3 
    4 using System;
    5 using System.DHTML;
    6 using ScriptFX;
    7 using ScriptFX.UI;
    8 
    9 namespace ThinkFarAhead.WordReporter.TestBed.ScriptsForWeb
   10 {
   11 
   12     public class Class1
   13     {
   14         public void Greet()
   15         {
   16             Script.Alert("Hi!");
   17         }
   18 
   19         public void Main()
   20         {
   21             new Class1().Greet();
   22         }
   23     }
   24 }
3) Compile and search for the *.js files created. Hey, at least I was searching for it forever! Here's my line of thinking went: If Script# is using MSBuild, the code for calling ssc.exe should be in the project.
   49   <Import Project="$(ProgramFiles)\nStuff\ScriptSharp\v1.0\nStuff.ScriptSharp.targets" />
Well, it does import some MSBuild targets. Let's see what is it:
   32     <ScriptCompilerTask
   33       Sources="@(Compile)"
   34       Resources="@(EmbeddedResource)"
   35       References="@(ReferencePath)"
   36       Defines="$(DefineConstants)"
   37       OutputPath="$(OutputPath)"
   38       ScriptPath="$(ScriptPath)"
   39       LocaleSubFolders="$(LocaleSubFolders)"
   40       ScriptName="$(ScriptName)"
   41       Template="$(TemplateFile)"
   42       CopyReferences="$(CopyReferences)"
   43       CSharpAssembly="@(IntermediateAssembly)"
   44       DocumentationFile="$(DocumentationFile)"
   45       SuppressDocumentation="$(SuppressDocumentation)">
   46       <Output TaskParameter="DebugScriptFile" ItemName="DebugScriptFile" />
   47       <Output TaskParameter="ReleaseScriptFile" ItemName="ReleaseScriptFile" />
   48     </ScriptCompilerTask>
 
Hm... it seems to be putting the scripts at $(ScriptPath). Let's see what's the path during compilation:
   49   <!-- Added by Vyas to know where Script# is keeping my files-->
   50   <Warning Text="Script Folder: $(ScriptPath)"/>
The project template is showing a value for $(ScriptPath) and I'm sure the compile-time warning added would confirm it
   22     <ScriptPath>..\..\..\App_Scripts\</ScriptPath>
Here's the compiler output:

------ Build started: Project: ThinkFarAhead.WordReporter.Web.Scripts, Configuration: Debug Any CPU ------

C:\Windows\Microsoft.NET\Framework\v3.5\Csc.exe /noconfig /nowarn:0028,1591,1701,1702 /nostdlib+ /errorreport:prompt /warn:4 /doc:..\ThinkFarAhead.WordReporter.Web.Scripts.xml /define:DEBUG /reference:"C:\Program Files (x86)\nStuff\ScriptSharp\v1.0\Framework\sscorlib.dll" /reference:"C:\Program Files (x86)\nStuff\ScriptSharp\v1.0\Framework\ssfx.Core.dll" /reference:"C:\Program Files (x86)\nStuff\ScriptSharp\v1.0\Framework\ssfx.UI.Forms.dll" /debug- /optimize+ /out:obj\Debug\ThinkFarAhead.WordReporter.Web.Scripts.dll /target:library Properties\AssemblyInfo.cs ClientCapabilityDetecter.cs

Compile complete -- 0 errors, 0 warnings

C:\Program Files (x86)\nStuff\ScriptSharp\v1.0\nStuff.ScriptSharp.targets : warning : Script Folder: ..\..\App_Scripts\

Done building project "ThinkFarAhead.WordReporter.Web.Scripts.csproj".

I would have tought it should put it inside the project folder! It's dereferencing it from the project folder and put it on the root for me. Project folder: D:\C#\ , Script output folder: D:\App_Scripts. I had looked at the samples before and it's putting the scripts correctly on the App_Scripts folder. Closer scrutiny this time reveals Nikhi's put the Script Projects "inside" the Web project itself at "bin\Scripts"! No wonder "..\..\..\App_Scripts" works for him.

Oh yes, I'm kicking myself for not figuring this one out much earlier!

Tip: Script# for VS.Net 2008 & Windows Vista 64

 

Those who are developing on a Vista 64 know VS.Net 2008 cannot debug 64-bit assemblies.  You need to select x86 as CPU for the resultant assembly to be debuggable.  Though on Script# projects, make sure you have "Any CPU" selected.  Otherwise, it would not generate *.js files.

<PropertyGroup Condition=" '$(Configuration)|$(Platform)' == 'Debug|AnyCPU' ">

  <OutputPath>bin\Debug\</OutputPath>

  <DefineConstants>DEBUG</DefineConstants>

  <ErrorReport>prompt</ErrorReport>

  <WarningLevel>4</WarningLevel>

  <NoWarn>0028, 1591</NoWarn>

  <DocumentationFile>bin\Debug\ThinkFarAhead.WordReporter.Web.Scriptlets.xml</DocumentationFile>

</PropertyGroup>

<PropertyGroup Condition=" '$(Configuration)|$(Platform)' == 'Release|AnyCPU' ">

  <OutputPath>bin\Release\</OutputPath>

  <DefineConstants>

  </DefineConstants>

  <ErrorReport>prompt</ErrorReport>

  <WarningLevel>4</WarningLevel>

  <NoWarn>0028, 1591</NoWarn>

  <DocumentationFile>bin\Release\ThinkFarAhead.WordReporter.Web.Scriptlets.xml</DocumentationFile>

</PropertyGroup>

DeskPins - Always On Top

Found a wonderful little gem of a program today: DeskPins.  Now I can make effective use of my 24" display!

DeskPins

Sunday, July 06, 2008

Extension Methods: Calling on an object instance

In C#, static methods could only be called through their respective type references.  The power of Extensions Methods lies in the fact they could be called on an object instance.  In fact, they could ONLY be called on an object instance.  This ability is vital for implementing Linq in C# 3.0.

    1 using System;
    2 using System.Collections.Generic;
    3 using System.Linq;
    4 using System.Text;
    5 
    6 namespace TestBed
    7 {
    8 
    9     public class TestExtensionMethods
   10     {
   11         public static void Main()
   12         {
   13 
   14             string val = "Vyas";
   15 
   16             //Static method of string class called through the class
   17             Console.WriteLine("Is Internered: {0}", string.IsInterned(val));
   18 
   19             //Static method called through an instance
   20             //Intellisense does not display it
   21             //Error: Member 'string.IsInterned(string)' cannot be 
   22             //accessed with an instance reference; 
   23             //qualify it with a type name instead
   24             //Console.WriteLine(val.IsInterned(val));
   25 
   26 
   27             //The ability for a static method to be called through an instance
   28             Console.WriteLine(val.Reverse());
   29 
   30             //Does not compile
   31             //Error: 'string' does not contain a definition for 'Reverse'
   32             //Console.WriteLine(string.Reverse(val));
   33             Console.Read();
   34         }
   35 
   36     }
   37 
   38     public static class StringUtils
   39     {
   40         public static string Reverse(this string arg)
   41         {
   42             char [] reversed;
   43             Array.Reverse(reversed = arg.ToCharArray());
   44             return new string(reversed);
   45 
   46         }
   47     }
   48 
   49 
   50 }
 

 

Saturday, July 05, 2008

My New Rig - Part II: Assembling

Apologies for posting this second issue after so long!  When quad-cores are going out of fashion and dual or quad-quad cores are in ;)

The story goes like this:

  1. I found SG975XBX2 does not have a VGA out!
    • Shelled out nearly INR 2500/- [around USD $55]
  2. The SG975XBX2 does not support Intel Core-2-Quad
  3. I waited for over 2 weeks to get a replacement [No D975XBX2].  The shopkeeper would tell one story or the other and kept me at bay [with my money securely in his pocket, of course :)] for a ASUS board.
  4. Finally, I gave in and asked for a MSI P35 Platinum Combo
    • I had to literally sit there for an hour to get this
  5. The new board MSI P35 Platinum Combo had dual RAM support (DDR2 & DDR3)
    • Aside:  When you turn on the power for the first time, it switches itself off and restarts, presumably to detect memory used.  I wonder what purpose the "toggle card" has.  We are supposed to switch direction of the card per type of RAM used.   As if the grave warnings threatening dire consequences if the type of RAM and the direction of the switch card is wrong weren't enough!
  6. Installed Vista 64 Enterprise
    • One of the perks of being a Volume Licensing Administrator for the company.  A MSDN Universal subscription
  7. The machine booted alright but the processor was overheating (about 95 degree C).  Eventually traced it to incorrectly installed Processor Fan.  Now it hovers around 35 degree C
  8. Alas, by now, my monitor, a 20" Samsung SyncMaster 206BW started displaying horizontal lines [it's still in Warranty but in Europe!].  There goes my 2000 Swedish Kroner down the drain!

Final Component List:

  • Intel Core 2 Quad Q6600
  • MSI P35 Platinum Combo
    • Integrated Sound 7.1
    • Integrated LAN Support
  • Transcend 4 GB DDR II RAM [800 MHz]
  • Nvidia GeForce 8400 GS

I took my Desktop with me when I shifted my base to US last month.  I found, to my dismay, my SMPS wouldn't support dual voltage and I shelled out $150 for an Antec S75QB.  Also bought a Samsung SyncMaster mentioned above for $550

  • Antec S75QB 750W ATX 12V
  • Samsung  SyncMaster 2493HM (24" LCD)

BUG(?): Hosting Word 2007 Document inside IE

I'm in the process of writing an Open Source Word based reporting tool. It requires me to have Word 2007 hosted inside IE. I have two problems: 1. The standard default Word 2007 SDI behavior opens a blank Word Window (without any documents) 2. The MDI behavior is stranger [Uncheck Show All Windows in the Taskbar] Here's a flash movie I made demonstrating the issue. You can see how Word 2007 is giving me grief! Oh, of course, this behavior may be by design.

Saturday, June 28, 2008

A post after a long time!

It had been a hectic year for me.   From Feb, it had been a whirlwind of events over which I had little control.  

  1. I was supposed to move to US for a year last Feb
  2. Sent my pregnant wife back to her folks as she'd have to manage alone if I were to fly
  3. The travel was postponed by couple of months!
    1. Blast the client that took that decision.  Managers seldom have the foggiest the ripple effects their decisions have.
  4. Took possession of my new apartment in Mar
  5. Vacated my then rented residence in Noida and moved all my things there single handedly
  6. Became a father [for the second time] to another fairy christened Sanchita in April.
  7. Was on a [well deserved] couple of week vacation right after that!
  8. Travelled to US was finally confirmed!
  9. Returned to Noida and suffered couple of bad [Luckily, only financially] car accidents where I had to claim Insurance 4 times!  [Two double claims, really]
  10. Was told I wouldn't be getting my car back before I travelled
  11. Inconvenienced a colleague and friend to pick it up and park it at my apartment
  12. Moved all of the unpacked items into the Guest Bedroom
  13. Let it out for couple of months [Lucky?]
  14. Visited my Wife & Kids before travel for couple of days!
  15. Flew finally to and here I am, in Reno, NV awaiting my family to join me in a month's time.
  16. Stayed in Extended Stay for a week
  17. Realized [first of many 'realizeds' ;)] that I could not locate my Travel adapter in my partially unpacked apartment
  18. Without a Driver's license, shelled out $30 to go to the nearest Radio Shack and bought my 3rd Travel adapter in as many trips.
  19. Bought a Samsung 24" TFT and a Microsoft Ego 4000 [my 2nd one] to go with my CPU brought from India [my barely 6 month old Core 2 Quad]!
  20. Realization dawned on my dumb skull that the SMPS in my India PC is 230 V
    1. This happened with me on the Extension, Iron as well!!!  Dumb thrice! [sigh].  Thrice is what I thought!  Hmm... I concede I'm no psychic.
  21. Reluctantly sunk 150$ [30$ mail-in rebate I'd never set my hands on] on a 750 Watt Silencer SMPS
  22. Received yesterday and started my quest for a Phillips Screwdriver!
  23. Sunk another $7 buying "Allied 16 Piece Ratcheting Screwdriver Set"
  24. Started today at last, and found my damned PC cabinet wouldn't make room for the new SMPS.
  25. So, now my machine's all opened up, wires dangling everywhere and I'll have to get a new Cabinet [I did feel some foreboding intuition when I scorned that combo offer at Newegg.com]
  26. But hey, did I tell you, albeit all the trouble,  I'm online  and of course it beats my laptop hands down!
    1. And my 24" monitor is a beauty!  I went for a Samsung even after the 20" TFT I had bought in Sweden developed twelve horizontal lines within a span of 6 months.

Guys/Gals, drop me a line at Linkedin / my official id for my latest co-ordinates.