Sunday, April 28, 2013

Hosting netTcp WCF Service in WAS

Code Download.

For this post I'm using Windows 8, but these steps should work in Windows 7 and Server 2008 also.

Some searching produced a MSDN post showing some commands that need to be executed if you're running Windows 7 or Server 2008. However these are not necessary in Windows 8.


"%WINDIR%\Microsoft.Net\Framework\v4.0.30319\aspnet_regiis" –i –enable

Running this command in Windows 8 returns:

Microsoft (R) ASP.NET RegIIS version 4.0.30319.17929
Administration utility to install and uninstall ASP.NET on the local machine.
Copyright (C) Microsoft Corporation.  All rights reserved.
Start installing ASP.NET (4.0.30319.17929).
This option is not supported on this version of the operating system.  Administr
ators should instead install/uninstall ASP.NET 4.5 with IIS8 using the "Turn Win
dows Features On/Off" dialog,  the Server Manager management tool, or the dism.e
xe command line tool.  For more details please see http://go.microsoft.com/fwlin
k/?LinkID=216771.
Finished installing ASP.NET (4.0.30319.17929).
 
The post also recommended running:
"%WINDIR%\Microsoft.Net\Framework\v4.0.30319\ServiceModelReg.exe" -r  
 
Which also returns something similar:

Microsoft (R) WCF/WF registration tool version 4.5.0.0
Copyright (c) Microsoft Corporation.  All rights reserved.

Administration utility that manages the installation and uninstallation of
WCF and WF components on a single machine.

[Error]This tool is not supported on this version of Windows. Administrators sho
uld instead install/uninstall Windows Communication Foundation features using th
e 'Turn Windows Features On/Off' dialog, or the dism command line tool.
  
 
Install IIS and WAS Hosting components with add/remove windows features:
 

After completing this re-running the aspnet_regiis command above still returns the same response, so this is definitely not necessary in Windows 8.

The above installation of windows components has automatically registered net.tcp with IIS.

Previously under Windows 7 running the following command would have been necessary:
%windir%\system32\inetsrv\appcmd.exe set site "Default Web Site" -+bindings.[protocol='net.tcp',bindingInformation='808:*']

You can check to ensure net.tcp has been enabled for the default web site by opening IIS and looking at the default web site bindings: (If you have multiple sites hosted inside IIS then net.tcp can be added manually using this dialog also)


Open the advanced settings for your virtual directory and ensure net.tcp is an enabled protocol, if not just type it in.

The new service virtual directory will use the "Default App Pool" this will be using the Framework v4, in integrated mode.  If your default app pool is different, create a new app pool with these settings.

You should now be able to browse to the service using a browser.  (The web.config of the service has enabled <serviceMetadata httpGetEnabled="true"/>)

Since httpGetEnabled is on, using the WcfTestClient.exe you can add the service using "http://localhost/WasTcpDemo/CalculatorService.svc".
However, the client config the tool has generated only allows communication with net.tcp for invoking service operations.
Given the web.config also allows for obtaining metadata over net.tcp you can also add the service using the address "net.tcp://localhost/WasTcpDemo/CalculatorService.svc".

Once the Test Client has added the service, you can remove the serviceMetadata element and the MetadataExchange binding to ensure net.tcp communications without exposed metadata.


References:

One Time setup: http://msdn.microsoft.com/en-us/library/ms751527.aspx
This post was based on the MSDN Example: http://msdn.microsoft.com/en-us/library/ms752218.aspx

Tuesday, February 19, 2013

Using Log4Net Appenders at different levels


<log4net>
  <appender name="SomeXmlAppender" type="log4net.Appender.RollingFileAppender">
    <pattern ... />
    <evaluator type="log4net.Core.LevelEvaluator">
      <threshold value="INFO"/>
    </evaluator>
    <filter type="log4net.Filter.LevelRangeFilter">
      <levelMin value="INFO" />
      <acceptOnMatch value="true" />
    </filter>
    <filter type="log4net.Filter.DenyAllFilter" />
  </appender>

  <appender name="SomeEventLogAppender" type="log4net.Appender.EventLogAppender">
    <pattern ... />
    <evaluator type="log4net.Core.LevelEvaluator">
      <threshold value="ERROR"/>
    </evaluator>
    <filter type="log4net.Filter.LevelRangeFilter">
      <levelMin value="ERROR" />
      <acceptOnMatch value="true" />
    </filter>
    <filter type="log4net.Filter.DenyAllFilter" />
  </appender>

  <root>
    <level value="DEBUG" />
    <appender-ref ref="SomeXmlAppender" />
    <appender-ref ref="SomeEventLogAppender" />
  </root>
</log4net>

Thursday, January 17, 2013

MoQ - Running tests in Parallel

It may not be accurate to say that MoQ (Quick start intro) is thread safe when running tests in parallel because it appears it is not in other circumstances.  Check out this blog post where they modified the source to fix a threading issue.

However, it appears that MoQ avoids the issue I described in the previous post about how Rhino falls over intermittently when running tests in parallel.  MoQ avoids this by design.  Here's the modified code from  Test1 converted to MoQ:


    [TestClass]
    public class Test1
    {
        [TestMethod]
        public void Test1a()
        {
            var dependency1 = new Mock<IDependency1>();
            var dependency2 = new Mock<IDependency2>();

            dependency1.Setup(m => m.DependentMethod("System.String")).Returns(false);

            dependency2.Setup(m => m.Kind).Returns(TypeKind.Foo);
            dependency2.Setup(m => m.StringProperty).Returns("System.String");

            var target = new TestSubject(dependency1.Object, dependency2.Object);
            Assert.IsFalse(target.SubjectMethod());
            dependency1.VerifyAll();
            dependency2.VerifyAll();
        }

        [TestMethod]
        public void Test1b()
        {
            var dependency1 = new Mock<IDependency1>();
            var dependency2 = new Mock<IDependency2>();

            dependency1.Setup(m => m.DependentMethod("System.String")).Returns(true);

            dependency2.Setup(m => m.Kind).Returns(TypeKind.Foo);
            dependency2.Setup(m => m.StringProperty).Returns("System.String");

            var target = new TestSubject(dependency1.Object, dependency2.Object);
            Assert.IsTrue(target.SubjectMethod());
            dependency1.VerifyAll();
            dependency2.VerifyAll();
        }
   }

These tests pass every time.
Even the updated brute force parallel tests runs ok.
    [TestClass]
    public class Test2
    {
        [TestMethod]
        public void BruteForceTest()
        {
            var threads = new Thread[30];
            for (int i = 0; i < threads.GetUpperBound(0); i++)
            {
                threads[i] = new Thread(this.ThreadAction);
                threads[i].Start();
            }

            for (int i = 0; i < threads.GetUpperBound(0); i++)
            {
                threads[i].Join();
            }
        }

        private void ThreadAction()
        {
            var dependency1 = new Mock<IDependency1>();
            var dependency2 = new Mock<IDependency2>();

            dependency1.Setup(m => m.DependentMethod("System.String")).Returns(false);

            dependency2.Setup(m => m.Kind).Returns(TypeKind.Foo);
            dependency2.Setup(m => m.StringProperty).Returns("System.String");

            var target = new TestSubject(dependency1.Object, dependency2.Object);
            target.SubjectMethod();
        }
    }