Creating a custom sub producer to only generate resources
Generating a CodeFluent Entities model looks at all the producers, and produce each one of them, assuming they have been enabled. The BOM producer is the most important producer and generates classes from your entities. If we break down that producer, we realize that it produces different things, such as templates, resources, membership providers, membership roles, constants…
What if you wanted to only produce resources, and nothing else?
One reason would be that your project has a lot of entities, your model is pretty much finished, but you still need to add resources. Moreover, your project is hosted on TFS online, and you do not want to check out, and check in, all the new generated files, especially if they have not changed!
By default, TFS checks out all the modified files (by a human or a code generator). Then, you need to check them back in. Hosted online, this means that the check in process would contain almost all the files of your BOM and it could be time consuming.
In this post we will create a custom sub producer that will only generate resources, and nothing else.
1. Creating the project
First, you need to create a new class library project, add some of the CodeFluent Entities references as well as 2 classes (BuildOnlyResources.cs and Constants.cs):
2. Writing classes
The BuildOnlyResources class extends the ICodeDomSubProducer interface to plug itself into the OnCodeDomProduction event. The first thing to do is to cancel the production of everything besides Resources. To do this, we check the eventType retrieved from the parameter of the OnCodeDomProduction method, and set the cancel property to true.
At this stage, the sub producer will stop generating all files, except the resources. Meanwhile, it will also delete the existing files, which is not what we want! We want to keep the existing files, without modifying them. This part is handled when the eventType corresponds to the UnitProducing value. There, we go through each class, and pretend they have been generated. That way, they will not be deleted if they exist. The method that does this is the AddToGeneratedFiles(path) method from the baseProducer class.
The Constants class simply contains 2 constants, used int the BuildOnlyResources class.
3. Adding options
We need to add a couple of options for our sub producer. The first is a boolean option that describes whether the sub producer is enabled or not. If not enabled, it will not be used during the generation. The second option is a boolean that describes whether the resources are produced or not.
4. Compiling the solution
We can now compile the solution in release mode and obtain a dll, called SubProducerResources.dll. In order to use that sub producer in our CodeFluent Entities model, we need to add this dll to the folder where CodeFluent Entities was installed, located at C:\Program Files (x86)\SoftFluent\CodeFluent\Modeler by default.
5. Displaying the subproducer in the modeler.
The last step is to be able to display that sub producer in the modeler. CodeFluent Entities looks at a config file located in: C:\Users\{user}\AppData\Roaming\CodeFluent.Modeler.Design\Custom.config. You need to create it because it does not exist. Its content needs to look like this:
<codeFluent.Modeler> <producerDescriptors> <producerDescriptor name="SubProducerResources" displayName="SubProducer Resources" category="My Custom Producers" typeName="SubProducerResources.BuildOnlyResources, SubProducerResources" /> </producerDescriptors> </codeFluent.Modeler>
6. Ready
Your sub producer is ready to be used! Open your CodeFluent Entities project, right-click on your BOM producer, and add a new sub producer. You should see your sub producer in the list:
Once added, it will appear under your BOM producer:
Here is what you are really looking for, the code for both BuildOnlyResources and Constants classes:
using System;
using System.CodeDom;
using System.Collections;
using System.Collections.Generic;
using System.ComponentModel;
using System.IO;
using System.Xml;
using CodeFluent.Model;
using CodeFluent.Model.Common.Design;
using CodeFluent.Model.Design;
using CodeFluent.Producers.CodeDom;
using CodeFluent.Runtime.Utilities;
namespace SubProducerResources
{
[Category("Business Layer Producers")]
[DisplayName("SubProducer Resources")]
[Producer(Constants.CustomResourcesProducerNamespaceUri, Constants.CustomResourcesProducerNamespacePrefix)]
public class BuildOnlyResources : ICodeDomSubProducer
{
private CodeDomBaseProducer _baseProducer;
private CodeFluent.Producers.CodeDom.SubProducer _subProducer;
[Description("Determines if sub producer is enabled.")]
[Category("Configuration")]
[DefaultValue(true)]
[DisplayName("Is Enabled")]
[ModelLevel(ModelLevel.Normal)]
public virtual bool Enabled
{
get
{
return XmlUtilities.GetAttribute(Element, "enabled", true);
}
set
{
XmlUtilities.SetAttribute(Element, "enabled", value.ToString().ToLowerInvariant());
}
}
[Description("Determines if resources are produced.")]
[Category("Configuration")]
[DefaultValue(true)]
[DisplayName("Produce Resources")]
[ModelLevel(ModelLevel.Normal)]
public virtual bool ProduceResources
{
get
{
return XmlUtilities.GetAttribute(Element, "produceResources", true);
}
set
{
XmlUtilities.SetAttribute(Element, "produceResources", value.ToString().ToLowerInvariant());
}
}
public virtual void Initialize(CodeDomBaseProducer baseProducer, CodeFluent.Producers.CodeDom.SubProducer subProducer, IDictionary context)
{
_baseProducer = baseProducer;
_subProducer = subProducer;
baseProducer.CodeDomProduction += OnCodeDomProduction;
}
public virtual void Produce(IDictionary context, CodeCompileUnit unit)
{
}
public virtual void Terminate(IDictionary context)
{
}
private void OnCodeDomProduction(object sender, CodeDomProductionEventArgs e)
{
if (!Enabled)
return;
if (e.EventType == CodeDomProductionEventType.ResourcesProducing)
{
if (!ProduceResources)
{
e.Cancel = true;
}
}
if (e.EventType == CodeDomProductionEventType.UnitsProducing)
{
e.Cancel = true;
IEnumerable<CodeCompileUnit> units = (CodeCompileUnit[])e.Argument;
foreach (CodeCompileUnit unit in units)
{
FakeProduceUnit(unit);
}
}
// adapt to your needs
if (e.EventType == CodeDomProductionEventType.ConstantsProducing ||
e.EventType == CodeDomProductionEventType.SRProducing ||
e.EventType == CodeDomProductionEventType.BasicAuthenticationModuleProducing ||
e.EventType == CodeDomProductionEventType.BitsServerProducing ||
e.EventType == CodeDomProductionEventType.MembershipProviderProducing ||
e.EventType == CodeDomProductionEventType.MembershipUserProducing ||
e.EventType == CodeDomProductionEventType.ProfileProviderProducing ||
e.EventType == CodeDomProductionEventType.RoleProviderProducing)
{
e.Cancel = true;
}
}
private void FakeProduceUnit(CodeCompileUnit unit)
{
if (unit == null)
throw new ArgumentNullException("unit");
BaseType baseType = UserData.GetBaseType(unit); // get the type related to this unit, if any
if (baseType == null)
return;
// check if the type was to be produced or not
if (!_baseProducer.MustProduce(baseType, CodeFluent.Producers.CodeDom.Constants.ModelProducerNamespaceUri))
return;
Set set = baseType as Set;
if (set != null)
{
if (!_baseProducer.MustProduce(set.ItemEntity, CodeFluent.Producers.CodeDom.Constants.ModelProducerNamespaceUri))
return;
}
// determine the final target path where the file should have gone, and pretend it's been generated
string path = ((CodeDomProducer)_baseProducer).GetTargetPath(baseType);
path = _baseProducer.GetProductionTargetPath(baseType, path, false, false);
if (File.Exists(path))
{
_baseProducer.AddToGeneratedFiles(path);
}
}
public XmlElement Element
{
get
{
if (_subProducer == null)
throw new CodeFluentCodeDomProducerException(GetType().FullName);
return _subProducer.Element;
}
set
{
}
}
}
}
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
namespace SubProducerResources
{
public sealed class Constants
{
public const string CustomResourcesProducerNamespaceUri = "http://www.softfluent.com/codefluent/producers.customResources/2013/1";
public const string CustomResourcesProducerNamespacePrefix = "cfcr";
private Constants()
{
}
}
}
Vincent Patry
Exploring the CodeFluent Runtime: ChunkedMemoryStream
Today, on the series “Exploring the CodeFluent Runtime” we are going to take a look at the ChunkedMemoryStream class on the CodeFluent.Runtime.Utilities namespace.
This class allows you to manipulate a memory stream by “chunks”. This can be useful when you are dealing with memory streams big enough (85,000 bytes) to be allocated on the Large Object Heap (LOH).
The ChunkedMemoryStream can be used instead of the System.IO.MemoryStream (mscorlib.dll) to avoid memory fragmentation.
Let’s build a simple example in order to compare the use of a System.IO.MemoryStream against the CodeFluent.Runtime.Utilities.ChunkedMemoryStream.
Let’s say I want to load a file’s content in memory (big enough to sit on the LOH).
static void Main(string[] args)
{
FileStream fileSm = new FileStream(@"file_path", FileMode.Open);
Stream ms = new MemoryStream();
fileSm.CopyTo(ms);
ms.Close();
fileSm.Close();
System.Diagnostics.Debugger.Break();
}
When the Debugger breaks let’s explore the LOH:
We can see that the LOH size is (17184 + 41943056 + 83886096 = 125846336 bytes) and we easily distinguish a memory allocation for 2 byte arrays (perhaps some buffers used internally when copying the data from one stream to another).
Let’s now change only one line in our code example and use the CodeFluent.Runtime.Utilities.ChunkedMemoryStream.
static void Main(string[] args)
{
FileStream fileSm = new FileStream(@"file_path", FileMode.Open);
Stream ms = new CodeFluent.Runtime.Utilities.ChunkedMemoryStream();
fileSm.CopyTo(ms);
ms.Close();
fileSm.Close();
System.Diagnostics.Debugger.Break();
}
And let’s explore the LOH:
We now see that the LOH size is 17184 bytes and we cannot see any trace of a byte array.
Using the ChunkedMemoryStream we avoid allocating memory on the LOH when manipulating big streams.
Remeber that the CodeFluent Runtime Client is a free library that provides very useful and powerful helpers like:
- XML utilities
- IO utilities
- Type conversion helpers
- JSON utilities
- … and many other
You can easily install the CodeFluent Runtime Client from Nugget.
PM> Install-package CodeFluentRuntimeClient
Regards,
Pablo Fernadez Duran
Patch text files after code generation with CodeFluent Entities
CodeFluent Entities provides a large set of concepts and tools to generate code as custom as wanted. But, it may be a reason you need to modify the output produced by the CodeFluent Entities engine when there is not an option or a feature that allows you do that.
The Patch Producer is a producer that lets you “patch” text files using regular expressions. You can find the Patch Producer under the Utility Producers category.
Path: can be a directory path or a file path. If relative, it is based from the directory containing the project root part.
File Search Pattern: is a file filter expression. Only used if “path” is a directory.
Search Pattern: a regular expression matching groups.
Replace: a key=value pair list separated by the “Replace Separator Character”.
You can use the default namespace in the path attribute using the syntax {1:DefaultNameSpace}
Example 1
CodeFluent Entities provides a “tracking” feature.
In most of the cases the CodeFluentUser.Name is of the form “Domain\UserName” and let’s say we only want to store in the database the “UserName” without the “Domain” (ie. The CodeFluentUser.UserName).
In my case I have a CodeFluent Entities project with a Business Object Model (BOM) producer and a SQL Server persistence producer. The BOM generated files are stored in a class library project having as name the default namespace.
So, I need to search all files matching “ *.cs ” in my BOM project:
And make the replacement using the regular expression:
,\s*persistence\.Context\.User\.(?<name>Name)\s*\)
And replace the matched value in the group name “name” by “UserName”:
If I build my CodeFluent Entities, now I have:
Example 2
CodeFluent Entities adds some information on each generated file about the generation itself. For example, for SQL files:
Let’s say we want to add the name our company within this information, something like “CodeFluent Generated for SoftFluent […]”
We add a new “Patch” producer.
As you can see, I store my SQL files in a folder named “SQL” in the same location as my BOM generated files (cf. example 1).
We build the CodeFluent Entities project and now we have:
Have fun.
Regards,
Pablo Fernandez Duran
Using the Cache Sub-Producer
CodeFluent Entities provides an integrated cache system for the Business Object Model (BOM) layer. The Object Model Cache (OMC) is not enabled by default. To add the cache feature to your BOM you need to first add a Cache sub producer.
If you set the “Is Default Enable” attribute to “True” the cache feature will be enabled for all the entities in your model. You can also decide to enable or not the cache feature by entity or by method.
As you can see in the image above, you can independently specify whether you want to enable the cache feature for Collections or not by changing the value of the “Is Collection Enabled” attribute.
If you enable the cache feature, when calling a “LoadXXX” method (ex. Load, LoadById…) on your entity will make that a cache verification is performed before trying to load the data from the data source (SQL server for example).
If you want to bypass the cache you can call the “NoCacheLoadXXX” method (ex. NoCacheLoad, NoCacheLoadById…). When saving or deleting an instance of an entity, the cache is cleared (for that entity) and you can clear manually the cache calling the “CacheClear” method on an entity (public static method).
You may considerate some points when using a Cache system:
- Complexity will be added to your application.
- Unexpected behaviors may appear if not using it correctly.
- The Object Model Cache provided by default is an in-memory cache, so it cannot be shared between servers.
- It is not interesting to use a Cache system if the cached data changes too often. It’s best to cache immutable or almost immutable data.
An example scenario when the Object Model Cache feature could be useful may be when storing “referential” data on a data base or data that does not change too often.
CodeFluent entities provides three types of Cache implementations:
- Simple Cache Manager, based on the ASP .NET cache (that can be used outside of ASP.NET) (CodeFluent.Runtime.Caching.SimpleCacheManager, CodeFluent.Runtime).
- Simple Localized Cache Manager, a sub-class of the Simple Cache Manager that can manage localized keys (CodeFluent.Runtime.Caching.LocaleCacheManager, CodeFluent.Runtime)
- Enterprise Library Cache Management, you must install the Enterprise Library in order to use it (CodeFluent.Runtime.Caching.EnterpriseLibraryCacheManager, CodeFluent.Runtime).
You can specify the type of cache you want to use on the “Runtime Cache Type Name” attribute (the full type name). You can use a different cache systems by scope (entity, method).
You can use a different or custom type of cache not provided by CodeFluent Entities, you only need to implement the CodeFluent.Runtime.Caching.ICacheManager interface.
Finally, you can disable the cache feature by configuration (only for the Simple Cache Manager and the Simple Localized Cache Manager), for a testing or development environment for example. You only need to add the following code to your app.config or web.config file:
<appSettings> <add key="CodeFluent.Runtime.Caching.SimpleCacheManager.Enabled" value="false"/> </appSettings>
Regards,
Pablo Fernandez Duran
Remove the current date and time to generated files
CodeFluent Entities adds some information to generated files every time a code production is run.
This information contains general information (for all producers) and specific information (for each producer):
- The CodeFluent Entities Build version.
- The current date and time.
- The Runtime version.
- The Target version.
- The Culture.
- The Encoding.
- - …
You might want to avoid CodeFluent Entities to add some of this information to generated code.
For example, each time a code production is made almost all generated files will have a new “generation date” even if the generated code is the same.
When using a source control system you will need to checkin/commit every single file even if only the generation date has changed. This can lead to conflicts and unnecessary merges.
Well, CodeFluent Entities provides an option to remove the “generation date and time” when running producers.
This options is found in the “advanced properties tab” at the project level (right click on the CodeFluent Entities project > Properties).
Set the defaultProducerProductionFlag flag to RemoveDiffs to avoid having the “date and time” on generated files.
Since the CodeFluent Entities build 702 (march 2013) the RemoveDiffs production flag option now also removes the Runtime Version value added to generated files.
Regards,
Pablo Fernandez Duran
Using the LINQ to SQL Sub-Producer
CodeFluent Entities gives you the possibility to make your generated Business Object Model (BOM) compatible with the LINQ to SQL data access infrastructure.
CodeFluent Entities ships a LINQ to SQL producer, that is in fact a Sub-Producer of the Business Object Model (BOM) Producer.
Let’s start by setting a model to work with.
For this post I will create a very simple model. A “Person” entity who has zero or more “Pets” of a given kind.

