Archive

Author Archive

WPF Universal Converter

February 3, 2015 Leave a comment

When you create an application using WPF, you often have to write converters to change one value to the desired type. The .NET Framework already provides some basics converter such as BooleanToVisibilityConverter. These converters are very specifics and not configurable. For example you cannot change the visibility from Collapsed to Hidden. We do not want to spend time to write common converter so we create the UniversalConverter.

The converter is located in the CodeFluent.Runtime.dll or CodeFluent.Runtime.Client.dll. Please use the Nuget Package Manager to add this Package on your project:

CodeFluentRuntime_Nuget

Let’s see how to use it!

Basic conversion

<Window.Resources>
    <windows:UniversalConverter x:Key="TypeConversionUniversalConverter" />
</Window.Resources>

<CheckBox IsChecked="{Binding Converter={StaticResource TypeConversionUniversalConverter},
   Mode=OneWay}" DataContext="true"/>
<CheckBox IsChecked="{Binding Converter={StaticResource TypeConversionUniversalConverter}, 
   Mode=OneWay}" DataContext="yes"/>

UniversalConverter uses ConvertUtilities to convert the value to the desired type so string values “true” and “yes” will be converted to the Boolean value “true”.

Switch Case syntax

You can create a list of cases to fit all your needs. For instance:

<windows:UniversalConverter x:Key="BooleanToVisibilityConverter">
    <cfr:UniversalConverter.Switch>
        <cfr:UniversalConverterCase Operator="Equal" Value="True" C
  onvertedValue="Visible" />
        <cfr:UniversalConverterCase Operator="Equal" Value="False" 
  ConvertedValue="Collapsed" />
    </cfr:UniversalConverter.Switch>
</cfr:UniversalConverter>

As a C# switch you can set a default value:

<cfr:UniversalConverter x:Key="BooleanToVisibilityConverter" DefaultValue="Visible">
    <cfr:UniversalConverter.Switch>
        <cfr:UniversalConverterCase Operator="Equal" Value="False" 
  ConvertedValue="Collapsed" />
    </cfr:UniversalConverter.Switch>
</cfr:UniversalConverter>

There are currently 13 operators:

  • Equal,
  • NotEqual,
  • GreaterThan,
  • GreaterThanOrEqual,
  • LesserThan,
  • LesserThanOrEqual,
  • Between: minimum and maximum value included => [min:max[,
  • StartsWith,
  • EndsWith,
  • Contains,
  • IsType: type match exactly,
  • IsOfType: type or direved types,
  • JavaScript: Yes, you can use JavaScript to evaluate a condition!

And some options:

  • StringComparison
  • Trim
  • Nullify

Here’s a list of examples using different operators:

Check if a string contains NewLine using JavaScript

<cfr:UniversalConverter x:Key="HasMultipleLinesConverter" DefaultValue="False">
    <cfr:UniversalConverter.Switch>
        <!--look for a CR or LF in the string string-->
        <cfr:UniversalConverterCase Value="/\r|\n/.exec(Value)!=null" 
  ConvertedValue="True" Operator="Javascript" />
    </cfr:UniversalConverter.Switch>
</cfr:UniversalConverter>

Set error message background and foreground color

<cfr:UniversalConverter x:Key="ErrorTextBackgroundConverter" DefaultValue="Red">
    <cfr:UniversalConverter.Switch>
        <cfr:UniversalConverterCase Value="" ConvertedValue="Transparent" />
    </cfr:UniversalConverter.Switch>
</cfr:UniversalConverter>
<cfr:UniversalConverter x:Key="ErrorTextForegroundConverter" DefaultValue="White">
    <cfr:UniversalConverter.Switch>
        <cfr:UniversalConverterCase Value="" ConvertedValue="Black" />
    </cfr:UniversalConverter.Switch>
</cfr:UniversalConverter>

Test if a value is over 21

<cfr:UniversalConverter x:Key="IsOver21Converter" DefaultValue="false">
    <cfr:UniversalConverter.Switch>
        <cfr:UniversalConverterCase Operator="GreaterThanOrEqual" Value="21" 
  ConvertedValue="true" Options="Convert" />
    </cfr:UniversalConverter.Switch>
</cfr:UniversalConverter>

Is teenager

<cfr:UniversalConverter x:Key="IsTeenagerConverter" DefaultValue="false">
    <cfr:UniversalConverter.Switch>
        <cfr:UniversalConverterCase Operator="Between" MinimumValue="13" 
  MaximumValue="20" ConvertedValue="true" Options="Convert" />
    </cfr:UniversalConverter.Switch>
</cfr:UniversalConverter>

Compare types

<cfr:UniversalConverter x:Key="TypeConverter" DefaultValue="false">
    <cfr:UniversalConverter.Switch>
        <cfr:UniversalConverterCase Operator="IsType" Value="System.String" 
  ConvertedValue="Type = String" />
        <cfr:UniversalConverterCase Operator="IsType" Value="System.Int32" 
  ConvertedValue="Type = int" />
        <cfr:UniversalConverterCase Operator="IsOfType" 
  Value="BaseClass, MyAssembly" ConvertedValue="Type is of type BaseClass" />
    </cfr:UniversalConverter.Switch>
</cfr:UniversalConverter>

Is empty

<cfr:UniversalConverter x:Key="IsEmptyConverter" DefaultValue="Not empty">
    <cfr:UniversalConverter.Switch>
        <cfr:UniversalConverterCase Operator="Equal" Options="Trim, Nullify" 
  ConvertedValue="Empty" />
    </cfr:UniversalConverter.Switch>
</cfr:UniversalConverter>

<TextBox x:Name="TextBox"/>
<TextBlock Text="{Binding ElementName=TextBox, Path=Text, 
  Converter={StaticResource IsEmptyConverter}}" />

If you need more examples, please let us know. Our team will be happy to help you J.

Happy converting,

The R&D team

Azure Cache Manager and Redis Cache Manager

January 27, 2015 Leave a comment

CodeFluent Entities allows to cache request results by using the Cache sub-producer:

CodeFluent entities provides out of the box 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).

