Synthesis 8.2.2 Released

I am happy to announce the release of Synthesis 8.2.2.

Synthesis is an object mapping framework for Sitecore that enables developing more reliable and maintainable sites in less time than traditional Sitecore development. It is a strongly typed template object generator that is easily understandable for developers with either a Sitecore or traditional .NET background.

What’s new?

Automatic Model Regeneration

Synthesis now ships by default with event handlers that automatically regenerate your model classes when templates are changed, renamed, moved, or deleted. Whereas before you’d have to manually request a regeneration, now you can just save the template and within 2-3 seconds your model classes have been updated.

Automatic Model Regeneration turns itself off if <compilation debug="false"> is set in the web.config. You can choose to disable it in published scenarios either this way or by deleting its Synthesis.AutoRegenerate.config file when deploying. #37

Previously Synthesis’ MVC helpers did not have a way to render a hyperlink field with an arbitrary HTML body within (e.g. an image, etc). This has been rectified in 8.2.2, with the new BeginHyperlinkFor helper. #31

@using(Html.BeginHyperlinkFor(m => m.HyperlinkField)) {
    <h1>Woohoo!</h1>
    <img src="homer.gif">
}

Config Files In Their Own Folder

The Synthesis configuration files have been moved to App_Config/Include/Synthesis for clarity. The NuGet package upgrade will take care of the migration.

.NET Framework 4.5.2

Synthesis 8.2.2 requires that the project it is installed on be targeting the .NET Framework 4.5.2 or later. This enables full Sitecore 8.2 compatibility. Synthesis 8.2.2 should work on Sitecore 8.1 or later.

Bug Fixes

  • Model source files whose contents have not changed in the current regeneration are now not rewritten to disk. This prevents their timestamp from changing and thus triggering a need to rebuild their host project. When using modular architecture, this can greatly reduce build times. #32
  • Fixed a bug when using Solr indexes where Synthesis’ regenerate process would throw an exception and possibly result in an incomplete model #34
  • Specifying a model output path in a directory that does not exist will now create that directory instead of erroring #35
  • The content search configuration has been adapted to register the Synthesis _templatesimplemented computed field in such a way that it works with 8.1 and 8.2’s new registration scheme, as well as with Solr indexes. Note that the Synthesis content search integrations (querying) do not otherwise support Solr still.
  • You can now disable the generation of Content Search elements in your models if you wish, using the EnableContentSearch setting. The default value is set in Synthesis.config. This will enable using models with fewer project reference requirements, if you do not need the search integrations.

Upgrading

If coming from Synthesis 8.2.x, the upgrade is via a simple NuGet upgrade. For earlier versions, consult the instructions on the release posts for the versions between what you’re on and where you’re going.

Thanks

Thanks to the community members who contributed to this release.

Synthesis 8.2.1 Released

I am happy to announce that Synthesis 8.2.1 is available on NuGet. This release primarily adds additional features.

What’s New?

Improved Multiple Configuration Support

Previously registering multiple configurations in Synthesis was possible but way too hard. Configurations may now register themselves using code, similar to MVC area registrations.

To register a new configuration with Synthesis 8.2.1:

  • Add a class to the assembly you want the configuration’s model to live in that derives from SynthesisConfigurationRegistration
  • Implement the abstract members of SynthesisConfigurationRegistration. Much deeper customization is also available by overriding other optional members.
  • Add a SynthesisConfigRegistrar processor to the initialize pipeline that is set to scan your assembly, e.g.

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    <pipelines>
    <initialize>
    <!-- IMPORTANT: Each registrar instance must have a unique hint value for the patch to work correctly. -->
    <processor type="Synthesis.Pipelines.Initialize.SynthesisConfigRegistrar, Synthesis" hint="Hinty McHintface">
    <assemblies hint="list:AddAssembly">
    <meAssembly>My.Assembly.WithModel</meAssembly>
    </assemblies>
    </processor>
    </initialize>
    </pipelines>
  • That’s it! Your configuration will now be activated.

