2012-08-29

ECO Persistence Mapper per connection

The Enterprise Core Objects Persistence Mapper is a singleton which is used by all EcoSpace instances.  It’s purpose is to load mapping information from the DB when your app starts and to cache it, improving performance.

I needed a connection per client, all running within a single application.  This was a problem because once the PMP is created its connection string is tied to a single database.  So I had to come up with a new PersistenceMapperDynamicSharer component.  It is used on the EcoSpace to specify the PMapper type; additionally you can specify a connection string to use.

It works by dynamically creating a descendant class of your PersistenceMapperProvider at runtime, one for each connection string.


public class PersistenceMapperDynamicSharer : PersistenceMapperSharer
{
static ReaderWriterLockSlim Locker = new ReaderWriterLockSlim();
static Dictionary
<string, PersistenceMapperProvider> MapperProviders = new Dictionary<string, PersistenceMapperProvider>();

[Browsable(false)]
public string ConnectionString { get; set; }

public override IPersistenceMapper GetPersistenceMapper(ITypeSystemService typeSystemService)
{
return GetPersistenceMapperProvider().GetPersistenceMapper(typeSystemService);
}

public override void ReturnPersistenceMapper(IPersistenceMapper persistenceMapper)
{
GetPersistenceMapperProvider().ReturnPersistenceMapper(persistenceMapper);
}

PersistenceMapperProvider GetPersistenceMapperProvider()
{
//No connection string = default mapper provider
if (string.IsNullOrEmpty(ConnectionString))
return PersistenceMapperProvider.GetInstance(MapperProviderType);

PersistenceMapperProvider result;
Locker.EnterUpgradeableReadLock();
try
{
if (MapperProviders.TryGetValue(ConnectionString, out result))
return result;
Locker.EnterWriteLock();
try
{
var mapperType = CreateNewPersistenceMapperProviderType();
result = (PersistenceMapperProvider)Activator.CreateInstance(mapperType);
((IDynamicallySharedPersistenceMapper)result).SetConnectionString(ConnectionString);
MapperProviders[ConnectionString] = result;
}
finally
{
Locker.ExitWriteLock();
}
}
finally
{
Locker.ExitUpgradeableReadLock();
}
return result;
}

Type CreateNewPersistenceMapperProviderType()
{
string guid = Guid.NewGuid().ToString();
var assemblyName = new AssemblyName(guid);
var assemblyBuilder = AppDomain.CurrentDomain.DefineDynamicAssembly(
assemblyName,
System.Reflection.Emit.AssemblyBuilderAccess.Run);
var moduleBuilder = assemblyBuilder.DefineDynamicModule(guid);
var typeBuilder = moduleBuilder.DefineType(
guid,
TypeAttributes.Class | TypeAttributes.Public,
MapperProviderType);
return typeBuilder.CreateType();
}
}


On my EcoSpace I have a method called ActivateWithConnectionString which I can use whenever I need to activate the EcoSpace connecting to a connection string OTHER than the default…



public void ActivateWithConnectionString(string connectionString)
{
persistenceMapperDynamicSharer1.ConnectionString = connectionString;
Active = true;
}


And on my PersistenceMapperProvider I need to implement IDynamicallySharedPersistenceMapper like so…



void IDynamicallySharedPersistenceMapper.SetConnectionString(string connectionString)
{
sqlConnection1.ConnectionString = connectionString;
}


Now I can benefit from the performance gains from the singleton-pattern implemented by PersistenceMapperProvider and connect to different databases.

PropertyChangedEventHandler is not marked as serializable

My data-transfer-objects implement INotifyPropertyChanged, which was giving me a problem whenever I tried to serialise them over a Remoting session.  If you try to add [NonSerialized] to the event you get an error informing you that you can only apply this attribute to fields, and not properties.

The solution is pretty simple, I think the .NET compiler should do this by default.

[NonSerialized]
PropertyChangedEventHandler propertyChanged;
public event PropertyChangedEventHandler PropertyChanged
{
add { propertyChanged += value; }
remove { propertyChanged -= value; }
}

Partial declarations of must not specify different base classes

I wanted to use a common base class for a set of UserControls in my WPF application, but when I changed the class’s ancestor in the code file and compiled I would get the error

“Partial declarations of must not specify different base classes”

This is because when you compile a WPF application Visual Studio generates a partial class in a code-behind file automatically, the base type specified is always “UserControl”.  To solve this problem change your XAML from this

 

<UserControl
x:Class="MyApp.MyControl"
/>


To this