Microsoft Azure introduces two cache services: Azure Managed Cache Service and Azure Redis cache (currently in preview).

Azure Cache is a family of distributed, in-memory, scalable solutions that enables you to build highly scalable and responsive applications by providing you super-fast access to your data. We offer the following types of Azure Cache:

  • Azure Redis Cache: Built on the open source Redis cache. This is a dedicated service, currently in Preview.
  • Managed Cache Service: Built on App Fabric Cache. This is a dedicated service, currently in General Availability.
  • In-Role Cache: Built on App Fabric Cache. This is a self-hosted cache, available via the Azure SDK.

Source: http://azure.microsoft.com/en-us/services/cache/

CodeFluent Entities already provide support some Azure features such as Azure Table and Azure Blob Storage, and we decided to continue our efforts to help our customers to use Microsoft Azure. This is why we release two new cache managers:

  • Redis Cache Manager
  • Azure Cache Manager

How to use Azure Redis Cache?

Download the Redis CacheManager from GitHub and add it to your project. You also need to add the following NuGet package: StackExchange.Redis.

Now you can change the cache producer configuration:

Then build the model.

Finally you have to configure the cache manager with the configuration file (app.config or web.config) to use your Redis server:

<appSettings>
    <add key="SoftFluent.Samples.RedisCache.Caching.RedisCacheManager.Configuration"
 value="sample.redis.cache.windows.net,allowAdmin=true,ssl=true,password=password" />

    <add key="SoftFluent.Samples.RedisCache.Caching.LocaleRedisCacheManager.Configuration"
 value="sample.redis.cache.windows.net,allowAdmin=true,ssl=true,password=password" />
</appSettings>

Note: if you use the Localization Aspect, you have to use SoftFluent.Samples.AzureCache.Caching.LocaleRedisCacheManager.

How to use Azure Cache Service and In-RoleCache?

Managed Cache Service and In-Role Cache use the same API, so you can use the same cache manager.

Download the CacheManager from GitHub and add it to your project. You also need to add the following NuGet package: Microsoft.WindowsAzure.Caching. Now you can change the cache producer configuration:

Then build the model.

Finally you have to configure the azure cache client: http://msdn.microsoft.com/en-us/library/azure/gg278346.aspx.

If you are not using the “default” cache, you can set the client name and cache name in the configuration file (app.config or web.config):

<appSettings>
    <add key="SoftFluent.Samples.AzureCache.Caching.AzureCacheManager.ClientName"
  value="default"/>

    <add key="SoftFluent.Samples.AzureCache.Caching.LocaleAzureCacheManager.CacheName"
  value="default"/>