Auto Friending

Along with simpler configuration registration, allowing your configurations to reference each other’s generated classes is also far easier with “Auto-Friending.”

To illustrate this, suppose you were using Habitat and in your Project layer you had templates that inherited Feature templates. Without auto-friending (or previously manual friending), the Project would generate duplicate interfaces for the Feature templates. This is a bad thing. But with friending, the Project generated template will simply inherit from the already existing Feature model, extending implicit dependency in the database into explicit dependency at a code level (also a good thing!).

With auto-friending, configurations automatically friend each other in the order they are registered. So for the example above, as long as the Feature’s model configuration was registered before the Project’s model, everything would Just Work. You can control the order of registration by the order in the SynthesisConfigRegistrar assemblies.

IRenderingContext and improved IoC support (Synthesis.Mvc)

A pattern that I’ve been using for a while (as have others) to improve testability is to make a facade over the RenderingContext that turns it into a Synthesis API and removes all Item dependencies. This IRenderingContext can be registered with your IoC container (to SitecoreRenderingContext) and constructor-injected into controller renderings to make Item-free controllers that are easy to test without any hacks. Even awesome hacks like FakeDb.

For example:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
public class FooController : Controller
{
private readonly IRenderingContext _renderingContext;

public FooController(IRenderingContext renderingContext)
{
_renderingContext = renderingContext;
}

public ActionResult Foo()
{
var dataSource = _renderingContext.GetRenderingDatasource<IExpectedTypeItem>();

if(dataSource == null)
{
// no datasource set, or datasource is wrong template type (or context item, if no datasource set)
return Content("Derp.");
}

var model = new FooViewModel(dataSource);

// set other model props here

// Note that none of this controller directly used Sitecore APIs and thus does not require FakeDb nor HTTP context
// to have unit tests written against it.

return View(model);
}
}

Additional, more specific interfaces are also available for more specific use cases: IContextItem, IContextDatabase, and IContextSite. These can all be bound to SitecoreRenderingContext and provide smaller interfaces for more specific tasks.

Config Patching by Default

Synthesis now ships with Synthesis.LocalConfig.config.example, which is designed to be duplicated to form your own configuration patch. This encourages leaving the default configurations alone, which in turn greatly simplifies upgrading. The documentation and README has also been updated to reflect this.

Improvements

  • The default settings have been improved:
    • Creating model backup files is now disabled by default because it is of questionable utility when using source control
    • The InterfaceOutputPath and ItemOutputPath settings have been deprecated and merged into a single ModelOutputPath because it’s silly to emit more than one model file. The separate settings will still operate if you wish to use them.
    • Uncommonly used settings have been removed from Synthesis.config (SitecoreKernelAssemblyPath, SynthesisAssemblyPath, and InterfaceSuffix). They continue to work if set, but are removed for brevity as they are generally not used other than at default values.
  • The SynthesisEditContext class has been marked obsolete because the pattern is a bad idea
  • WebForms related classes have been marked obsolete because don’t use WebForms
  • The ability to attempt to automatically rebuild the project containing the model on startup has been removed due to being a generally bad idea
  • The ModelOutputBasePath setting has been added. This path is prepended to the ModelOutputPath for all configurations. The advantage of using this is that for people who work out of webroot, they can use <sc.variable> values in a setting (e.g. the out of webroot project location) whereas Sitecore does not expand variables in the ModelOutputPath. #27

Bug Fixes

  • Setting max backups to 0 no longer results in an infinite loop and now does not make backup files #28
  • Registering the same assembly twice in the type list provider will no longer scan the assembly twice
  • Wildcards that do not end in (e.g. Foo..Web) will not operate correctly when adding assemblies to the type list provider

Upgrading

Upgrading should be as simple as a NuGet upgrade*. If you have customized your Synthesis.config you may need to merge it with the default (or even better make it a patch file).

