Sunday, May 16, 2010

Managed Extensibility Framework .Net 4.0

In the past, I have worked with projects that involved extensibility . I have been on projects that lets the functionality of the application to be extended. To achieve this in Microsoft.Net framework we have System.AddIn (AddIn pipeline), VSTA (Visual Studio tools for Application) Applications and Component Model. Open source ventures such as Spring.Net , Unity framework , Structure Map etc.

Previously I have blogged about Unity and AddIn pipeline development to achieve functional extensibility . With the release of .Net 4.0 , new kid is on the block MEF (Managed Extensibility Framework). This framework enables us to write extensible application using the Attribute Programming model, although framework is not restricted to a particular programming model and is itself fully extensible. When I began exploring the framework I found it simple and light weight . There was not that much effort as it took in System.AddIn development, to develop application, from either AddIn developer or hosting application side.

Microsoft them self made Visual Studio 2010 Editor extensible by using MEF. We can write extensions for VS2010 code editor and there are great samples available at CodePlex.

MEF attribute model allows as to extend application by using attributes on the parts, that we want to be composed dynamically. In .Net 4.0 System.Component Model.Composition.dll is the assembly to be referenced to start developing MEF application. Namespaces to be used are : -

using System.ComponentModel.Composition;
using System.ComponentModel.Composition.Hosting;

In MEF the component that we want to take part in composition are called parts.Parts are the component on which the attributes are applied. We can apply attribute to the part to make it available for other parts to consume and attribute to request service of parts.

Export attribute is applied on the parts the we want to expose.
Import attribute is applied on the property or constructor of the parts, that wants the services of exported parts. Contracts are the identifiers of the Import and Export attributes. For example :--


public interface IStockService
{
}

[Export(typeof(IStockService))]
public class BSE : IStockService
{
}

[Export(typeof(IStockService))]
public class LSE : IStockService
{
}

[Export(typeof(IStockService))]
public class NSE : IStockService
{
}

public class MyStockApp
{
[ImportMany]
public IEnumerable<IStockService> StockService
{
get;
set;
}
}




.

We can also have multiple imports , all we have to do is mark property by ImportMany.
After we have defined our parts , we need code to initiate the parts and map importers to exporters. To do this we need a catalog to discover the parts , parts can be discovered from a assembly, assemblies in a directory, from specific type . MEF provide various catalogs :- AssemblyCatalog, TypeCatalog, DirectoryCatalog ,AggregateCatalog etc. Next we need container that composes all the parts , when we call compose method.


AssemblyCatalog catalog =
new AssemblyCatalog(System.Reflection.Assembly.GetExecutingAssembly());
CompositionContainer container = new CompositionContainer(catalog);
container.ComposeParts(this);


.

By default all the export parts are singleton, meaning they will have same instance for all the importing parts. But this features can be controlled by partCreationPolicies. We can provide new instance of export to each import.


[Export(typeof(IStockService))]
[PartCreationPolicy(System.ComponentModel.Composition.CreationPolicy.NonShared) ]
//[PartCreationPolicy(System.ComponentModel.Composition.CreationPolicy.Shared)]
public class BSE : IStockService
{
}



.

When we are importing many imports of a Contract , and want to decide which implementation to import , we can use ExportMetadata. ExportMetaData is applied on exports to separate them from other implementation.It takes a key and value as parameter to to its job.


public enum ServiceType
{
Furtures,
Corporate,
Forex
}

[InheritedExport ]
public class ServiceMetaData
{
public const string ServiceType = "ServiceType";
}

[Export(typeof(IStockService))]
[ExportMetadata(ServiceMetaData.ServiceType, ServiceType.Corporate)]
public class LSE : IStockService
{
}



.
After we have categorized our exports , at the importing end, we ImportMany in IEnumerable collection . We use System.Lazy to access the metadata and decide based on metadata which implementation to use. System.Lazy delays the initialization of the parts until the value of the part is actually accessed.



public class MyStockApp
{
[ImportMany]
public IEnumerable < System.Lazy <IStockService,
Dictionary< string,object >>> StockServices
{
get;
set;
}

public IStockService GetService()
{
var service =
from i in this.StockServices
where (ServiceType)i.Metadata[ServiceMetaData.ServiceType]
== ServiceType.Forex
select i.Value;

return (IStockService)service;
}

public void Compose()
{
AssemblyCatalog catalog =
new AssemblyCatalog(System.Reflection.Assembly.GetExecutingAssembly());
CompositionContainer container = new CompositionContainer(catalog);
container.ComposeParts(this);
}
}


.

[InheritedExport] can also be applied to the Export to define that the subclass of this Export will also provide export service. While importing many imports we can define [ImportMany(AllowRecomposition=true)], to define that all the new parts added to directory or assembly will be automatically discovered, composed and updated.

http://msdn.microsoft.com/en-us/magazine/ee291628.aspx

Friday, May 14, 2010

Garbage.Collector - 4.0

