Sunday, September 15, 2013

Creating a MSDeploy package outside of Visual Studio – gotchas

I meet with a lot of customers that have the same problems creating packages that can deploy to IIS successfully. Here is my 3 stage process.

  1. Create a web application (SampleWebApplication.sln), check it renders a page and then close Visual Studio
  2. Create a batch file at the same location as the sln file, lets say Package.bat and run it.

msbuild SampleWebApp.sln /p:DeployOnBuild=true;Configuration=Release;PackageLocation=c:\src\test\SampleWebApp.zip;DeployIisAppPath="Default Web Site\SampleWebApp"

  • By supplying the DeployOnBuild property this is the only way to call the /t:Package on a solution – otherwise you would have to build the csproj instead.
  • If you do not supply the DeployIisAppPath then inside the SampleWebApp.SetParameters.xml file you will see that the IIS Application is suffixed with _deploy which comes from the default Microsoft.Web.Publishing.targets
  • If you do not supply the PackageLocation you will find that the output is in the obj\Release\Packages folder

3.  Deploy it with msdeploy. Get a command prompt and invoke the batch file that is created for you

C:\src\test\SampleWebApp.deploy.cmd /Y /M:simian-work

All done, you should have a package that you can deploy to your server from a command line. Next we look at customising IIS a bit more.

Sunday, May 19, 2013

Changing the WCF Concurrency programatically

I have a customer who contacted me regarding a WCF service that is currently configured to have a 'Single' InstanceContextMode and during testing they have noticed that there is only ever one concurrent thread. Now this is by design as the default setting for the Concurrency is 'Single'. Ideally it would need to be set as 'Multiple' for more than one operation to be handled at a time.

Now, the customer is too close to their delivery date to recompile their code at this stage and wants to see the different options that WCF offers them within configuration. However, the InstanceContextMode and ConcurrencyMode attributes are normally set declaratively within the ServiceBehaviour attribute in the code behind. That would mean a recompilation of the service. This post is about changing this behaviour programmatically as an extension in a separate assembly.

In order to test this I wanted to create a behaviour that prevents the service from starting if it is set to 'Single' Concurrency.

using System;
using System.Collections.ObjectModel;
using System.ServiceModel;
using System.ServiceModel.Channels;
using System.ServiceModel.Description;

public class MultipleConcurrencyServiceValidator : IServiceBehavior
{
    public void Validate(ServiceDescription serviceDescription, ServiceHostBase serviceHostBase)
    {
        var behaviour = serviceDescription.Behaviors.Find<ServiceBehaviorAttribute>();
        if (behaviour.ConcurrencyMode == ConcurrencyMode.Single)
        {
            throw new InvalidOperationException("ConcurrencyMode set at Single - should be Multiple.");
        }
    }

    public void AddBindingParameters(ServiceDescription serviceDescription, ServiceHostBase serviceHostBase, Collection<ServiceEndpoint> endpoints, BindingParameterCollection bindingParameters)
    {
    }

    public void ApplyDispatchBehavior(ServiceDescription serviceDescription, ServiceHostBase serviceHostBase)
    {
    }
}
Ok, so the main points to note in this class are that we are able to interrogate the service description and retrieve the ServiceBehaviorAttribute and check what value it has been set to. But, we are not able to change any of its values, if we were to place some code in the ApplyDispatchBehavior and set the ConcurrencyMode it would not take effect as the service has already been started. Let's link this class to our service behaviour within our config file

    <behaviors>
      <serviceBehaviors>
        <behavior name="WCFConcurrency35.Service1Behavior">
          <multipleConcurrencyValidator />
        </behavior>
      </serviceBehaviors>
    </behaviors>
    <extensions>
      <behaviorExtensions>
        <add name="multipleConcurrencyValidator" type="WcfExtensions.Extensions.MultipleConcurrencyServiceValidator, Wcf.Extensions" />
      </behaviorExtensions>
    </extensions>

We add the type reference in and give it a name and then just add this element into the serviceBehaviour. In order to test it, we simply add the following line to our service and browse to it.

[ServiceBehavior(InstanceContextMode = InstanceContextMode.Single, ConcurrencyMode = ConcurrencyMode.Single)]
public class Service1 : IService1

Now with our new class hooked up if we were to browse to it, we would get our exception thrown. So next let's create some code that will change the concurrency mode and get this to work again. So normally, we should create our own ServiceHost but this is just a quick example to change a behaviour that is not exposed by the framework. Let's create a service host factory class.

using System;
using System.ServiceModel;
using System.ServiceModel.Activation;

public class ConcurrentServiceHostFactory : ServiceHostFactory
{
    public override ServiceHostBase CreateServiceHost(string constructorString, Uri[] baseAddresses)
    {
        var serviceHost = base.CreateServiceHost(constructorString, baseAddresses);
        serviceHost.Description.Behaviors.Find<ServiceBehaviorAttribute>().ConcurrencyMode = ConcurrencyMode.Multiple;
        return serviceHost;
    }

    protected override ServiceHost CreateServiceHost(Type serviceType, Uri[] baseAddresses)
    {
        var serviceHost = base.CreateServiceHost(serviceType, baseAddresses);
        serviceHost.Description.Behaviors.Find<ServiceBehaviorAttribute>().ConcurrencyMode = ConcurrencyMode.Multiple;
        return serviceHost;
    }
}

This is just simple code to create our service host, change the service behaviour and return it as normal. Next, we need to get our service to be created with this factory and that is simple too; edit the svc file like so

<%@ ServiceHost Factory="Wcf.Extensions.ConcurrentServiceHostFactory" />
 
So now, we have that all tested, all I have to do to change my concurrency on an already compiled application is to add a simple Factory line into the markup of the svc file.

New job

So in 2009 I started a contract where all of my blog writing was encouraged to be internal. Personally this sucks; I believe that keeping information regarding technology inside a company's borders goes against the 'community'. As a developer lots of the knowledge I have gained has been from blogs, articles and knowledge bases. So at the start of the year, I started a new permanent position at Microsoft as an Application Development Manager. I have made a pact to start up my blog again and try and give back to the community.