<local:SomeBaseTypeYouWantToUse
x:Class="MyApp.MyControl"
xmlns:local
="clr-namespace:NameSpace.To.Your.BaseClass"
/>

A WebServer for MonoTouch that also parses posted form data (HttpListenerRequest)

I found a few examples of web servers for MonoTouch but none of them parsed the data sent in a POST request.  I looked around the web and was unable to find any examples of how to achieve this.  So now that I’ve written it myself I’ve decided to share my own implementation.  This includes not only the code for processing the form post data but also for registering request handlers etc.

Here is an example of how you would use the web server

public BookUploadViewController()
:
base("BookUploadViewController", null)
{
RequestHandler
= new DefaultRequestHandler();
var defaultActionHandlerFactory
= new DefaultActionHandlerFactory();
RegisterActionHandlers(defaultActionHandlerFactory);
RequestHandler.AddActionHandlerFactory(defaultActionHandlerFactory);

WebServer
= new EmbeddedWebServer(RequestHandler);
}

void RegisterActionHandlers(DefaultActionHandlerFactory factory)
{
factory.RegisterHandler(
request
=> request.RawUrl == "/",
request
=> new IndexActionHandler(request)
);
factory.RegisterHandler(
request
=>
string.Compare(request.RawUrl, "/Upload", true) == 0 &&
string.Compare(request.HttpMethod, "POST", true) == 0,
request
=> new UploadActionHandler(request)
);
}

public override void ViewDidAppear(bool animated)
{
base.ViewDidAppear(animated);
StatusLabel.Text
= string.Format("Server listening on\r\nhttp://{0}:8080", GetIPAddress ());
WebServer.Start(
8080);
}

public override void ViewDidDisappear (bool animated)
{
base.ViewDidDisappear(animated);
WebServer.Stop();
}



And here are two app specific examples of request handlers



class IndexActionHandler : DefaultActionHandler
{
public IndexActionHandler(HttpListenerRequest request)
:
base(request)
{
}

public override ActionResult Execute()
{
var result
= new HtmlResult();
result.AppendLine(
"<html>");
result.AppendLine(
"<body>");
result.AppendLine(
"<h1>Upload an image</h1>");
result.AppendLine(
"<form action='/Upload' enctype='multipart/form-data' method='post'>");
result.AppendLine (
"<input name='Image' type='file'/><br/>");
result.AppendLine(
"<input name='Upload' type='submit' text='Upload'/>");
result.AppendLine(
"</form>");
result.AppendLine(
"</body>");
result.AppendLine(
"</html>");
return result;
}
}

class UploadActionHandler : DefaultActionHandler
{
public UploadActionHandler(HttpListenerRequest request)
:
base(request)
{
}

public override ActionResult Execute()
{
string errorMessage = null;
var file
= FormData.GetFile("Image");
if (file == null
|| file.FileData == null
|| file.FileData.Length == 0
|| string.IsNullOrEmpty(file.FileName))
errorMessage
= "No image uploaded";

if (errorMessage == null)
ProcessFile(file);

var result
= new HtmlResult();
result.AppendLine(
"<html>");
result.AppendLine(
"<body>");
if (errorMessage == null)
result.AppendLine(
"<h1>File uploaded successfully</h1>");
else
{
result.AppendLine(
"<h1>Error</h1>");
result.AppendLine(
"<h2>" + errorMessage + "</h2>");
}
result.AppendLine(
"</body>");
result.AppendLine(
"</html>");
return result;
}

void ProcessFile(MultiPartStreamFileValue postedFile)
{
string fileName = "Where to save the file";
using (var fileStream =
new FileStream(fileName, FileMode.Create, FileAccess.Write, FileShare.None))
{
fileStream.Write(postedFile.FileData,
0, postedFile.FileData.Length);
}
}
}


You can download the source code here

2009-06-05

Embarcadero should revive Bold for Delphi

I've recently been doing some work on a Bold for Delphi application. I am really quite surprised how much I am still impressed with this framework, it really was (and still is) so much ahead of its time.

Embarcadero really should revive this product and put it back into Delphi. They could make it a free addition to Delphi, or maybe even ship it with Delphi as an open source project.

Embarcadero! You have a great tool here, don't hide it away, use it!

2009-06-02

Bing

I searched for "mrpmorris" on bing.com recently.  Now on Google it would show the address of my blog as the first result, which is very relevant.  On Bing it showed a page from a web chat from over 3 years ago, not very impressive.

Not sure how long this photo will remain on the web for, but I found it quite interesting...