Archive

Archive for May, 2013

Using flags enumeration with ASP.NET MVC and CodeFluent Entities


 

Enumeration support

 
 
CodeFluent Entities provides full support of “enumeration” types and multi value enumerations (flag enumeration).
 

Enumeration support

Enumeration support


 
To declare a multi value enumeration, go to the enumeration type properties and set the, go to the enumeration type properties and set the Multi Value property to True.
 
Multi Value flag

Multi Value flag


 
And since the build version (646) you can set an enumeration value as the combination of other values (by their name).
 
Enumeration value

Enumeration value


 

Using enumeration values with ASP.NET MVC

 
Let’s use these concepts on an ASP.NET MVC application, I will use the model above as an example. I also have a MediaController with an Index action to list all Medias and an Edit action (Get and Post).
 
The default template for an enumeration value is a textbox, so if I write something like this:

@Html.EditorFor(m => m.MediaType)

 
I will get a textbox for my enumeration value.
 

Textbox for enumeration value

Textbox for enumeration value


 
This will work but the user will have to write a correct enumeration value, and unless each user knows all the possible enumeration values, this is not an acceptable solution.
 
It would be better to display a dropdown list instead. Let’s create a template named Choice.cshtml on the Views\Shared\EditorTemplates folder.
 

@model Enum
@{
var items = from object value in Enum.GetValues(Model.GetType())
select new { Value = value, Text = value.ToString() };
SelectList list = new SelectList(items, "Value", "Text", Model);
}
@Html.DropDownList("", list)

 
And now if we choose this as the template for our enumeration:
 

@Html.EditorFor(m => m.MediaType, "Choice")

 

Dropdown list for enumeration

Dropdown list for enumeration


 
This works fine and we can use the Choice.cshtml template for any enumeration type.
 

Using multi enumeration values with ASP.NET MVC

 
Let’s now do the same work for a multi value enumeration (flag enumeration). First we create a template named MultiChoice.cshtml on the Views\Shared\EditorTemplates folder.
 

@model Enum
@{
var items = from object value in Enum.GetValues(Model.GetType())
select new { Value = value, Text = value.ToString() };
IEnumerable selected = CodeFluent.Runtime.Utilities.ConvertUtilities.SplitEnumValues(Model);
MultiSelectList list = new MultiSelectList(items, "Value", "Text", selected);
}
@Html.DropDownList("", list, new { multiple = "multiple" })

 
We use here a method on the CodeFluent.Runtime.Utilities namespace to split a flag value into a list of enumeration values.
Let’s try it for our multi value enumeration.
 

@Html.EditorFor(m => m.ReleaseFormat, "MultiChoice")

 

Multiple dropdown list for enumeration

Multiple dropdown list for enumeration


 
This seems to work but it doesn’t, when I try to save my form, not all values are saved (from the flag multi value enumeration). This is because MVC does not bind correctly the multi value enumeration to my model.
 
We need to add a custom model binder (System.Web.Mvc.IModelBinder) and a value provider (System.Web.Mvc.IValueProvider). I will use some utilities classes that are used for the ASP.NET Web Site V2 producer, they can be found under the Templates folder in the CodeFluent Entities installation location (Program Files (x86)\SoftFluent\CodeFluent\Modeler\Templates\UI\AspNetMvc\Code\Utilities.cs.tpl). I will copy the content of the file in my ASP.NET MVC project filling the correct namespace. Don’t forget to add a reference to the CodeFluent.Runtime.Web assembly.
 
EntityBinder and EntityValueProvider

EntityBinder and EntityValueProvider


 
Finally, we register the EntityBinder and the EntityValueProviderFactory classes that we have just added. On the Application Start:
 

ValueProviderFactories.Factories.Add(new EntityValueProviderFactory());
ModelBinderProviders.BinderProviders.Add(new EntityBinder());

 
This time everything works great.
 
This post was inspired by the CodeFluent Entities templates when wondering what the ASP.NET Web Site V2 producer generates Winking smile.
 
 
Regards,
 
 
Pablo Fernandez Duran
 
 

Defining type mappers when importing a database using the Importer Wizard


You can use the Importer Wizard to import an existing data base as a CodeFluent Entities model. You can access the Importer from the Modeler or the solution explorer on your CodeFluent Entities project (right click).
 

The Importer Wizard

The Importer Wizard


 
The importer makes a mapping between the data source types and the CodeFluent Entities types. But, you may want to define your own mapping configuration for a given type.
 
To do that, go to the “advanced properties” of the Importer Wizard and select “Type Mappers” under the “Input Mapping” group and add your type mapper.
 
Type Mappers Configuration

Type Mappers Configuration


 
Add an Importer Type Mapper

Add an Importer Type Mapper


 
Let’s say I am importing a SQL Server 2012 database and I have a field of type “time” (more information about SQL Server 2012 type mapping here), well I would like to have a CLR type “TimeSpan” mapped to it. When I take a look at the imported model I can see that the mapped type is “time”, but when I generate the Business Object Model (BOM) layer I have a property of type “System.DateTime (nullable)”. This is because the SQL Server type “time” did not exist before the SQL Server 2008 version.
 
SQL Server time type

SQL Server time type


 
time to DateTime mapping

time to DateTime mapping


 
So we can define a “type mapper” for the SQL Server type “time”.
 
elapsedtime mapper

elapsedtime mapper


 

We could also have chosen “System.TimeSpan”, “timespan” or “duration” as the “Type Name”.

 
And now we have a CLR type “System.TimeSpan (nullable)” in our BOM for a SQL Server 2012 type “time”.
 

time to TimeSpan mapping

time to TimeSpan mapping


 

Remember that you can save your Importer Wizard configuration.

 
You can find more resources about the Importer Wizard here.
 
 
Regards,
 
Pablo Fernandez Duran
 
 

Creating a custom sub producer to only generate resources

May 16, 2013 6 comments

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):

class library project

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:

custom sub producer

Once added, it will appear under your BOM producer:

Custom Sub 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:
 

LOH using MemoryStream

LOH using MemoryStream


 
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:
 

LOH using ChunkedMemoryStream

LOH using ChunkedMemoryStream


 
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.
 

Patch producer

Patch producer


 
Add a Patch

Add a Patch


 
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.
 

Tracking User Name

Tracking User Name


 
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:
 
.cs Search Path

.cs Search Path


 
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”:
 
UserName replace

UserName replace


 
If I build my CodeFluent Entities, now I have:
 
UserName replaced

UserName replaced


 
 

Example 2

 
CodeFluent Entities adds some information on each generated file about the generation itself. For example, for SQL files:
 

Generation information

Generation information


 
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.
 
Generation information Patch

Generation information Patch


 
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:
 
Generation information Patched

Generation information Patched


 
Have fun.
 
Regards,
Pablo Fernandez Duran