</appSettings>

Note: if you use the Localization Aspect, you have to use SoftFluent.Samples.AzureCache.Caching.LocaleAzureCacheManager.

If you think we can add some useful functionalities to CodeFluent Entities, please share your idea on the forum.

Happy caching,

The R&D Team

Categories: Cache Tags: , ,

How to parse a command line?

January 16, 2015 1 comment

The CodeFluent Runtime offers to applications a clean and concise class for manipulating command line arguments and related tasks. Add the nugget package and refers the CommandLineUtilities class.

This class parses your command line arguments, find all parameters starting with – or / and all the values linked. I assumed that a value could be separated from a parameter with a : or a =.

During this article we are going to simulate this execution:

/Program.exe –ProductName:Word /SendEmail=true -amount:10.5

GetArgument

Gets a positioned argument from the command line and convert it to the type of the default value. If the argument is not found or if the value cannot be converted to the expected type, it returns the default value (internally it uses ConvertUtilities).

CommandLineUtilities.GetArgument(name:"ProductName", defaultValue:string.Empty); // -> “Word”
CommandLineUtilities.GetArgument(name:"ProductName", defaultValue:0); // -> 0
CommandLineUtilities.GetArgument(name:"SendEmail", defaultValue:false); // -> True
CommandLineUtilities.GetArgument("amount", double.MaxValue, new CultureInfo("en-US")); // -> 10.5D

HasArgument

Determines whether the argument is specified in the command line.

CommandLineUtilities.HasArgument(name:"ProductName"); // -> True
CommandLineUtilities.HasArgument(name:"debug"); // -> false

NamedArguments

List all arguments, the name will be the key.

// -> {{“ ProductName”,”Word”},{“SendEmail”,”true”}}
CommandLineUtilities.NamedArguments;

HelpRequested

Gets a value indicating whether help was requested.

// /Progam.exe /HELP
CommandLineUtilities.HelpRequested; // -> True


Happy CLI-ing !

The R&D Team.

Custom Naming Convention

January 8, 2015 Leave a comment

Since CodeFluent Entities infers a meta-model from your model, before any producer is called to generate a single line of code, a full representation of your application is in-memory. Thanks to this inference step and the resulting meta-model, developers can apply application wide changes.

One of the possible application wide changes is to change the way all database objects are named through a naming convention. By default a set of naming conventions are provided by CodeFluent Entities:

  • FormatNamingConvention
  • LowerCaseNamingConvention
  • UpperCaseNamingConvention
  • DecamelizeNamingConvention
  • DecamelizeLowerCaseNamingConvention
  • DecamelizeUpperCaseNamingConvention

And you can also implement your own naming convention to fit your needs as we’ll see in this post.

Create the custom Naming Convention

The naming convention is a class so we create a class library project and add references to

  • CodeFluent.Runtime.dll
  • CodeFluent.Model.dll
  • CodeFluent.Model.Common.dll

Those DLL are located in the installation folder of CodeFluent Entities.

Create a class that implements IProjectNamingConvention or inherits from an existing Naming Convention:

using System.Collections;
using CodeFluent.Model.Common.Naming;
using CodeFluent.Model.Naming;
using CodeFluent.Model.Persistence;

namespace SoftFluent.Samples.CustomNamingConvention
{
    public class MyNamingConvention : FormatNamingConvention
    {
        public override string GetName(INamedObject obj, IDictionary context)
        {
            var procedure = obj as Procedure;
            if (procedure != null)
            {
                if (procedure.Table != null &&
                    procedure.Table.Entity != null &&
                    procedure.Table.Entity.Store != null)
                {
                    return procedure.Table.Entity.Store.Name + "_" + base.GetName(obj, context);
                }

                if (procedure.Method != null &&
                    procedure.Method.Entity != null &&
                    procedure.Method.Entity.Store != null)
                {
                    return procedure.Method.Entity.Store.Name + "_" + base.GetName(obj, context);
                }
            }

            return base.GetName(obj, context);
        }
    }
}

This naming convention prefix parameter name with the store name

Setting the naming convention

Add a reference in the CodeFluent entities project to your class library project:

Now you can open model project properties and set the naming convention with its full type name:

 

That’s all J Now all procedures are prefixed by the store name:

Happy naming,

The R&D Team

What’s new with CodeFluent Entities 801?