Managed memory management in .Net is done through Garbage Collector .It keeps track of all the used and unused memory through weak and strong references. With the release of .Net 4.0 ,G.C has been significantly enhanced. Lets see first the working of G.C and then what's new in .Net 4.0.

G.C traverses G.C roots and from roots it visit every object pointed by root and so on. This creates a object graph of objects that G.C maintains on heap and are marked as alive. All non referencing objects are freed and the memory compacted to avoid fragmentation.

G.C heap is allocated by the O.S and is the part of process working set. G.C heap is one continuous memory addresses block. To maintain the life time of objects G.C divides the heap in three generation Gen0,Gen1 and Gen2. Object that survives the G.C cycle are promoted to next generation.

Older the object its on lower memory addresses and newly allocated objects are on higher memory addresses. Size limits of each generation is limited and is dynamically changing to optimize the allocation, depending on the allocation rates.
Memory allocated to the generation is in segments and typically 16mb is assigned to the Gen0 and so on for Gen1, Gen2. New segments are only allocated to Gen1 and Gen2.
Older the object gets , it is promoted to the next generation and newly created objects are in Gen0. Performing G.C for Gen2 is expensive than for Gen0 and Gen1. So more objects we have in Gen1 and Gen2 , more time will they take to get deallocated.
Objects that are more than 85 KB in size are allocated on the Large Object Heap.

Most active heap generation is Gen0. G.C preforms collection and compactation in two ways :-

1) Full Collection that include the collection of all the
generations.

2) Partial Collections :- that include collection of ephemeral generation (Gen0 and Gen1).

Full collection is expensive, so CLR delays the G.C for full collection.
G.C collection is called when Gen0 reaches its threshold, GC.Collect() is called or system has low memory.

G.C can be divided into two types blocking G.C or Server G.C and Concurrent G.C or workstation G.C.

Server G.C is blocking G.C that means , when the G.C start the collection process all other managed threads are suspended for the application . After G.C has reclaimed the memory and finished the compaction of memory heap , all managed suspended threads are resumed.

In case of Concurrent G.C , we are allowed to allocate memory while the G.C is in progress, but this applies only to the full G.C. If its not the full G.C then its Ephemeral G.C (Gen0 and Gen1 G.C) , that means it is blocking G.C and not concurrent G.C . So , the server G.C and ephemeral G.C are always blocking G.C.

Concurrent G.C allows us to simultaneously allocate even if the full G.C is in progress. But if during the full G.C we exceeds the segment limit while doing allocation then we have to wait for the ephemeral G.C to be performed. So there is again issue of latency(Time period for which the application threads were suspended.).

In CLR 4.0 , there is the concept of the Background and Foreground G.C . Like concurrent G.C, when we are out of memory in ephemeral segment we do not have to wait for the another cycle of ephemeral G.C , but a foreground thread will be initiated to do ephemeral G.C , while the full G.C is in progress(Background G.C).So we can have both background full G.C going on along with foreground G.C for ephemeral generation. This reduces the latency time. As for now background G.C is only available for the workstation G.C and server G.C are still blocking G.C.

The G.C heap is allocated in segments and is part of the process working set.
When we allocate the memory for new objects and do enough allocation that one segment is full, now G.C will be allocated another segment by the O.S for new allocation. If both the segment are full and we haven't released objects of our application then these two segments are the committed memory from our process working set. Now if we start releasing the objects of our application, G.C will find unreferenced objects and will start collecting them. Memory will be freed and our process heap will have free memory available. But CLR may or may not release this free memory to the O.S , depending upon the memory emergency by the O.S.

CLR optimizes the memory management and can assume that application will be needing memory soon , resulting in free memory on process heap.

This free memory can be returned back to the O.S, if there is memory scarcity detected by O.S. This is why sometime we notice high memory working set in Task Manager but the indication of actual tied up memory is the memory committed.

http://blogs.msdn.com/maoni/archive/2008/11/19/so-what-s-new-in-the-clr-4-0-gc.aspx

http://blogs.msdn.com/salvapatuel/archive/2009/06/10/background-and-foreground-gc-in-net-4.aspx

Saturday, May 8, 2010

.Net 4.0 :- Memory Mapped Files

Until now managed code developers were oblivious to the delight of memory mapped files and its performance benifits. Now with the coming of .Net 4.0 CLR , its available to be explored. Managing dynamic memory on Windows NT is traditionally done by using Win32 API's. Various methods are provided in API to manage Global and process heap.

As for memory mapped files methods, they provide us the way to treat files on the disk as they were loaded in dynamic memory. Using memory mapped file we can map part or full file to the memory address in our process space.

Now read/write are as simple as doing it with dynamic memory. All memory related operation internally are handled by the Virtual memory manager.
It uses paging and caching to optimize the io operation.

This leads to the less actual hard disk read/write. Additionally we do not need to load whole file. Memory mapped files can be used to share a common memory between two processes. Common memory object is given a name and name is used by different processes to access it. Win 32 API exposes various method to achieve MMF like ,CreateFileMapping(),OpenFileMapping(),MapViewOfFile() etc.

For managed code developers we got it under System.IO .

