Automating Releases with SFTP

I’m trying to automate the deployment process for a website. I’m using Psake for the build process and Migrator.Net for the db migrations. Which left the problem of getting the code to the server. I’ve taken a stab that this using this guide to setup SFTP with a restricted user with just SFTP access using public/private keys.

Next was to automate the file upload, first I just used at batch file and psftp.exe, this worked except it re-uploads everything, much of which didn’t change. So, next was FileZilla, no luck there. Finally, WinSCP which works ok, but it doesn’t seem to allow a fully automated sync of files, but it does get close.


Asp.Net MVC CheckBoxList HtmlHelper Extension

I added some more methods to the code provided by Tyler Garlick’s CheckBoxList for ASP.net MVC to allow a dictionary to be passed in place of a list of SelectListItems and an optional list of selected ids. Anyway, here’s the full class.

using System.Collections.Generic;
using System.Linq;
using System.Text;
  
namespace System.Web.Mvc
{
    public static class CheckBoxListHelper
    {
        public static string CheckBoxList(this HtmlHelper helper, string name, IDictionary<string, string> items)
        {
            return CheckBoxList(helper, name, items, null, null);
        }
  
        public static string CheckBoxList(this HtmlHelper helper, string name, IDictionary<string, string> items, IDictionary<string, object> checkboxHtmlAttributes)
        {
            return CheckBoxList(helper, name, items, null, checkboxHtmlAttributes);
        }
  
        public static string CheckBoxList(this HtmlHelper helper, string name, IDictionary<string, string> items, IEnumerable<string> selectedValues)
        {
            return CheckBoxList(helper, name, items, selectedValues, null);
        }
  
        public static string CheckBoxList(this HtmlHelper helper, string name, IDictionary<string, string> items, IEnumerable<string> selectedValues, IDictionary<string, object> checkboxHtmlAttributes)
        {
            var selectListItems = from i in items
                                  select new SelectListItem
                                             {
                                                 Text = i.Key,
                                                 Value = i.Value,
                                                 Selected = (selectedValues != null && selectedValues.Contains(i.Value))
                                             };
  
            return CheckBoxList(helper, name, selectListItems, checkboxHtmlAttributes);
        }
  
        public static string CheckBoxList(this HtmlHelper helper, string name, IEnumerable<SelectListItem> items)
        {
            return CheckBoxList(helper, name, items, null);
        }
  
        public static string CheckBoxList(this HtmlHelper helper, string name, IEnumerable<SelectListItem> items, IDictionary<string, object> checkboxHtmlAttributes)
        {
            var output = new StringBuilder();
  
            foreach (var item in items)
            {
                output.Append(&ldquo;&ldquo;);
                var checkboxList = new TagBuilder("input&rdquo;);
                checkboxList.MergeAttribute(&ldquo;type&rdquo;, &ldquo;checkbox&rdquo;);
                checkboxList.MergeAttribute(&ldquo;name&rdquo;, name);
                checkboxList.MergeAttribute(&ldquo;value&rdquo;, item.Value);
  
                // Check to see if it&rsquo;s checked
                if (item.Selected)
                    checkboxList.MergeAttribute(&ldquo;checked&rdquo;, &ldquo;checked&rdquo;);
  
                // Add any attributes
                if (checkboxHtmlAttributes != null)
                    checkboxList.MergeAttributes(checkboxHtmlAttributes);
  
                checkboxList.SetInnerText(item.Text);
                output.Append(checkboxList.ToString(TagRenderMode.SelfClosing));
                output.Append(&ldquo;  &rdquo; + item.Text + &ldquo;&rdquo;);
            }
  
            return output.ToString();
        }
    }
}

On the view you can pass a dictionary made from items in your view model and selected values form your view model.

<div>
    ${Html.CheckBoxList(&ldquo;Product.Categories&rdquo;,
      ViewData.Model.Categories.ToDictionary(c => c.Name, c => c.Id.ToString()),
      ViewData.Model.Product.Categories.Select(c => c.Id.ToString()))}
</div>

In the controller you can access the form values in the request as a comma list of values by the name of the form field.

Request.Form["Product.Categories"]

Hope this helps and thanks to Tyler Garlick for meat of the code.

[UPDATE] Tyler has updated is code for MVC 2.0, here.


Spark T4 Templates For S#arp Architecture

Here’s a quick conversion of the Views to Spark views for the CurdScaffolding of S#arp Architecture V1. I’m still new to T4 and Spark, so they might need some adjustment, but they seem to work ok for a simple entities.

SparkTT.zip


NHibernate String Enumeration Mapping

Here’s what’s needed to have NHibernate map an enumeration by the enumeration name instead of the number.

<property name="DayOfWeek" type="NHibernate.Type.EnumStringType`1[System.DayOfWeek, mscorlib], NHibernate"></property>

NHibernate Session Per Request Using Castles WcfFacility

I was under the false impression that the NHibernateFacility would handle session by request, needed for lazy loading collections, when used with the WcfFacility in an IIS setting. This might work if you use ASP.NET compatibility mode, however, it’s not a recommended solution and I needed to support multiple database connections. Soooo … after searching and reading some other great posts to get me in the right direction I came up with the following solutions.

First the posts that helped me with this:

Second what I’m building on:

  • Castle.Windsor
  • Castle.NHibernateFacility
  • Castle.WcfFacility
  • Running on IIS

The solution:

First off we have a class used to hold the ISession references for the duration of the request.

public sealed class NHibernateContextExtension : IExtension, IDisposable
{
    public List Sessions { get; set; }
  
    public NHibernateContextExtension()
    {
        Sessions = new List();
    }
  
    public void Attach(InstanceContext owner)
    { }
  
    public void Detach(InstanceContext owner)
    { }
  
    public void Dispose()
    {
        if (Sessions != null)
            Sessions.ForEach(s => s.Close());
    }
}

Next we need to hook into the WCF call at the before and after invoke. This is where we create the needed ISession instances and store in the above class.

public class WcfSessionPerRequestCallContextInitializer : ICallContextInitializer
{
    private readonly ISessionManager sessionManager; 
    private readonly string[] dbAliases;
  
    public WcfSessionPerRequestCallContextInitializer(ISessionManager sessionManager, string[] dbAliases)
    {
        sessionManager = sessionManager; 
        dbAliases = dbAliases;
    }
  
    public object BeforeInvoke(InstanceContext instanceContext, IClientChannel channel, Message message)
    {
        var extension = new NHibernateContextExtension();
  
        foreach (var dbAlias in dbAliases) 
            extension.Sessions.Add(sessionManager.OpenSession(dbAlias));

        instanceContext.Extensions.Add(extension);
        return extension;
    }
    
    public void AfterInvoke(object correlationState)
    {
        if (correlationState != null)
            ((IDisposable)correlationState).Dispose();
    }
}

Now we needed to hook the ICallContextInitializer into WCF using a IServiceBehavior. The WcfFacility will add this to all WCF services if it’s registered on the container.

public class WcfSessionPerRequestBehavior : IServiceBehavior
{
    private readonly ISessionManager sessionManager; 
    private string[] dbAliases = { "nh.facility.default" };
    public string[] DbAliases
    {
        get { return dbAliases; } 
        set { dbAliases = value; }
    }

    public WcfSessionPerRequestBehavior(ISessionManager sessionManager)
    {
        sessionManager = sessionManager; 
    }

    public void Validate(ServiceDescription serviceDescription, ServiceHostBase serviceHostBase)
    {
    }
  
    public void AddBindingParameters(ServiceDescription serviceDescription, ServiceHostBase serviceHostBase, Collection endpoints, BindingParameterCollection bindingParameters)
    {
    }
  