* as long as you are using Sitecore 8.1. As with the 8.2.0 release, it is designed only for Sitecore 8.1 due to breaking Sitecore API changes in 8.1. Sorry about that :(

Thanks!

Thank you to the community members who contributed to this release:

As always, happy coding!

Synthesis Object Mapping Performance

This morning I saw a post on the performance of the Glass Mapper by Konstantin Cherkasov and thought I’d run a quick test of Synthesis in a similar situation. In Konstantin’s testing, he found a GlassCast + field access to be nearly 2,000 times slower than using the Sitecore API to access the same field value.

I decided to read the entire contents of the web db, then convert it all to Synthesis items and read the display name field, since they’d all have that. In my case, that worked out to 5148 items - less than Konstantin’s test with 20,000 but it was what was handy. Note that with Synthesis, AsStronglyTypedCollectionOf() returns a collection of IStandardTemplateItem. This doesn’t mean it’s not doing any fancy mapping, however - this is just the base interface for all items. Individual collection items are still mapped to the appropriate template class; e.g. for an Article, you could do if(collectionItem is IArticleItem) and it would be true.

This gist shows the code I used, and average results. Synthesis was about 3x slower than the native Sitecore APIs (native: 16-20ms, Synthesis: 54-60ms, sample size 5148 items); still suboptimal, but a heck of a lot less than 2000x.

The difference is probably mostly due to the fact that Synthesis is a wrapper (internally it reads from an Item) instead of a mapper (full POCOs/proxies), so it can be a lot lazier about loading values.

Synthesis 8.1 Released

Synthesis 8.1 has been released to NuGet. This is a minor feature release that also resolves an issue with the model provider caching in Synthesis 8.0.

DPI-aware image support

The new `@Html.DpiAwareImageFor()MVC helper method emits asrcset` along with the image that enables “retina images” served from the media library. To use it, you basically upload the image 2x (or 3x for the highest DPI devices) larger than it would normally display. Devices that support the higher resolution will automatically acquire the higher resolution version, and lower resolution devices will use the regular version.

Note that this is only for DPI-aware images. The more advanced forms of srcset and picture that enable viewport-based features (‘responsive images’) are not supported at this time. Last I checked not well supported by browsers either.

WebActivator removed as a dependency

Synthesis 8.0 depended on WebActivator to register its startup tasks. In 8.1, these have moved to the more Sitecorian initialize pipeline.

Improved config schema

The Synthesis.config file has been broken into three files: Synthesis.config (global model configuration), Synthesis.ControlPanel.config (enables the control panel page), and Synthesis.Startup.config (enables on-startup sync checks and regeneration). This makes it much easier to deploy Synthesis to a Content Delivery server, as you can simply delete all but Synthesis.config and be secure.

Upgrade Instructions

Synthesis 8.1 is a NuGet upgrade away. However to cover the new configuration changes, you do need to make a couple tweaks to an existing Synthesis.config.

  • remove <registerDefaultConfiguration value="true" /> (Synthesis 8.0 only)
  • remove the whole <synchronizationSettings> node in Synthesis.config (its values now live in Synthesis.Startup.config)
  • remove pipelines/httpRequestBegin in Synthesis.config (values now live in Synthesis.ControlPanel.config)
  • add default configuration registration to Synthesis.config <pipelines>:

    <initialize>
        <!-- REGISTER DEFAULT CONFIGURATION
            If this processor is registered, the configuration values below for providers are loaded into a Default Configuration.
            This enables Synthesis to work out of the box if you do not need multiple configurations.
    
            For multiple configurations you may leave this active if you want to keep the default configuration and add your own on top of it,
            or remove it to register only your own configurations. Configurations are registered by calling ProviderResolver.RegisterConfiguration()
            - e.g. in more initialize pipeline processors.
    
            NOTE: Do not register multiple configurations that contain overlapping templates.
        -->
        <processor type="Synthesis.Pipelines.Initialize.RegisterDefaultConfiguration, Synthesis"/>
    </initialize>
    
  • if using the optimizeCompilations setting to speed up Sitecore 8 startup time, turn it off temporarily after the upgrade or clear your temporary asp.net files folder, because the helper structure changed slightly during the upgrade and the cached razor files will be invalid.

Announcing Synthesis 8.0

I am happy to announce the availability of Synthesis 8.0. Synthesis is an object mapping framework for Sitecore that takes advantage of integrating the code generation with the mapping framework. This enables very high speed object mapping, LINQ-to-indexes support, model sync checking, and deep interface support for template inheritance and unit testability.

What’s new in Synthesis 8.0

Sitecore MVC Support

There are relatively few reasons to stick with Web Forms any longer for Sitecore development. Synthesis 8 introduces full-scale Sitecore MVC support, including:

  • A high-speed model provider for view renderings: you can use @model IMySynthesisTypeItem transparently on view renderings
  • HTML helpers designed to make it easy to work with Synthesis models and enable Experience Editor (e.g. `@Html.ImageFor(x=>x.MyImageField)`)
  • Invalid model types on view renderings are trapped and contained to only the rendering involved, preventing the whole page from exploding due to one rendering failing. Messaging is shown to preview and editing users to show the failed rendering.
  • Diagnostic HTML comments are injected around renderings when dynamic debug compilation is enabled, showing the start and end of each rendering, its name, render time, and output cache diagnostics.

The functionality of the Synthesis.Mvc package is largely similar to Blade combined with Synthesis.Blade except that Blade is for Web Forms and Synthesis.Mvc is for Sitecore MVC. The Synthesis.Mvc HTML helpers are fully compatible with Synthesis.Blade’s.

Multiple configurations

Synthesis now supports more than one model configuration. This enables, for example, generating a separate model per-site for a multi-site installation of Sitecore. The additional configurations are registered similarly to MVC areas, using either WebActivator, the <initialize> pipeline, or Global.asax. There is some basic documentation available.

Configurations may also be friends, which enables sharing template classes across configurations that are aware of each other. For example, if you have a ‘shared’ set of templates that multiple sites’ templates derive from, making the shared model a ‘friend’ of your site model will enable your site model to derive from the shared model’s interfaces.

New control panel

Synthesis 8 uses a control panel that is hooked from the httpRequestBegin pipeline instead of using a HTTP handler and HTTP module. This enables Synthesis to require no web.config changes at all to install or remove. The control panel is multiple-configuration aware.

This control panel uses a configurable activation URL to allow you to put it where you want it. The default is /synthesis.aspx.

Installation and Upgrade

Synthesis 8 is available from NuGet right now. Initial installation is as simple as installing the Synthesis NuGet package (and, if you want MVC support the Synthesis.Mvc package). There is a README that opens after installation that helps you get started and configure it.

Upgrading does require merging the current Synthesis.config with your existing one. A few settings have been added or modified in this version to support the control panel and multiple configurations. You will also need to remove the Synthesis HTTP handler and HTTP module from web.config if you have them registered. Otherwise upgrade is as simple as upgrading the NuGet package and, if appropriate, installing the MVC package.

Synthesis 8.0 is designed for Sitecore 7.2 and later due to content search API versioning, and was primarily developed and tested on Sitecore 8.0 Update-1.

Under the hood changes

  • Modular generator: The code generator has been refactored and improved into a two-stage design where metadata (e.g. template hierarchy) is generated first, and passed to a code generator. This enables plugging in custom code generators if desired (if you’re feeling brave, it should be completely possible to say emit a Glass model from Synthesis’ generator). Metadata generation also enables multiple configurations to refer to each other.
  • Sitecore-isolated generation classes: All providers involved in generation no longer have any direct hooks to the Sitecore API. This hypothetically enables non-Sitecore database datasources for generation - for example, .item files on disk.
  • The default TypeListProvider allows for wildcards when specifying assemblies to scan for model types. Useful for cases where you have an assembly per site and don’t want to register them all individually.
  • The NuGet package now includes a README file that provides some basic directions for getting started with Synthesis, as this has been a previously lacking area of the documentation
  • Generated Synthesis models are now less prone to causing SCM merge conflicts. The Synthesis version stamp has been reduced to x.x instead of x.x.x.x on attributes, and the ‘generated by .net framework version x’ is removed from the header, which could cause problems if one developer had say .18072 and the other .17345; producing constant pointless model changes in the repository.
  • IStandardTemplateItem now has a Children property, which is an alias to .Axes.GetChildren(), to make it feel more at home for those used to the Item API.

Bug fixes

  • There was a problem with the way the template inheritance cycle rejection was implemented in 7.3.3 that caused multilevel inheritance on templates who had fields named the same as their template would generate invalid models. This has been fixed.
  • Setting the value of a HyperlinkField.Href with an external URL value (e.g. http://google.com) would cause it to save the link as an internal link type and Sitecore to flag it as a broken link. These are now correctly set as link type external.
  • When using LINQ-to-indexes and calling the GetResults() extension method, an exception will no longer be thrown. The exception is due to some misbehaving private reflection deep in Sitecore, and the workaround is even more private reflection. The authorities have been notified ;)

Synthesis 7.3 released

Synthesis 7.3 has been released to NuGet and GitHub.

The big new feature in 7.3 is the Synthesis.Mvc package, which adds a Synthesis-compatible Sitecore MVC model resolution mechanism. This enables you to create View Renderings that transparently can use a Synthesis type as a model without any additional work:

@model IFooItem

<h1>@Html.TextFor(x => x.SomeSitecoreField)</h1>

The Mvc library also includes:

  • Helpers to make it simple to render Synthesis fields (like TextFor above). If you’ve ever used Blade these helpers are essentially identical.
  • Rendering diagnostics, also similar to Blade, which adds HTML comments around renderings with useful data - like whether it was output cached - whenever the site is run with debug compilation enabled. A great tool if you work with frontend devs who never know what rendering markup came from.
  • Altered handling of invalid rendering model types. By default, an exception that takes the whole page down is thrown if a view declares an @model and receives something other than that type. This can cause issues if your datasource item is ever an invalid item ID or something similar. Synthesis.Mvc changes this behavior by simply hiding renderings with invalid datasource types; if in preview or edit mode a message is shown in place of the rendering explaining why it’s hidden.

    Installing Synthesis.Mvc is easy: Just add the NuGet package to your web project. It consists of a single assembly in /bin and the Synthesis.Mvc.config file that registers pipelines in /App_Config/Include.

Bug fixes

Several bugs were also fixed in Synthesis 7.3:

  • The mechanism Synthesis uses to generate media URLs was simplified as Sitecore 6.5 is no longer supported. This makes the media URLs on image and file fields valid in all cases, even when forcing media to have the server in the URL. Thanks to Jeremy Clifton and Robert Pate for the PR.
  • The Synthesis-wrapped version of Axes.GetPreviousSibling() incorrectly called GetNextSibling() internally. Thanks to @ullmark for the PR
  • If two templates formed an inheritance cycle, generating Synthesis would cause a stack overflow. This is no longer the case, however it will still emit code that won’t compile (as the interfaces will create a cycle in C#). Thanks to @GreyGhostStudio for the issue report.
  • The constructor of TestNumericField incorrectly took an int? when it should have been decimal?. Thanks to Robert Hardy for the PR.

Upgrading to 7.3

The configuration format for 7.3 has no changes, so upgrading is as simple as upgrading your NuGet packages. The Mvc support is a new separate NuGet package that would need to be installed.

Synthesis 7.2.1 released

Synthesis 7.2.1 has been released to NuGet.

This release includes:

  • a bug fix from @Gobiner for internal links with query strings,
  • a bug fix for content search index issues when the master database has been removed, reported by @GreyGhostStudio
  • the Add<T>() method of Synthesis objects now supports interfaces instead of just concrete types. A suggestion from @ullmark

In addition, Synthesis 7.2.1 has been tested on the Sitecore 8 technical preview and operates without issue.

Have fun!

Synthesis 7.2 released

Synthesis 7.2 has been released on NuGet. This release includes a number of enhancements to the content search APIs to accomdate more real world situations, as well as several general bug fixes and improvements.

Synthesis 7.2 only runs on Sitecore 7.2.x due to changes in the content search APIs in 7.2. It is hypothetically compatible with Sitecore 7.5 as that is supposed to be based on the 7.2 core but I have not tested it. Previous versions of Synthesis are not compatible with Sitecore 7.2 because they are compiled against the earlier content search APIs.

So what’s changed?

  • The Uri property on template items has been renamed ItemUri to avoid confusion with the similarly named Url property
  • Standard item properties related to searches - namely Statistics and Paths - have been flattened into properties on IStandardTemplateItem itself. This allows you to easily use them in content search queries
  • Additional TemplateName, Path, ParentId, AncestorIds, DatabaseName, and SearchableContent properties have been added to IStandardTemplateItem to support content search queries
  • Added WhereResultIsValidDatabaseItem() and TakeValidDatabaseItems() LINQ extension methods. These allow you to filter index-based result sets and remove any index entries that do not have valid database-based equivalents. Due to the way Synthesis transparently promotes index-based items to database items, this can avoid runtime exceptions during promotion if the index item has no database equivalent or security denies access to the database equivalent.
  • Synthesis no longer requires a global registration of its document type mapper now that Sitecore 7.2 supports overriding the mapper via an ExecutionContext
  • Multiple ExecutionContext parameters can now be passed to GetSynthesisQueryable
  • Support for doing OR and AND searches over collections, such as multilist targets, via the ContainsOr and ContainsAnd extension methods (original implementation by @jason_bert)
  • Integrated @jorgelusar‘s web test runner to improve visibility of Synthesis’ unit tests. Added a lot of tests to cover and document the content search functionality available.
  • Added support for using multilist, datetime, and lookup field values from the index without object promotion, if the value is stored in the index.
  • The ignoreStandardFilters parameter on GetSynthesisQueryable() was incorrectly being ignored
  • Fixed a bug where StartupRegenerateProjectPath entries starting with ~ were not correctly resolved (thanks @delgadobyron!)
  • Generating templates whose name starts with a number will now work correctly (prefixed with _), courtesy of @martijn_b0s
  • Using the SelectSingleItem() and SelectItems() queries on a template item will no longer cause an error if the query returns no results, courtesy of @martijn_b0s
  • A number of hacks to fix issues in the Sitecore search expression parser that were fixed in Sitecore 7.2 have been removed.

As always, thanks to the community members who use and contribute to Synthesis - you all rock. Feel free to hit me up on Twitter or report an issue or pull request on GitHub if you run into problems.

A Fury of Updates

Put me on a plane to the Sitecore MVP Summit and I’m going to write software! All of these updates are available on GitHub for source and NuGet for packages.

Synthesis.Blade.Ninject

This is an extension to Synthesis.Blade that enables automagical constructor dependency injection to any presenter using the Ninject IoC container. I previously blogged about how to do this (it’s not that complex) but now doing DI with Blade is as simple as a NuGet package. Simply wire up Ninject with your dependencies, add some dependencies to a presenter constructor, install this package, and you’re good to go. Here’s a simple example of a presenter using DI to get a repository dependency:

public class TestPresenter : SynthesisPresenter<TestModel, ITestTemplateItem>
{
    private readonly ITestRepository _repository;

    // this constructor parameter will be automatically set by Blade via Ninject
    public TestPresenter(ITestRepository repository)
    {
        _repository = repository;
    }

    public override TestModel GetModel(IView view, ITestTemplateItem item)
    {
        var model = new TestModel();

        model.Frob = _repository.GetFrob(item);

        return model;
    }
}

Note: It’s trivial to implement the same constructor injection with a different IoC container, or without using Synthesis integration. Take a look at the source for Synthesis.Blade.Ninject and it should be pretty obvious what to do :)

Note2: Make sure to use the above Synthesis.Blade 7.0.1 configuration file, or the installation may not work correctly and patch the wrong thing.

Blade 2.0.1

This is a minor release with enhancements to testability and bug fixes.

  • The “Page” property on IView is now marked as obsolete, as it exposes a lot of untestable data to a presenter
  • IView now has a ViewContext property that exposes the HttpContextBase for the current request, enabling testable access to request and response data within presenters
  • Fixed a bug that caused unexpected presenter resolution when using inheritance in model types (IView became covariant in Blade 2, which meant that IView<BaseClass> became similar to IView<DerivedClass>, and the base class presenter might be selected first in some cases) - fix courtesy of @gobiner

Synthesis 7.0.1

This is a minor release that corrects an oversight in 7.0.0 where some of the new field type interfaces did not have setters for their values. This prevented editing items when using field type interfaces. Bug report courtesy of @gobiner.

Synthesis.Blade 7.0.1

This is a minor release that resolves an issue with the default configuration file if multiple patches were present to the Blade PresenterFactory. To upgrade an existing installation, simply edit Synthesis.Blade.config and change the presenter factory patch line to read like so (changing the ‘instead’ attribute):

<presenterFactory patch:instead="*" type="Synthesis.Blade.Configuration.SynthesisPresenterFactory, Synthesis.Blade" />

Announcing Synthesis 7

Synthesis 7 is now available on NuGet. This version brings a number of new features and bug fixes largely aimed at supporting unit testing of sites that are built with Synthesis. Version 7 is compatible with Sitecore 7 Update-1 and Update-2.

Fully mockable generated item classes

Previous versions of Synthesis would generate classes that had concrete field types, such as RichTextField, that were strongly tied to the Sitecore item APIs or search APIs. This prevented easily creating mock versions of the class for testing purposes. Synthesis 7 changes that by allowing you to define both a private concrete field type mapping and and public interface mapping, such as this:

[IndexField("title")]
public ITextField Title {
    get { return new TextField(/* ... */);
}

Now each field can be easily mocked with a mocking framework of your choice, enabling you to create totally Sitecore API free instances of Synthesis items. For example, using Moq:

var item = new Mock<IFooItem>();
item.SetupGet(x => x.Title).Returns(new TestTextField("isn't this nice?"));

string result = item.Object.Title.RawValue; // "isn't this nice?"

But wait! What about those pesky metadata properties like statistics, database, and editing? Those are annoying, huh. Well Synthesis 7 uses adapter classes to make those mockable too.

public IDatabaseAdapter Database { get; }

It’s very easy to add a public interface to a field type mapping; you simply add an interface attribute to the mapping:

<map field="Single-Line Text" type="Synthesis.FieldTypes.TextField, Synthesis" interface="Synthesis.FieldTypes.Interfaces.ITextField, Synthesis" />

New testing package

There is now a Synthesis.Testing package on NuGet that contains some dummy field type implementations to help you write cleaner mocks of Synthesis item types. The TestTestField class referred to in the Moq example above is part of the testing package.

Injecting custom field implementations on a per-template-field basis

Previously you were able to map a Synthesis field class to a Sitecore field type. Synthesis 7 enables you to get more specific and map a field class to a specific field on a template. This enables you to provide custom behavior for specific fields.

<templateFieldMappings hint="raw:AddTemplateMapping">
    <map template="Content Section" field="Content" type="Synthesis.FieldTypes.TextField, Synthesis" interface="Synthesis.FieldTypes.Interfaces.ITextField, Synthesis" />
</templateFieldMappings>

The template specification can be the template name, full path, or ID interchangeably. The field can be either the field name or field ID.

Better missing field messages

If you’ve used Synthesis long, you’ve probably seen this one. You add a template field, generate your model, and forget to publish the field. Suddenly you get a really helpful “Parameter cannot be null” error that doesn’t tell you anything about the field name that actually caused it. Synthesis 7 fixes that problem, and reports the field name that was missing instead of a generic error message.

Bug fixes

  • Modified default behavior of synthesis.axd. In Synthesis 5-6, if the model was detected as synchronized, no option to force a rebuild would be available. Problem is, configuration changes (e.g. changing the root namespace) do not invalidate the template signatures - so there were times when a ‘synchronized’ model would need to be force rebuilt. In Synthesis 7, the handler always rebuilds the model even if synchronization is detected.
  • Synthesis will no longer generate invalid C# code when faced with a template or field name that starts with a number. Leading numbers are automatically prefixed with _ so as to retain valid C#.
  • Fix media item URL generation error when LinkProvider has AlwaysIncludeServerUrl enabled. Previously, links like /http://foo/~/media/bar would be generated. Fix contributed by Dave Peterson
  • Removed a hack that allowed the LINQ extension GetSynthesisQueryable() to work, because it was fixed in Sitecore 7 Update-1.

Breaking changes

  • Due to the new adapter classes, code that uses the Database property may break. The adapter class returns Synthesis types, whereas the Synthesis 6 version returned Sitecore Item instances. This enables decoupling the IDatabaseAdapter from the Sitecore API.
  • If using interfaces for your object properties (which you will need to manually enable if upgrading), the type of those properties will change. This may break code such as view models that contains fields as properties.
  • Support for implicit field conversions (e.g. to treat a TextField as a string) have been removed. These do not work when using interfaces, and generally are a bad idea because they can allow unexpected behavior (is an implicit conversion to use a raw value? field renderer?).
  • Support for the FileListField (File Drop Area) field type has been removed
  • Support for the WordDocumentField field type has been removed
  • The IFieldMappingProvider interface signature has changed to enable injecting custom field types on a field level. Custom providers may need minor refactoring.
  • Synthesis.Blade: the signature of the SynthesisPresenter.GetItem() method has changed from protected to public (a breaking change for all presenters based on this). Unfortunately, this was by far the simplest and cleanest avenue to allow for injecting arbitrary Synthesis item data sources for testing purposes.

Upgrading

Upgrading to Synthesis 7 is a process that takes a bit of work.

  • First, upgrade the NuGet package to Synthesis 7
  • After upgrading the NuGet package, you should remove the field mappings in Synthesis.config to the removed Word Document field and File Drop Area field types. The Word field mapping may not exist depending on what version you’re coming from.

    <map field="File Drop Area" type="Synthesis.FieldTypes.FileListField, Synthesis" /> <!-- remove this from Synthesis.config -->
    
  • Next, you will need to regenerate the Synthesis model. Do not build the project at this point, because the model format has changed in Synthesis 7 and the existing model will be full of build errors. Hit /synthesis.axd and force a regeneration, which will remove any build errors not caused by a breaking change as outlined above.

    • If some sort of global handler (such as a httpRequestBegin pipeline handler) is causing an error before you even get to synthesis.axd temporarily disable it for the purposes of regenerating the model.
  • By default, a Synthesis 7 upgrade will not enable using interfaces for field types (unless you overwrite Synthesis.config during the install, which is not recommended). Should you wish to enable interfaces, simply look at the default config file and merge the interface attributes in under <fieldMappings> to your config, then regenerate.
  • If using Synthesis.Blade, you will need to change the visibility on GetItem() for any presenters that use SynthesisPresenter as their base class to public, instead of protected.
  • Verify that the case of your content search config patch at the bottom of Synthesis.config matches the case in your Sitecore.ContentSearch.Lucene.DefaultIndexConfiguration.config. The case of the default config changed in Update-2, but depending on how you upgraded yours might not have. See this blog post for details as to why this is necesary. If the case is incorrect, Synthesis LINQ queries will not work correctly.
  • Fix any remaining build issues caused by breaking changes (if any), and test the site.

Feedback

I’d love to hear from you if you have trouble or ideas. Send me an issue on GitHub!

As always, the Synthesis source is available under the MIT license, so feel free to hack away - and send me a pull request ;)