December 19, 2014 Leave a comment

Today we release the build 801. This build includes lots of new features:

Cache Producer and array

 

The Cache Producer creates a unique key for each method call based on the method name and its parameter values:

cacheKey = SimpleCacheManager.BuildCacheKey("ad5a4755bc1df9345e1a73e2ae38",
                                             pageIndex, pageSize, 
                                             pageOptions, ids);

The BuildCacheKey method handles common parameter types such as String, Boolean, Integer, DateTime, etc. But it does not handle complex types such as array for the simple reason that there are many ways to handle them. We decided to let you handle those cases as you want depending of your context. We introduce a new optional parameter “Build Cache Key Method Name”:

The generated code will be:

cacheKey = CustomerCollection.CustomBuildCacheKey("ad5a4755bc1df9345e1a73e2ae38",
                                                   pageIndex, pageSize, 
                                                   pageOptions, ids);

This way you can create the key the way you want!

Use existing .NET enumeration and type

 

CodeFluent Entities can reuse existing .NET enumeration or .NET type. The modeler now lets you add those type on the surface:

The enumeration and all its values will be added to the surface:

The same apply with .NET type such as “System.Drawing.Point”

SQL Server Producer & “Nullable” Table Value Parameters

 

When you create a CFQL method with persistence nullable array parameter:

LOAD(guid[]
ids?) WHERE Id IN (@ids)

The SQL Server producer generates the following code:

DECLARE @_c_ids int; SELECT @_c_ids= COUNT(*) FROM @ids
IF(@_c_ids = 0)
BEGIN
    SELECT [Customer].[Customer_Id], [Customer].[Customer_FirstName], 
           [Customer].[Customer_LastName]
        FROM [Customer]
END
ELSE
BEGIN
    SELECT [Customer].[Customer_Id], [Customer].[Customer_FirstName], 
           [Customer].[Customer_LastName]
        FROM [Customer]
        WHERE [Customer].[Customer_Id] IN (SELECT * FROM @ids)
END

IS NULL is translated to Array is empty because TVP cannot be NULL. We think this check is the most logical in this case.

Starter Wizard

 

Starter wizard supports new project templates:

Pivot Script improvements

 

The SQL Server Pivot Script producer has many new options to select what to produce (tables, procedures, functions, etc.):

Sorting Project Resources

 

Project resources grid allows to sort rows by name, class or value:

Visual Studio 2015 Preview

 

As we mentioned this week, CodeFluent Entities now supports Visual Studio 2015 Preview.

codefluent2015

You can download this build here, or update your version using the Licensing tool. Remember that you can follow the latest new features and bug fixes of CodeFluent Entities subscribing to this RSS.

Happy downloading!

The R&D Team

Categories: News

Visual Studio 2015 Preview

December 15, 2014 Leave a comment

One month ago, we told you that CodeFluent Entities runs great on Visual Studio 2013 Community. The story continues and CodeFluent Entities now supports Visual Studio 2015 Preview.

visual studio 2015

Indeed, a preview of VS 2015 is available for those ready to dive into next-generation development tool. We’re especially excited to announce that you can create or open your CodeFluent Entities models directly from Visual Studio 2015 :

codefluent2015

You can learn more about the new features of Visual Studio 2015 Preview here:

You can download the latest version of CodeFluent Entities here, or update your version using the Licensing tool. Remember that you can follow the latest new features and bug fixes of CodeFluent Entities subscribing to this RSS.

Happy downloading,

The R&D Team

Categories: News Tags:

Multi-tenant using multiple Schemas

December 4, 2014 Leave a comment

In this post we will see how to create a multi-tenant application using one schema by tenant. The idea is to create one CodeFluent Entities model and use it to generate as many database schemas as needed.

The generated database will contains one schema by tenant:

But to keep the usage as simple as possible, only one Business Object Model is generated. The schema is selected at runtime:

Note: The following procedure uses the Custom meta-compiler host feature which is available only with CodeFluent Entities Personal or Ultimate

Generate the database

 

The idea is to keep the model untouched, so we create a console application which:

  • Load the CodeFluent Entities model
  • Change entity schema in memory (the original model won’t be changed)
  • Generate code
class Program
{
    private static string _schema;
    private static string _projectPath;
    private static bool _changeTargetDirectory;