    public void ApplyDispatchBehavior(ServiceDescription serviceDescription, ServiceHostBase serviceHostBase)
    {
        foreach (var cdb in serviceHostBase.ChannelDispatchers)
        {
            var channelDispatcher = cdb as ChannelDispatcher;
            if (null != channelDispatcher)
            {
                foreach (var endpointDispatcher in channelDispatcher.Endpoints)
                {
                    foreach (var dispatchOperation in endpointDispatcher.DispatchRuntime.Operations)
                    {
                        dispatchOperation.CallContextInitializers.Add(new WcfSessionPerRequestCallContextInitializer(sessionManager, _dbAliases));
                    }
                }
            }
        }
    }
}

Lastly, register the behavior with the container and provide any aliases needed.

container.Register(
    Component.For()
        .ImplementedBy()
        .DependsOn(new Hashtable { { "DbAliases", new[] { "nh.facility.default" } } })
    );

Unit Testing WCF Security with Castles WcfFacility

Building off David Tchepak’s post “Faking WCF Authentication”, here’s some code to override the Service Host creation when using the Castle WcfFacility.

The main integration points are a custom IWcfServiceModel and IServiceHostBuilder using the custom model. Both points have abstract base classes to build from. The model in this case is just an empty class used by the facility for finding the builder.

public class TestSecurityServiceModel : WcfServiceModel<TestSecurityServiceModel>
{
}

The service host builder is where we inject the authorization data we want available in our services. This host and authorization code are from David’s post, check out that for the TestAuthPolicy, TestPrincipal, and TestIdentity code. Here’s the builder.

public class SecurityDefaultServiceHostBuilder : AbstractServiceHostBuilder<TestSecurityServiceModel>
{
    public SecurityDefaultServiceHostBuilder(IKernel kernel)
        : base(kernel)
    {
    }
  
    protected override ServiceHost CreateServiceHost(ComponentModel model, TestSecurityServiceModel serviceModel, params Uri[] baseAddresses)
    {
        return CreateServiceHost(model, GetEffectiveBaseAddresses(serviceModel, baseAddresses));
    }
  
    protected override ServiceHost CreateServiceHost(ComponentModel model, Uri[] baseAddresses)
    {
        return InjectAuthorizationPolicies(new DefaultServiceHost(model, baseAddresses));
    }
  
    protected override ServiceHost CreateServiceHost(Type serviceType, Uri[] baseAddresses)
    {
        return InjectAuthorizationPolicies(new DefaultServiceHost(serviceType, baseAddresses));
    }
  
    private static ServiceHost InjectAuthorizationPolicies(ServiceHost host)
    {
        host.Authorization.ExternalAuthorizationPolicies
            = new List<IAuthorizationPolicy> { new TestAuthPolicy() }.AsReadOnly();
  
        host.Authorization.PrincipalPermissionMode = PrincipalPermissionMode.Custom;
  
        return host;
    }
}

It’s creating an instance of the DefaultServiceHost and added the authorization properties needed before returning the created service host.

Lastly, we need to integrate this with the WcfFacility. This is don’t at two points, first we need to tell the facility about our custom building and model with the AddServiceHostBuilder method.

var facility = new WcfFacility();
_container.AddFacility("wcf", facility);
facility.Services.AddServiceHostBuilder<SecurityDefaultServiceHostBuilder, TestSecurityServiceModel>();

Then when registering a service we set the ActAs model to the new TestSecurityServiceModel. This tells the facility to use the SecurityDefaultServiceHostBuilder to the service host.

Component.For<IService>()
    .ImplementedBy<Service>()
    .Named("MyService")
    .ActAs(new TestSecurityServiceModel()
    .AddEndpoints(
        WcfEndpoint.BoundTo(new NetTcpBinding { PortSharingEnabled = true })
            .At(MyServiceAddress))),

Now, when a client channel connects to this service the service host will be built by the new builder and have the authorization data needed to test the service.

IService client = ChannelFactory<IService>.CreateChannel(
    new NetTcpBinding { PortSharingEnabled = true }, new EndpointAddress(MyServiceAddress));
client.ServiceCall(1);

This was used for unit/integration tests, but could be used to simply extend the service host when used in the WcfFacility.


Getting Started With The Spark View Engine

Here’s some quick notes for getting started with the Spark View Engine on ASP.NET MVC, including setting up a container (Castle Windsor).

Spark