using System.IO;
using System.IO.MemoryMappedFiles;

  //Process 1
private static void MMFileWrite()
{
MemoryMappedFileSecurity CustomSecurity =
new MemoryMappedFileSecurity();

MemoryMappedFile memFileObject =
MemoryMappedFile.CreateFromFile(
new FileStream(@"C:\MyMemMapFile.map",
FileMode.Create,FileAccess.ReadWrite,
FileShare.ReadWrite),
"MyMapFile", //Name
1024 * 1024, //Size
MemoryMappedFileAccess.ReadWrite,
CustomSecurity,
HandleInheritability.Inheritable,//Child processes
false);// Dispose filestream

using(MemoryMappedViewAccessor view
= memFileObject.CreateViewAccessor())
{
MyMemContent content =
content = new MyMemContent();
content.Id = 1;
content.High = 45;
content.Low = 39;
content.Bid = 43;
content.Close = 42;
view.Write(1,ref content);
}
}





//Process 2
private static void MMFileRead()
{
MemoryMappedFile memFileObject
= MemoryMappedFile.OpenExisting(
@"MyMapFile",
MemoryMappedFileRights.FullControl,
HandleInheritability.Inheritable);

using (MemoryMappedViewAccessor view
= memFileObject.CreateViewAccessor())
{
MyMemContent content =
content = new MyMemContent();
view.Read(1, out content);
}
}
Memory mapped file should have shared attribute so that , processes accessing it can read / write.
There is another thing , if we dispose the MemoryMappedFile object , then the file is no more accessible for read/write operation. Content to be written to the memory file should be of value type and if we are wrtting the custom structure to file then it should not contain any reference type.

Sunday, May 2, 2010

Assembly on a fly

Recently I was on a project that needed me to create assemblies on a fly from source code contained on the disk in simple txt files.
The way to go was CodeDom way.

This blog is all about CodeDom. We will see how to generate the assembly in memory from a simple .cs/txt file containing n number of classes.
Lets for example we have simple .cs file having a single class.


Class MyClass
{

public int MyId
{
get;
set;

}

public string MyName
{
get;
set;
}

public string MySSNO
{
get;
set;

}

public MyClass(int id, string name, string ssno)
{
this.MyId = id;
this.MyName = name;
this.MySSNo = ssno;

}

}


We have this class in .cs file on disk.

Namespaces to use for in memory assembly creation are:-

using System.CodeDom.Compiler;
using System.CodeDom;
using Microsoft.CSharp;


These namespaces contains the classes that we will use to compile our code and create in memory assembly.

Lets start with initializing these classes.


CodeDomProvider provider = new
Microsoft.CSharp.CSharpCodeProvider();
ICodeCompiler compiler = provider.CreateCompiler();
CompilerParameters parms = new CompilerParameters();


Now we will set the parameters for the compiler.

parms.GenerateExecutable = false;
parms.GenerateInMemory = true;
parms.IncludeDebugInformation = false;
parms.CompilerOptions = String.Format("/lib:\"{0}\"",
Path.Combine(Environment.GetFolderPath(Environment.SpecialFolder.ProgramFiles), @"Reference Assemblies\Microsoft\Framework\v3.0")) + String.Format(" /lib:\"{0}\"",
Path.Combine(Environment.GetFolderPath(Environment.SpecialFolder.ProgramFiles), @"Reference Assemblies\Microsoft\Framework\v3.5"));


If there are any assemblies that our code references we can add them as:-

parms.ReferencedAssemblies.Add("PresentationCore.dll");
parms.ReferencedAssemblies.Add("PresentationFramework.dll");
parms.ReferencedAssemblies.Add("System.dll");
parms.ReferencedAssemblies.Add("System.configuration.dll");
parms.ReferencedAssemblies.Add("System.Core.dll");
parms.ReferencedAssemblies.Add("System.Drawing.dll");
parms.ReferencedAssemblies.Add("System.Data.dll");
parms.ReferencedAssemblies.Add("System.XML.dll");
parms.ReferencedAssemblies.Add("WindowsBase.dll");


Next step is to read the .cs file content, i.e our source code.

string fileContent = string.Empty;
StreamReader reader = null;

using (FileStream csFileStream = new FileStream(filePath,
FileMode.Open, FileAccess.Read))
{
reader = new StreamReader(csFileStream);
fileContent = reader.ReadToEnd();
reader.Close();
}


After reading our source code as string , we will create a compile unit for out source code and compile it .

CodeCompileUnit compileUnit = new CodeSnippetCompileUnit
(fileContent);
CompilerResults results = compiler.CompileAssemblyFromDom(parms,
compileUnit);


We will check for any errors that came during the compilation.

//Report errors if any.
if (results.Errors.Count > 0)
{
CompilerErrorCollection errors = results.Errors;

for (int i = 0; i < errors.Count; i++ )
{
Console.WriteLine(errors[i].ErrorText.ToString());
}
}


if there are no errors during compilation , we have got our in memory assembly.

Assembly myIMemoryAssembly = results.CompiledAssembly;