    static void Main()
    {
        _projectPath = CommandLineUtilities.GetArgument("path", (string)null) ?? CommandLineUtilities.GetArgument(0, (string)null);
        _schema = ConvertUtilities.Nullify(CommandLineUtilities.GetArgument("schema", (string)null) ?? CommandLineUtilities.GetArgument(1, (string)null), true);
        _changeTargetDirectory = CommandLineUtilities.GetArgument("changeTargetDirectory", true);

        // Load the model
        Project project = new Project();
        project.Entities.ListChanged += Entities_ListChanged; // Change schema as soon as the entity is loaded
        project.Load(_projectPath, ProjectLoadOptions.Default);

        // Update producer target directory
        if (!string.IsNullOrEmpty(_schema) && _changeTargetDirectory)
        {
            foreach (var producer in project.Producers)
            {
                var sqlServerProducer = producer.Instance as SqlServerProducer;
                if (sqlServerProducer != null)
                {
                    sqlServerProducer.Production += SqlServerProducer_Production;
                }
            }
        }

        // Generate code
        project.Produce();
    }

    private static readonly HashSet<IProducer> _producers = new HashSet<IProducer>();
    private static void SqlServerProducer_Production(object sender, ProductionEventArgs e)
    {
        SqlServerProducer sqlServerProducer = sender as SqlServerProducer;
        if (sqlServerProducer == null)
            return;

        if (_producers.Contains(sqlServerProducer))
            return;

        sqlServerProducer.EditorTargetDirectory = Path.Combine(sqlServerProducer.EditorTargetDirectory, _schema);
        _producers.Add(sqlServerProducer);
    }

    private static void Entities_ListChanged(object sender, ListChangedEventArgs e)
    {
        if (e.ListChangedType != ListChangedType.ItemAdded)
            return;

        var entityCollection = sender as EntityCollection;
        if (entityCollection == null || e.NewIndex < 0 || e.NewIndex >= entityCollection.Count)
            return;

        Entity entity = entityCollection[e.NewIndex];
        Console.WriteLine("Changing schema of entity '{0}' from '{1}' to '{2}'", entity.ClrFullTypeName, entity.Schema, _schema);
        entity.Schema = _schema;
    }
}

That’s it… We can now use this console application to generate the persistence layer:

SoftFluent.MultiTenantGenerator.exe "Sample.Model\Sample.Model.cfxproj" "SoftFluent"
SoftFluent.MultiTenantGenerator.exe "Sample.Model\Sample.Model.cfxproj" "Contoso"

You can create a script to call program this for each tenant.

Select the right tenant at runtime

 

We generate only one Business Object Model (BOM) for all tenants. This BOM access by default to the schema specified in the CodeFluent Entities model. In our case we want to change this schema at runtime depending on the context (user, Uri, etc.).

To access the database, the generated code use CodeFluentPersistence:

CodeFluentPersistence has a hook system (ICodeFluentPersistenceHook) that allows to change the default CodeFluentPersistence behavior. In our case the idea is to change the CreateStoredProcedureCommand method behavior to use the right schema. Here’s the code:

public class SchemaPersistenceHook : BasePersistenceHook
{
    private bool _processing = false;
    public override bool BeforeCreateStoredProcedureCommand(string schema, string package, string intraPackageName, string name)
    {
        if (_processing)
            return false;

        _processing = true;
        try
        {
            string currentSchema = GetTenant();
            Persistence.CreateStoredProcedureCommand(currentSchema, package, intraPackageName, name);
        }
        finally
        {
            _processing = false;
        }

        return true;
    }

    public virtual string GetTenant()
    {
            // TODO: Implement your own logic
            return CodeFluentUser.Current.UserDomainName;
    }
}

Finally we have to declare our persistence hook in the configuration file so CodeFluentPersistence will use it automatically:

<?xml version="1.0" encoding="utf-8" ?>
<configuration>
  <configSections>
    <section name="Sample" type="CodeFluent.Runtime.CodeFluentConfigurationSectionHandler, CodeFluent.Runtime" />
  </configSections>

  <Sample persistenceHookTypeName="Sample.SchemaPersistenceHook, Sample" />
</configuration>

That’s it. With a few lines of codes and the power of CodeFluent Entities you can change the default behavior to fit your needs. Can you do the same with other products?

The source code is available on our GitHub repository.

Happy tenanting,

The R&D team

Follow

Get every new post delivered to your Inbox.

Join 56 other followers