  1. Reference the Spark assemblies Spark.dll, Spark.Web.Mvc.dll, and SparkLanguage.

  2. Configure and add the view engine in the MvcApplication class (full class below)

    var settings = new SparkSettings() .SetDebug(true) //.SetPageBaseType(“Your.NonDefault.BaseSparkView”) //.AddAssembly(“YourAssembly”) .AddNamespace(“System”) .AddNamespace(“System.Collections.Generic”) .AddNamespace(“System.Linq”) .AddNamespace(“System.Web.Mvc”) .AddNamespace(“System.Web.Mvc.Html”);

    ViewEngines.Engines.Add(new SparkViewFactory(settings));

  3. Add an Application.spark file to the Shared Views folder. The engine looks for this file as the site master layout file. It will also look for one with the controller name to use for views related to that controller, ex, Home.spark for the HomeController.

    <use content="title" />

Apart from the general syntax, there are two things to note both regarding the Use tag. File looks for other views in the shared folder to render. While the content looks for content to render in it’s place which can be set in a sub view, as below. content=”view” is the view being rendered.

  1. The view, Index.spark, is just a normal view. The tag defines the content used for the title in the Application.spark view above.

    My Home Page </assets:title>

    ${"Hello world"}

    ${Guid.NewGuid().ToString("n")}

The documentation on the Spark site is pretty good.

Container Setup

Thanks to Matt Halls post for pointing me to the integration point for adding a container to MVC for controller creation, the IControllerFactory.

public class ControllerFactory : IControllerFactory
{
    private readonly IWindsorContainer container; 
    public ControllerFactory(IWindsorContainer container)
    {
        container = container;
    }

    public IController CreateController(RequestContext requestContext, string controllerName)
    {
        return (IController) container.Resolve(controllerName.ToLowerInvariant() + "controller"); 
    }

    public void ReleaseController(IController controller)
    {
        container.Release(controller);
    }
}

Next setup the container in the MvcApplication class and set the factory in MVC with the ControllerBuilder.Current.SetControllerFactory method. Also register the controllers in the container.

public class MvcApplication : HttpApplication
{
    private WindsorContainer container; 
    public static void RegisterRoutes(RouteCollection routes)
    {
        routes.IgnoreRoute("{resource}.axd/{*pathInfo}");
  
        routes.MapRoute(
            "Default",                                              // Route name
            "{controller}/{action}/{id}",                           // URL with parameters
            new { controller = "Home", action = "Index", id = "" }  // Parameter defaults
        );
    }
  
    protected void Application_Start()
    {
        RegisterRoutes(RouteTable.Routes);
  
        ControllerBuilder.Current.SetControllerFactory(GetControllerFactory());
  
        var settings = new SparkSettings()
            .SetDebug(true)
            //.SetPageBaseType("Your.NonDefault.BaseSparkView")
            //.AddAssembly("YourAssembly")
            .AddNamespace("System")
            .AddNamespace("System.Collections.Generic")
            .AddNamespace("System.Linq")
            .AddNamespace("System.Web.Mvc")
            .AddNamespace("System.Web.Mvc.Html");
  
        ViewEngines.Engines.Add(new SparkViewFactory(settings));
    }
  
    private IControllerFactory GetControllerFactory()
    {
        container = new WindsorContainer();
  
        container.Register(AllTypes 
              .Of<IController>()
              .FromAssembly(typeof (HomeController).Assembly)
              .Configure(c => c.Named(c.ServiceType.Name.ToLowerInvariant()).LifeStyle.Transient));

        container.AddFacility("logging", new LoggingFacility(LoggerImplementation.Trace));
  
        return new ControllerFactory(_container);
    }
}

Brutalist Framework