Archive
Generate ASP .NET Web API Controllers using Templates
In a precedent post we have shown how to build an ASP .NET WebAPI Controller to access the generated Business Object Model (BOM).
We saw how to implement manually a Web API Controller for one entity of our model.
Now, we are going to see how to build a Template in order to automatically generate a Web API Controller for each one of the entities in our model.
We are going to use the “CarRental” demo project included with CodeFluent Entities. It was the same sample project that we used when we created the Web API Controller.
The first thing we have to do is create our template file.
Our template must be prefixed by “[Template]” and have an extension of type “.tpl”.
Before writing our template let’s create a producer for our template.
The “Source Directory” is the location of our template folder and the “Target Directory” is where our files will be generated, in my case I have a folder called “ApiControllers” in my MVC 4 Web Application project.
At the bottom of our template we fix some parameters.
[%@ template enumerable="Producer.Project.Entities" enumerableItemName="entity" enumerableTargetPathFunc='Path.Combine(Path.GetDirectoryName(TargetPath), entity.Name) + "Controller.cs"' %]
That means that we are going to iterate through all the entities in our project (Producer.Project.Entities). Inside the template we can access the current enumerated entity by the name “entity”. And the name of the generated file (for each entity) will be “[EntityName]Controller.cs”.
Now we can write the content of our Api Controller. Let’s start by creating only the Controller class.
//------------------------------------------------------------------------------
// <auto-generated>
// This code was generated by the Template Producer.
// Changes to this file may cause incorrect behavior and will be lost if
// the code is regenerated.
// </auto-generated>
//------------------------------------------------------------------------------
namespace [%=entity.Namespace%].Web.ApiControllers
{
using System.Collections.Generic;
using System;
using System.Net;
using System.Net.Http;
using System.Web.Http;
public class [%=entity.Name%]Controller : ApiController
{
}
}
If we build our CodeFluent Entities project we must see our Api Controllers appear.
Now let’s implement the Api Controller methods. We will use almost the same implementation as we did in the post “Using ASP .NET Web API with CodeFluent Entities”.
// GET api/[%=entity.Name%]
public IEnumerable<[%=entity.Name%]> Get()
{
return [%=entity.SetFullTypeName%].LoadAll();
}
// POST api/[%=entity.Name%]
public HttpResponseMessage Post([FromBody][%=entity.Name%] value)
{
if(value == null || !value.Save())
{
return Request.CreateResponse(HttpStatusCode.BadRequest);
}
return Request.CreateResponse(HttpStatusCode.OK, value);
}
// PUT api/[%=entity.Name%]
public HttpResponseMessage Put([FromBody][%=entity.Name%] value)
{
if(value == null || !value.Save())
{
return Request.CreateResponse(HttpStatusCode.BadRequest);
}
return Request.CreateResponse(HttpStatusCode.OK, value);
}
For the Delete and Get (for a single element) methods we need to do some work to manage the entity keys. Indeed, it is possible that some entities have multiple keys.
// DELETE api/[%=entity.Name%]/*ids
public HttpResponseMessage Delete(string ids)
{
ids = ids.Replace('/', '|');
[%=entity.ClrFullTypeName%] value = [%=entity.ClrFullTypeName%].LoadByEntityKey(ids);
if(value != null && value.Delete())
{
return Request.CreateResponse(HttpStatusCode.NoContent);
}
return Request.CreateResponse(HttpStatusCode.NotFound);
}
// GET api/[%=entity.Name%]/*ids
public [%=entity.Name%] Get(string ids)
{
ids = ids.Replace('/', '|');
[%=entity.ClrFullTypeName%] value = [%=entity.ClrFullTypeName%].LoadByEntityKey(ids);
if(value == null)
{
throw new HttpResponseException(HttpStatusCode.NotFound);
}
return value;
}
We use a feature in MVC (and Web API) routes that allows us to handle a variable number of segments in a URL pattern.
So we will need to make some changes in our routing configuration. I have registered my routes for the Web API in a separate file called “WebApiConfig” (cf. Using ASP .NET Web API with CodeFluent Entities). The trick lies in the “*” before the parameter name (*ids).
config.Routes.MapHttpRoute(
name: "DefaultApi",
routeTemplate: "api/{controller}/{*ids}",
defaults: new { ids = RouteParameter.Optional }
);
For example, in order to retrieve a specific instance of the entity “InventoryDetail” we need three keys, so the URL to get an instance of “InventoryDetail” will be: http://server/api/InventroyDetail/1/2/3.
If we build our CodeFluent Entities project and take a look at the inside of a Controller we will see the complete implementation.
Now we only have to test our Controllers. We can use the same tests that we have done in the precedent post related to the ASP .NET Web API.
Regards.
Pablo Fernandez Duran
Website Templates and Custom Renderers
There are basically two ways to customize web sites generated by CodeFluent Entities:
1) edit the generated files in place. The generated code is very readable, and by design easy to customize.
2) modify how the out-of-the-box site is generated. Please note these auto-generated sites are very well suited for back-end/back-office/administration/testing/sample purpose. However, they are generated using site templates, and these templates can be customized. We will try to explain how.
Site templates are located in \Program Files (x86)\SoftFluent\CodeFluent\Modeler\Templates\UI. Here you will find the various templates for ASP.NET, MVC, Ajax, etc…
These templates are a good start to build your own. Each template is composed of two directories:
- A directory that contains a cf_template.xml which is the template manifest, used by tools such as Visual Studio. Let’s say it’s named ‘MyAspNet’ for our example.
- Another directory named [directoryName]_Renderers. So it should be named MyAspNet_Renderers for our example.
Both directories can contain template files (text files with the .tpl extension) or any other files. Template files are files that are executable files and can run in the context of the model being produced (more here:http://www.softfluent.co…_TheTemplateEngine.html and here: http://www.softfluent.co…s_TemplateProducer.html).
The first directory will define the target site files. The renderers directory will contains the renderers implementation. Now the question: what is a renderer?
A renderer in a CodeFluent Entities model is an abstract platform-independent item which basically has two important properties: a name, and a type (unspecified, read, write, create, column, parameter), and will be used to define how a concept will be rendered ultimately on a specific platform (whatever that platform will be: web, winforms, WPF, etc.).
Renderers can be associated with properties, view properties, entities or method parameters. Renderers can be shared.
For example, let’s suppose you handle a lot of IP Address in your application. There’s nothing built-in in the product but many entities have properties that are of the IP Address type. Then, you would declare a renderer named ‘IPAddress’ (for example) and associate this renderer to all the properties of that type.
At production time, a producer such as the ASP.NET producer will relate the renderer definition to a concrete UI artifact using it’s name and type. In the case of the ASP.NET producer, a renderer will be simply represented by a file, containing some HTML (or ASP.NET) fragment. You can see what the out-of-the-box renderers look like if you open the files in the [directory]_Renderers directory of the out-of-the-box templates. A renderer file name starts with “Renderer.”.
Let’s go to CodeFluent Entities installation directory, and navigate through the Templates\UI directory. Here you can see a set of folders containing the templates and renderer.
We’re going to create a new template from an existing one and also add a renderer. To do so copy the following folders to a folder called “UI” in the location of your choice (Note the folder root must contain ‘UI’):
- AspNet
- AspNet_Renderers
- AspNetWebForms
- AspNetWebForms_Renderers
Rename the last two copied folders like this:
- CustomWebsite
- CustomWebsite_Renderers
- You should have something like this:
We We copied two website templates because the AspNetWebForms template inherits the AspNet template.
You can already customize your website here. For instance edit CustomWebsite\Default.aspx.tpl, and modify the page title by modifying the
<%@ Page %> tag with something like this:
<%@ Page Title=”This is my Custom Website Home Page” …
Now add a new file called Renderer.MyContactSource.tpl in the CustomWebsite_Renderers folder. Open this file in a text editor such as NotePad and type the following text: “this is my custom Contact Source”. It is an unspecified renderer because the file name does not end with Write, or Column for example.
Now start Visual Studio, and create a CodeFluent Entities project (Demo.ContactManager, C#, SQL Server, ASP.NET WebForms). Go in the Contact Entity, select the ContactSource property and add a ‘MyContactSource’ renderer of unspecified type:

Now, double-click on the ASP.NET Webforms producer, and configure it to point to your custom site template:

Build the project, and execute the generated web site. You should now see this when you try to Add or Edit a new Contact:

what happened is, at generation time, every time a property is associated with the MyContactSource renderer, it will be rendered using the content of the Renderer.MyContactSource.tpl file. This file just contain a pure (HTML) text, but it could contain anything you would like, including server-side ASP.NET controls. This file can also contain template code so you can indeed have it vary using the model and the source object it was instantiated from at generation time.
For example, if you don’t like the drop down list that’s used to represent relations by default, you can just modify the Renderer.Relation.Write.tpl content and this will change how relations are rendered (in write mode) in every screen of the application, because Relation is the name of the default renderer associated with M:0/1 or 0/1:M relations. Association is the name of the default renderer associated with M:N relations.
Besides, navigate back to the homepage and note that Tab’s title reflects our change made in the Default.aspx file.
Therefore, thanks to Renderers and custom templates you can generate full customized websites.
Cheers
Using the SQL Server Template Producer to generate Clustered Indexes
In this post we’ll see how using CodeFluent Entities’ SQL Server Template Producer, you can generate SQL scripts using the built-in template engine whilst accessing the inferred meta-model, and then automatically deploy the generated script on your desired server.
By default SQL Azure and SQL Server add the clustered index on the primary key if a clustered index on the table does not already exist and if you do not specify a unique nonclustered index. In the case where the primary key is of GUID type it won’t be efficient. The reason for this is that GUIDs are generated in non-sequential order and SQL Server orders a clustered index sequentially. It will work – SQL Server will let you build a clustered index around a unique identifier column, however it will cause the SQL Server to do unnecessary work and cause performance slowdowns.
That being said, what we can do is using the SQL Template Producer to remove all inefficient clustered indexes and recreate them on the right columns. Let’s even go a bit further and create a little aspect that will add a property on each property to tell if a clustered index needs to be created or not on that particular property.
Add a new Part called IsClusteredIndexAspect and past it the following code (replacing the defaultNamespace’s value by yours):
<cf:project xmlns:cf=”http://www.softfluent.com/codefluent/2005/1” defaultNamespace=”yourNamespace”>
<cf:pattern name=”IsClusteredIndex Aspect” namespaceUri=”http://www.sample.com/aspects/isclusteredindexaspect/2012/11” preferredPrefix=”sa” step=”Tables”>
<cf:message class=”_doc”>
This aspect creates an extra IsClusteredIndex bool property on every property.
</cf:message><cf:descriptor name=”IsClusteredIndex” typeName=”boolean” targets=”Property” defaultValue=”false” displayName=”IsClusteredIndex” description=”Should the IsClusteredIndex Aspect apply to this property?” />
</cf:pattern>
</cf:project>
This will create our aspect and add a IsClusteredIndex property on each property in the “Aspects and Producers” property grid:
You can by now choose which property you want to use as a clustered index. Obviously this property should be set to true only on one property by entity since clustered index cannot be applied on several columns.
Now let’s write a script that will remove all clustered indexes and then create new ones based on the columns selected thanks to our aspect. In a file called “[Template]CreateIndexes.sql” add it the following code (Note that this code is only an illustration for this post, it does not take into account constraints, primary keys and so on):
[%@ namespace name="CodeFluent.Model"%]
[%@ namespace name="CodeFluent.Model.Persistence"%]
[%@ namespace name="CodeFluent.Producers.SqlServer"%]
/* [%=Producer.GetSignature()%] */
[%foreach (Entity e in Producer.Project.Entities)
{%]
--remove any existing clustered index on e.Table.FullName
--[...]
[%foreach (Property p in e.Properties)
{
if (p.GetAttributeValue("sa:IsClusteredIndex", false))
{%]
--create your index such as:
CREATE CLUSTERED INDEX [CL_[%=p.Entity.Table.Name%]] ON [%=p.Entity.Table.FullName%] ([[%=p.Column.Name%]]);
GO
[%}
}
}%]
Create a folder called “Template” under the file folder of your CodeFluent Entities project:
Right click on that folder and choose “Add existing item” then browse to your template file and select it.
Now in your CodeFluent Entities project, add an instance of the SQL Server Template Producer with your Template directory as the “Source Directory” and set the “Target Directory” to the project of you choice and then build over your model. The SQL Server Template Producer will generate a script file from your template, and run the script on the server removing and creating clustered indexes. Therefore using the template producer you can quickly create complex scripts by taking advantage of the meta model.
Cheers,
Thibault NESTOR
Generating unit test skeleton using the Template Producer
We already introduced the Template Producer in a previous post with a small example showing how to generate a DGML graph from a CodeFluent Entities model. This post is another example to remind you how easy it is to generate text files using the Template Producer whilst accessing the inferred meta-model.
Let’s say we’d like to generate a skeleton for our unit tests. By skeleton I mean a vb or csharp file by entity that will contain test methods ready to be implemented.
Assuming we are writing a pretty simple bank application. Our model has an “Account” entity and 3 methods (to deposit, withdraw, and transfer funds) as follow:
Supposing we’re using Nunit as unit-testing framework, let’s create our template to be used by the Template Producer:
[%@ namespace name="System"%]
[%@ namespace name="CodeFluent.Model"%]
[%@ namespace name="CodeFluent.Model.Code"%]
[%@ template enumerable='Producer.Project.Entities' enumerableItemName="entity" enumerableTargetPathFunc='Path.Combine(Path.GetDirectoryName(TargetPath), String.Format("{0}Tests", entity.ClrFullTypeName)) + ".cs"' %]
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using NUnit.Framework;
namespace [%= entity.Namespace %]
{
[TestFixture]
public class [%= String.Format("{0}Tests", entity.Name) %]
{
[SetUp]
public void Init()
{
/* ... */
}
[TearDown]
public void Cleanup()
{
/* ... */
}
[% foreach(Method m in entity.Methods) { if (!m.Enabled) continue; %]
[Test]
[%= String.Format("public void {0}Test()", m.Name) %]
{
/* ... */
}
[% } %]
}
}
Basically, what the template does is that it iterates through all entities of the project as well as each method to write a file by entity containing a test class with all test methods.
- Create a class library project called Bank.UnitTests to store all your unit tests and add it a reference to Nunit framework.
- Add a Template Producer and set the Source directory to your Templates folder created earlier and the Target directory to the Bank.UnitTests project.
The Template Producer instance will execute all templates placed in the Templates directory, and place output files in the Bank.UnitTests project directory.
Building your model should produce one file called Bank.AccountTests.cs with all the test methods ready to be implemented:
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using NUnit.Framework;
namespace Bank
{
[TestFixture]
public class AccountTests
{
[SetUp]
public void Init()
{
/* ... */
}
[TearDown]
public void Cleanup()
{
/* ... */
}
[Test]
public void DepositTest()
{
/* ... */
}
[Test]
public void WithdrawTest()
{
/* ... */
}
[Test]
public void TransferFundsTest()
{
/* ... */
}
}
}
As you can see, this short and simple example gives you an idea of what it is possible to do by taking advantage of the meta model using the Template Producer.
Want to know more? You’ll find more information on the Template Producer here.
Cheers,
Thibault NESTOR
Generating a WPF Smart Client using the Smart Client Producer
Hello!
In a previous posts, we showed you the output of the WPF Smart Client Producer. In this post we’ll show you how to generate a WPF smart client. It will be a WPF application consuming WCF services thanks to a proxy and the data will be stored in a database
.
Creating the solution
Start by creating a new CodeFluent Project. We’ll use the “ContactManager Sample Model” for the purpose of this article.![]()
Add a new Class Library project named “ContactManager” to your solution. It will be used to host the generated files corresponding to your Business Object model and WCF service’s contracts. Add it a folder called “ServicesConfig” that will be used to store your WCF service’s configuration files.
Add a new Class Library project named “ContactManager.Proxy” to your solution. It will be used to host the generated files corresponding to the proxy.
Add a new SQL Server Database project named “ContactManager.Persistence” to your solution. It will be used to host your generated SQL scripts.
Add a new WPF application project named “ContactManager.SmartClient” to your solution. It will be used to host the generated files of your WPF application. Remove the MainWindow.xaml file since we are going to generate our own. Also, by default, Microsoft Visual Studio 2010 sets the target framework to .NET Framework 4 Client Profile. Go to the property of your project and change the target to .NET Framework 4 in order to use the standard libraries.
Adding the producers
The Business Object Model Producer
To generate your Business Objects model, add the Business Object Model Producer to your CodeFluent Entities project by clicking “Add new producer” on the “Producers” folder in Visual Studio’s Solution Explorer, expand the Business Layer Producers node and select it:
In the Target Directory field, select your Class Library project called ContactManager.
Click OK.
The SQL Server Producer
To generate your persistence scripts, add the SQL Server Producer (or the one that suits your configuration) to your CodeFluent Entities project by clicking “Add new producer” on the “Producers” folder in Visual Studio’s Solution Explorer, expand the Persistence Layer Producers node and select it:
In the Connection String field enter your connection string used to connect to your SQL Server. Also in the Target Directory field, select your SQL Server Database project called ContactManager.Persistence. Finally in the Target Version field, select your SQL Server version.
The Service Object Model Producer
To generate your WCF service and your proxy, add the Service Object Model Producer to your CodeFluent Entities project by clicking “Add new SubProducer” on your “Business Object Model” producer in Visual Studio’s Solution Explorer, expand the Business Layer Producers node and select it:
In the Target Directory field, select your Class Library project called ContactManager.Proxy and click OK.
The Template Producer
Note: The Template producer is not mandatory. However, it is really handy if you want to be able to quickly run and test your WCF service using the CodeFluent Entities Hoster.
Lets now generate the configuration files of your WCF service. Add the Template Producer to your CodeFluent Entities project by clicking “Add new producer” on the “Producers” folder in Visual Studio’s Solution Explorer, expand the Utility Producers node and select it:
In the Source Directory field select the “Server” folder located at “CodeFluent Entities installation folder > Modeler >Templates > ServiceModel”. And in the Target Directory field, select the folder called ServicesConfig located in your Class Library project called ContactManager, then click OK.
The WPF Smart Client Producer
Then, to generate your WPF smart client, add the WPF Smart Client Producer to your CodeFluent Entities project by clicking “Add new producer” on the “Producers” folder in Visual Studio’s Solution Explorer, expand the Application Producers node and select it:
In the Target Directory field, select your WPF application project called ContactManager.SmartClient and click OK.
Generating code
Now to start generating code, build your CodeFluent Entities project called ContactManager.Model.
Here is the visual studio solution you should have by now, each project containing the generated code (your database should have been created too):
Building and running the application
At this stage, your application has been generated and is almost ready to be built and run. Since your WPF application uses the Proxy you need to add your Class Library project called ContactManager.Proxy as a reference to your WPF application project called ContactManager.SmartClient project.
Now you can build your solution, then run your WCF service as you usually do or thanks to the CodeFluent Entities Hoster using your generated service configuration files. Finally start your WPF application.
Tip: If you use the CodeFluent Entities Hoster, a quick and easy way to ensure the executable is automatically copied to the output directory is to add a reference to it. This is absolutely not required to compile your Business Object model (your Class Library called ContactManager), it’s just a shortcut to have the executable in the output directory without having to create post-build events.
And tadaaa! You’ve created your 100% functional WPF smart client without a single line of code!
Enjoy!
Thibault Nestor
CodeFluent Entities: Writing a Template Generating One File Per Entity
Following the previous post “Generating Custom Code For All Entities” a colleague showed me the greatest way ever to iterate on a collection of concepts and generate text a file for each from a template, so I thought I’d share it ![]()
In this post we’ll write a template to generate a C# file per entity extending the one generated by the Business Object Model producer. The generated file should look like this one:
namespace Sample
{
public partial class Customer
{
public static Customer LoadFromLob(string entityKey)
{
// TODO: load from external LOB
}
public void SendToLob()
{
// TODO: save current instance to external LOB
}
}
}
To generate code like the one above I created a template file named “[Template]entity.tpl”.
Note: The “[Template]” prefix is important as it indicates the producer to run the template. Other than that, the rest of the name doesn’t matter as we’ll name our output files <EntityName>.g.cs and this will be done in the template.
Here’s my template:
[%@ template enumerable='Producer.Project.Entities' enumerableItemName="entity" enumerableTargetPathFunc='Path.Combine(Path.GetDirectoryName(TargetPath), entity.Name) + ".g.cs"' %]
//------------------------------------------------------------------------------
// <auto-generated>
// This code was generated by the Template Producer.
//
// Changes to this file may cause incorrect behavior and will be lost if
// the code is regenerated.
// </auto-generated>
//------------------------------------------------------------------------------
namespace [%=entity.Namespace%]
{
public partial class [%=entity.Name%]
{
public static [%=entity.Name%] LoadFromLob(string entityKey)
{
// TODO: load from external LOB
}
public void SendToLob()
{
// TODO: save current instance to external LOB
}
}
}
Instead of all the code which we used to have I now have a single line which will have the exact same effect. Here’s a description of what it does:
- the enumerable attribute takes an IEnumerable as an input. In our case, I’ve set it to take as input all entities of my project. This is possible as all producers have a Project property corresponding to the model inferred from your model.
- the enumerableItemName attribute corresponds to the item name which I named “entity” as I’m enumerating on all entities. That’s basically the variable name of my foreach, and that’s how I can use the “entity” variable in the rest of my template.
- the enumerableTargetPathFunc is a code snippet to be called to compute the target path of the generated file. This is thanks to this snippet that I’m generating files named as “<EntityName>.g.cs”.
Running my new template, here’s the result:
//------------------------------------------------------------------------------
// <auto-generated>
// This code was generated by the Template Producer.
//
// Changes to this file may cause incorrect behavior and will be lost if
// the code is regenerated.
// </auto-generated>
//------------------------------------------------------------------------------
namespace Sample
{
public partial class Customer
{
public static Customer LoadFromLob(string entityKey)
{
// TODO: load from external LOB
}
public void SendToLob()
{
// TODO: save current instance to external LOB
}
}
}
Carl Anderson
CodeFluent Entities: Generating Custom Code For All Entities
We often have questions on our forums of CodeFluent Entities users who’d like to add custom methods to all entities of their project.
A convenient way to do this is by writing a template of those custom methods and run them on all entities, and this is what we’ll see in this post.
Scenario
Say I have some line of business, external to my application, but with which every now and then I want to be able to synchronize my generated classes. As a consequence, I’d like all my entity classes to have two extra methods: a SendToLob and LoadFromLob.
Solution
To do so we’re going to write a template which, for each entity, will add those two methods in a partial class, extending the generated code. To do so we’ll create a single template which will create one .CS file for each entity.
Here’s our template (named “[Template]entity.g.cs”):
[%@ template language="CSharp" output="false"%]
[%@ namespace name="System" %]
[%@ namespace name="CodeFluent.Model" %]
[%@ namespace name="CodeFluent.Producers.CodeDom" %]
[%@ namespace name="CodeFluent.Model.UI" %]
[%@ namespace name="CodeFluent.Model.UI.ControlDefinitions" %]
[%@ namespace name="CodeFluent.Producers.CodeDom.UI" %]
[%@ namespace name="System.IO" %]
[%
Entity entity = null;
if (Context["inTemplate"] == null)
{
Context["inTemplate"] = true; // anything would do, other than null
foreach(Entity e in Producer.Project.Entities)
{
// build a new target path & re-run ourselves
string targetPath = Path.Combine(
Path.GetDirectoryName(TargetPath),
Path.GetFileName(TargetPath).Replace("entity", e.Name));
using (GeneratedFile file = new GeneratedFile(Producer.Project, targetPath))
{
if ((file.HasBeenChanged) && ((e.ProductionFlags & ProductionFlags.Overwrite) == 0))
{
Producer.RaiseProduction(Producer, file.CreateFileSkipEvent("entity.g.cs"));
continue;
}
// note: we don't care about the output="false" here
Producer.RaiseProduction(Producer, ProductionEventArgs.CreateFileTemplateGenerateEvent(targetPath, Template.FilePath));
file.Open(Producer, Producer.OutputEncoding);
// add the entity to the context
Context["entity"] = e;
// update targetPath
Context["TargetPath"] = targetPath;
// go recursive, and this will jump to the else part of this file
Template.Run(file.Writer, Context);
}
}
}
else
{
entity = (Entity)Context["entity"];
%]
namespace [%=entity.Namespace%]
{
public partial class [%=entity.Name%]
{
public static [%=entity.Name%] LoadFromLob(string entityKey)
{
// TODO: load from external LOB
}
public void SendToLob()
{
// TODO: save current instance to external LOB
}
}
}
[% }%]
The first part of the template iterates on all entities, and re-runs itself to create a file where the “entity” file name was replaced by the actual entity name. The second part of the template is the actual code to be placed in the generated file.
Then:
- Add an instance of the Template Producer to your model,
- Set its source directory to point to the directory containing our [Template]entity.g.cs file,
- Set its target directory to be the same as your Business Object Model Producer so the generated classes will be in the same directory.
You’re now ready to go, generate over!
Result
Extra files were generated (one per entity) extending your already existing generated classes:
And here’s the content of the Customer.g.cs file:
namespace Sample
{
public partial class Customer
{
public static Customer LoadFromLob(string entityKey)
{
// TODO: load from external LOB
}
public void SendToLob()
{
// TODO: save current instance to external LOB
}
}
}
Remarks
Drawbacks of this method are that:
- it creates one extra file per entity,
- if entity classes are generated in subfolders (e.g. multiple namespaces) it will require extra code to handle.
Other options to obtain the same output but without those drawbacks could be to:
- Generate a single class file extending all classes (a little ugly, yet so effective
) - Create a CodeFluent Aspect instead of using templates to add code snippets to all entities!
Hope this helps,
Carl Anderson
Generating Documentation
CodeFluent Entities provides a documentation sub-producer which allows you to:
- Decorate all members with XML comments (usable by Visual Studio IntelliSense and help tools),
- Generate XML, batch and configuration files to create a .CHM documentation using Sandcastle.
To benefit from it, you first need to add an instance of the sub-producer. To do so, select the Business Object Model Producer instance of your project, right-click on it and select “Add New SubProducer”. Then in the “Add New SubProducer” dialog, select “Documentation” in the tree view and configure it:
Note: the only required property is the “Sandcastle Target Directory “which needs to be specified so the producer knows where to generate its output files. If producing Sandcastle files, you need to have Sandcastle installed before generating and ensure the Sandcastle path is correct so you’ll be able to use the generated files right away.
Since decorating all members of all your generated classes all the time can be quite an overkill during developments, it is disabled by default in the Business Object Model producer, so you need to enable it as well. Double-click on your Business Object Model producer instance to open its configuration and set “Generate Xml Documentation” to “True”:
In the XML this looks like something like that:
<cf:producer typeName="CodeFluent.Producers.CodeDom.CodeDomProducer, CodeFluent.Producers.CodeDom">
<cf:configuration targetDirectory="..\Sample" outputName="{0}.dll" generateDocumentation="true">
<subProducer typeName="CodeFluent.Producers.Documentation.DocumentationProducer, CodeFluent.Producers.Documentation"
targetDirectory="..\Doc" sourceDirectory="%CF_TEMPLATES_PATH%\Documentation" />
</cf:configuration>
</cf:producer>
Build over your project and you’ll see that all your members have XML remarks on them! Moreover, in the Sandcastle Target Directory you specified, you’ll see a set of files allowing you to generate a .CHM file documenting the generated objet model ![]()
Razor Syntax Support
We introduced the Text Template Engine in previous posts such as this one, or this one; and both posts feature some quick examples of how to use the default syntax to create templates:
- use [%= foo %] to print the value of the foo variable,
- use [% foreach (string value in values) %] to embed C# statements.
Starting with the next CodeFluent Entities build (> 50401.587), the CodeFluent Template Engine now supports Razor.
Razor, is basically a new view engine for ASP.NET MVC developed by Microsoft and shipped with ASP.NET MVC 3. Basically, the main goal of Razor is that it’s compact, expressive and fluid. To quote Scott Guthrie (view source):
Razor minimizes the number of characters and keystrokes required in a file, and enables a fast, fluid coding workflow. Unlike most template syntaxes, you do not need to interrupt your coding to explicitly denote server blocks within your HTML. The parser is smart enough to infer this from your code. This enables a really compact and expressive syntax which is clean, fast and fun to type.
To generate files from templates using the Razor syntax you need:
- To be in .NET 4,
- References to the CodeFluent.Runtime.dll and CodeFluent.Model.Common.dll (versions strictly upper than 50401.587),
- A reference to System.Web.Razor
As an example, here’s a template which loads from its context a string array containing all NBA teams, and lists them in a text file:
@ template engine=”razor”
Generated @System.DateTime.Now
@{
string[] nbaTeams = (string[])Context["NbaTeams"];
}Current NBA Teams:
@foreach (string team in nbaTeams) {
<text>- @team</text>
}
Check-out this nice blog post for a quick reference on the Razor syntax.
Then here’s the code using CodeFluent’s Template Engine which runs the template and prints its output on the console:
class Program
{
private static string[] _nbaTeams = { /* All Teams...*/ };
static void Main(string[] args)
{
Template template = new Template();
template.Load("Sample.txt", TemplateOptions.Default);
template.Build();
Hashtable context = new Hashtable();
context["NbaTeams"] = _nbaTeams;
template.Run(Console.Out, context);
}
}
Here’s the output:
Generated 04/12/2011 14:42:13
Current NBA Teams:
– Boston Celtics
– New Jersey Nets
– New York Knicks
– Philadelphia 76ers
– Toronto Raptors
– Dallas Mavericks
– Houston Rockets
– Memphis Grizzlies
– New Orleans Hornets
– San Antonio Spurs
– Chicago Bulls
– Cleveland Cavaliers
– Detroit Pistons
– Indiana Pacers
– Milwaukee Bucks
– Denver Nuggets
– Minnoseta Timberwolves
– Portland Trail Blazers
– Oklahoma City Thunder
– Utah Jazz
– Atlanta Hawks
– Charlotte Bobcats
– Miami Heat
– Orlando Magic
– Washington Wizards
– Golden State Warriors
– Los Angeles Clippers
– Los Angeles Lakers
– Phoenix Suns
– Sacramento Kings


