Friday, November 07, 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.

  • Evaluate the component per your current and future needs
  • Make sure it is functionally fit for your requirements
  • Gather metrics - if you're using a ASP.Net Server Control use Fiddler2 / WDH that support #2
  • Don't be influenced by what is being used currently
  • Don't go by popularity of the component or just because you've used it in your previous project
  • Make sure you can get support when required [not everyone have the threat of a multi-million dollar law suit in their arsenal]
  • Can they roll a custom build to fix your issue?
  • What is your backup plan if the component have to be replaced?
  • Have you identified a suitable alternative?
  • Is your design isolates 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!

    Thursday, July 17, 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 }
     

     

    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)