Pet management model
I will also add Class Library project to my solution so I can store the generated code by CodeFluent Entities.
I will add a Persistence producer (SQL Server) and a Business Object Model Producer. I will set the Target Directory to my Class Library project for both producers.
Now I can add my Linq-To-Sql producer. As said before, this producer is a Sub-Producer of the BOM Producer, so I have to add it to the BOM Producer.

Add Sub-Producer

LINQ to SQL Sub-Producer
As you can see, there is no configuration required for this Sub-Producer.
We need to set the “Default Entity Tracking Mode” to “None” at the project level to avoid any problem with the LINQ to SQL query provider.

Default Entity Tracking Modes
Let’s build our CodeFluent Entities project, and open a BOM class so we can see what has been generated.

LINQ to SQL attributes
We now see that our class has been decorated with LINQ to SQL attributes. We also see that the “System.Data.Linq” namespace is not defined. To fix that we need to add a reference to the “System.Data.Linq” assembly in our BOM project.
We have now a LINQ to SQL compliant BOM.
Let’s test it using LINQ to SQL.
For that I will add a simple Console application. Then I add a reference to my BOM project, to the CodeFluent.Runtime assembly and to the System.Data.Linq assembly. And add the right application configuration.
We will use the DataContext class provided by the LINQ to SQL infrastructure to manipulate data (insert, delete, update and read). And we can retrieve the connection string from the CodeFluentContext class.
string connectionString = CodeFluentContext.Get(PetsManagement.Constants.PetsManagementStoreName).Persistence.ConnectionString;
using (DataContext context = new DataContext(connectionString))
{
}
Let’s start by adding some data to our database:
string connectionString = CodeFluentContext.Get(PetsManagement.Constants.PetsManagementStoreName).Persistence.ConnectionString;
using (DataContext context = new DataContext(connectionString))
{
Person bart = new Person { Name = "Bart" };
Pet bartsDog = new Pet { Name = "Santa's Little Helper", Age = 2, Kind = PetKind.Dog };
bartsDog.Owner = bart;
Pet bartsCat = new Pet { Name = "Snowball II", Age = 3, Kind = PetKind.Cat };
bartsCat.Owner = bart;//not true, is Lisa
Person pablo = new Person { Name = "Pablo" };
Pet pablosDog = new Pet { Name = "Shiny", Age = 17, Kind = PetKind.Dog };
pablosDog.Owner = pablo;
Pet pablosDog2 = new Pet { Name = "Vanilla", Age = 10, Kind = PetKind.Dog };
pablosDog2.Owner = pablo;
Person ferb = new Person { Name = "Ferb" };
Pet ferbsPet = new Pet { Name = "Perry", Age = 32, Kind = PetKind.Platypus };
ferbsPet.Owner = ferb;
context.GetTable<Person>().InsertAllOnSubmit(new[] { bart, pablo, ferb });
context.GetTable<Pet>().InsertAllOnSubmit(new[] { bartsDog, bartsCat, pablosDog, pablosDog2, ferbsPet });
context.SubmitChanges();
}
Now let’s retrieve all the pets grouped by “Pet kind”.
string connectionString = CodeFluentContext.Get(PetsManagement.Constants.PetsManagementStoreName).Persistence.ConnectionString;
using (DataContext context = new DataContext(connectionString))
{
var petsByKind = from pet in context.GetTable<Pet>()
group pet by pet.Kind into gr
select gr;
foreach (IGrouping<PetKind, Pet> kindGroup in petsByKind)
{
Console.WriteLine("----" + kindGroup.Key + "----");
foreach (Pet pet in kindGroup)
{
Console.WriteLine(pet.Name + " : " + pet.Owner.Name);
}
}
}
The result is:

Pets grouped by kind
Let’s now delete a cat named “Snowball II” which owners name is “Bart”.
string connectionString = CodeFluentContext.Get(PetsManagement.Constants.PetsManagementStoreName).Persistence.ConnectionString;
using (DataContext context = new DataContext(connectionString))
{
Pet petToDelete = (
from person in context.GetTable<Person>()
where
person.Name == "Bart"
from pet in person.Pets
where
pet.Kind == PetKind.Cat &&
pet.Name == "Snowball II"
select pet
)
.FirstOrDefault();
if (petToDelete != null)
{
context.GetTable<Pet>().DeleteOnSubmit(petToDelete);
context.SubmitChanges();
}
}
Thanks to the LINQ to SQL Sub-Producer we can use the LINQ to SQL infrastructure with our BOM, but there are several limitations and several concepts/features that can be done by CodeFluent Entities and not supported by LINQ to SQL: The CodeFluent Entities model is richer than LINQ to SQL (rules, validation, aspects, advanced relations, automatic tracking, cache, circular dependencies, multi-databases…).
Regards,
Pablo Fernandez Duran
CodeFluent Entities and Syncfusion for an amazing application!
When applications are beautiful, fast and robust at the same time, we qualify them as amazing. If you think it also means a long development process, then you have not seen applications using both SoftFluent and Syncfusion products altogether!
SoftFluent and Syncfusion have partnered to help you build these amazing applications in no time. CodeFluent makes the application highly functional, while Syncfusion makes the application interface elegant and user-friendly.
CodeFluent Entities is a unique product integrated into Visual Studio which allows developers to generate database scripts, code, web services and UIs in the Microsoft .NET platform. The code generation process is model-first and continuous: from your declarative model, a meta-model will be inferred which code generators will then translate into code. Over 20 code generators (a.k.a. producers’) are provided out of the box and can be combined to create your own application following your desired architecture, using your desired technologies.
Syncfusion, Inc. provides the broadest range of enterprise-class software components and tools for the Microsoft .NET platform. With Syncfusion, developers can move beyond simply coding applications to delivering real business innovation—the elegant user interfaces, business intelligence dashboards, and sophisticated reporting that today’s business users need, in the formats they demand.
Whether you need to build applications with WinForms or WPF, or websiteswith WebForms or MVC, SoftFluent and Syncfusion provide all the necessary tools to help you.
To show you how it works, we built a full application using CodeFluent Entities and Syncfusion components. With Visual Studio 2012, we have created a WPF application that consumes web services to communicate with an SQL Server 2008 database. The database we used is a sample database of Microsoft SQL Server, called AdventureWorks.
.
The application can be created in five steps:
.
1. CodeFluent Entities project
Create a CodeFluent Entities project in Visual Studio 2012. You also need a class library project that contains the business-object model, a class library project (Proxy) that contains your web service contracts, and the WPF application.
.
2. Import the AdventureWorks database
If you right-click on the CodeFluent Entities project, you will have the option to import an existing database or model as you can see on the screenshot below.
Then follow the instructions to import the AdventureWorks database.
.
3. Set up the producers
Once the database has been imported, you can view the visual model inside the CodeFluent Entities project (Surface > Default) as you can see here:
Now that you have your model, you need to add producers. These producers are responsible for generating code for your application.
The first producer is the BOM (Business Object Model) producer, which corresponds to the business logic. The code generated will be classes for each entity of your model. This code is exceptionally readable and can be customized using partial classes, if needed. Also, this producer contains a sub- producer responsible for generating services.
The second producer is the SQL producer responsible for generating SQL scripts, such as tables, views, and stored procedures.
The third producer is the WPF ClickOnce Smart Client, which is responsible for generating UIs. These UIs are generated using templates, located in the CodeFluent Folder. We will discuss this in more detail later.
The fourth producer is the Template, responsible for creating a host for the web services.
The fifth producer is the Command Line Execution producer, responsible for running a batch file that will insert data in your database.
.
4. Generation
The model is ready to be generated. In a single click, the CodeFluent Entities project will load your model in memory, and run each of the producers to generate ASP.NET code (C# in this example), SQL scripts and WPF controls. The application is almost ready to run. The last steps are to:
- Set up the connection string in your WPF application.
- Set up the application that hosts the web services to run at the same time as the WPF application.
That is all you need to do in order to run the application! When you launch the application, you will have a list of all entities, and you will be able to manipulate the data of these entities with generic methods such as load, load all, update, delete, and save. Each of these actions will consume the web services that are being hosted in the other application.
.
5. SyncFusion Components
The full running application uses standard ASP.NET controls for your WPF application. Though these components are functional, they are not always the best-looking ones. This is where Syncfusion comes in to transform a functional application into an amazing application.
CodeFluent Entities generates reusable controls for the application, so that one control can be used in several pages. As a result, the work consists in updating these ASP.NET standards controls by using Syncfusion controls, to end up with a highly functional and beautiful application:
Interface displaying the list of departments
.
Interface displaying the edition of a department in a popup
.
Interface displaying the edition of the SalesTerritory field that corresponds to a list prefilled with a related entity
.
Using the power of CodeFluent Entities to generate functional applications quickly, and the power of Syncfusion’s beautiful components, you can create amazing applications in no time.
.
6. Unlimited possibilities
To go further with CodeFluent Entities and Syncfusion integration, you can reuse Syncfusion components in other applications at no cost. Indeed, CodeFluent Entities uses templates to generate components, such as the view page, the edit form and so on. These templates are available in the CodeFluent folder (where it was installed, usually in \CodeFluent\Modeler\Templates\SmartClient).
Extremely simple to read and to understand, these templates can be modified to produce pages with custom components, such as the ones provided by Syncfusion. By doing so, each CodeFluent Entities project can reuse these templates to produce amazing applications. Although you have developed a WPF application in this example, you can do the same with all other types of applications, such as WinForms, WebForms, MVC, mobile or any combination of these technologies.
.
If you want to download the sample project demo please click here: http://www.softfluent.com/downloads/AdventureWorksReloaded.zip





















