# Friday, June 10, 2011
T4 preprocessed templates are a neat way of generating text at run time, which can be deployed to machines without Visual Studio. Here's MSDN

Here's a simple template, ClassWriter.tt, which must be marked CustomTool = "TextTemplatingFilePreprocessor" in properties (not "TextTemplatingFileGenerator" which is a normal T4).
<#@ template language="C#" #>
<#@ import namespace="System.Linq" #>
<#@ parameter type="Generator.Model.Table" name="table" #>
using System;
 
namespace <#= table.Namespace #>
{
    [Serializable]
    public class <#= table.Name #>
    {
<#  foreach(var column in table.Columns.Where(c=> !c.Hidden)) { #>
        public virtual <#= column.Type #> <#= column.Name #> { get; set; }
<#    } #>
    }
}

At development time, Visual Studio generates the class in the corresponding namespace which you can then call (yeah, it generates code for generating code...).

Notice we're passing a parameter, which has to have the full namespaced name (even "string" has to be "System.String").

The generated class is partial and the parameters are property getters with a backing field. MSDN suggests that to pass in your parameters you should manually code a partial class with conventional properties or a constructor. Actually, there's an easier no-code way. Use the Session property (which is just a Dictionary<string, object>) which you can use with an Initialize() method. Like this:

//create the class generated by TextTemplatingFilePreprocessor 
var generator = new ClassWriter();
//create a session dictionary, fill it and initialize
generator.Session = new Dictionary<stringobject>();
generator.Session.Add("table", table);
generator.Initialize();
//transform!
var text = generator.TransformText();
The key things to watch out for:
  • you must create the Session dictionary (it's not initialized internally)
  • you must call Initialize() after it's populated.

You can also use System.Runtime.Remoting.Messaging.CallContext but weirdly you must still initialize the Session dictionary (Initialize checks Session first, then CallContext).
 
You may be tempted to reuse the T4 template class like this.
//don't do this
var generator = new ClassWriter();
foreach (var item in list)
{
    generator.Session = new Dictionary<stringobject>();
    generator.Session.Add("table", item);
    generator.Initialize();
    var txt = generator.TransformText();
    WriteText(item, txt);
}
The template class actually uses an internal StringBuilder called GenerationEnvironment. So each call returns everything you wrote before. You can't actually reset the StringBuilder (although you can append to it with Write overloads). So, always create the template class within the loop.



posted on Friday, June 10, 2011 1:50:55 PM (Romance Daylight Time, UTC+02:00)  #    Comments [0]
# Monday, May 02, 2011
Strong named assemblies cannot reference assemblies which aren't strong named.

Decompile with ildasm and recompile with ilasm using your key.

Default ILDASM and ILASM locations as of .Net 4.0

"C:\Program Files\Microsoft SDKs\Windows\v7.0A\bin\ildasm.exe" ClassLibrary.dll /out:ClassLibrary.il
"C:\Windows\Microsoft.NET\Framework\v4.0.30319\ilasm.exe" ClassLibrary.il /res:ClassLibrary.res /dll /key:myKey.snk /out:ClassLibrary.dll

posted on Monday, May 02, 2011 2:50:05 PM (Romance Daylight Time, UTC+02:00)  #    Comments [0]
# Monday, April 25, 2011

Shortly after the last release of Database Schema Reader, here's another release.

Last time I added a CopyToSQLite tool, which reads (almost) any database and creates a SQLite clone. I also added experimental support for SQLServer CE 4.0, but it had some big limitations.

So the obvious next step was to fix some of those limitations, and that's what this release focuses on. Unfortunately CopyToSQLite.exe is now a little misnamed. Winking smile

I added a little bit of conversion code so VARCHAR(MAX) found in the origin database gets converted to NTEXT (and VARBINARY to IMAGE). The reading of SQLServer CE 4 databases got improved too (capturing the  foreign and unique keys and identity columns).

SQLServer allows an integer column to be marked as "Identity" so it will be auto-generated (the equivalent in Oracle is to create a sequence and an insert trigger). But you can't include the identity column when you insert a row. So, when cloning data, SQLServer also allows identity-inserts with SET IDENTITY_INSERT [MyTable] ON/OFF. When you've done that, you should reset the identity seed with DBCC CHECKIDENT.

But in SQLServer CE 4, there is no DBCC CHECKIDENT. You have to do an ALTER TABLE [MyTable] ALTER COLUMN [IdentityColumn] IDENTITY (999,1) (where 999 is the new max(IdentityColumn)). It's another of those little gotchas between SQLServer and SQLServer CE.

SQLServer CE 4 has some great new paging syntax:

SELECT Id, Name FROM MyTable
ORDER BY Name
OFFSET 10 ROWS
FETCH NEXT 5 ROWS ONLY

It's similar to the LIMIT/OFFSET syntax in MySQL and SQLite, but (reasonably enough) must follow an ORDER BY. Rather than offset/skipping a number of rows, I'd like to specify just page number and page size - or another formula. The SQLServer 2011/Denali documentation shows the offset/fetch syntax for a start row/end row expression:

SELECT DepartmentID, Name, GroupName
FROM HumanResources.Department
ORDER BY DepartmentID ASC
OFFSET @StartingRowNumber - 1 ROWS
FETCH NEXT @EndingRowNumber - @StartingRowNumber + 1 ROWS ONLY

But that doesn't work in SQLServer CE 4. You can use parameters, or constants, or expressions with constants, but apparently not expressions with constants and parameters. Oh well, it's still much better than horrible OVER subqueries.

Overall, the "CopyToSQLite" to SQLServer CE 4 seems to work well. Using easily deployable file databases like SQLServer CE and SQLite is simple and powerful.

posted on Monday, April 25, 2011 12:13:17 PM (Romance Daylight Time, UTC+02:00)  #    Comments [0]
# Saturday, April 09, 2011

My Codeplex project, Database Schema Reader, has a new version.

I needed to create a SQLite database was a replica of a parent SQL Server database. The existing project could easily read the schema, and the code generation tools could give me the table DDL and the insert SQL. It was just a matter of executing the SQL and creating the database file.

So I created another simple Windows Forms UI. The SqlWriter class needed some tweaks for SQLite support (and I added integration tests).

For fun, I decided to see if it could also support Microsoft's latest version of SQL Server CE 4.0.

SQL Server CE 4.0 is, like SQLite, an in-process database which can be XCOPY deployed. And unlike previous versions, it is easily able to run ASP.Net websites (it's the default database behind WebMatrix). And 4.0 provides the standard ADO GetSchema which my Database Schema Reader uses (3.5 throws a Not Implemented exception).

It has some of the same limitations as SQLite, such as no stored procedures (good riddance), and no output parameters. But it also has additional limitations. In SQLite you can batch together multiple SQL statements in a single line and execute them in one command. You can't in SQL Server CE.

Unlike SQLite's weakly typed and very simple data types, SQL Server CE 4.0 has most of the standard data types as SQL Server Express and full versions. Unfortunately, this was the big problem. If your table is defined with an IDENTITY primary key, you can't insert the data row with the same primary key, and subsequent foreign key relationships are broken. It's a pretty critical limitation for my scenario.

SQL Server CE 4 only supports a subset of SQL Server data types. The one data type it didn't support, which my database (and later versions of Northwind) use, is NVARCHAR(MAX). You have to use the horrible old NTEXT data type. I could have written a DDL provider that translates varchar max to ntext, but I don't think it's worth the effort.

So my SQL Server CE creation program has major limitations, compared to the SQLite version. It's built into CopyToSQLite.exe, and auto-detects if you've installed SQL Server CE, but you have to have a very simple database for it to work.

SQL Server CE 4 also doesn't support the ADO Sync framework which allows you to synchronize a disconnected database to a parent SQL Server database. Even SQL Server 2008 R2 Management Studio doesn't support it (you have to use Visual Studio 2010 with SP1).

The new FETCH /OFFSET syntax for paging, that will be SQL Server 11, is very nice though. I'm looking forward to that.

posted on Saturday, April 09, 2011 8:05:41 PM (Romance Daylight Time, UTC+02:00)  #    Comments [1]
# Thursday, April 07, 2011
VS 2010 web.config transformations are great.
Change your development web.config which looks like this:

<?xml version="1.0"?>
 
<configuration>
  <connectionStrings>
    <add name="ApplicationServices"
         connectionString="data source=.\SQLEXPRESS;Integrated Security=SSPI;AttachDBFilename=|DataDirectory|aspnetdb.mdf;User Instance=true"
         providerName="System.Data.SqlClient" />
  </connectionStrings>
 
  <system.web>
    <compilation debug="true" targetFramework="4.0">

by adding a Web.DeployTest.config file which looks like this:

<?xml version="1.0"?>
<configuration xmlns:xdt="http://schemas.microsoft.com/XML-Document-Transform">
 
  <connectionStrings>
    <add name="ApplicationServices" connectionString="Data Source=StaticVoidSqlServer;Initial Catalog=Northwind;Integrated Security=SSPI;" providerName="System.Data.SqlClient"
         xdt:Transform="SetAttributes" xdt:Locator="Match(name)"/>
  </connectionStrings>
 
</configuration>

Only by default it's tied up with the build configurations (Debug, Release etc) and the Web deploy story.
But I don't want a web deployment package. I want:
  • a normal "Release" configuration build
  • a directory containing all the website files that I can XCopy deploy (like old school Visual Studio 2008 publish)
  • the web.config transformed with my custom "DeployTest" name.
Doing it this way means the web.DeployTest.config is not automatically nested under the web.config (and I should mark it as BuildAction=None).
But that's my requirements. So I wrote an MSBuild file.

Batch file (build.bat)

First here's a standard batch file, "build.bat", to launch it (I want MSBuild 4.0):
%systemroot%\Microsoft.Net\Framework\v4.0.30319\MSBuild.exe build.proj  /t:Release & pause

MSBuild script (build.proj)


<?xml version="1.0" encoding="utf-8" ?> <Project ToolsVersion="4.0" xmlns="http://schemas.microsoft.com/developer/msbuild/2003" DefaultTargets="Release">   <UsingTask TaskName="TransformXml" AssemblyFile="$(MSBuildExtensionsPath)\Microsoft\VisualStudio\v10.0\Web\Microsoft.Web.Publishing.Tasks.dll" />   <PropertyGroup>     <!-- properties that are used in this build file - referenced as $(PropertyName) -->     <ProjectName>StaticVoid</ProjectName>     <DeployConfiguration>DeployTest</DeployConfiguration>     <PublishPath>$(MSBuildProjectDirectory)\..\Publish\</PublishPath>     <OutputPath>$(PublishPath)\StaticVoid\</OutputPath>     <PackagePath>$(PublishPath)\StaticVoidPackage\</PackagePath>     <TransformInputFile>..\StaticVoid\Web.config</TransformInputFile>     <TransformFile>..\StaticVoid\Web.$(DeployConfiguration).config</TransformFile>     <TransformOutputFile>$(OutputPath)\Web.config</TransformOutputFile>     <ImageResourcesPath>..\ImageResources</ImageResourcesPath>   </PropertyGroup>   <ItemGroup>     <ImageResources Include="$(ImageResourcesPath)\*.jpg" />   </ItemGroup>   <!-- targets -->   <Target Name="PublishWebsite">     <Message Text="Publishing Website" />     <RemoveDir Directories="$(PublishPath)"/>     <!-- do a deploy -->     <MSBuild Projects="..\StaticVoid\StaticVoid.csproj" Properties="Configuration=Release;OutputPath=$(PackagePath);DeployOnBuild=true;DeployTarget=PipelinePreDeployCopyAllFilesToOneFolder;AutoParameterizationWebConfigConnectionStrings=false;_PackageTempDir=$(OutputPath)"/>   </Target>   <Target Name="Transform">     <!-- transform the web.config -->     <TransformXml Source="$(TransformInputFile)"                   Transform="$(TransformFile)"                   Destination="$(TransformOutputFile)" />   </Target>   <Target Name="BuildWebsite" DependsOnTargets="PublishWebsite">     <!-- we don't need the deployment package, we wanted the published files to copy manually -->     <RemoveDir Directories="$(PackagePath)"/>     <!-- copy the unmanaged resources -->     <Copy SourceFiles="@(ImageResources)" DestinationFolder="$(PublishPath)images" SkipUnchangedFiles="true" />   </Target>      <Target Name="Release" DependsOnTargets="BuildWebsite; Transform;">   </Target> </Project>
 

A little explanation

The MSBuild task for the website project (StaticVoid.csproj) has a whole set of extra properties set which make it do a deploy.
(Broken here to be easier to read:)
    <MSBuild Projects="..\StaticVoid\StaticVoid.csproj" Properties="Configuration=Release;
OutputPath=$(PackagePath);
DeployOnBuild=true;
DeployTarget=PipelinePreDeployCopyAllFilesToOneFolder;
AutoParameterizationWebConfigConnectionStrings=false;
_PackageTempDir=$(OutputPath)
"/>

The regular deployment package is written to $(PackagePath). I don't care about that, so I delete it.
The actual directory and files that I wanted are written to $(OutputPath) using the _PackageTempDir property.

For the transform, note the msbuild xml must have Project ToolsVersion="4.0" and
<UsingTask TaskName="TransformXml" 
AssemblyFile
="$(MSBuildExtensionsPath)\Microsoft\VisualStudio\v10.0\Web\Microsoft.Web.Publishing.Tasks.dll" />
And then the transformation:
    <TransformXml Source="$(TransformInputFile)"                   Transform="$(TransformFile)"                   Destination="$(TransformOutputFile)" />
with $(TransformFile) defined as
<TransformFile>..\StaticVoid\Web.$(DeployConfiguration).config</TransformFile>
Simply changing the DeployConfiguration property lets me have test and production builds which transform things nicely.

Update: the old _CopyWebApplication still works too

In Visual Studio 2008 you could use this task:
    <MSBuild Projects="..\StaticVoid\StaticVoid.csproj"
             Targets="ResolveReferences;_CopyWebApplication"
             Properties="Configuration=Release;
                         WebProjectOutputDir=$(OutputPath);
                         OutDir=$(OutputPath)\bin\" />
This still works in Visual Studio 2010's MSBuild (and you don't have a package directory to delete).
The transforms can still be done manually.


posted on Thursday, April 07, 2011 12:34:35 PM (Romance Daylight Time, UTC+02:00)  #    Comments [0]
# Monday, February 14, 2011

My little Codeplex project has had a few updates lately, with a new release tonight. This weekend I was transferring a SqlServer database onto MySQL, so I fixed up the SQL generation capabilities and added it to the UI.

Simply, it now can read the SqlServer schema (or almost any other ADO database), and write out the DDL for a MySQL database. Or an Oracle one. It should also work from Oracle to SqlServer etc.

Of course this only works for simple databases. Mine had a couple of uniqueidentifer columns (GUIDs), which don't translate to anything other than in SqlServer, so that was fixed up manually. Check constraints can be problematic, and it doesn't touch views or, God forbid, triggers and stored procedures. It won't roundtrip accurately (say SqlServer to MySql to SqlServer) because we are generalizing datatypes each time.

It works on my database. Winking smile

posted on Monday, February 14, 2011 10:02:01 PM (Romance Standard Time, UTC+01:00)  #    Comments [0]
# Wednesday, January 26, 2011

I've updated the Database Schema Reader CodePlex project with basic code generation.

The original code (vintage 2005) did all sorts of things like generating ADO data access classes and, over I added NHibernate mapping, Castle ActiveRecord, and Enterprise Library validation block attributes. It's old code (that is, ugly and horrible), so I stole bits of code and made it just do something a lot simpler.

Now it reads the table schema and turns them into simple POCO classes that are NHibernate compatible (virtual properties, override Equals and GetHashCode, composite keys are made into Key classes). There's also (simplistic) NHibernate mapping. And finally it has .Net 3.5's DataAnnotations for validation.

For quick and simple data-driven code, it's an okay starting point. It is just a starting point- not a data driven solution. There is a UI, but it's the most basic one I could design - it's certainly not anything like the Linq2Sql or EF designers (there are NHibernate mapping designers out there). But once you've got started in NHibernate you'll prefer to continue in code-first mode anyway.

If your database is a mess (I've seen a few with no primary keys .) it won't be much help!

posted on Wednesday, January 26, 2011 9:36:04 PM (Romance Standard Time, UTC+01:00)  #    Comments [0]
# Saturday, November 13, 2010

messeberlin2010

What was hot:

Windows Phone 7. The stand where you could try the various handsets was always busy. Several people had their own sets (last year, it was iPhones everywhere). There were adverts all over Berlin too. It won't worry Apple, and Android has reached enough mass to secure second place, but Microsoft should easily beat Symbian and Blackberry especially if they keep up the momentum on updates and new features (HTML 5 browser, apps through private company portals rather than Microsoft's public marketplace).

The cloud. Lots of focus on aspects of Azure, including the announcement of private clouds (Hyper V Cloud) with hosting available. On the developer track, I was pretty interested to learn about the future of distributed LINQ, based on the Microsoft Research DryadLinq project. That project allows you to run distributed (Map/Reduce) queries over an HPC cluster. The future goal is to run it on Azure nodes. Just like in PLINQ where you can append "AsParallel" to a linq statement, you will be able to add "AsDistributed" and the linq statement will be broken up into computation units and run on different nodes (your app.config will also have configuration to help the create the job graph).

Kinect. The graphics are simple and Wii-like, but the demo stand was very popular.

Silverlight. There were quite a few technical Silverlight sessions. From talking to people, it seems Silverlight has taken off for line of business apps within intranets, at least in Microsoft environments where Windows Forms or WPF would have been used before. On the public web, it hasn't dented Flash and Flex, and the only public success is Netflix. But for .Net based IT departments it seems the obvious choice for RIA. The risk from the recent publicity is that managers won't want to invest in it because they think it's dead. Based on the number of sessions here, it's still key to Microsoft.

Berlin. It was cold and grey, and you could only get out after dark, but it's an interesting city to explore. Transport was easy too.

What was not:

Developers. There isn't a lot new this year for developers. We have no new Visual Studio/.Net version.

Although I complained earlier about the heavy "IT Pro" bias, I heard that some infrastructure guys were also disappointed by the content- too much simple introductions and marketing and not enough meat.

Internet connectivity (at the start of the week). Wireless was terrible on the first day, but it did improve - it was excellent on Thursday and Friday. There seemed to be many more power and wired connections this year. Okay, perhaps this point should also be in the "hot" category!

Crowds, It was very busy, and the huge space and confusing layout of the Messe made navigating to sessions a little tricky at times.

Loot. Crap. A stupid little swim-bag, and lots of T-shirts. The organizers and exhibitors have a major lack of imagination and, obviously, money. Where were the USB sticks and other useful give-aways from previous years?

Where's HTML 5?

There were a couple of HTML 5 sessions showing off IE 9, and pretty impressive it is too. There was a pleasing acknowledgement that other browsers exist and also target HTML 5, and IE 9 is just catching up. But there is no tooling, or apparently any due dates. In MVC you can just write the HTML and reference Modenizr etc to trigger down-level support, but there is no intellisense or code colouring yet, let alone HtmlHelpers. It wouldn't be difficult to traditional ASP.Net webcontrols for key HTML 5 tags. It's not just <video>; what I'd like is <input type="date" with an browser datepicker (and down-level detection to add jQuery UI). iPhone and Android (but not Windows Phone 7 yet) have strong HTML 5 features which we want to use. Oh, and the next version of Windows Phone needs to have HTML 5 capabilities to match the desktop IE9. Maybe longer term could Silverlight XAML be converted to SVG?

Where's Alt.Net?

As traditional, this was a Microsoft-only conference. Several presenters used Resharper,  and there was the odd passing mention of NHibernate. But when you talk to other attendees, NHibernate, log4Net and other testing frameworks such as NUnit and MbUnit are in widespread use - my impression is that Entity Framework is some way behind. With Oracle doing it's best to alienate Java developers, Microsoft could start showing a friendlier face with a few sessions for Mono, IoC, mocking, BDD, NoSQL etc.

Future

I enjoyed TechEd, but I think the moral of this year is, only go to a TechEd Europe when Microsoft are launching a new Visual Studio or other major developer tool.

posted on Saturday, November 13, 2010 5:51:23 PM (Romance Standard Time, UTC+01:00)  #    Comments [0]
# Tuesday, November 09, 2010

I'm back in Berlin for the Microsoft TechEd conference. It's huge- thousands of people, and even though the exhibition halls are like aircraft hangars they are packed with people, desperate to get free croissants, T-shirts and other baubles.

berlintechedThere's a lot of "IT pro" (windows admins) content, in the exhibitors and session schedule, and developers like me have thinner pickings (unless you just want croissants and T shirts, which evidently most do).

The only new stuff for developers is Windows Phone 7. The demo stand with various windows phones to try was always packed, and yes, they do look nice. Some cloud stuff, which is clearly a key target for Microsoft. Otherwise it's a rehash of the Visual Studio 2010 and .Net 4 introductory stuff from last year, which was fine last year when it was new but it's a little tired now. Very thin pickings on ASP, a single (introductory) session on MVC, a little on parallel. There is quite a bit on Silverlight, but everyone outside this audience now thinks Microsoft have killed it.

The goody bag is just a simple sports sack (I'm still carrying the rather nice laptop bag from last year). No free Windows 7 Ultimate disc this year (well, you do get a TechNet subscription so that's 5 licenses there, but still.) The free stuff from the vendors in the exhibition hall is showing signs of the economic downturn too. Lots of competitions though.

Only 3 more days of crowds, food, beer, and T-shirt collecting to go.

posted on Tuesday, November 09, 2010 10:26:28 PM (Romance Standard Time, UTC+01:00)  #    Comments [0]
# Monday, November 01, 2010

A long time ago I wrote my database schema reader. It was 2005, .Net 2.0 was just out and I was learning about the new features. .Net 2.0's ADO DbProviderFactory had a nice idea, GetSchema, to get database independent schema information. But the GetSchema collections were slightly different for each database, and they were data tables. So I wrote a simple facade over them to get proper classes.

Initially I used it to generate CRUD stored procedures, and then to generate data access code, even including NHibernate mappings. I even did some (simple) database conversions. All this was quite icky, and each time I did the code-gen a different way, but the core facade worked well.

After getting a couple of queries about the extracts I'd already posted, I thought I might as well put up the entire source code. So here's the codeplex project with the source code, and even some basic SQL code-gen.

I picked Codeplex just because it's more .Net-centric than Google code or github, plus I'm more familiar with TFS and Subversion source control. It was pretty easy. I don't expect many downloads (if any!), but maybe a couple of people can steal the relevant bits of source code.

Check out the database schema reader codeplex project.

posted on Monday, November 01, 2010 12:59:33 PM (Romance Standard Time, UTC+01:00)  #    Comments [0]